src/misc/vlm.c : export the current playlist item's index for each instance
[vlc.git] / share / http / js / functions.js
1 /*****************************************************************************
2  * functions.js: VLC media player web interface
3  *****************************************************************************
4  * Copyright (C) 2005-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /* global variables */
25
26 var old_time = 0;
27
28 /**********************************************************************
29  * Misc utils
30  *********************************************************************/
31
32 /* XMLHttpRequest wrapper */
33 function loadXMLDoc( url, callback )
34 {
35   // branch for native XMLHttpRequest object
36   if ( window.XMLHttpRequest )
37   {
38     req = new XMLHttpRequest();
39     req.onreadystatechange = callback;
40     req.open( "GET", url, true );
41     req.send( null );
42   // branch for IE/Windows ActiveX version
43   }
44   else if ( window.ActiveXObject )
45   {
46     req = new ActiveXObject( "Microsoft.XMLHTTP" );
47     if ( req )
48     {
49       req.onreadystatechange = callback;
50       req.open( "GET", url, true );
51       req.send();
52     }
53   }
54 }
55
56 /* fomat time in second as hh:mm:ss */
57 function format_time( s )
58 {
59     var hours = Math.floor(s/3600);
60     var minutes = Math.floor((s/60)%60);
61     var seconds = Math.floor(s%60);
62     if( hours < 10 ) hours = "0"+hours;
63     if( minutes < 10 ) minutes = "0"+minutes;
64     if( seconds < 10 ) seconds = "0"+seconds;
65     return hours+":"+minutes+":"+seconds;
66 }
67
68 /* delete all a tag's children and add a text child node */
69 function set_text( id, val )
70 {
71     var elt = document.getElementById( id );
72     while( elt.hasChildNodes() )
73         elt.removeChild( elt.firstChild );
74     elt.appendChild( document.createTextNode( val ) );
75 }
76
77 /* set item's 'element' attribute to value */
78 function set_css( item, element, value )
79 {
80     for( var j = 0; j < document.styleSheets.length; j++ )
81     {
82         cssRules = document.styleSheets[j].cssRules;
83         for( var i = 0; i < cssRules.length; i++)
84         {
85             if( cssRules[i].selectorText == item )
86             {
87                 cssRules[i].style.setProperty( element, value, null );
88                 return;
89             }
90         }
91     }
92 }
93
94 /* get item's 'element' attribute */
95 function get_css( item, element )
96 {
97     for( var j = 0; j < document.styleSheets.length; j++ )
98     {
99         cssRules = document.styleSheets[j].cssRules;
100         for( var i = 0; i < cssRules.length; i++)
101         {
102             if( cssRules[i].selectorText == item )
103             {
104                 return cssRules[i].style.getPropertyValue( element );
105             }
106         }
107     }
108 }
109
110 function toggle_show( id )
111 {
112     var element = document.getElementById( id );
113     if( element.style.display == 'block' || element.style.display == '' )
114     {
115         element.style.display = 'none';
116     }
117     else
118     {
119         element.style.display = 'block';
120     }
121 }
122 function toggle_show_node( id )
123 {
124     var element = document.getElementById( 'pl_'+id );
125     var img = document.getElementById( 'pl_img_'+id );
126     if( element.style.display == 'block' || element.style.display == '' )
127     {
128         element.style.display = 'none';
129         img.setAttribute( 'src', 'images/plus.png' );
130         img.setAttribute( 'alt', '[+]' );
131     }
132     else
133     {
134         element.style.display = 'block';
135         img.setAttribute( 'src', 'images/minus.png' );
136         img.setAttribute( 'alt', '[-]' );
137     }
138 }
139
140 function show( id ){ document.getElementById( id ).style.display = 'block'; }
141
142 function hide( id ){ document.getElementById( id ).style.display = 'none'; }
143
144 function checked( id ){ return document.getElementById( id ).checked; }
145
146 function value( id ){ return document.getElementById( id ).value; }
147
148 function radio_value( name )
149 {
150     var radio = document.getElementsByName( name );
151     for( var i = 0; i < radio.length; i++ )
152     {
153         if( radio[i].checked )
154         {
155             return radio[i].value;
156         }
157     }
158     return "";
159 }
160
161 function check_and_replace_int( id, val )
162 {
163     var objRegExp = /^\d\d*$/;
164     if( value( id ) != ''
165         && ( !objRegExp.test( value( id ) )
166              || parseInt( value( id ) ) < 1 ) )
167         document.getElementById( id ).value = val;
168 }
169
170 function addslashes( str ){ return str.replace(/\'/g, '\\\''); }
171
172 function disable( id ){ document.getElementById( id ).disabled = true; }
173
174 function enable( id ){ document.getElementById( id ).disabled = false; }
175
176 function button_over( element ){ element.style.border = "1px solid #000"; }
177
178 function button_out( element ){ element.style.border = "1px solid #fff"; }
179
180 /* toggle show help under the buttons */
181 function toggle_btn_text()
182 {
183     if( get_css( '.btn_text', 'display' ) == 'none' )
184     {
185         set_css( '.btn_text', 'display', 'block' );
186     }
187     else
188     {
189         set_css( '.btn_text', 'display', 'none' );
190     }
191 }
192
193 /**********************************************************************
194  * Interface actions
195  *********************************************************************/
196 /* input actions */
197 function in_play()
198 {
199     var input = value('input_mrl');
200     if( value('sout_mrl') != '' )
201         input += ' '+value('sout_mrl');
202     var url = 'requests/status.xml?command=in_play&input='+escape( input );
203     loadXMLDoc( url, parse_status );
204     setTimeout( 'update_playlist()', 1000 );
205 }
206 function in_enqueue()
207 {
208     var input = value('input_mrl');
209     if( value('sout_mrl') != '' )
210         input += ' '+value('sout_mrl');
211     var url = 'requests/status.xml?command=in_enqueue&input='+escape( input );
212     loadXMLDoc( url, parse_status );
213     setTimeout( 'update_playlist()', 1000 );
214 }
215
216 /* playlist actions */
217 function pl_play( id )
218 {
219     loadXMLDoc( 'requests/status.xml?command=pl_play&id='+id, parse_status );
220     setTimeout( 'update_playlist()', 1000 );
221 }
222 function pl_pause()
223 {
224     loadXMLDoc( 'requests/status.xml?command=pl_pause', parse_status );
225 }
226 function pl_stop()
227 {
228     loadXMLDoc( 'requests/status.xml?command=pl_stop', parse_status );
229     setTimeout( 'update_playlist()', 1000 );
230 }
231 function pl_next()
232 {
233     loadXMLDoc( 'requests/status.xml?command=pl_next', parse_status );
234     setTimeout( 'update_playlist()', 1000 );
235 }
236 function pl_previous()
237 {
238     loadXMLDoc( 'requests/status.xml?command=pl_previous', parse_status );
239     setTimeout( 'update_playlist()', 1000 );
240 }
241 function pl_delete( id )
242 {
243     loadXMLDoc( 'requests/status.xml?command=pl_delete&id='+id, parse_status );
244     setTimeout( 'update_playlist()', 1000 );
245 }
246 function pl_empty()
247 {
248     loadXMLDoc( 'requests/status.xml?command=pl_empty', parse_status );
249     setTimeout( 'update_playlist()', 1000 );
250 }
251 function pl_sort()
252 {
253     /* FIXME */
254     loadXMLDoc( 'requests/status.xml?command=pl_sort', parse_status );
255     setTimeout( 'update_playlist()', 1000 );
256 }
257 function pl_shuffle()
258 {
259     loadXMLDoc( 'requests/status.xml?command=pl_random', parse_status );
260     setTimeout( 'update_playlist()', 1000 );
261 }
262 function pl_loop()
263 {
264     loadXMLDoc( 'requests/status.xml?command=pl_loop', parse_status );
265 }
266 function pl_repeat()
267 {
268     loadXMLDoc( 'requests/status.xml?command=pl_repeat', parse_status );
269 }
270
271 /* misc actions */
272 function volume_down()
273 {
274     loadXMLDoc( 'requests/status.xml?command=volume&val=-20', parse_status );
275 }
276 function volume_up()
277 {
278     loadXMLDoc( 'requests/status.xml?command=volume&val=%2B20', parse_status );
279 }
280 function fullscreen()
281 {
282     loadXMLDoc( 'requests/status.xml?command=fullscreen', parse_status );
283 }
284 function update_status()
285 {
286     loadXMLDoc( 'requests/status.xml', parse_status );
287 }
288 function update_playlist()
289 {
290     loadXMLDoc( 'requests/playlist.xml', parse_playlist );
291 }
292
293 /**********************************************************************
294  * Parse xml replies to XMLHttpRequests
295  *********************************************************************/
296 /* parse request/status.xml */
297 function parse_status()
298 {
299     if( req.readyState == 4 )
300     {
301         if( req.status == 200 )
302         {
303             var status = req.responseXML.documentElement;
304             var new_time = status.getElementsByTagName( 'time' )[0].firstChild.data;
305             if( old_time > new_time )
306                 setTimeout('update_playlist()',50);
307             old_time = new_time;
308             set_text( 'time', format_time( new_time ) );
309             set_text( 'length', format_time( status.getElementsByTagName( 'length' )[0].firstChild.data ) );
310             if( status.getElementsByTagName( 'volume' ).length != 0 )
311                 set_text( 'volume', Math.floor(status.getElementsByTagName( 'volume' )[0].firstChild.data/5.12)+'%' );
312             set_text( 'state', status.getElementsByTagName( 'state' )[0].firstChild.data );
313             if( status.getElementsByTagName( 'state' )[0].firstChild.data == "playing" )
314             {
315                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/pause.png' );
316             }
317             else
318             {
319                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/play.png' );
320             }
321         }
322         else
323         {
324             /*alert( 'Error! HTTP server replied: ' + req.status );*/
325         }
326     }
327 }
328
329 /* parse playlist.xml */
330 function parse_playlist()
331 {
332     if( req.readyState == 4 )
333     {
334         if( req.status == 200 )
335         {
336             var answer = req.responseXML.documentElement;
337             var playtree = document.getElementById( 'playtree' );
338             var pos = document.createElement( "div" );
339             var pos_top = pos;
340             var elt = answer.firstChild;
341             while( elt )
342             {
343                 if( elt.nodeName == "node" )
344                 {
345                     if( pos.hasChildNodes() )
346                         pos.appendChild( document.createElement( "br" ) );
347                     var nda = document.createElement( 'a' );
348                     pos.appendChild( nda );
349                     nda.setAttribute( 'href', 'javascript:toggle_show_node(\''+elt.getAttribute( 'id' )+'\');' );
350                     var ndai = document.createElement( 'img' );
351                     nda.appendChild( ndai );
352                     ndai.setAttribute( 'src', 'images/minus.png' );
353                     ndai.setAttribute( 'alt', '[-]' );
354                     ndai.setAttribute( 'id', 'pl_img_'+elt.getAttribute( 'id' ) );
355                     pos.appendChild( document.createTextNode( ' ' + elt.getAttribute( 'name' ) ) );
356                     var nd = document.createElement( "div" );
357                     pos.appendChild( nd );
358                     nd.setAttribute( 'class', 'pl_node' );
359                     nd.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
360                 }
361                 else if( elt.nodeName == "leaf" )
362                 {
363                     if( pos.hasChildNodes() )
364                     pos.appendChild( document.createElement( "br" ) );
365                     var pl = document.createElement( "a" );
366                     pos.appendChild( pl );
367                     pl.setAttribute( 'class', 'pl_leaf' );
368                     pl.setAttribute( 'href', 'javascript:pl_play('+elt.getAttribute( 'id' )+');' );
369                     pl.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
370                     if( elt.getAttribute( 'current' ) == 'current' )
371                     {
372                         pl.setAttribute( 'style', 'font-weight: bold;' );
373                         document.getElementById( 'nowplaying' ).textContent
374                             = elt.getAttribute( 'name' );
375                     }
376                     pl.setAttribute( 'title', elt.getAttribute( 'uri' ));
377                     pl.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
378                     pos.appendChild( document.createTextNode( ' ' ) );
379                     var del = document.createElement( "a" );
380                     pos.appendChild( del );
381                     del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
382                     del.appendChild( document.createElement( "img" ) );
383                     del = del.lastChild;
384                     del.setAttribute( 'src', 'images/delete_small.png' );
385                     del.setAttribute( 'alt', '(delete)' );
386                 }
387                 if( elt.firstChild )
388                 {
389                     elt = elt.firstChild;
390                     pos = pos.lastChild;
391                 }
392                 else if( elt.nextSibling )
393                 {
394                     elt = elt.nextSibling;
395                     pos = pos;
396                 }
397                 else
398                 {
399                     elt = elt.parentNode.nextSibling;
400                     pos = pos.parentNode;
401                 }
402             }
403             while( playtree.hasChildNodes() )
404                 playtree.removeChild( playtree.firstChild );
405             playtree.appendChild( pos_top );
406         }
407         else
408         {
409             /*alert( 'Error! HTTP server replied: ' + req.status );*/
410         }
411     }
412 }
413
414 /* parse browse.xml */
415 function parse_browse_dir( )
416 {
417     if( req.readyState == 4 )
418     {
419         if( req.status == 200 )
420         {
421             var answer = req.responseXML.documentElement;
422             var browser = document.getElementById( 'browser' );
423             var pos = document.createElement( "div" );
424             var elt = answer.firstChild;
425             while( elt )
426             {
427                 if( elt.nodeName == "element" )
428                 {
429                     pos.appendChild( document.createElement( "a" ) );
430                     pos.lastChild.setAttribute( 'class', 'browser' );
431                     if( elt.getAttribute( 'type' ) == 'directory' )
432                     {
433                         pos.lastChild.setAttribute( 'href', 'javascript:browse_dir(\''+addslashes(elt.getAttribute( 'path' ))+'\');');
434                     }
435                     else
436                     {
437                         pos.lastChild.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(elt.getAttribute( 'path' ))+'\');' );
438                     }
439                     pos.lastChild.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
440                     if( elt.getAttribute( 'type' ) == 'directory' )
441                     {
442                         pos.appendChild( document.createTextNode( ' ' ) );
443                         pos.appendChild( document.createElement( "a" ) );
444                         pos.lastChild.setAttribute( 'class', 'browser' );
445                         pos.lastChild.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(elt.getAttribute( 'path' ))+'\');');
446                         pos.lastChild.appendChild( document.createTextNode( '(select)' ) );
447                     }
448                     pos.appendChild( document.createElement( "br" ) );
449                 }
450                 elt = elt.nextSibling;
451             }
452             while( browser.hasChildNodes() )
453                 browser.removeChild( browser.firstChild );
454             browser.appendChild( pos );
455         }
456         else
457         {
458             /*alert( 'Error! HTTP server replied: ' + req.status );*/
459         }
460     }
461 }
462
463 /**********************************************************************
464  * Input dialog functions
465  *********************************************************************/
466 function hide_input( )
467 {
468     document.getElementById( 'input_file' ).style.display = 'none';
469     document.getElementById( 'input_disc' ).style.display = 'none';
470     document.getElementById( 'input_network' ).style.display = 'none';
471 }
472
473 /* update the input MRL using data from the input file helper */
474 /* FIXME ... subs support */
475 function update_input_file()
476 {
477     var mrl = document.getElementById( 'input_mrl' );
478
479     mrl.value = value( 'input_file_filename' );
480 }
481
482 /* update the input MRL using data from the input disc helper */
483 function update_input_disc()
484 {
485     var mrl = document.getElementById( 'input_mrl' );
486     var type = radio_value( "input_disc_type" );
487     var device = value( "input_disc_dev" );
488
489     check_and_replace_int( 'input_disc_title', 0 );
490     check_and_replace_int( 'input_disc_chapter', 0 );
491     check_and_replace_int( 'input_disc_subtrack', '' );
492     check_and_replace_int( 'input_disc_audiotrack', 0 );
493
494     var title = value( 'input_disc_title' );
495     var chapter = value( 'input_disc_chapter' );
496     var subs = value( 'input_disc_subtrack' );
497     var audio = value( 'input_disc_audiotrack' );
498
499     mrl.value = "";
500
501     if( type == "dvd" )
502     {
503         mrl.value += "dvd://";
504     }
505     else if( type == "dvdsimple" )
506     {
507         mrl.value += "dvdsimple://";
508     }
509     else if( type == "vcd" )
510     {
511         mrl.value += "vcd://";
512     }
513     else if( type == "cdda" )
514     {
515         mrl.value += "cdda://";
516     }
517
518     mrl.value += device;
519
520     if( title )
521     {
522         mrl.value += "@"+title;
523         if( chapter && type != "cdda" )
524             mrl.value += ":"+chapter;
525     }
526
527     if( type != "cdda" )
528     {
529         if( subs != '' )
530             mrl.value += " :sub-track="+subs;
531         if( audio != '' )
532             mrl.value += " :audio-track="+audio;
533     }
534
535 }
536
537 /* update the input MRL using data from the input network helper */
538 function update_input_net()
539 {
540     var mrl = document.getElementById( 'input_mrl' );
541     var type = radio_value( "input_net_type" );
542     
543     check_and_replace_int( 'input_net_udp_port', 1234 );
544     check_and_replace_int( 'input_net_udpmcast_port', 1234 );
545
546     mrl.value = "";
547
548     if( type == "udp" )
549     {
550         mrl.value += "udp://";
551         if( checked( 'input_net_udp_forceipv6' ) )
552             mrl.value += "[::]";
553         if( value( 'input_net_udp_port' ) )
554             mrl.value += ":"+value( 'input_net_udp_port' );
555     }
556     else if( type == "udpmcast" )
557     {
558         mrl.value += "udp://@"+value( 'input_net_udpmcast_address');
559         if( value( 'input_net_udpmcast_port' ) )
560             mrl.value += ":"+value( 'input_net_udpmcast_port' );
561     }
562     else if( type == "http" )
563     {
564         var url = value( 'input_net_http_url' );
565         if( url.substring(0,7) != "http://"
566             && url.substring(0,8) != "https://"
567             && url.substring(0,6) != "ftp://"
568             && url.substring(0,6) != "mms://"
569             && url.substring(0,7) != "mmsh://" )
570             mrl.value += "http://";
571         mrl.value += url;
572     }
573     else if( type == "rtsp" )
574     {
575         var url = value( 'input_net_rtsp_url' );
576         if( url.substring(0,7) != "rtsp://" )
577             mrl.value += "rtsp://";
578         mrl.value += url;
579     }
580
581     if( checked( "input_net_timeshift" ) )
582         mrl.value += " :access-filter=timeshift";
583 }
584
585 /**********************************************************************
586  * Sout dialog functions
587  *********************************************************************/
588 /* toggle show the full sout interface */
589 function toggle_show_sout_helper()
590 {
591     var element = document.getElementById( "sout_helper" );
592     if( element.style.display == 'block' )
593     {
594         element.style.display = 'none';
595         document.getElementById( "sout_helper_toggle" ).value = 'Full sout interface';
596     }
597     else
598     {
599         element.style.display = 'block';
600         document.getElementById( "sout_helper_toggle" ).value = 'Hide sout interface';
601     }
602 }
603
604 /* update the sout MRL using data from the sout_helper */
605 function update_sout()
606 {
607     var mrl = document.getElementById( 'sout_mrl' );
608     mrl.value = "";
609
610     check_and_replace_int( 'sout_http_port', 8080 );
611     check_and_replace_int( 'sout_mmsh_port', 8080 );
612     check_and_replace_int( 'sout_rtp_port', 1234 );
613     check_and_replace_int( 'sout_udp_port', 1234 );
614     check_and_replace_int( 'sout_ttl', 1 );
615
616     if( checked( 'sout_soverlay' ) )
617     {
618         disable( 'sout_scodec' );
619         disable( 'sout_sub' );
620     }
621     else
622     {
623         enable( 'sout_scodec' );
624         enable( 'sout_sub' );
625     }
626
627     var transcode =  checked( 'sout_vcodec_s' ) || checked( 'sout_acodec_s' )
628                   || checked( 'sout_sub' )      || checked( 'sout_soverlay' );
629
630     if( transcode )
631     {
632         mrl.value += ":sout=#transcode{";
633         var alot = false; /* alot == at least one transcode */
634         if( checked( 'sout_vcodec_s' ) )
635         {
636             mrl.value += "vcodec="+value( 'sout_vcodec' )+",vb="+value( 'sout_vb' )+",scale="+value( 'sout_scale' );
637             alot = true;
638         }
639         if( checked( 'sout_acodec_s' ) )
640         {
641             if( alot ) mrl.value += ",";
642             mrl.value += "acodec="+value( 'sout_acodec' )+",ab="+value( 'sout_ab' );
643             if( value( 'sout_channels' ) )
644                 mrl.value += ",channels="+value( 'sout_channels' );
645             alot = true;
646         }
647         if( checked( 'sout_soverlay' ) )
648         {
649             if( alot ) mrl.value += ",";
650             mrl.value += "soverlay";
651             alot = true;
652         }
653         else if( checked( 'sout_sub' ) )
654         {
655             if( alot ) mrl.value += ",";
656             mrl.value += "scodec="+value( 'sout_scodec' );
657             alot = true;
658         }
659         mrl.value += "}";
660     }
661
662     var output = checked( 'sout_display' ) + checked( 'sout_file' )
663                + checked( 'sout_http' )    + checked( 'sout_mmsh' )
664                + checked( 'sout_rtp' )     + checked( 'sout_udp' );
665
666     if( output )
667     {
668         if( transcode )
669             mrl.value += ":";
670         else
671             mrl.value += ":sout=#";
672         var aloo = false; /* aloo == at least one output */
673         var mux = radio_value( 'sout_mux' );
674         var ttl = parseInt( value( 'sout_ttl' ) );
675         if( output > 1 ) mrl.value += "duplicate{";
676         if( checked( 'sout_display' ) )
677         {
678             if( output > 1 ) mrl.value += "dst="
679             mrl.value += "display";
680             aloo = true;
681         }
682         if( checked( 'sout_file' ) )
683         {
684             if( aloo ) mrl.value += ",";
685             if( output > 1 ) mrl.value += "dst="
686             mrl.value += "std{access=file,mux="+mux+",dst="+value( 'sout_file_filename' )+"}";
687             aloo = true;
688         }
689         if( checked( 'sout_http' ) )
690         {
691             if( aloo ) mrl.value += ",";
692             if( output > 1 ) mrl.value += "dst="
693             mrl.value += "std{access=http,mux="+mux+",dst="+value( 'sout_http_addr' );
694             if( value( 'sout_http_port' ) )
695                 mrl.value += ":"+value( 'sout_http_port' );
696             mrl.value += "}";
697             aloo = true;
698         }
699         if( checked( 'sout_mmsh' ) )
700         {
701             if( aloo ) mrl.value += ",";
702             if( output > 1 ) mrl.value += "dst="
703             mrl.value += "std{access=mmsh,mux="+mux+",dst="+value( 'sout_mmsh_addr' );
704             if( value( 'sout_mmsh_port' ) )
705                 mrl.value += ":"+value( 'sout_mmsh_port' );
706             mrl.value += "}";
707             aloo = true;
708         }
709         if( checked( 'sout_rtp' ) )
710         {
711             if( aloo ) mrl.value += ",";
712             if( output > 1 ) mrl.value += "dst="
713             mrl.value += "std{access=rtp";
714             if( ttl ) mrl.value += "{ttl="+ttl+"}";
715             mrl.value += ",mux="+mux+",dst="+value( 'sout_rtp_addr' );
716             if( value( 'sout_rtp_port' ) )
717                 mrl.value += ":"+value( 'sout_rtp_port' );
718             if( checked( 'sout_sap' ) )
719             {
720                 mrl.value += ",sap";
721                 if( value( 'sout_sap_group' ) != '' )
722                 {
723                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
724                 }
725                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
726             }
727             mrl.value += "}";
728             aloo = true;
729         }
730         if( checked( 'sout_udp' ) )
731         {
732             if( aloo ) mrl.value += ",";
733             if( output > 1 ) mrl.value += "dst="
734             mrl.value += "std{access=udp";
735             if( ttl ) mrl.value += "{ttl="+ttl+"}";
736             mrl.value += ",mux="+mux+",dst="+value( 'sout_udp_addr' );
737             if( value('sout_udp_port' ) )
738                 mrl.value += ":"+value( 'sout_udp_port' );
739             if( checked( 'sout_sap' ) )
740             {
741                 mrl.value += ",sap";
742                 if( value( 'sout_sap_group' ) != '' )
743                 {
744                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
745                 }
746                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
747             }
748             mrl.value += "}";
749             aloo = true;
750         }
751         if( output > 1 ) mrl.value += "}";
752     }
753
754     if( ( transcode || output ) && checked( 'sout_all' ) )
755         mrl.value += " :sout-all";
756 }
757
758 /* reset sout mrl value */
759 function reset_sout()
760 {
761     document.getElementById('sout_mrl').value = value('sout_old_mrl');
762 }
763
764 /* save sout mrl value */
765 function save_sout()
766 {
767     document.getElementById('sout_old_mrl').value = value('sout_mrl');
768 }
769
770 /**********************************************************************
771  * Browser dialog functions
772  *********************************************************************/
773 /* only browse() should be called directly */
774 function browse( dest )
775 {
776     document.getElementById( 'browse_dest' ).value = dest;
777     browse_dir( document.getElementById( 'browse_lastdir' ).value );
778     show( 'browse' );
779 }
780 function browse_dir( dir )
781 {
782     document.getElementById( 'browse_lastdir' ).value = dir;
783     loadXMLDoc( 'requests/browse.xml?dir='+dir, parse_browse_dir );
784 }
785 function browse_path( p )
786 {
787     document.getElementById( value( 'browse_dest' ) ).value = p;
788     hide( 'browse' );
789     document.getElementById( value( 'browse_dest' ) ).focus();
790 }
791
792 /**********************************************************************
793  * Periodically update stuff in the interface
794  *********************************************************************/
795 function loop_refresh_status()
796 {
797     setTimeout( 'loop_refresh_status()', 1000 );
798     update_status();
799 }
800 function loop_refresh_playlist()
801 {
802     /* setTimeout( 'loop_refresh_playlist()', 10000 ); */
803     update_playlist();
804 }
805 function loop_refresh()
806 {
807     setTimeout( 'loop_refresh_status()', 1 );
808     setTimeout( 'loop_refresh_playlist()', 1 );
809 }
810