New http interface
[vlc.git] / share / http / functions.js
1 /*****************************************************************************
2  * functions.js: VLC media player web interface
3  *****************************************************************************
4  * Copyright (C) 2005 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 function loadXMLDoc( url, callback )
25 {
26   // branch for native XMLHttpRequest object
27   if ( window.XMLHttpRequest )
28   {
29     req = new XMLHttpRequest();
30     req.onreadystatechange = callback;
31     req.open( "GET", url, true );
32     req.send( null );
33   // branch for IE/Windows ActiveX version
34   }
35   else if ( window.ActiveXObject )
36   {
37     req = new ActiveXObject( "Microsoft.XMLHTTP" );
38     if ( req )
39     {
40       req.onreadystatechange = callback;
41       req.open( "GET", url, true );
42       req.send();
43     }
44   }
45 }
46
47 function format_time( s )
48 {
49     hours = Math.floor(s/3600);
50     minutes = Math.floor((s/60)%60);
51     seconds = s%60;
52     if( hours < 10 ) hours = "0"+hours;
53     if( minutes < 10 ) minutes = "0"+minutes;
54     if( seconds < 10 ) seconds = "0"+seconds;
55     return hours+":"+minutes+":"+seconds;
56 }
57
58
59 function in_play()
60 {
61     input = value('input_mrl');
62     if( value('sout_mrl') != '' )
63         input += ' '+value('sout_mrl');
64     url = 'requests/status.xml?command=in_play&input='+escape(input);
65     loadXMLDoc( url, parse_status );
66 }
67 function in_enqueue()
68 {
69     input = value('input_mrl');
70     if( value('sout_mrl') != '' )
71         input += ' '+value('sout_mrl');
72     url = 'requests/status.xml?command=in_enqueue&input='+escape(input);
73     loadXMLDoc( url, parse_status );
74 }
75 function pl_play( id )
76 {
77     loadXMLDoc( 'requests/status.xml?command=pl_play&id='+id, parse_status );
78 }
79 function pl_pause()
80 {
81     loadXMLDoc( 'requests/status.xml?command=pl_pause', parse_status );
82 }
83 function pl_stop()
84 {
85     loadXMLDoc( 'requests/status.xml?command=pl_stop', parse_status );
86 }
87 function pl_next()
88 {
89     loadXMLDoc( 'requests/status.xml?command=pl_next', parse_status );
90 }
91 function pl_previous()
92 {
93     loadXMLDoc( 'requests/status.xml?command=pl_previous', parse_status );
94 }
95 function pl_delete( id )
96 {
97     loadXMLDoc( 'requests/status.xml?command=pl_delete&id='+id, parse_status );
98 }
99 function pl_empty()
100 {
101     loadXMLDoc( 'requests/status.xml?command=pl_empty', parse_status );
102 }
103 function volume_down()
104 {
105     loadXMLDoc( 'requests/status.xml?command=volume&val=-20', parse_status );
106 }
107 function volume_up()
108 {
109     loadXMLDoc( 'requests/status.xml?command=volume&val=%2B20', parse_status );
110 }
111 function fullscreen()
112 {
113     loadXMLDoc( 'requests/status.xml?command=fullscreen', parse_status );
114 }
115 function update_status()
116 {
117     loadXMLDoc( 'requests/status.xml', parse_status );
118 }
119 function update_playlist()
120 {
121     loadXMLDoc( 'requests/playlist.xml', parse_playlist );
122 }
123
124 function parse_status()
125 {
126     if( req.readyState == 4 )
127     {
128         if( req.status == 200 )
129         {
130             status = req.responseXML.documentElement;
131             document.getElementById( 'time' ).textContent = format_time( status.getElementsByTagName( 'time' )[0].firstChild.data );
132             document.getElementById( 'length' ).textContent = format_time( status.getElementsByTagName( 'length' )[0].firstChild.data );
133             if( status.getElementsByTagName( 'volume' ).length != 0 )
134             document.getElementById( 'volume' ).textContent = Math.floor(status.getElementsByTagName( 'volume' )[0].firstChild.data/5.12)+"%";
135             document.getElementById( 'state' ).textContent = status.getElementsByTagName( 'state' )[0].firstChild.data;
136             if( status.getElementsByTagName( 'state' )[0].firstChild.data == "playing" )
137             {
138                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/pause.png' );
139             }
140             else
141             {
142                 document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/play.png' );
143             }
144         }
145         else
146         {
147             /*alert( 'Error! HTTP server replied: ' + req.status );*/
148         }
149     }
150 }
151
152 function parse_playlist()
153 {
154     if( req.readyState == 4 )
155     {
156         if( req.status == 200 )
157         {
158             answer = req.responseXML.documentElement;
159             playtree = document.getElementById( 'playtree' );
160             pos = playtree;
161             while( playtree.hasChildNodes() )
162                 playtree.removeChild( playtree.firstChild );
163             elt = answer.firstChild;
164             while( elt )
165             {
166                 if( elt.nodeName == "node" )
167                 {
168                     pos.appendChild( document.createElement( "div" ) );
169                     pos.lastChild.setAttribute( 'class', 'pl_node' );
170                     pos.lastChild.setAttribute( 'onclick', 'pl_play('+elt.getAttribute( 'id' )+');' );
171                     pos.lastChild.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
172                     pos.lastChild.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
173                 }
174                 else if( elt.nodeName == "leaf" )
175                 {
176                     pos.appendChild( document.createElement( "a" ) );
177                     pl = pos.lastChild;
178                     pl.setAttribute( 'class', 'pl_leaf' );
179                     pl.setAttribute( 'href', 'javascript:pl_play('+elt.getAttribute( 'id' )+');' );
180                     pl.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
181                     if( elt.getAttribute( 'current' ) == 'current' )
182                         pl.setAttribute( 'style', 'font-weight: bold;' );
183                     pl.setAttribute( 'title', elt.getAttribute( 'uri' ));
184                     pl.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
185                 }
186                 if( elt.firstChild )
187                 {
188                     elt = elt.firstChild;
189                     pos = pos.lastChild;
190                 }
191                 else if( elt.nextSibling )
192                 {
193                     elt = elt.nextSibling;
194                     pos = pos;
195                 }
196                 else
197                 {
198                     elt = elt.parentNode.nextSibling;
199                     pos = pos.parentNode;
200                 }
201             }
202         }
203         else
204         {
205             /*alert( 'Error! HTTP server replied: ' + req.status );*/
206         }
207     }
208 }
209
210 function set_css( item, element, value )
211 {
212     for( j = 0; j<document.styleSheets.length; j++ )
213     {
214         cssRules = document.styleSheets[j].cssRules;
215         for( i = 0; i<cssRules.length; i++)
216         {
217             if( cssRules[i].selectorText == item )
218             {
219                 cssRules[i].style.setProperty( element, value, null );
220                 return;
221             }
222         }
223     }
224 }
225
226 function get_css( item, element )
227 {
228     for( j = 0; j<document.styleSheets.length; j++ )
229     {
230         cssRules = document.styleSheets[j].cssRules;
231         for( i = 0; i<cssRules.length; i++)
232         {
233             if( cssRules[i].selectorText == item )
234             {
235                 return cssRules[i].style.getPropertyValue( element );
236             }
237         }
238     }
239 }
240
241 function toggle_btn_text()
242 {
243     if( get_css( '.btn_text', 'display' ) == 'none' )
244     {
245         set_css( '.btn_text', 'display', 'block' );
246     }
247     else
248     {
249         set_css( '.btn_text', 'display', 'none' );
250     }
251 }
252
253 function toggle_show_sout_helper()
254 {
255     element = document.getElementById( "sout_helper" );
256         if( element.style.display == 'block' )
257     {
258         element.style.display = 'none';
259         document.getElementById( "sout_helper_toggle" ).value = 'Full sout interface';
260     }
261     else
262     {
263         element.style.display = 'block';
264         document.getElementById( "sout_helper_toggle" ).value = 'Hide sout interface';
265     }
266 }
267
268 function toggle_show( id )
269 {
270     element = document.getElementById( id );
271     if( element.style.display == 'block' || element.style.display == '' )
272     {
273         element.style.display = 'none';
274     }
275     else
276     {
277         element.style.display = 'block';
278     }
279 }
280
281 function show( id )
282 {
283     document.getElementById( id ).style.display = 'block';
284 }
285 function hide( id )
286 {
287     document.getElementById( id ).style.display = 'none';
288 }
289
290 function hide_input( )
291 {
292     document.getElementById( 'input_file' ).style.display = 'none';
293     document.getElementById( 'input_disc' ).style.display = 'none';
294     document.getElementById( 'input_network' ).style.display = 'none';
295 }
296
297 function checked( id )
298 {
299     return document.getElementById( id ).checked;
300 }
301 function value( id )
302 {
303     return document.getElementById( id ).value;
304 }
305 function radio_value( name )
306 {
307     radio = document.getElementsByName( name );
308     for( i = 0; i<radio.length; i++ )
309     {
310         if( radio[i].checked )
311         {
312             return radio[i].value;
313         }
314     }
315     return "";
316 }
317 function disable( id )
318 {/* FIXME */
319     return document.getElementById( id ).value;
320 }
321
322 function check_and_replace_int( id, val )
323 {
324     var objRegExp = /^\d\d*$/;
325     if( value( id ) != ''
326         && ( !objRegExp.test( value( id ) )
327              || parseInt( value( id ) ) < 1 ) )
328         document.getElementById( id ).value = val;
329
330 }
331
332 function disable( id )
333 {
334     document.getElementById( id ).disabled = true;
335 }
336
337 function enable( id )
338 {
339     document.getElementById( id ).disabled = false;
340 }
341
342 function button_over( element )
343 {
344     element.style.border = "1px solid black";
345 }
346
347 function button_out( element )
348 {
349     element.style.border = "1px none black";
350 }
351
352 /* update the input MRL using data from the input file helper */
353 /* FIXME ... subs support */
354 function update_input_file()
355 {
356     mrl = document.getElementById( 'input_mrl' );
357
358     mrl.value = value( 'input_file_filename' );
359 }
360
361 /* update the input MRL using data from the input disc helper */
362 function update_input_disc()
363 {
364     mrl = document.getElementById( 'input_mrl' );
365     type = radio_value( "input_disc_type" );
366     device = value( "input_disc_dev" );
367
368     check_and_replace_int( 'input_disc_title', 0 );
369     check_and_replace_int( 'input_disc_chapter', 0 );
370     check_and_replace_int( 'input_disc_subtrack', '' );
371     check_and_replace_int( 'input_disc_audiotrack', 0 );
372
373     title = value( 'input_disc_title' );
374     chapter = value( 'input_disc_chapter' );
375     subs = value( 'input_disc_subtrack' );
376     audio = value( 'input_disc_audiotrack' );
377
378     mrl.value = "";
379
380     if( type == "dvd" )
381     {
382         mrl.value += "dvd://";
383     }
384     else if( type == "dvdsimple" )
385     {
386         mrl.value += "dvdsimple://";
387     }
388     else if( type == "vcd" )
389     {
390         mrl.value += "vcd://";
391     }
392     else if( type == "cdda" )
393     {
394         mrl.value += "cdda://";
395     }
396
397     mrl.value += device;
398
399     if( title )
400     {
401         mrl.value += "@"+title;
402         if( chapter && type != "cdda" )
403             mrl.value += ":"+chapter;
404     }
405
406     if( type != "cdda" )
407     {
408         if( subs != '' )
409             mrl.value += " :sub-track="+subs;
410         if( audio != '' )
411             mrl.value += " :audio-track="+audio;
412     }
413
414 }
415
416 /* update the input MRL using data from the input network helper */
417 function update_input_net()
418 {
419     mrl = document.getElementById( 'input_mrl' );
420     type = radio_value( "input_net_type" );
421     
422     check_and_replace_int( 'input_net_udp_port', 1234 );
423     check_and_replace_int( 'input_net_udpmcast_port', 1234 );
424
425     mrl.value = "";
426
427     if( type == "udp" )
428     {
429         mrl.value += "udp://";
430         if( checked( 'input_net_udp_forceipv6' ) )
431             mrl.value += "[::]";
432         if( value( 'input_net_udp_port' ) )
433             mrl.value += ":"+value( 'input_net_udp_port' );
434     }
435     else if( type == "udpmcast" )
436     {
437         mrl.value += "udp://@"+value( 'input_net_udpmcast_address');
438         if( value( 'input_net_udpmcast_port' ) )
439             mrl.value += ":"+value( 'input_net_udpmcast_port' );
440     }
441     else if( type == "http" )
442     {
443         url = value( 'input_net_http_url' );
444         if( url.substring(0,7) != "http://"
445             && url.substring(0,8) != "https://"
446             && url.substring(0,6) != "ftp://"
447             && url.substring(0,6) != "mms://"
448             && url.substring(0,7) != "mmsh://" )
449             mrl.value += "http://";
450         mrl.value += url;
451     }
452     else if( type == "rtsp" )
453     {
454         url = value( 'input_net_rtsp_url' );
455         if( url.substring(0,7) != "rtsp://" )
456             mrl.value += "rtsp://";
457         mrl.value += url;
458     }
459
460     if( checked( "input_net_timeshift" ) )
461         mrl.value += " :access-filter=timeshift";
462 }
463
464 /* update the sout MRL using data from the sout_helper */
465 function update_sout()
466 {
467     mrl = document.getElementById( 'sout_mrl' );
468     mrl.value = "";
469
470     check_and_replace_int( 'sout_http_port', 8080 );
471     check_and_replace_int( 'sout_mmsh_port', 8080 );
472     check_and_replace_int( 'sout_rtp_port', 1234 );
473     check_and_replace_int( 'sout_udp_port', 1234 );
474     check_and_replace_int( 'sout_ttl', 1 );
475
476     if( checked( 'sout_soverlay' ) )
477     {
478         disable( 'sout_scodec' );
479         disable( 'sout_sub' );
480     }
481     else
482     {
483         enable( 'sout_scodec' );
484         enable( 'sout_sub' );
485     }
486
487     transcode =  checked( 'sout_vcodec_s' ) || checked( 'sout_acodec_s' )
488                  || checked( 'sout_sub' ) || checked( 'sout_soverlay' );
489
490     if( transcode )
491     {
492         mrl.value += ":sout=#transcode{";
493         alot = false; /* alot == at least one transcode */
494         if( checked( 'sout_vcodec_s' ) )
495         {
496             mrl.value += "vcodec="+value( 'sout_vcodec' )+",vb="+value( 'sout_vb' )+",scale="+value( 'sout_scale' );
497             alot = true;
498         }
499         if( checked( 'sout_acodec_s' ) )
500         {
501             if( alot ) mrl.value += ",";
502             mrl.value += "acodec="+value( 'sout_acodec' )+",ab="+value( 'sout_ab' );
503             if( value( 'sout_channels' ) )
504                 mrl.value += ",channels="+value( 'sout_channels' );
505             alot = true;
506         }
507         if( checked( 'sout_soverlay' ) )
508         {
509             if( alot ) mrl.value += ",";
510             mrl.value += "soverlay";
511             alot = true;
512         }
513         else if( checked( 'sout_sub' ) )
514         {
515             if( alot ) mrl.value += ",";
516             mrl.value += "scodec="+value( 'sout_scodec' );
517             alot = true;
518         }
519         mrl.value += "}";
520     }
521
522     output = checked( 'sout_display' ) + checked( 'sout_file' )
523              + checked( 'sout_http' ) + checked( 'sout_mmsh' )
524              + checked( 'sout_rtp' )  + checked( 'sout_udp' );
525
526     if( output )
527     {
528         if( transcode )
529             mrl.value += ":";
530         else
531             mrl.value += ":sout=#";
532         aloo = false; /* aloo == at least one output */
533         mux = radio_value( 'sout_mux' );
534         ttl = parseInt( value( 'sout_ttl' ) );
535         if( output > 1 ) mrl.value += "duplicate{";
536         if( checked( 'sout_display' ) )
537         {
538             if( output > 1 ) mrl.value += "dst="
539             mrl.value += "display";
540             aloo = true;
541         }
542         if( checked( 'sout_file' ) )
543         {
544             if( aloo ) mrl.value += ",";
545             if( output > 1 ) mrl.value += "dst="
546             mrl.value += "std{access=file,mux="+mux+",dst="+value( 'sout_file_filename' )+"}";
547             aloo = true;
548         }
549         if( checked( 'sout_http' ) )
550         {
551             if( aloo ) mrl.value += ",";
552             if( output > 1 ) mrl.value += "dst="
553             mrl.value += "std{access=http,mux="+mux+",dst="+value( 'sout_http_addr' );
554             if( value( 'sout_http_port' ) )
555                 mrl.value += ":"+value( 'sout_http_port' );
556             mrl.value += "}";
557             aloo = true;
558         }
559         if( checked( 'sout_mmsh' ) )
560         {
561             if( aloo ) mrl.value += ",";
562             if( output > 1 ) mrl.value += "dst="
563             mrl.value += "std{access=mmsh,mux="+mux+",dst="+value( 'sout_mmsh_addr' );
564             if( value( 'sout_mmsh_port' ) )
565                 mrl.value += ":"+value( 'sout_mmsh_port' );
566             mrl.value += "}";
567             aloo = true;
568         }
569         if( checked( 'sout_rtp' ) )
570         {
571             if( aloo ) mrl.value += ",";
572             if( output > 1 ) mrl.value += "dst="
573             mrl.value += "std{access=rtp";
574             if( ttl ) mrl.value += "{ttl="+ttl+"}";
575             mrl.value += ",mux="+mux+",dst="+value( 'sout_rtp_addr' );
576             if( value( 'sout_rtp_port' ) )
577                 mrl.value += ":"+value( 'sout_rtp_port' );
578             if( checked( 'sout_sap' ) )
579             {
580                 mrl.value += ",sap";
581                 if( value( 'sout_sap_group' ) != '' )
582                 {
583                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
584                 }
585                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
586             }
587             mrl.value += "}";
588             aloo = true;
589         }
590         if( checked( 'sout_udp' ) )
591         {
592             if( aloo ) mrl.value += ",";
593             if( output > 1 ) mrl.value += "dst="
594             mrl.value += "std{access=udp";
595             if( ttl ) mrl.value += "{ttl="+ttl+"}";
596             mrl.value += ",mux="+mux+",dst="+value( 'sout_udp_addr' );
597             if( value('sout_udp_port' ) )
598                 mrl.value += ":"+value( 'sout_udp_port' );
599             if( checked( 'sout_sap' ) )
600             {
601                 mrl.value += ",sap";
602                 if( value( 'sout_sap_group' ) != '' )
603                 {
604                     mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
605                 }
606                 mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
607             }
608             mrl.value += "}";
609             aloo = true;
610         }
611         if( output > 1 ) mrl.value += "}";
612     }
613
614     if( ( transcode || output ) && checked( 'sout_all' ) )
615         mrl.value += " :sout-all";
616 }
617
618 /* reset sout mrl value */
619 function reset_sout()
620 {
621     document.getElementById('sout_mrl').value = value('sout_old_mrl');
622 }
623
624 function save_sout()
625 {
626     document.getElementById('sout_old_mrl').value = value('sout_mrl');
627 }
628
629 function loop_refresh_status()
630 {
631     setTimeout( 'loop_refresh_status()', 1000 );
632     update_status();
633 }
634 function loop_refresh_playlist()
635 {
636     setTimeout( 'loop_refresh_playlist()', 3000 );
637     update_playlist();
638 }
639 function loop_refresh()
640 {
641     setTimeout('loop_refresh_status()',0);
642     setTimeout('loop_refresh_playlist()',0);
643 }