Commit bba2eae5 authored by Jean-Baptiste Kempf's avatar Jean-Baptiste Kempf

Remove oldhttp

Sure, this will be unpopular, and this will likely kill you kittens, but
maintaining 2 http interface is stupid and counter-productive.
Let's hope luahttp will finally get fixed.
parent 7cfe1ace
......@@ -503,27 +503,6 @@ VLC-release.app: vlc
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/lua/http/requests/`basename $${i}` ; \
done
$(INSTALL) -m 644 $(srcdir)/share/lua/http/requests/README.txt $(top_builddir)/VLC-release.app/Contents/MacOS/share/lua/http/requests/README.txt
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/dialogs
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/js
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/images
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/requests
$(INSTALL) -m 644 $(srcdir)/share/http/.hosts $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/.hosts
for i in $(srcdir)/share/http/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/`basename $${i}` ; \
done
for i in $(srcdir)/share/http/dialogs/* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/dialogs/`basename $${i}` ; \
done
for i in $(srcdir)/share/http/js/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/js/`basename $${i}` ; \
done
for i in $(srcdir)/share/http/images/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/images/`basename $${i}` ; \
done
for i in $(srcdir)/share/http/requests/*.* ; do \
$(INSTALL) -m 644 $${i} $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/requests/`basename $${i}` ; \
done
$(INSTALL) -m 644 $(srcdir)/share/http/requests/README.txt $(top_builddir)/VLC-release.app/Contents/MacOS/share/http/requests/README.txt
$(INSTALL) -m 644 $(srcdir)/share/vlc512x512.png $(top_builddir)/VLC-release.app/Contents/MacOS/share/vlc512x512.png
$(INSTALL) -d $(top_builddir)/VLC-release.app/Contents/MacOS/share/locale
cat $(top_srcdir)/po/LINGUAS | while read i; do \
......@@ -716,9 +695,6 @@ if BUILD_LUA
cp -r $(destdir)/share/vlc/lua/* $(win32_destdir)/lua
endif
if BUILD_HTTPD
cp -r $(destdir)/share/vlc/http $(win32_destdir)
endif
if BUILD_SKINS
cp -r $(destdir)/share/vlc/skins2 $(win32_destdir)/skins
endif
......
......@@ -55,6 +55,7 @@ Interfaces
* Skins2: fullscreen controller support, relative placement support
and important cleanups and optimisations
* ncurses: heavy refactor of the complete interface
* removal of http interface in favor of luahttp
Video Output:
* New video output based on Direct2D for Windows 7 and Vista (with Platform Update)
......
......@@ -335,7 +335,7 @@ case "${host_os}" in
VLC_ADD_LDFLAGS([vlc],[-mwindows])
VLC_ADD_LIBS([win32text],[-lgdi32])
VLC_ADD_LIBS([cdda vcdx sdl_image aout_sdl vout_sdl],[-lwinmm])
VLC_ADD_LIBS([access_http access_mms access_udp access_tcp access_ftp access_rtmp access_output_udp access_output_shout access_output_rtmp sap oldhttp stream_out_standard stream_out_select stream_out_rtp stream_out_raop vod_rtsp access_realrtsp rtp oldrc netsync gnutls growl_udp flac ts audioscrobbler lua remoteosd zvbi audiobargraph_a netsync],[-lws2_32])
VLC_ADD_LIBS([access_http access_mms access_udp access_tcp access_ftp access_rtmp access_output_udp access_output_shout access_output_rtmp sap stream_out_standard stream_out_select stream_out_rtp stream_out_raop vod_rtsp access_realrtsp rtp oldrc netsync gnutls growl_udp flac ts audioscrobbler lua remoteosd zvbi audiobargraph_a netsync],[-lws2_32])
VLC_ADD_LIBS([filesystem], [-lshlwapi])
dnl
dnl DEP and ASLR options
......@@ -366,7 +366,7 @@ case "${host_os}" in
fi
if test "${SYS}" = "mingwce"; then
# add ws2 for closesocket, select, recv
VLC_ADD_LIBS([libvlccore access_http access_mms access_udp access_tcp access_ftp access_rtmp access_output_udp access_output_rtmp sap oldhttp netsync audioscrobbler growl rtp stream_out_standard stream_out_select stream_out_rtp remoteosd ts audiobargraph_a netsync],[-lws2])
VLC_ADD_LIBS([libvlccore access_http access_mms access_udp access_tcp access_ftp access_rtmp access_output_udp access_output_rtmp sap netsync audioscrobbler growl rtp stream_out_standard stream_out_select stream_out_rtp remoteosd ts audiobargraph_a netsync],[-lws2])
VLC_ADD_LIBS([libvlccore],[-lmmtimer])
AC_CHECK_PROGS(U2D, [unix2dos todos], unix2dos)
ac_default_prefix="`pwd`/_wince"
......@@ -1642,7 +1642,6 @@ AC_ARG_ENABLE(httpd,
[ --enable-httpd HTTP daemon (default enabled)])
if test "${enable_httpd}" != "no"
then
VLC_ADD_PLUGIN([oldhttp])
AC_DEFINE(ENABLE_HTTPD, 1, Define if you want the HTTP dameon support)
fi
AM_CONDITIONAL(BUILD_HTTPD, [test "${enable_httpd}" != "no"])
......@@ -4241,7 +4240,6 @@ AC_CONFIG_FILES([
modules/codec/spudec/Makefile
modules/codec/wmafixed/Makefile
modules/control/Makefile
modules/control/http/Makefile
modules/control/dbus/Makefile
modules/control/globalhotkeys/Makefile
modules/demux/Makefile
......
......@@ -528,7 +528,6 @@ Section $Name_Section01 SEC01
!insertmacro InstallFolder locale
@BUILD_OSDMENU_TRUE@ !insertmacro InstallFolder osdmenu
@BUILD_SKINS_TRUE@ !insertmacro InstallFolder skins
@BUILD_HTTPD_TRUE@ !insertmacro InstallFolder http
@BUILD_LUA_TRUE@ !insertmacro InstallFolder lua
; Generate the cache and add it to uninstall.log
......
SUBDIRS = http globalhotkeys dbus
SUBDIRS = globalhotkeys dbus
SOURCES_gestures = gestures.c
SOURCES_netsync = netsync.c
SOURCES_ntservice = ntservice.c
......
SOURCES_oldhttp = \
http.c \
http.h \
rpn.c \
macro.c \
macros.h \
mvar.c \
util.c \
$(NULL)
/*****************************************************************************
* http.c : HTTP/HTTPS Remote control interface
*****************************************************************************
* Copyright (C) 2001-2006 the VideoLAN team
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "http.h"
#include <vlc_plugin.h>
#include <vlc_url.h>
#include <vlc_fs.h>
#include <assert.h>
/*****************************************************************************
* Module descriptor
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close( vlc_object_t * );
#define HOST_TEXT N_( "Host address" )
#define HOST_LONGTEXT N_( \
"Address and port the HTTP interface will listen on. It defaults to " \
"all network interfaces (0.0.0.0)." \
" If you want the HTTP interface to be available only on the local " \
"machine, enter 127.0.0.1" )
#define SRC_TEXT N_( "Source directory" )
#define SRC_LONGTEXT N_( "Source directory" )
#define HANDLERS_TEXT N_( "Handlers" )
#define HANDLERS_LONGTEXT N_( \
"List of handler extensions and executable paths (for instance: " \
"php=/usr/bin/php,pl=/usr/bin/perl)." )
#define ART_TEXT N_( "Export album art as /art" )
#define ART_LONGTEXT N_( \
"Allow exporting album art for current playlist items at the " \
"/art and /art?id=<id> URLs." )
#define CERT_TEXT N_( "Certificate file" )
#define CERT_LONGTEXT N_( "HTTP interface x509 PEM certificate file " \
"(enables SSL)." )
#define KEY_TEXT N_( "Private key file" )
#define KEY_LONGTEXT N_( "HTTP interface x509 PEM private key file." )
#define CA_TEXT N_( "Root CA file" )
#define CA_LONGTEXT N_( "HTTP interface x509 PEM trusted root CA " \
"certificates file." )
#define CRL_TEXT N_( "CRL file" )
#define CRL_LONGTEXT N_( "HTTP interace Certificates Revocation List file." )
vlc_module_begin ()
set_shortname( N_("HTTP"))
set_description( N_("HTTP remote control interface") )
set_category( CAT_INTERFACE )
set_subcategory( SUBCAT_INTERFACE_MAIN )
add_string ( "http-host", NULL, HOST_TEXT, HOST_LONGTEXT, true )
add_string ( "http-src", NULL, SRC_TEXT, SRC_LONGTEXT, true )
#if defined( HAVE_FORK ) || defined( WIN32 )
add_string ( "http-handlers", NULL, HANDLERS_TEXT, HANDLERS_LONGTEXT, true )
#endif
add_bool ( "http-album-art", false, ART_TEXT, ART_LONGTEXT, true )
set_section( N_("HTTP SSL" ), 0 )
add_loadfile ( "http-intf-cert", NULL, CERT_TEXT, CERT_LONGTEXT, true )
add_loadfile ( "http-intf-key", NULL, KEY_TEXT, KEY_LONGTEXT, true )
add_loadfile ( "http-intf-ca", NULL, CA_TEXT, CA_LONGTEXT, true )
add_loadfile ( "http-intf-crl", NULL, CRL_TEXT, CRL_LONGTEXT, true )
set_capability( "interface", 0 )
set_callbacks( Open, Close )
add_shortcut( "http" )
vlc_module_end ()
/*****************************************************************************
* Local prototypes
*****************************************************************************/
int ArtCallback( httpd_handler_sys_t *p_args,
httpd_handler_t *p_handler, char *_p_url,
uint8_t *_p_request, int i_type,
uint8_t *_p_in, int i_in,
char *psz_remote_addr, char *psz_remote_host,
uint8_t **pp_data, int *pi_data );
/*****************************************************************************
* Activate: initialize and create stuff
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t*)p_this;
intf_sys_t *p_sys;
char *psz_address;
char *psz_cert = NULL, *psz_key = NULL, *psz_ca = NULL,
*psz_crl = NULL;
int i_port = 0;
char *psz_src = NULL;
psz_address = var_CreateGetNonEmptyString( p_intf, "http-host" );
if( psz_address != NULL )
{
char *psz_parser = strrchr( psz_address, ':' );
if( psz_parser )
{
*psz_parser++ = '\0';
i_port = atoi( psz_parser );
}
}
else
psz_address = strdup("");
p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
if( !p_intf->p_sys )
{
free( psz_address );
return( VLC_ENOMEM );
}
p_sys->p_playlist = pl_Get( p_this );
p_sys->p_input = NULL;
p_sys->p_vlm = NULL;
p_sys->psz_address = psz_address;
p_sys->i_port = i_port;
p_sys->p_art_handler = NULL;
/* determine file handler associations */
p_sys->i_handlers = 0;
p_sys->pp_handlers = NULL;
#if defined( HAVE_FORK ) || defined( WIN32 )
psz_src = var_InheritString( p_intf, "http-handlers" );
if( psz_src != NULL )
{
char *p = psz_src;
while( p != NULL )
{
http_association_t *p_handler;
char *psz_ext = p;
char *psz_program, *psz_options;
p = strchr( p, '=' );
if( p == NULL ) break;
*p++ = '\0';
psz_program = p;
p = strchr( p, ',' );
if( p != NULL )
*p++ = '\0';
p_handler = malloc( sizeof( http_association_t ) );
p_handler->psz_ext = strdup( psz_ext );
psz_options = FirstWord( psz_program, psz_program );
p_handler->i_argc = 0;
p_handler->ppsz_argv = NULL;
TAB_APPEND( p_handler->i_argc, p_handler->ppsz_argv,
strdup( psz_program ) );
while( psz_options != NULL && *psz_options )
{
char *psz_next = FirstWord( psz_options, psz_options );
TAB_APPEND( p_handler->i_argc, p_handler->ppsz_argv,
strdup( psz_options ) );
psz_options = psz_next;
}
/* NULL will be appended later on */
TAB_APPEND( p_sys->i_handlers, p_sys->pp_handlers, p_handler );
}
free( psz_src );
}
#endif
/* determine SSL configuration */
psz_cert = var_InheritString( p_intf, "http-intf-cert" );
if ( psz_cert != NULL )
{
msg_Dbg( p_intf, "enabling TLS for HTTP interface (cert file: %s)",
psz_cert );
psz_key = var_InheritString( p_intf, "http-intf-key" );
psz_ca = var_InheritString( p_intf, "http-intf-ca" );
psz_crl = var_InheritString( p_intf, "http-intf-crl" );
if( i_port <= 0 )
i_port = 8443;
}
else
{
if( i_port <= 0 )
i_port= 8080;
}
msg_Dbg( p_intf, "base %s:%d", psz_address, i_port );
p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_intf), psz_address,
i_port, psz_cert, psz_key, psz_ca,
psz_crl );
free( psz_cert );
free( psz_key );
free( psz_ca );
free( psz_crl );
if( p_sys->p_httpd_host == NULL )
{
msg_Err( p_intf, "cannot listen on %s:%d", psz_address, i_port );
free( p_sys->psz_address );
free( p_sys );
return VLC_EGENERIC;
}
else
{
char psz_tmp[NI_MAXHOST + 6];
/* Ugly hack to run several HTTP servers on different ports */
snprintf( psz_tmp, sizeof (psz_tmp), "%s:%d", psz_address, i_port + 1 );
var_Create(p_intf->p_libvlc, "http-host", VLC_VAR_STRING );
var_SetString( p_intf->p_libvlc, "http-host", psz_tmp );
}
p_sys->i_files = 0;
p_sys->pp_files = NULL;
psz_src = var_InheritString( p_intf, "http-src" );
if( psz_src == NULL )
{
char *data_path = config_GetDataDir( p_intf );
if( asprintf( &psz_src, "%s" DIR_SEP "http", data_path ) == -1 )
psz_src = NULL;
free( data_path );
}
if( psz_src == NULL )
{
msg_Err( p_intf, "invalid web interface source directory" );
goto failed;
}
/* remove trainling \ or / */
if( psz_src[strlen( psz_src ) - 1] == '\\' ||
psz_src[strlen( psz_src ) - 1] == '/' )
{
psz_src[strlen( psz_src ) - 1] = '\0';
}
ParseDirectory( p_intf, psz_src, psz_src );
if( p_sys->i_files <= 0 )
{
msg_Err( p_intf, "cannot find any file in directory %s", psz_src );
goto failed;
}
if( var_InheritBool( p_intf, "http-album-art" ) )
{
/* FIXME: we're leaking h */
httpd_handler_sys_t *h = malloc( sizeof( httpd_handler_sys_t ) );
if( !h )
goto failed;
h->file.p_intf = p_intf;
h->file.file = NULL;
h->file.name = NULL;
/* TODO: use ACL and login/password stuff here too */
h->p_handler = httpd_HandlerNew( p_sys->p_httpd_host,
"/art", NULL, NULL, NULL,
ArtCallback, h );
p_sys->p_art_handler = h->p_handler;
}
free( psz_src );
return VLC_SUCCESS;
failed:
free( psz_src );
free( p_sys->pp_files );
httpd_HostDelete( p_sys->p_httpd_host );
free( p_sys->psz_address );
free( p_sys );
return VLC_EGENERIC;
}
/*****************************************************************************
* Close: destroy interface
*****************************************************************************/
static void Close ( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t *)p_this;
intf_sys_t *p_sys = p_intf->p_sys;
int i;
#ifdef ENABLE_VLM
if( p_sys->p_vlm )
vlm_Delete( p_sys->p_vlm );
#endif
for( i = 0; i < p_sys->i_files; i++ )
{
if( p_sys->pp_files[i]->b_handler )
httpd_HandlerDelete( ((httpd_handler_sys_t *)p_sys->pp_files[i])->p_handler );
else
httpd_FileDelete( p_sys->pp_files[i]->p_file );
if( p_sys->pp_files[i]->p_redir )
httpd_RedirectDelete( p_sys->pp_files[i]->p_redir );
if( p_sys->pp_files[i]->p_redir2 )
httpd_RedirectDelete( p_sys->pp_files[i]->p_redir2 );
free( p_sys->pp_files[i]->file );
free( p_sys->pp_files[i]->name );
free( p_sys->pp_files[i] );
}
free( p_sys->pp_files );
for( i = 0; i < p_sys->i_handlers; i++ )
{
http_association_t *p_handler = p_sys->pp_handlers[i];
int j;
free( p_handler->psz_ext );
for( j = 0; j < p_handler->i_argc; j++ )
free( p_handler->ppsz_argv[j] );
if( p_handler->i_argc )
free( p_handler->ppsz_argv );
free( p_handler );
}
if( p_sys->i_handlers )
free( p_sys->pp_handlers );
if( p_sys->p_art_handler )
httpd_HandlerDelete( p_sys->p_art_handler );
httpd_HostDelete( p_sys->p_httpd_host );
free( p_sys->psz_address );
free( p_sys );
}
/****************************************************************************
* HttpCallback:
****************************************************************************
* a file with b_html is parsed and all "macro" replaced
****************************************************************************/
static void Callback404( httpd_file_sys_t *p_args, char **pp_data,
int *pi_data )
{
char *p = *pp_data = malloc( 10240 );
if( !p )
{
return;
}
p += sprintf( p, "Content-Type: text/html\n" );
p += sprintf( p, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" );
p += sprintf( p, "<head>\n" );
p += sprintf( p, "<title>Error loading %s</title>\n", p_args->file );
p += sprintf( p, "</head>\n" );
p += sprintf( p, "<body>\n" );
p += sprintf( p, "<h1><center>Error loading %s for %s</center></h1>\n", p_args->file, p_args->name );
p += sprintf( p, "<a href=\"http://www.videolan.org/\">VideoLAN</a>\n" );
p += sprintf( p, "</body>\n" );
p += sprintf( p, "</html>\n" );
*pi_data = strlen( *pp_data );
}
static void ParseExecute( httpd_file_sys_t *p_args, char *p_buffer,
int i_buffer, char *p_request,
char **pp_data, int *pi_data )
{
intf_sys_t *p_sys = p_args->p_intf->p_sys;
int i_request = p_request != NULL ? strlen( p_request ) : 0;
char *dst;
char position[4]; /* percentage */
char time[12]; /* in seconds */
char length[12]; /* in seconds */
audio_volume_t i_volume;
char volume[5];
const char *state;
char stats[20];
assert( p_sys->p_input == NULL );
/* FIXME: proper locking anyone? */
p_sys->p_input = playlist_CurrentInput( p_sys->p_playlist );
if( p_sys->p_input )
{
snprintf( position, sizeof(position), "%d",
(int)(var_GetFloat( p_sys->p_input, "position" ) * 100.));
snprintf( time, sizeof(time), "%"PRIi64,
var_GetTime( p_sys->p_input, "time" ) / CLOCK_FREQ );
snprintf( length, sizeof(length), "%"PRIi64,
var_GetTime( p_sys->p_input, "length" ) / CLOCK_FREQ );
switch( var_GetInteger( p_sys->p_input, "state" ) )
{
case PLAYING_S: state = "playing"; break;
case OPENING_S: state = "opening/connecting"; break;
case PAUSE_S: state = "paused"; break;
default: state = "stop"; break;
}
}
else
{
strcpy( position, "0" );
strcpy( time, "0" );
strcpy( length, "0" );
state = "stop";
}
i_volume = aout_VolumeGet( p_sys->p_playlist );
snprintf( volume, sizeof(volume), "%d", (int)i_volume );
p_args->vars = mvar_New( "variables", "" );
mvar_AppendNewVar( p_args->vars, "url_param",
i_request > 0 ? "1" : "0" );
mvar_AppendNewVar( p_args->vars, "url_value", p_request );
mvar_AppendNewVar( p_args->vars, "version", VERSION_MESSAGE );
mvar_AppendNewVar( p_args->vars, "copyright", COPYRIGHT_MESSAGE );
mvar_AppendNewVar( p_args->vars, "vlc_compile_by", VLC_CompileBy() );
mvar_AppendNewVar( p_args->vars, "vlc_compile_host",
VLC_CompileHost() );
mvar_AppendNewVar( p_args->vars, "vlc_compiler", VLC_Compiler() );
mvar_AppendNewVar( p_args->vars, "stream_position", position );
mvar_AppendNewVar( p_args->vars, "stream_time", time );
mvar_AppendNewVar( p_args->vars, "stream_length", length );
mvar_AppendNewVar( p_args->vars, "volume", volume );
mvar_AppendNewVar( p_args->vars, "stream_state", state );
mvar_AppendNewVar( p_args->vars, "charset", "UTF-8" );
/* Stats */
if( p_sys->p_input )
{
/* FIXME: Workarround a stupid assert in input_GetItem */
input_item_t *p_item = p_sys->p_input && p_sys->p_input->p
? input_GetItem( p_sys->p_input )
: NULL;
if( p_item )
{
vlc_mutex_lock( &p_item->p_stats->lock );
#define STATS_INT( n ) sprintf( stats, "%"PRIi64, p_item->p_stats->i_ ## n ); \
mvar_AppendNewVar( p_args->vars, #n, stats );
#define STATS_FLOAT( n ) sprintf( stats, "%f", p_item->p_stats->f_ ## n ); \
mvar_AppendNewVar( p_args->vars, #n, stats );
STATS_INT( read_bytes )
STATS_FLOAT( input_bitrate )
STATS_INT( demux_read_bytes )
STATS_FLOAT( demux_bitrate )
STATS_INT( decoded_video )
STATS_INT( displayed_pictures )
STATS_INT( lost_pictures )
STATS_INT( decoded_audio )
STATS_INT( played_abuffers )
STATS_INT( lost_abuffers )
STATS_INT( sent_packets )
STATS_INT( sent_bytes )
STATS_FLOAT( send_bitrate )
#undef STATS_INT
#undef STATS_FLOAT
vlc_mutex_unlock( &p_item->p_stats->lock );
}
}
SSInit( &p_args->stack );
/* allocate output */
*pi_data = i_buffer + 1000;
dst = *pp_data = malloc( *pi_data );
/* we parse executing all <vlc /> macros */
Execute( p_args, p_request, i_request, pp_data, pi_data, &dst,
&p_buffer[0], &p_buffer[i_buffer] );
*dst = '\0';
*pi_data = dst - *pp_data;
if( p_sys->p_input != NULL )
{
vlc_object_release( p_sys->p_input );
p_sys->p_input = NULL;
}
SSClean( &p_args->stack );
mvar_Delete( p_args->vars );
}
int HttpCallback( httpd_file_sys_t *p_args,
httpd_file_t *p_file,
uint8_t *_p_request,
uint8_t **_pp_data, int *pi_data )
{
VLC_UNUSED(p_file);
char *p_request = (char *)_p_request;
char **pp_data = (char **)_pp_data;
FILE *f;
if( ( f = vlc_fopen( p_args->file, "r" ) ) == NULL )
{
Callback404( p_args, pp_data, pi_data );
return VLC_SUCCESS;
}
if( !p_args->b_html )
{
FileLoad( f, pp_data, pi_data );
}
else
{
int i_buffer;
char *p_buffer;
/* first we load in a temporary buffer */
FileLoad( f, &p_buffer, &i_buffer );
ParseExecute( p_args, p_buffer, i_buffer, p_request, pp_data, pi_data );
free( p_buffer );
}
fclose( f );
return VLC_SUCCESS;
}
/****************************************************************************
* HandlerCallback:
****************************************************************************
* call the external handler and parse vlc macros if Content-Type is HTML
****************************************************************************/
int HandlerCallback( httpd_handler_sys_t *p_args,
httpd_handler_t *p_handler, char *_p_url,
uint8_t *_p_request, int i_type,
uint8_t *_p_in, int i_in,
char *psz_remote_addr, char *psz_remote_host,
uint8_t **_pp_data, int *pi_data )
{
VLC_UNUSED(p_handler); VLC_UNUSED(_p_in);
char *p_url = (char *)_p_url;
char *p_request = (char *)_p_request;
char **pp_data = (char **)_pp_data;
char *p_in = (char *)_p_in;
int i_request = p_request != NULL ? strlen( p_request ) : 0;
char *p;
int i_env = 0;
char **ppsz_env = NULL;
char *psz_tmp;
size_t i_buffer;
char *p_buffer;
char *psz_cwd, *psz_file = NULL;
int i_ret;
/* Create environment for the CGI */
TAB_APPEND( i_env, ppsz_env, strdup("GATEWAY_INTERFACE=CGI/1.1") );
TAB_APPEND( i_env, ppsz_env, strdup("SERVER_PROTOCOL=HTTP/1.1") );
TAB_APPEND( i_env, ppsz_env, strdup("SERVER_SOFTWARE=VLC "VERSION) );
switch( i_type )
{
case HTTPD_MSG_GET:
TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=GET") );
break;
case HTTPD_MSG_POST:
TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=POST") );
break;
case HTTPD_MSG_HEAD:
TAB_APPEND( i_env, ppsz_env, strdup("REQUEST_METHOD=HEAD") );
break;
default:
break;
}
if( i_request )
{
if( -1==asprintf( &psz_tmp, "QUERY_STRING=%s", p_request ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
if( -1==asprintf( &psz_tmp, "REQUEST_URI=%s?%s", p_url, p_request ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
}
else
{
if( -1==asprintf( &psz_tmp, "REQUEST_URI=%s", p_url ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
}
if( -1==asprintf( &psz_tmp, "SCRIPT_NAME=%s", p_url ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
#define p_sys p_args->file.p_intf->p_sys
if( -1==asprintf( &psz_tmp, "SERVER_NAME=%s", p_sys->psz_address ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
if( -1==asprintf( &psz_tmp, "SERVER_PORT=%u", p_sys->i_port ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
#undef p_sys
p = getenv( "PATH" );
if( p != NULL )
{
if( -1==asprintf( &psz_tmp, "PATH=%s", p ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
}
#ifdef WIN32
p = getenv( "windir" );
if( p != NULL )
{
if( -1==asprintf( &psz_tmp, "SYSTEMROOT=%s", p ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
}
#endif
if( psz_remote_addr != NULL && *psz_remote_addr )
{
if( -1==asprintf( &psz_tmp, "REMOTE_ADDR=%s", psz_remote_addr ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
}
if( psz_remote_host != NULL && *psz_remote_host )
{
if( -1==asprintf( &psz_tmp, "REMOTE_HOST=%s", psz_remote_host ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
}
if( i_in )
{
p = p_in;
for ( ; ; )
{
if( !strncasecmp( p, "Content-Type: ", strlen("Content-Type: ") ) )
{
char *end = strchr( p, '\r' );
if( end == NULL )
break;
*end = '\0';
if( -1==asprintf( &psz_tmp, "CONTENT_TYPE=%s", p ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
*end = '\r';
}
if( !strncasecmp( p, "Content-Length: ",
strlen("Content-Length: ") ) )
{
char *end = strchr( p, '\r' );
if( end == NULL )
break;
*end = '\0';
if( -1==asprintf( &psz_tmp, "CONTENT_LENGTH=%s", p ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
*end = '\r';
}
p = strchr( p, '\n' );
if( p == NULL || p[1] == '\r' )
{
p = NULL;
break;
}
p++;
}
}
psz_file = strrchr( p_args->file.file, DIR_SEP_CHAR );
if( psz_file != NULL )
{
psz_file++;
if( -1==asprintf( &psz_tmp, "SCRIPT_FILENAME=%s", psz_file ) )
psz_tmp = NULL;
TAB_APPEND( i_env, ppsz_env, psz_tmp );
TAB_APPEND( p_args->p_association->i_argc,
p_args->p_association->ppsz_argv, psz_file );
}
TAB_APPEND( i_env, ppsz_env, NULL );
TAB_APPEND( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
NULL );
psz_tmp = strdup( p_args->file.file );
p = strrchr( psz_tmp, DIR_SEP_CHAR );
if( p != NULL )
{
*p = '\0';
psz_cwd = psz_tmp;
}
else
{
free( psz_tmp );
psz_cwd = NULL;
}
i_ret = vlc_execve( p_args->file.p_intf, p_args->p_association->i_argc,
p_args->p_association->ppsz_argv, ppsz_env, psz_cwd,
(char *)p_in, i_in, &p_buffer, &i_buffer );
TAB_REMOVE( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
NULL );
TAB_REMOVE( p_args->p_association->i_argc, p_args->p_association->ppsz_argv,
psz_file );
free( psz_cwd );
while( i_env )
TAB_REMOVE( i_env, ppsz_env, ppsz_env[0] );
if( i_ret == -1 )
{
Callback404( (httpd_file_sys_t *)p_args, pp_data, pi_data );
return VLC_SUCCESS;
}
p = p_buffer;
while( strncasecmp( p, "Content-Type: text/html",
strlen("Content-Type: text/html") ) )
{
p = strchr( p, '\n' );
if( p == NULL || p[1] == '\r' )
{
p = NULL;
break;
}
p++;
}
if( p == NULL )
{
*pp_data = p_buffer;
*pi_data = i_buffer;
}
else
{
ParseExecute( (httpd_file_sys_t *)p_args, p_buffer, i_buffer,
p_request, pp_data, pi_data );
free( p_buffer );
}
return VLC_SUCCESS;
}
int ArtCallback( httpd_handler_sys_t *p_args,
httpd_handler_t *p_handler, char *_p_url,
uint8_t *p_request, int i_type,
uint8_t *p_in, int i_in,
char *psz_remote_addr, char *psz_remote_host,
uint8_t **pp_data, int *pi_data )
{
VLC_UNUSED(p_handler); VLC_UNUSED(_p_url); VLC_UNUSED(i_type);
VLC_UNUSED(p_in); VLC_UNUSED(i_in); VLC_UNUSED(psz_remote_addr);
VLC_UNUSED(psz_remote_host);
char *psz_art = NULL;
intf_thread_t *p_intf = p_args->file.p_intf;
intf_sys_t *p_sys = p_intf->p_sys;
char psz_id[16];
input_item_t *p_item = NULL;
int i_id;
psz_id[0] = '\0';
if( p_request )
ExtractURIValue( (char *)p_request, "id", psz_id, 15 );
i_id = atoi( psz_id );
if( i_id )
{
playlist_Lock( p_sys->p_playlist );
playlist_item_t *p_pl_item = playlist_ItemGetById( p_sys->p_playlist,
i_id );
if( p_pl_item )
p_item = p_pl_item->p_input;
playlist_Unlock( p_sys->p_playlist );
}
else
{
/* FIXME: Workarround a stupid assert in input_GetItem */
if( p_sys->p_input && p_sys->p_input->p )
p_item = input_GetItem( p_sys->p_input );
}
if( p_item )
{
psz_art = input_item_GetArtURL( p_item );
}
if( psz_art )
{
char *psz = make_path( psz_art );
free( psz_art );
psz_art = psz;
}
if( psz_art == NULL )
{
msg_Dbg( p_intf, "No album art found" );
Callback404( &p_args->file, (char**)pp_data, pi_data );
return VLC_SUCCESS;
}
FILE *f = vlc_fopen( psz_art, "r" );
if( f == NULL )
{
msg_Dbg( p_intf, "Couldn't open album art file %s", psz_art );
Callback404( &p_args->file, (char**)pp_data, pi_data );
free( psz_art );
return VLC_SUCCESS;
}
free( psz_art );
char *p_data = NULL;
int i_data;
FileLoad( f, &p_data, &i_data );
fclose( f );
char *psz_ext = strrchr( psz_art, '.' );
if( psz_ext ) psz_ext++;
#define HEADER "Content-Type: image/%s\n" \
"Content-Length: %d\n" \
"\n"
char *psz_header;
int i_header_size = asprintf( &psz_header, HEADER, psz_ext, i_data );
#undef HEADER
if( likely(i_header_size != -1) )
{
*pp_data = malloc( i_header_size + i_data );
if( likely(*pp_data != NULL) )
{
*pi_data = i_header_size + i_data;
memcpy( *pp_data, psz_header, i_header_size );
memcpy( *pp_data+i_header_size, p_data, i_data );
}
free( psz_header );
}
free( p_data );
return VLC_SUCCESS;
}
/*****************************************************************************
* http.h: Headers for the HTTP interface
*****************************************************************************
* Copyright (C) 2001-2007 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef _HTTP_H_
#define _HTTP_H_
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <vlc_common.h>
#include <stdlib.h>
#include <strings.h>
#include <vlc_interface.h>
#include <vlc_playlist.h>
#include <vlc_aout.h>
#include <vlc_vout.h> /* for fullscreen */
#include <vlc_httpd.h>
#include <vlc_vlm.h>
#include <vlc_network.h>
#include <vlc_acl.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( WIN32 ) && !defined( UNDER_CE )
# include <io.h>
#endif
/* stat() support for large files on win32 */
#if defined( WIN32 ) && !defined( UNDER_CE )
# define stat _stati64
#endif
/** \defgroup http_intf HTTP Interface
* This is the HTTP remote control interface. It is fully customizable
* by writing HTML pages using custom <vlc> tags.
*
* These tags use so-called macros.
*
* These macros can manipulate variables. For more complex operations,
* a custom RPN evaluator with many built-in functions is provided.
* @{
*/
/*****************************************************************************
* Local defines
*****************************************************************************/
#define MAX_DIR_SIZE 2560
#define STACK_MAX 100 //< Maximum RPN stack size
/*****************************************************************************
* Utility functions
*****************************************************************************/
/** \defgroup http_utils Utilities
* \ingroup http_intf
* Utilities
* @{
*/
/* File and directory functions */
/** This function recursively parses a directory and adds all files */
int ParseDirectory( intf_thread_t *p_intf, char *psz_root,
char *psz_dir );
/** This function loads a file into a buffer */
int FileLoad( FILE *f, char **pp_data, int *pi_data );
/** This function returns the real path of a file or directory */
char *RealPath( const char *psz_src );
/** This command parses the "seek" command for the HTTP interface
* and performs the requested action */
void HandleSeek( intf_thread_t *p_intf, char *p_value );
/* URI Handling functions */
/** This function extracts the value for a given argument name
* from an HTTP request */
const char *ExtractURIValue( const char *restrict psz_uri,
const char *restrict psz_name,
char *restrict psz_value, size_t i_value_max );
char *ExtractURIString( const char *restrict psz_uri,
const char *restrict psz_name );
/** \todo Describe this function */
int TestURIParam( char *psz_uri, const char *psz_name );
/** This function parses a MRL */
input_item_t *MRLParse( intf_thread_t *, const char *psz, char *psz_name );
/** Return the first word from a string (works in-place) */
char *FirstWord( char *psz, char *new );
/**@}*/
/****************************************************************************
* Variable handling functions
****************************************************************************/
/** \defgroup http_vars Macro variables
* \ingroup http_intf
* These variables can be used in the <vlc> macros and in the RPN evaluator.
* The variables make a tree: each variable can have an arbitrary
* number of "children" variables.
* A number of helper functions are provided to manipulate the main variable
* structure
* @{
*/
/**
* \struct mvar_t
* This structure defines a macro variable
*/
typedef struct mvar_s
{
char *name; ///< Variable name
char *value; ///< Variable value
int i_field; ///< Number of children variables
struct mvar_s **field; ///< Children variables array
} mvar_t;
/** This function creates a new variable */
mvar_t *mvar_New( const char *name, const char *value );
/** This function deletes a variable */
void mvar_Delete( mvar_t *v );
/** This function adds f to the children variables of v, at last position */
void mvar_AppendVar( mvar_t *v, mvar_t *f );
/** This function duplicates a variable */
mvar_t *mvar_Duplicate( const mvar_t *v );
/** This function adds f to the children variables of v, at fist position */
void mvar_PushVar( mvar_t *v, mvar_t *f );
/** This function removes f from the children variables of v */
void mvar_RemoveVar( mvar_t *v, mvar_t *f );
/** This function retrieves the child variable named "name" */
mvar_t *mvar_GetVar( mvar_t *s, const char *name );
/** This function retrieves the value of the child variable named "field" */
const char *mvar_GetValue( mvar_t *v, const char *field );
/** This function creates a variable with the given name and value and
* adds it as first child of vars */
void mvar_PushNewVar( mvar_t *vars, const char *name,
const char *value );
/** This function creates a variable with the given name and value and
* adds it as last child of vars */
void mvar_AppendNewVar( mvar_t *vars, const char *name,
const char *value );
/** @} */
/** \defgroup http_sets Sets *
* \ingroup http_intf
* Sets are an application of the macro variables. There are a number of
* predefined functions that will give you variables whose children represent
* VLC internal data (playlist, stream info, ...)
* @{
*/
/** This function creates a set variable which represents a series of integer
* The arg parameter must be of the form "start[:stop[:step]]" */
mvar_t *mvar_IntegerSetNew( const char *name, const char *arg );
/** This function creates a set variable with a list of SD plugins */
mvar_t *mvar_ServicesSetNew( intf_thread_t *p_intf, char *name );
/** This function creates a set variable with the contents of the playlist */
mvar_t *mvar_PlaylistSetNew( intf_thread_t *p_intf, char *name,
playlist_t *p_pl );
/** This function creates a set variable with the contents of the Stream
* and media info box */
mvar_t *mvar_InfoSetNew( char *name, input_thread_t *p_input );
/** This function creates a set variable with the input parameters */
mvar_t *mvar_InputVarSetNew( intf_thread_t *p_intf, char *name,
input_thread_t *p_input,
const char *psz_variable );
/** This function creates a set variable representing the files of the psz_dir
* directory */
mvar_t *mvar_FileSetNew( intf_thread_t *p_intf, char *name,
char *psz_dir );
/** This function creates a set variable representing the VLM streams */
mvar_t *mvar_VlmSetNew( char *name, vlm_t *vlm );
/** This function converts the listing of a playlist node into a mvar set.
* It must be entered WITH playlist lock! */
void PlaylistListNode( intf_thread_t *p_intf, playlist_t *p_pl,
playlist_item_t *p_node, char *name, mvar_t *s,
int i_depth );
/**@}*/
/*****************************************************************************
* RPN Evaluator
*****************************************************************************/
/** \defgroup http_rpn RPN Evaluator
* \ingroup http_intf
* @{
*/
/**
* \struct rpn_stack_t
* This structure represents a stack of RPN commands for the HTTP interface
* It is attached to a request
*/
typedef struct
{
char *stack[STACK_MAX];
int i_stack;
} rpn_stack_t;
/** This function creates the RPN evaluator stack */
void SSInit( rpn_stack_t * );
/** This function cleans the evaluator stack */
void SSClean( rpn_stack_t * );
/* Evaluate and execute the RPN Stack */
void EvaluateRPN( intf_thread_t *p_intf, mvar_t *vars,
rpn_stack_t *st, char *exp );
/* Push an operand on top of the RPN stack */
void SSPush ( rpn_stack_t *, const char * );
/* Remove the first operand from the RPN Stack */
char *SSPop ( rpn_stack_t * );
/* Pushes an operand at a given position in the stack */
void SSPushN ( rpn_stack_t *, int );
/* Removes an operand at the given position in the stack */
int SSPopN ( rpn_stack_t *, mvar_t * );
/**@}*/
/****************************************************************************
* Macro handling (<vlc ... stuff)
****************************************************************************/
/** \defgroup http_macros <vlc> Macros Handling
* \ingroup http_intf
* A macro is a code snippet in the HTML page looking like
* <vlc id="macro_id" param1="value1" param2="value2">
* Macros string ids are mapped to macro types, and specific handling code
* must be written for each macro type
* @{
*/
/** \struct macro_t
* This structure represents a HTTP Interface macro.
*/
typedef struct
{
char *id; ///< Macro ID string
char *param1; ///< First parameter
char *param2; ///< Second parameter
} macro_t;
/** This function parses a file for macros */
void Execute( httpd_file_sys_t *p_args,
char *p_request, int i_request,
char **pp_data, int *pi_data,
char **pp_dst,
const char *_src, const char *_end );
/**@}*/
/**
* Core stuff
*/
/** \struct httpd_file_sys_t
* This structure represent a single HTML file to be parsed by the macros
* handling engine */
struct httpd_file_sys_t
{
intf_thread_t *p_intf;
httpd_file_t *p_file;
httpd_redirect_t *p_redir;
httpd_redirect_t *p_redir2;
char *file;
char *name;
bool b_html, b_handler;
/* inited for each access */
rpn_stack_t stack;
mvar_t *vars;
};
/** \struct http_association_t
* Structure associating an extension to an external program
*/
typedef struct http_association_t
{
char *psz_ext;
int i_argc;
char **ppsz_argv;
} http_association_t;
/** \struct httpd_handler_sys_t
* This structure represent a single CGI file to be parsed by the macros
* handling engine */
struct httpd_handler_sys_t
{
httpd_file_sys_t file;
/* HACK ALERT: this is added below so that casting httpd_handler_sys_t
* to httpd_file_sys_t works */
httpd_handler_t *p_handler;
http_association_t *p_association;
};
/** \struct intf_sys_t
* Internal service structure for the HTTP interface
*/
struct intf_sys_t
{
httpd_host_t *p_httpd_host;
int i_files;
httpd_file_sys_t **pp_files;
int i_handlers;
http_association_t **pp_handlers;
httpd_handler_t *p_art_handler;
playlist_t *p_playlist;
input_thread_t *p_input;
vlm_t *p_vlm;
char *psz_address;
unsigned short i_port;
};
/** This function is the main HTTPD Callback used by the HTTP Interface */
int HttpCallback( httpd_file_sys_t *p_args,
httpd_file_t *,
uint8_t *p_request,
uint8_t **pp_data, int *pi_data );
/** This function is the HTTPD Callback used for CGIs */
int HandlerCallback( httpd_handler_sys_t *p_args,
httpd_handler_t *p_handler, char *_p_url,
uint8_t *_p_request, int i_type,
uint8_t *_p_in, int i_in,
char *psz_remote_addr, char *psz_remote_host,
uint8_t **_pp_data, int *pi_data );
/**@}*/
#endif
/*****************************************************************************
* macro.c : Custom <vlc> macro handling
*****************************************************************************
* Copyright (C) 2001-2005 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "http.h"
#include "macros.h"
#include <vlc_url.h>
static int MacroParse( macro_t *m, char *psz_src )
{
char *dup = strdup( (char *)psz_src );
char *src = dup;
char *p;
int i_skip;
#define EXTRACT( name, l ) \
src += l; \
p = strchr( src, '"' ); \
if( p ) \
{ \
*p++ = '\0'; \
} \
m->name = strdup( src ); \
if( !p ) \
{ \
break; \
} \
src = p;
/* init m */
m->id = NULL;
m->param1 = NULL;
m->param2 = NULL;
/* parse */
src += 4;
while( *src )
{
while( *src == ' ')
{
src++;
}
if( !strncmp( src, "id=\"", 4 ) )
{
EXTRACT( id, 4 );
}
else if( !strncmp( src, "param1=\"", 8 ) )
{
EXTRACT( param1, 8 );
}
else if( !strncmp( src, "param2=\"", 8 ) )
{
EXTRACT( param2, 8 );
}
else
{
break;
}
}
if( strstr( src, "/>" ) )
{
src = strstr( src, "/>" ) + 2;
}
else
{
src += strlen( src );
}
if( m->id == NULL )
{
m->id = strdup( "" );
}
if( m->param1 == NULL )
{
m->param1 = strdup( "" );
}
if( m->param2 == NULL )
{
m->param2 = strdup( "" );
}
i_skip = src - dup;
free( dup );
return i_skip;
#undef EXTRACT
}
static void MacroClean( macro_t *m )
{
free( m->id );
free( m->param1 );
free( m->param2 );
}
static int StrToMacroType( const char *name )
{
int i;
if( !name || *name == '\0')
{
return MVLC_UNKNOWN;
}
for( i = 0; StrToMacroTypeTab[i].psz_name != NULL; i++ )
{
if( !strcmp( name, StrToMacroTypeTab[i].psz_name ) )
{
return StrToMacroTypeTab[i].i_type;
}
}
return MVLC_UNKNOWN;
}
static void MacroDo( httpd_file_sys_t *p_args,
macro_t *m,
char *p_request, int i_request,
char **pp_data, int *pi_data,
char **pp_dst )
{
intf_thread_t *p_intf = p_args->p_intf;
intf_sys_t *p_sys = p_args->p_intf->p_sys;
playlist_t *p_playlist = p_sys->p_playlist;
char control[512];
#define ALLOC( l ) \
{ \
int __i__ = *pp_dst - *pp_data; \
*pi_data += (l); \
*pp_data = xrealloc( *pp_data, *pi_data ); \
*pp_dst = (*pp_data) + __i__; \
}
#define PRINT( str ) \
ALLOC( strlen( str ) + 1 ); \
*pp_dst += sprintf( *pp_dst, "%s", str );
#define PRINTS( str, s ) \
ALLOC( strlen( str ) + strlen( s ) + 1 ); \
{ \
char * psz_cur = *pp_dst; \
*pp_dst += sprintf( *pp_dst, str, s ); \
while( psz_cur && *psz_cur ) \
{ \
/* Prevent script injection */ \
if( *psz_cur == '<' ) *psz_cur = '*'; \
if( *psz_cur == '>' ) *psz_cur = '*'; \
psz_cur++ ; \
} \
}
switch( StrToMacroType( m->id ) )
{
case MVLC_CONTROL:
if( i_request <= 0 )
{
break;
}
ExtractURIValue( p_request, "control", control, 512 );
if( *m->param1 && !strstr( m->param1, control ) )
{
msg_Warn( p_intf, "unauthorized control=%s", control );
break;
}
switch( StrToMacroType( control ) )
{
case MVLC_PLAY:
{
int i_item;
char item[512];
ExtractURIValue( p_request, "item", item, 512 );
i_item = atoi( item );
/* id = 0 : simply ask playlist to play */
if( i_item == 0 )
{
playlist_Play( p_sys->p_playlist );
msg_Dbg( p_intf, "requested playlist play" );
break;
}
playlist_Control( p_sys->p_playlist, PLAYLIST_VIEWPLAY,
pl_Unlocked, NULL,
playlist_ItemGetById( p_sys->p_playlist,
i_item ) );
msg_Dbg( p_intf, "requested playlist item: %i", i_item );
break;
}
case MVLC_STOP:
playlist_Control( p_sys->p_playlist, PLAYLIST_STOP,
pl_Unlocked );
msg_Dbg( p_intf, "requested playlist stop" );
break;
case MVLC_PAUSE:
playlist_Control( p_sys->p_playlist, PLAYLIST_PAUSE,
pl_Unlocked );
msg_Dbg( p_intf, "requested playlist pause" );
break;
case MVLC_NEXT:
playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP,
pl_Unlocked, 1 );
msg_Dbg( p_intf, "requested playlist next" );
break;
case MVLC_PREVIOUS:
playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP,
pl_Unlocked, -1 );
msg_Dbg( p_intf, "requested playlist previous" );
break;
case MVLC_FULLSCREEN:
if( p_sys->p_input )
{
bool fs = var_ToggleBool( p_sys->p_playlist,
"fullscreen" );
vout_thread_t *p_vout = input_GetVout( p_sys->p_input );
if( p_vout )
{
var_SetBool( p_vout, "fullscreen", fs );
vlc_object_release( p_vout );
msg_Dbg( p_intf, "requested fullscreen toggle" );
}
}
break;
case MVLC_SEEK:
{
char value[30];
ExtractURIValue( p_request, "seek_value", value, 30 );
decode_URI( value );
HandleSeek( p_intf, value );
break;
}
case MVLC_VOLUME:
{
char vol[8];
audio_volume_t i_volume;
int i_value;
ExtractURIValue( p_request, "value", vol, 8 );
i_volume = aout_VolumeGet( p_sys->p_playlist );
decode_URI( vol );
if( vol[0] == '+' )
{
i_value = atoi( vol + 1 );
if( (i_volume + i_value) > AOUT_VOLUME_MAX )
{
aout_VolumeSet( p_sys->p_playlist, AOUT_VOLUME_MAX );
msg_Dbg( p_intf, "requested volume set: max" );
}
else
{
aout_VolumeSet( p_sys->p_playlist, (i_volume + i_value) );
msg_Dbg( p_intf, "requested volume set: +%i", (i_volume + i_value) );
}
}
else if( vol[0] == '-' )
{
i_value = atoi( vol + 1 );
if( (i_volume - i_value) < AOUT_VOLUME_MIN )
{
aout_VolumeSet( p_sys->p_playlist, AOUT_VOLUME_MIN );
msg_Dbg( p_intf, "requested volume set: min" );
}
else
{
aout_VolumeSet( p_sys->p_playlist, (i_volume - i_value) );
msg_Dbg( p_intf, "requested volume set: -%i", (i_volume - i_value) );
}
}
else if( strstr(vol, "%") != NULL )
{
i_value = atoi( vol );
if( (i_value <= 400) && (i_value>=0) ){
aout_VolumeSet( p_sys->p_playlist, (i_value * (AOUT_VOLUME_MAX - AOUT_VOLUME_MIN))/400+AOUT_VOLUME_MIN);
msg_Dbg( p_intf, "requested volume set: %i%%", atoi( vol ));
}
}
else
{
i_value = atoi( vol );
if( ( i_value <= AOUT_VOLUME_MAX ) && ( i_value >= AOUT_VOLUME_MIN ) )
{
aout_VolumeSet( p_sys->p_playlist, atoi( vol ) );
msg_Dbg( p_intf, "requested volume set: %i", atoi( vol ) );
}
}
break;
}
/* playlist management */
case MVLC_ADD:
{
char mrl[1024], psz_name[1024], tmp[1024];
char *p, *str;
input_item_t *p_input;
ExtractURIValue( p_request, "mrl", tmp, 1024 );
decode_URI( tmp );
ExtractURIValue( p_request, "name", psz_name, 1024 );
decode_URI( psz_name );
if( !*psz_name )
{
memcpy( psz_name, tmp, 1024 );
}
/* addslashes for backward compatibility with the old
* http intf */
p = mrl; str = tmp;
while( *str != '\0' )
{
if( *str == '"' || *str == '\'' || *str == '\\' )
{
*p++ = '\\';
}
*p++ = *str;
str++;
}
*p = '\0';
p_input = MRLParse( p_intf, mrl, psz_name );
char *psz_uri = p_input ? input_item_GetURI( p_input ) : NULL;
if( psz_uri && *psz_uri &&
playlist_AddInput( p_sys->p_playlist, p_input,
PLAYLIST_APPEND, PLAYLIST_END,
true, pl_Unlocked) == VLC_SUCCESS )
msg_Dbg( p_intf, "requested mrl add: %s", mrl );
else
msg_Warn( p_intf, "adding mrl failed: %s", mrl );
free( psz_uri );
if( p_input )
vlc_gc_decref( p_input );
break;
}
case MVLC_DEL:
{
int *p_items = NULL;
size_t i_nb_items = 0;
char item[512];
const char *p_parser = p_request;
/* Get the list of items to delete */
while( (p_parser =
ExtractURIValue( p_parser, "item", item, 512 )) )
{
if( !*item ) continue;
int i_item = atoi( item );
p_items = xrealloc( p_items,
(i_nb_items + 1) * sizeof(*p_items) );
p_items[i_nb_items] = i_item;
i_nb_items++;
}
for( size_t i = 0; i < i_nb_items; i++ )
{
PL_LOCK;
playlist_item_t *p_item;
msg_Dbg( p_intf, "requested playlist delete: %d",
p_items[i] );
p_item = playlist_ItemGetById( p_sys->p_playlist,
p_items[i] );
if( p_item )
playlist_DeleteFromInput( p_sys->p_playlist,
p_item->p_input,
false );
PL_UNLOCK;
}
free( p_items );
break;
}
case MVLC_KEEP:
{
int *p_items = NULL;
size_t i_nb_items = 0, i;
char item[512];
const char *p_parser = p_request;
/* Get the list of items to keep */
while( (p_parser =
ExtractURIValue( p_parser, "item", item, 512 )) )
{
if( !*item ) continue;
int i_item = atoi( item );
p_items = xrealloc( p_items,
(i_nb_items + 1) * sizeof(*p_items) );
p_items[i_nb_items] = i_item;
i_nb_items++;
}
PL_LOCK;
size_t size = p_sys->p_playlist->items.i_size;
for( i = 0; i < size; i++ )
{
size_t j;
/* Check if the item is in the keep list */
for( j = 0 ; j < i_nb_items ; j++ )
{
if( p_items[j] ==
ARRAY_VAL(p_sys->p_playlist->items,i)->i_id)
break;
}
if( j == i_nb_items )
{
msg_Dbg( p_intf, "requested playlist delete: %d",
p_sys->p_playlist->items.p_elems[i]->i_id );
playlist_DeleteFromInput( p_sys->p_playlist,
p_sys->p_playlist->items.p_elems[i]->p_input,
false );
}
}
PL_UNLOCK;
free( p_items );
break;
}
case MVLC_EMPTY:
{
playlist_Clear( p_sys->p_playlist, pl_Unlocked );
msg_Dbg( p_intf, "requested playlist empty" );
break;
}
case MVLC_SORT:
{
char type[12];
char order[2];
char item[512];
int i_order;
int i_item;
ExtractURIValue( p_request, "type", type, 12 );
ExtractURIValue( p_request, "order", order, 2 );
ExtractURIValue( p_request, "item", item, 512 );
i_item = atoi( item );
if( order[0] == '0' ) i_order = ORDER_NORMAL;
else i_order = ORDER_REVERSE;
if( !strcmp( type , "title" ) )
{
PL_LOCK;
playlist_RecursiveNodeSort( p_sys->p_playlist,
/* Ugly hack,but not worse than before ... */
p_sys->p_playlist->p_root_onelevel,
SORT_TITLE_NODES_FIRST,
( i_order == 0 ) ? ORDER_NORMAL : ORDER_REVERSE );
PL_UNLOCK;
msg_Dbg( p_intf, "requested playlist sort by title (%d)" , i_order );
}
else if( !strcmp( type , "author" ) )
{
PL_LOCK;
playlist_RecursiveNodeSort( p_sys->p_playlist, /*playlist_ItemGetById( p_sys->p_playlist, i_item ),*/
p_sys->p_playlist->p_root_onelevel,
SORT_ARTIST,
( i_order == 0 ) ? ORDER_NORMAL : ORDER_REVERSE );
PL_UNLOCK;
msg_Dbg( p_intf, "requested playlist sort by author (%d)" , i_order );
}
else if( !strcmp( type , "shuffle" ) )
{
PL_LOCK;
playlist_RecursiveNodeSort( p_sys->p_playlist, /*playlist_ItemGetById( p_sys->p_playlist, i_item ),*/
p_sys->p_playlist->p_root_onelevel,
SORT_RANDOM,
( i_order == 0 ) ? ORDER_NORMAL : ORDER_REVERSE );
PL_UNLOCK;
msg_Dbg( p_intf, "requested playlist shuffle");
}
break;
}
case MVLC_MOVE:
{
char psz_pos[6];
char psz_newpos[6];
int i_pos;
int i_newpos;
ExtractURIValue( p_request, "psz_pos", psz_pos, 6 );
ExtractURIValue( p_request, "psz_newpos", psz_newpos, 6 );
i_pos = atoi( psz_pos );
i_newpos = atoi( psz_newpos );
/* FIXME FIXME TODO TODO XXX XXX
( duplicate from rpn.c )
if ( i_pos < i_newpos )
{
playlist_Move( p_sys->p_playlist, i_pos, i_newpos + 1 );
}
else
{
playlist_Move( p_sys->p_playlist, i_pos, i_newpos );
}
msg_Dbg( p_intf, "requested move playlist item %d to %d", i_pos, i_newpos);
FIXME FIXME TODO TODO XXX XXX */
break;
}
/* admin function */
case MVLC_CLOSE:
{
char id[512];
ExtractURIValue( p_request, "id", id, 512 );
msg_Dbg( p_intf, "requested close id=%s", id );
#if 0
if( p_sys->p_httpd->pf_control( p_sys->p_httpd, HTTPD_SET_CLOSE, id, NULL ) )
{
msg_Warn( p_intf, "close failed for id=%s", id );
}
#endif
break;
}
case MVLC_SHUTDOWN:
{
msg_Dbg( p_intf, "requested shutdown" );
libvlc_Quit( p_intf->p_libvlc );
break;
}
#ifdef ENABLE_VLM
/* vlm */
case MVLC_VLM_NEW:
case MVLC_VLM_SETUP:
{
static const char vlm_properties[][9] =
{
/* no args */
"enabled", "disabled", "loop", "unloop",
/* args required */
"input", "output", "option", "date", "period",
"repeat", "append", "",
};
vlm_message_t *vlm_answer;
char name[512];
char *psz = xmalloc( strlen( p_request ) + 1000 );
char *p = psz;
char *vlm_error;
int i;
if( p_intf->p_sys->p_vlm == NULL )
p_intf->p_sys->p_vlm = vlm_New( p_intf );
if( p_intf->p_sys->p_vlm == NULL )
{
free( psz );
break;
}
ExtractURIValue( p_request, "name", name, 512 );
if( StrToMacroType( control ) == MVLC_VLM_NEW )
{
char type[20];
ExtractURIValue( p_request, "type", type, 20 );
p += sprintf( psz, "new %s %s", name, type );
}
else
{
p += sprintf( psz, "setup %s", name );
}
/* Parse the request */
for( i = 0; vlm_properties[i][0]; i++ )
{
char val[512];
ExtractURIValue( p_request,
vlm_properties[i], val, 512 );
decode_URI( val );
if( strlen( val ) > 0 && i >= 4 )
{
p += sprintf( p, " %s %s", vlm_properties[i], val );
}
else if( TestURIParam( p_request, vlm_properties[i] ) && i < 4 )
{
p += sprintf( p, " %s", vlm_properties[i] );
}
}
vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz, &vlm_answer );
if( vlm_answer->psz_value == NULL ) /* there is no error */
{
vlm_error = strdup( "" );
}
else
{
if( asprintf( &vlm_error , "%s : %s" ,
vlm_answer->psz_name,
vlm_answer->psz_value ) == -1 )
vlm_error = NULL;
}
mvar_AppendNewVar( p_args->vars, "vlm_error", vlm_error );
vlm_MessageDelete( vlm_answer );
free( vlm_error );
free( psz );
break;
}
case MVLC_VLM_DEL:
{
vlm_message_t *vlm_answer;
char name[512];
char psz[512+10];
if( p_intf->p_sys->p_vlm == NULL )
p_intf->p_sys->p_vlm = vlm_New( p_intf );
if( p_intf->p_sys->p_vlm == NULL ) break;
ExtractURIValue( p_request, "name", name, 512 );
sprintf( psz, "del %s", name );
vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz, &vlm_answer );
/* FIXME do a vlm_answer -> var stack conversion */
vlm_MessageDelete( vlm_answer );
break;
}
case MVLC_VLM_PLAY:
case MVLC_VLM_PAUSE:
case MVLC_VLM_STOP:
case MVLC_VLM_SEEK:
{
vlm_message_t *vlm_answer;
char name[512];
char psz[512+10];
if( p_intf->p_sys->p_vlm == NULL )
p_intf->p_sys->p_vlm = vlm_New( p_intf );
if( p_intf->p_sys->p_vlm == NULL ) break;
ExtractURIValue( p_request, "name", name, 512 );
if( StrToMacroType( control ) == MVLC_VLM_PLAY )
sprintf( psz, "control %s play", name );
else if( StrToMacroType( control ) == MVLC_VLM_PAUSE )
sprintf( psz, "control %s pause", name );
else if( StrToMacroType( control ) == MVLC_VLM_STOP )
sprintf( psz, "control %s stop", name );
else if( StrToMacroType( control ) == MVLC_VLM_SEEK )
{
char percent[20];
ExtractURIValue( p_request, "percent", percent, 512 );
sprintf( psz, "control %s seek %s", name, percent );
}
vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz, &vlm_answer );
/* FIXME do a vlm_answer -> var stack conversion */
vlm_MessageDelete( vlm_answer );
break;
}
case MVLC_VLM_LOAD:
case MVLC_VLM_SAVE:
{
vlm_message_t *vlm_answer;
char file[512];
char psz[512];
if( p_intf->p_sys->p_vlm == NULL )
p_intf->p_sys->p_vlm = vlm_New( p_intf );
if( p_intf->p_sys->p_vlm == NULL ) break;
ExtractURIValue( p_request, "file", file, 512 );
decode_URI( file );
if( StrToMacroType( control ) == MVLC_VLM_LOAD )
sprintf( psz, "load %s", file );
else
sprintf( psz, "save %s", file );
vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz, &vlm_answer );
/* FIXME do a vlm_answer -> var stack conversion */
vlm_MessageDelete( vlm_answer );
break;
}
#endif /* ENABLE_VLM */
default:
if( *control )
{
PRINTS( "<!-- control param(%s) unsupported -->", control );
}
break;
}
break;
case MVLC_SET:
{
char value[512];
int i;
float f;
if( i_request <= 0 ||
*m->param1 == '\0' ||
strstr( p_request, m->param1 ) == NULL )
{
break;
}
ExtractURIValue( p_request, m->param1, value, 512 );
decode_URI( value );
switch( StrToMacroType( m->param2 ) )
{
case MVLC_INT:
i = atoi( value );
config_PutInt( p_intf, m->param1, i );
break;
case MVLC_FLOAT:
f = atof( value );
config_PutFloat( p_intf, m->param1, f );
break;
case MVLC_STRING:
config_PutPsz( p_intf, m->param1, value );
break;
default:
PRINTS( "<!-- invalid type(%s) in set -->", m->param2 )
}
break;
}
case MVLC_GET:
{
char value[512];
int i;
float f;
char *psz;
lldiv_t div;
if( *m->param1 == '\0' )
{
break;
}
switch( StrToMacroType( m->param2 ) )
{
case MVLC_INT:
i = config_GetInt( p_intf, m->param1 );
sprintf( value, "%d", i );
break;
case MVLC_FLOAT:
f = config_GetFloat( p_intf, m->param1 );
div = lldiv( f * 1000000 , 1000000 );
sprintf( value, "%lld.%06u", div.quot,
(unsigned int)div.rem );
break;
case MVLC_STRING:
psz = config_GetPsz( p_intf, m->param1 );
if( psz != NULL )
{
strlcpy( value, psz,sizeof( value ) );
free( psz );
}
else
*value = '\0';
msg_Dbg( p_intf, "%d: value = \"%s\"", __LINE__, value );
break;
default:
snprintf( value, sizeof( value ),
"invalid type(%s) in set", m->param2 );
break;
}
PRINTS( "%s", value );
break;
}
case MVLC_VALUE:
{
char *s;
const char *v;
if( m->param1 )
{
EvaluateRPN( p_intf, p_args->vars, &p_args->stack, m->param1 );
s = SSPop( &p_args->stack );
v = mvar_GetValue( p_args->vars, s );
}
else
{
v = s = SSPop( &p_args->stack );
}
PRINTS( "%s", v );
free( s );
break;
}
case MVLC_RPN:
EvaluateRPN( p_intf, p_args->vars, &p_args->stack, m->param1 );
break;
/* Useful to learn stack management */
case MVLC_STACK:
{
int i;
msg_Dbg( p_intf, "stack" );
for (i=0;i<(&p_args->stack)->i_stack;i++)
msg_Dbg( p_intf, "%d -> %s", i, (&p_args->stack)->stack[i] );
break;
}
case MVLC_UNKNOWN:
default:
PRINTS( "<!-- invalid macro id=`%s' -->", m->id );
msg_Dbg( p_intf, "invalid macro id=`%s'", m->id );
break;
}
#undef PRINTS
#undef PRINT
#undef ALLOC
}
static
char *MacroSearch( char *src, char *end, int i_mvlc, bool b_after )
{
int i_id;
int i_level = 0;
while( src < end )
{
if( src + 4 < end && !strncmp( (char *)src, "<vlc", 4 ) )
{
int i_skip;
macro_t m;
i_skip = MacroParse( &m, src );
i_id = StrToMacroType( m.id );
switch( i_id )
{
case MVLC_IF:
case MVLC_FOREACH:
i_level++;
break;
case MVLC_END:
i_level--;
break;
default:
break;
}
MacroClean( &m );
if( ( i_mvlc == MVLC_END && i_level == -1 ) ||
( i_mvlc != MVLC_END && i_level == 0 && i_mvlc == i_id ) )
{
return src + ( b_after ? i_skip : 0 );
}
else if( i_level < 0 )
{
return NULL;
}
src += i_skip;
}
else
{
src++;
}
}
return NULL;
}
void Execute( httpd_file_sys_t *p_args,
char *p_request, int i_request,
char **pp_data, int *pi_data,
char **pp_dst,
const char *_src, const char *_end )
{
intf_thread_t *p_intf = p_args->p_intf;
char *src, *dup, *end;
char *dst = *pp_dst;
src = dup = xmalloc( _end - _src + 1 );
end = src +( _end - _src );
memcpy( src, _src, _end - _src );
*end = '\0';
/* we parse searching <vlc */
while( src < end )
{
char *p;
int i_copy;
p = strstr( src, "<vlc" );
if( p < end && p == src )
{
macro_t m;
src += MacroParse( &m, src );
//msg_Dbg( p_intf, "macro_id=%s", m.id );
switch( StrToMacroType( m.id ) )
{
case MVLC_INCLUDE:
{
FILE *f;
int i_buffer;
char *p_buffer;
char psz_file[MAX_DIR_SIZE];
char *p;
char sep;
#if defined( WIN32 ) || defined( __OS2__ )
sep = '\\';
#else
sep = '/';
#endif
if( m.param1[0] != sep )
{
strcpy( psz_file, p_args->file );
p = strrchr( psz_file, sep );
if( p != NULL )
strcpy( p + 1, m.param1 );
else
strcpy( psz_file, m.param1 );
}
else
{
strcpy( psz_file, m.param1 );
}
/* We hereby assume that psz_file is in the
* local character encoding */
if( ( f = fopen( psz_file, "r" ) ) == NULL )
{
msg_Warn( p_args->p_intf,
"unable to include file %s (%m)",
psz_file );
break;
}
/* first we load in a temporary buffer */
FileLoad( f, &p_buffer, &i_buffer );
/* we parse executing all <vlc /> macros */
Execute( p_args, p_request, i_request, pp_data, pi_data,
&dst, &p_buffer[0], &p_buffer[i_buffer] );
free( p_buffer );
fclose(f);
break;
}
case MVLC_IF:
{
bool i_test;
char *endif;
EvaluateRPN( p_intf, p_args->vars, &p_args->stack, m.param1 );
if( SSPopN( &p_args->stack, p_args->vars ) )
{
i_test = 1;
}
else
{
i_test = 0;
}
endif = MacroSearch( src, end, MVLC_END, true );
if( i_test == 0 )
{
char *start = MacroSearch( src, endif, MVLC_ELSE, true );
if( start )
{
char *stop = MacroSearch( start, endif, MVLC_END, false );
if( stop )
{
Execute( p_args, p_request, i_request,
pp_data, pi_data, &dst, start, stop );
}
}
}
else if( i_test == 1 )
{
char *stop;
if( ( stop = MacroSearch( src, endif, MVLC_ELSE, false ) ) == NULL )
{
stop = MacroSearch( src, endif, MVLC_END, false );
}
if( stop )
{
Execute( p_args, p_request, i_request,
pp_data, pi_data, &dst, src, stop );
}
}
src = endif;
break;
}
case MVLC_FOREACH:
{
char *endfor = MacroSearch( src, end, MVLC_END, true );
char *start = src;
char *stop = MacroSearch( src, end, MVLC_END, false );
if( stop )
{
mvar_t *index;
int i_idx;
mvar_t *v;
if( !strcmp( m.param2, "integer" ) )
{
char *arg = SSPop( &p_args->stack );
index = mvar_IntegerSetNew( m.param1, arg );
free( arg );
}
else if( !strcmp( m.param2, "directory" ) )
{
char *arg = SSPop( &p_args->stack );
index = mvar_FileSetNew( p_intf, m.param1, arg );
free( arg );
}
else if( !strcmp( m.param2, "services" ) )
{
index = mvar_ServicesSetNew( p_intf, m.param1 );
}
else if( !strcmp( m.param2, "playlist" ) )
{
index = mvar_PlaylistSetNew( p_intf, m.param1,
p_intf->p_sys->p_playlist );
}
else if( !strcmp( m.param2, "information" ) )
{
index = mvar_InfoSetNew( m.param1,
p_intf->p_sys->p_input );
}
else if( !strcmp( m.param2, "program" )
|| !strcmp( m.param2, "title" )
|| !strcmp( m.param2, "chapter" )
|| !strcmp( m.param2, "audio-es" )
|| !strcmp( m.param2, "video-es" )
|| !strcmp( m.param2, "spu-es" ) )
{
index = mvar_InputVarSetNew( p_intf, m.param1,
p_intf->p_sys->p_input,
m.param2 );
}
#ifdef ENABLE_VLM
else if( !strcmp( m.param2, "vlm" ) )
{
if( p_intf->p_sys->p_vlm == NULL )
p_intf->p_sys->p_vlm = vlm_New( p_intf );
index = mvar_VlmSetNew( m.param1, p_intf->p_sys->p_vlm );
}
#endif
#if 0
else if( !strcmp( m.param2, "hosts" ) )
{
index = mvar_HttpdInfoSetNew( m.param1, p_intf->p_sys->p_httpd, HTTPD_GET_HOSTS );
}
else if( !strcmp( m.param2, "urls" ) )
{
index = mvar_HttpdInfoSetNew( m.param1, p_intf->p_sys->p_httpd, HTTPD_GET_URLS );
}
else if( !strcmp( m.param2, "connections" ) )
{
index = mvar_HttpdInfoSetNew(m.param1, p_intf->p_sys->p_httpd, HTTPD_GET_CONNECTIONS);
}
#endif
else if( ( v = mvar_GetVar( p_args->vars, m.param2 ) ) )
{
index = mvar_Duplicate( v );
}
else
{
msg_Dbg( p_intf, "invalid index constructor (%s)", m.param2 );
src = endfor;
break;
}
for( i_idx = 0; i_idx < index->i_field; i_idx++ )
{
mvar_t *f = mvar_Duplicate( index->field[i_idx] );
//msg_Dbg( p_intf, "foreach field[%d] name=%s value=%s", i_idx, f->name, f->value );
free( f->name );
f->name = strdup( m.param1 );
mvar_PushVar( p_args->vars, f );
Execute( p_args, p_request, i_request,
pp_data, pi_data, &dst, start, stop );
mvar_RemoveVar( p_args->vars, f );
mvar_Delete( f );
}
mvar_Delete( index );
src = endfor;
}
break;
}
default:
MacroDo( p_args, &m, p_request, i_request,
pp_data, pi_data, &dst );
break;
}
MacroClean( &m );
continue;
}
i_copy = ( (p == NULL || p > end ) ? end : p ) - src;
if( i_copy > 0 )
{
int i_index = dst - *pp_data;
*pi_data += i_copy;
*pp_data = xrealloc( *pp_data, *pi_data );
dst = (*pp_data) + i_index;
memcpy( dst, src, i_copy );
dst += i_copy;
src += i_copy;
}
}
*pp_dst = dst;
free( dup );
}
/*****************************************************************************
* macros.h : Macros mapping for the HTTP interface
*****************************************************************************
* Copyright (C) 2001-2005 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "http.h"
enum macroType
{
MVLC_UNKNOWN = 0,
MVLC_CONTROL,
MVLC_PLAY,
MVLC_STOP,
MVLC_PAUSE,
MVLC_NEXT,
MVLC_PREVIOUS,
MVLC_ADD,
MVLC_DEL,
MVLC_EMPTY,
MVLC_SEEK,
MVLC_KEEP,
MVLC_SORT,
MVLC_MOVE,
MVLC_VOLUME,
MVLC_FULLSCREEN,
MVLC_CLOSE,
MVLC_SHUTDOWN,
MVLC_VLM_NEW,
MVLC_VLM_SETUP,
MVLC_VLM_DEL,
MVLC_VLM_PLAY,
MVLC_VLM_PAUSE,
MVLC_VLM_STOP,
MVLC_VLM_SEEK,
MVLC_VLM_LOAD,
MVLC_VLM_SAVE,
MVLC_INCLUDE,
MVLC_FOREACH,
MVLC_IF,
MVLC_RPN,
MVLC_STACK,
MVLC_ELSE,
MVLC_END,
MVLC_GET,
MVLC_SET,
MVLC_INT,
MVLC_FLOAT,
MVLC_STRING,
MVLC_VALUE
};
/* Static mapping of macros type to macro strings */
static const struct
{
const char *psz_name;
int i_type;
}
StrToMacroTypeTab [] =
{
{ "control", MVLC_CONTROL },
/* player control */
{ "play", MVLC_PLAY },
{ "stop", MVLC_STOP },
{ "pause", MVLC_PAUSE },
{ "next", MVLC_NEXT },
{ "previous", MVLC_PREVIOUS },
{ "seek", MVLC_SEEK },
{ "keep", MVLC_KEEP },
{ "fullscreen", MVLC_FULLSCREEN },
{ "volume", MVLC_VOLUME },
/* playlist management */
{ "add", MVLC_ADD },
{ "delete", MVLC_DEL },
{ "empty", MVLC_EMPTY },
{ "sort", MVLC_SORT },
{ "move", MVLC_MOVE },
/* admin control */
{ "close", MVLC_CLOSE },
{ "shutdown", MVLC_SHUTDOWN },
/* vlm control */
{ "vlm_new", MVLC_VLM_NEW },
{ "vlm_setup", MVLC_VLM_SETUP },
{ "vlm_del", MVLC_VLM_DEL },
{ "vlm_play", MVLC_VLM_PLAY },
{ "vlm_pause", MVLC_VLM_PAUSE },
{ "vlm_stop", MVLC_VLM_STOP },
{ "vlm_seek", MVLC_VLM_SEEK },
{ "vlm_load", MVLC_VLM_LOAD },
{ "vlm_save", MVLC_VLM_SAVE },
{ "rpn", MVLC_RPN },
{ "stack", MVLC_STACK },
{ "include", MVLC_INCLUDE },
{ "foreach", MVLC_FOREACH },
{ "value", MVLC_VALUE },
{ "if", MVLC_IF },
{ "else", MVLC_ELSE },
{ "end", MVLC_END },
{ "get", MVLC_GET },
{ "set", MVLC_SET },
{ "int", MVLC_INT },
{ "float", MVLC_FLOAT },
{ "string", MVLC_STRING },
/* end */
{ NULL, MVLC_UNKNOWN }
};
/*****************************************************************************
* mvar.c : Variables handling for the HTTP Interface
*****************************************************************************
* Copyright (C) 2001-2007 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "http.h"
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include <vlc_fs.h>
#include <vlc_services_discovery.h>
/* Utility function for scandir */
static int Filter( const char *foo )
{
return strcmp( foo, "." );
};
static int InsensitiveAlphasort( const char **foo1,
const char **foo2 )
{
return strcasecmp( *foo1, *foo2 );
};
mvar_t *mvar_New( const char *name, const char *value )
{
mvar_t *v = malloc( sizeof( mvar_t ) );
if( !v ) return NULL;
v->name = strdup( name );
v->value = strdup( value ? value : "" );
v->i_field = 0;
v->field = xmalloc( sizeof( mvar_t * ) );
v->field[0] = NULL;
return v;
}
void mvar_Delete( mvar_t *v )
{
int i;
free( v->name );
free( v->value );
for( i = 0; i < v->i_field; i++ )
{
mvar_Delete( v->field[i] );
}
free( v->field );
free( v );
}
void mvar_AppendVar( mvar_t *v, mvar_t *f )
{
v->field = xrealloc( v->field, sizeof( mvar_t * ) * ( v->i_field + 2 ) );
v->field[v->i_field] = f;
v->i_field++;
}
mvar_t *mvar_Duplicate( const mvar_t *v )
{
int i;
mvar_t *n;
n = mvar_New( v->name, v->value );
for( i = 0; i < v->i_field; i++ )
{
mvar_AppendVar( n, mvar_Duplicate( v->field[i] ) );
}
return n;
}
void mvar_PushVar( mvar_t *v, mvar_t *f )
{
v->field = xrealloc( v->field, sizeof( mvar_t * ) * ( v->i_field + 2 ) );
if( v->i_field > 0 )
{
memmove( &v->field[1], &v->field[0], sizeof( mvar_t * ) * v->i_field );
}
v->field[0] = f;
v->i_field++;
}
void mvar_RemoveVar( mvar_t *v, mvar_t *f )
{
int i;
for( i = 0; i < v->i_field; i++ )
{
if( v->field[i] == f )
{
break;
}
}
if( i >= v->i_field )
{
return;
}
if( i + 1 < v->i_field )
{
memmove( &v->field[i], &v->field[i+1], sizeof( mvar_t * ) * ( v->i_field - i - 1 ) );
}
v->i_field--;
/* FIXME should do a realloc */
}
mvar_t *mvar_GetVar( mvar_t *s, const char *name )
{
/* format: name[index].field */
const char *field = strchr( name, '.' );
char base[1 + (field ? (size_t)(field - name) : strlen( name ))];
char *p;
int i_index, i;
strlcpy( base, name, sizeof (base) );
if( field != NULL )
field++;
if( ( p = strchr( base, '[' ) ) != NULL )
{
char *end;
unsigned long l = strtoul( p, &end, 0 );
if( ( l > INT_MAX ) || strcmp( "]", end ) )
return NULL;
*p++ = '\0';
i_index = (int)l;
}
else
{
i_index = 0;
}
for( i = 0; i < s->i_field; i++ )
{
if( !strcmp( s->field[i]->name, base ) )
{
if( i_index > 0 )
{
i_index--;
}
else
{
if( field )
{
return mvar_GetVar( s->field[i], field );
}
else
{
return s->field[i];
}
}
}
}
return NULL;
}
const char *mvar_GetValue( mvar_t *v, const char *field )
{
if( *field == '\0' )
{
return v->value;
}
else
{
mvar_t *f = mvar_GetVar( v, field );
if( f )
{
return f->value;
}
else
{
return field;
}
}
}
void mvar_PushNewVar( mvar_t *vars, const char *name,
const char *value )
{
mvar_t *f = mvar_New( name, value );
mvar_PushVar( vars, f );
}
void mvar_AppendNewVar( mvar_t *vars, const char *name,
const char *value )
{
mvar_t *f = mvar_New( name, value );
mvar_AppendVar( vars, f );
}
/* arg= start[:stop[:step]],.. */
mvar_t *mvar_IntegerSetNew( const char *name, const char *arg )
{
char *dup = strdup( arg );
char *str = dup;
mvar_t *s = mvar_New( name, "set" );
while( str )
{
char *p;
int i_start,i_stop,i_step;
int i_match;
p = strchr( str, ',' );
if( p )
{
*p++ = '\0';
}
i_step = 0;
i_match = sscanf( str, "%d:%d:%d", &i_start, &i_stop, &i_step );
if( i_match == 1 )
{
i_stop = i_start;
i_step = 1;
}
else if( i_match == 2 )
{
i_step = i_start < i_stop ? 1 : -1;
}
if( i_match >= 1 )
{
int i;
if( ( i_start <= i_stop && i_step > 0 ) ||
( i_start >= i_stop && i_step < 0 ) )
{
for( i = i_start; ; i += i_step )
{
char value[79];
if( ( i_step > 0 && i > i_stop ) ||
( i_step < 0 && i < i_stop ) )
{
break;
}
sprintf( value, "%d", i );
mvar_PushNewVar( s, name, value );
}
}
}
str = p;
}
free( dup );
return s;
}
/********************************************************************
* Special sets handling
********************************************************************/
mvar_t *mvar_PlaylistSetNew( intf_thread_t *p_intf, char *name,
playlist_t *p_pl )
{
mvar_t *s = mvar_New( name, "set" );
playlist_Lock( p_pl );
PlaylistListNode( p_intf, p_pl, p_pl->p_root_category , name, s, 0 );
playlist_Unlock( p_pl );
return s;
}
mvar_t *mvar_InfoSetNew( char *name, input_thread_t *p_input )
{
mvar_t *s = mvar_New( name, "set" );
int i, j;
if( p_input == NULL || p_input->p == NULL /* workarround assert in input_GetItem */ )
{
return s;
}
vlc_mutex_lock( &input_GetItem(p_input)->lock );
for ( i = 0; i < input_GetItem(p_input)->i_categories; i++ )
{
info_category_t *p_category = input_GetItem(p_input)->pp_categories[i];
mvar_t *cat = mvar_New( name, "set" );
mvar_t *iset = mvar_New( "info", "set" );
mvar_AppendNewVar( cat, "name", p_category->psz_name );
mvar_AppendVar( cat, iset );
for ( j = 0; j < p_category->i_infos; j++ )
{
info_t *p_info = p_category->pp_infos[j];
mvar_t *info = mvar_New( "info", "" );
/* msg_Dbg( p_input, "adding info name=%s value=%s",
psz_name, psz_value ); */
mvar_AppendNewVar( info, "name", p_info->psz_name );
mvar_AppendNewVar( info, "value", p_info->psz_value );
mvar_AppendVar( iset, info );
}
mvar_AppendVar( s, cat );
}
vlc_mutex_unlock( &input_GetItem(p_input)->lock );
return s;
}
mvar_t *mvar_ServicesSetNew( intf_thread_t *p_intf, char *psz_name )
{
mvar_t *s = mvar_New( psz_name, "set" );
char **longnames;
char **names = vlc_sd_GetNames( p_intf, &longnames, NULL );
if( names == NULL )
goto out;
for( size_t i = 0; names[i]; i++ )
{
mvar_t *sd = mvar_New( "sd", names[i] );
mvar_AppendNewVar( sd, "name", longnames[i] );
mvar_AppendVar( s, sd );
free( names[i] );
free( longnames[i] );
}
free( longnames );
free( names );
out:
return s;
}
mvar_t *mvar_InputVarSetNew( intf_thread_t *p_intf, char *name,
input_thread_t *p_input,
const char *psz_variable )
{
intf_sys_t *p_sys = p_intf->p_sys;
mvar_t *s = mvar_New( name, "set" );
vlc_value_t val, val_list, text_list;
int i_type, i;
if( p_input == NULL )
{
return s;
}
/* Check the type of the object variable */
i_type = var_Type( p_sys->p_input, psz_variable );
/* Make sure we want to display the variable */
if( i_type & VLC_VAR_HASCHOICE )
{
var_Change( p_sys->p_input, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
if( val.i_int == 0 ) return s;
if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
return s;
}
else
{
return s;
}
switch( i_type & VLC_VAR_TYPE )
{
case VLC_VAR_VOID:
case VLC_VAR_BOOL:
case VLC_VAR_VARIABLE:
case VLC_VAR_STRING:
case VLC_VAR_INTEGER:
break;
default:
/* Variable doesn't exist or isn't handled */
return s;
}
if( var_Get( p_sys->p_input, psz_variable, &val ) < 0 )
{
return s;
}
if( var_Change( p_sys->p_input, psz_variable, VLC_VAR_GETLIST,
&val_list, &text_list ) < 0 )
{
if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
return s;
}
for( i = 0; i < val_list.p_list->i_count; i++ )
{
char psz_int[21];
mvar_t *itm;
switch( i_type & VLC_VAR_TYPE )
{
case VLC_VAR_STRING:
itm = mvar_New( name, "set" );
mvar_AppendNewVar( itm, "name", text_list.p_list->p_values[i].psz_string );
mvar_AppendNewVar( itm, "id", val_list.p_list->p_values[i].psz_string );
snprintf( psz_int, sizeof(psz_int), "%d",
( !strcmp( val.psz_string,
val_list.p_list->p_values[i].psz_string )
&& !( i_type & VLC_VAR_ISCOMMAND ) ) );
mvar_AppendNewVar( itm, "selected", psz_int );
mvar_AppendVar( s, itm );
break;
case VLC_VAR_INTEGER:
itm = mvar_New( name, "set" );
mvar_AppendNewVar( itm, "name", text_list.p_list->p_values[i].psz_string );
snprintf( psz_int, sizeof(psz_int), "%"PRId64,
val_list.p_list->p_values[i].i_int );
mvar_AppendNewVar( itm, "id", psz_int );
snprintf( psz_int, sizeof(psz_int), "%d",
( val.i_int == val_list.p_list->p_values[i].i_int )
&& !( i_type & VLC_VAR_ISCOMMAND ) );
mvar_AppendNewVar( itm, "selected", psz_int );
mvar_AppendVar( s, itm );
break;
default:
break;
}
}
/* clean up everything */
if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
var_FreeList( &val_list, &text_list );
return s;
}
#if 0
mvar_t *mvar_HttpdInfoSetNew( char *name, httpd_t *p_httpd, int i_type )
{
mvar_t *s = mvar_New( name, "set" );
httpd_info_t info;
int i;
if( !p_httpd->pf_control( p_httpd, i_type, &info, NULL ) )
{
for( i= 0; i < info.i_count; )
{
mvar_t *inf;
inf = mvar_New( name, "set" );
do
{
/* fprintf( stderr," mvar_HttpdInfoSetNew: append name=`%s' value=`%s'\n",
info.info[i].psz_name, info.info[i].psz_value ); */
mvar_AppendNewVar( inf,
info.info[i].psz_name,
info.info[i].psz_value );
i++;
} while( i < info.i_count && strcmp( info.info[i].psz_name, "id" ) );
mvar_AppendVar( s, inf );
}
}
/* free mem */
for( i = 0; i < info.i_count; i++ )
{
free( info.info[i].psz_name );
free( info.info[i].psz_value );
}
if( info.i_count > 0 )
{
free( info.info );
}
return s;
}
#endif
mvar_t *mvar_FileSetNew( intf_thread_t *p_intf, char *name,
char *psz_dir )
{
mvar_t *s = mvar_New( name, "set" );
char **ppsz_dir_content;
int i_dir_content, i;
psz_dir = RealPath( psz_dir );
/* parse psz_src dir */
if( ( i_dir_content = vlc_scandir( psz_dir, &ppsz_dir_content, Filter,
InsensitiveAlphasort ) ) == -1 )
{
if( errno != ENOENT && errno != ENOTDIR )
msg_Warn( p_intf, "error while scanning dir %s (%m)", psz_dir );
free( psz_dir );
return s;
}
for( i = 0; i < i_dir_content; i++ )
{
#ifdef HAVE_SYS_STAT_H
struct stat stat_info;
#endif
char *psz_name = ppsz_dir_content[i], *psz_ext, *psz_dummy;
char psz_tmp[strlen( psz_dir ) + 1 + strlen( psz_name ) + 1];
mvar_t *f;
#if defined( WIN32 ) || defined( __OS2__ )
if( psz_dir[0] == '\0' || (psz_dir[0] == '\\' && psz_dir[1] == '\0') )
{
strcpy( psz_tmp, psz_name );
}
else
#endif
{
sprintf( psz_tmp, "%s"DIR_SEP"%s", psz_dir, psz_name );
#ifdef HAVE_SYS_STAT_H
if( vlc_stat( psz_tmp, &stat_info ) == -1 )
{
free( psz_name );
continue;
}
#endif
}
f = mvar_New( name, "set" );
/* put lower-case file extension in 'ext' */
psz_ext = strrchr( psz_name, '.' );
psz_ext = strdup( psz_ext != NULL ? psz_ext + 1 : "" );
for( psz_dummy = psz_ext; *psz_dummy != '\0'; psz_dummy++ )
*psz_dummy = tolower( *psz_dummy );
mvar_AppendNewVar( f, "ext", psz_ext );
free( psz_ext );
#if defined( WIN32 ) || defined( __OS2__ )
if( psz_dir[0] == '\0' || (psz_dir[0] == '\\' && psz_dir[1] == '\0') )
{
char psz_tmp[3];
sprintf( psz_tmp, "%c:", psz_name[0] );
mvar_AppendNewVar( f, "name", psz_name );
mvar_AppendNewVar( f, "basename", psz_tmp );
mvar_AppendNewVar( f, "type", "directory" );
mvar_AppendNewVar( f, "size", "unknown" );
mvar_AppendNewVar( f, "date", "unknown" );
}
else
#endif
{
char psz_buf[20];
char psz_tmp[strlen( psz_dir ) + 1 + strlen( psz_name ) + 1];
sprintf( psz_tmp, "%s"DIR_SEP"%s", psz_dir, psz_name );
mvar_AppendNewVar( f, "name", psz_tmp );
mvar_AppendNewVar( f, "basename", psz_name );
#ifdef HAVE_SYS_STAT_H
if( S_ISDIR( stat_info.st_mode ) )
{
mvar_AppendNewVar( f, "type", "directory" );
}
else if( S_ISREG( stat_info.st_mode ) )
{
mvar_AppendNewVar( f, "type", "file" );
}
else
{
mvar_AppendNewVar( f, "type", "unknown" );
}
snprintf( psz_buf, sizeof( psz_buf ), "%"PRId64,
(int64_t)stat_info.st_size );
mvar_AppendNewVar( f, "size", psz_buf );
struct tm tm;
strftime( psz_buf, sizeof( psz_buf ), "Y-%m-%d %H:%M:%S",
localtime_r( &stat_info.st_mtime, &tm ) );
mvar_AppendNewVar( f, "date", psz_buf );
#else
mvar_AppendNewVar( f, "type", "unknown" );
mvar_AppendNewVar( f, "size", "unknown" );
mvar_AppendNewVar( f, "date", "unknown" );
#endif
}
mvar_AppendVar( s, f );
free( psz_name );
}
free( psz_dir );
free( ppsz_dir_content );
return s;
}
static void mvar_VlmSetNewLoop( char *name, vlm_t *vlm, mvar_t *s,
vlm_message_t *el, bool b_name )
{
/* Over name */
mvar_t *set;
int k;
/* Add a node with name and info */
set = mvar_New( name, "set" );
if( b_name )
{
mvar_AppendNewVar( set, "name", el->psz_name );
}
for( k = 0; k < el->i_child; k++ )
{
vlm_message_t *ch = el->child[k];
if( ch->i_child > 0 )
{
mvar_VlmSetNewLoop( ch->psz_name, vlm, set, ch, false );
}
else
{
if( ch->psz_value )
{
mvar_AppendNewVar( set, ch->psz_name, ch->psz_value );
}
else
{
mvar_AppendNewVar( set, el->psz_name, ch->psz_name );
}
}
}
mvar_AppendVar( s, set );
}
mvar_t *mvar_VlmSetNew( char *name, vlm_t *vlm )
{
mvar_t *s = mvar_New( name, "set" );
#ifdef ENABLE_VLM
vlm_message_t *msg;
int i;
if( vlm == NULL ) return s;
if( vlm_ExecuteCommand( vlm, "show", &msg ) )
return s;
for( i = 0; i < msg->i_child; i++ )
{
/* Over media, schedule */
vlm_message_t *ch = msg->child[i];
int j;
for( j = 0; j < ch->i_child; j++ )
{
/* Over name */
vlm_message_t *el = ch->child[j];
vlm_message_t *inf, *desc;
char psz[6 + strlen(el->psz_name)];
sprintf( psz, "show %s", el->psz_name );
if( vlm_ExecuteCommand( vlm, psz, &inf ) )
continue;
desc = inf->child[0];
mvar_VlmSetNewLoop( el->psz_name, vlm, s, desc, true );
vlm_MessageDelete( inf );
}
}
vlm_MessageDelete( msg );
#endif /* ENABLE_VLM */
return s;
}
/*****************************************************************************
* rpn.c : RPN evaluator for the HTTP Interface
*****************************************************************************
* Copyright (C) 2001-2006 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "http.h"
#include <vlc_url.h>
#include <vlc_meta.h>
#include <vlc_strings.h>
static vlc_object_t *GetVLCObject( intf_thread_t *p_intf,
const char *psz_object,
bool *pb_need_release )
{
intf_sys_t *p_sys = p_intf->p_sys;
vlc_object_t *p_object = NULL;
*pb_need_release = false;
if( !strcmp( psz_object, "VLC_OBJECT_LIBVLC" ) )
p_object = VLC_OBJECT(p_intf->p_libvlc);
else if( !strcmp( psz_object, "VLC_OBJECT_PLAYLIST" ) )
p_object = VLC_OBJECT(p_sys->p_playlist);
else if( !strcmp( psz_object, "VLC_OBJECT_INPUT" ) )
p_object = VLC_OBJECT(p_sys->p_input);
else if( p_sys->p_input )
{
if( !strcmp( psz_object, "VLC_OBJECT_VOUT" ) )
p_object = VLC_OBJECT( input_GetVout( p_sys->p_input ) );
else if( !strcmp( psz_object, "VLC_OBJECT_AOUT" ) )
p_object = VLC_OBJECT( input_GetAout( p_sys->p_input ) );
if( p_object )
*pb_need_release = true;
}
else
msg_Warn( p_intf, "unknown object type (%s)", psz_object );
return p_object;
}
void SSInit( rpn_stack_t *st )
{
st->i_stack = 0;
}
void SSClean( rpn_stack_t *st )
{
while( st->i_stack > 0 )
{
free( st->stack[--st->i_stack] );
}
}
void SSPush( rpn_stack_t *st, const char *s )
{
if( st->i_stack < STACK_MAX )
{
st->stack[st->i_stack++] = strdup( s );
}
}
char *SSPop( rpn_stack_t *st )
{
if( st->i_stack <= 0 )
{
return strdup( "" );
}
else
{
return st->stack[--st->i_stack];
}
}
int SSPopN( rpn_stack_t *st, mvar_t *vars )
{
char *name;
char *end;
int i;
name = SSPop( st );
i = strtol( name, &end, 0 );
if( end == name )
{
const char *value = mvar_GetValue( vars, name );
i = atoi( value );
}
free( name );
return( i );
}
void SSPushN( rpn_stack_t *st, int i )
{
char v[12];
snprintf( v, sizeof (v), "%d", i );
SSPush( st, v );
}
void EvaluateRPN( intf_thread_t *p_intf, mvar_t *vars,
rpn_stack_t *st, char *exp )
{
intf_sys_t *p_sys = p_intf->p_sys;
while( exp != NULL && *exp != '\0' )
{
char *p, *s;
/* skip space */
while( *exp == ' ' )
{
exp++;
}
if( *exp == '\'' )
{
/* extract string */
p = FirstWord( exp, exp );
SSPush( st, exp );
exp = p;
continue;
}
/* extract token */
p = FirstWord( exp, exp );
s = exp;
if( p == NULL )
{
exp += strlen( exp );
}
else
{
exp = p;
}
if( *s == '\0' )
{
break;
}
/* 1. Integer function */
if( !strcmp( s, "!" ) )
{
SSPushN( st, !SSPopN( st, vars ) );
}
else if( !strcmp( s, "^" ) )
{
SSPushN( st, SSPopN( st, vars ) ^ SSPopN( st, vars ) );
}
else if( !strcmp( s, "&" ) )
{
SSPushN( st, SSPopN( st, vars ) & SSPopN( st, vars ) );
}
else if( !strcmp( s, "|" ) )
{
SSPushN( st, SSPopN( st, vars ) | SSPopN( st, vars ) );
}
else if( !strcmp( s, "+" ) )
{
SSPushN( st, SSPopN( st, vars ) + SSPopN( st, vars ) );
}
else if( !strcmp( s, "-" ) )
{
int j = SSPopN( st, vars );
int i = SSPopN( st, vars );
SSPushN( st, i - j );
}
else if( !strcmp( s, "*" ) )
{
SSPushN( st, SSPopN( st, vars ) * SSPopN( st, vars ) );
}
else if( !strcmp( s, "/" ) )
{
int i, j;
j = SSPopN( st, vars );
i = SSPopN( st, vars );
SSPushN( st, j != 0 ? i / j : 0 );
}
else if( !strcmp( s, "%" ) )
{
int i, j;
j = SSPopN( st, vars );
i = SSPopN( st, vars );
SSPushN( st, j != 0 ? i % j : 0 );
}
/* 2. integer tests */
else if( !strcmp( s, "=" ) )
{
SSPushN( st, SSPopN( st, vars ) == SSPopN( st, vars ) ? -1 : 0 );
}
else if( !strcmp( s, "!=" ) )
{
SSPushN( st, SSPopN( st, vars ) != SSPopN( st, vars ) ? -1 : 0 );
}
else if( !strcmp( s, "<" ) )
{
int j = SSPopN( st, vars );
int i = SSPopN( st, vars );
SSPushN( st, i < j ? -1 : 0 );
}
else if( !strcmp( s, ">" ) )
{
int j = SSPopN( st, vars );
int i = SSPopN( st, vars );
SSPushN( st, i > j ? -1 : 0 );
}
else if( !strcmp( s, "<=" ) )
{
int j = SSPopN( st, vars );
int i = SSPopN( st, vars );
SSPushN( st, i <= j ? -1 : 0 );
}
else if( !strcmp( s, ">=" ) )
{
int j = SSPopN( st, vars );
int i = SSPopN( st, vars );
SSPushN( st, i >= j ? -1 : 0 );
}
/* 3. string functions */
else if( !strcmp( s, "strcat" ) )
{
char *s2 = SSPop( st );
char *s1 = SSPop( st );
char *str = malloc( strlen( s1 ) + strlen( s2 ) + 1 );
strcpy( str, s1 );
strcat( str, s2 );
SSPush( st, str );
free( s1 );
free( s2 );
free( str );
}
else if( !strcmp( s, "strcmp" ) )
{
char *s2 = SSPop( st );
char *s1 = SSPop( st );
SSPushN( st, strcmp( s1, s2 ) );
free( s1 );
free( s2 );
}
else if( !strcmp( s, "strncmp" ) )
{
int n = SSPopN( st, vars );
char *s2 = SSPop( st );
char *s1 = SSPop( st );
SSPushN( st, strncmp( s1, s2 , n ) );
free( s1 );
free( s2 );
}
else if( !strcmp( s, "strsub" ) )
{
int n = SSPopN( st, vars );
int m = SSPopN( st, vars );
int i_len;
char *s = SSPop( st );
char *str;
if( n >= m )
{
i_len = n - m + 1;
}
else
{
i_len = 0;
}
str = malloc( i_len + 1 );
memcpy( str, s + m - 1, i_len );
str[ i_len ] = '\0';
SSPush( st, str );
free( s );
free( str );
}
else if( !strcmp( s, "strlen" ) )
{
char *str = SSPop( st );
SSPushN( st, strlen( str ) );
free( str );
}
else if( !strcmp( s, "str_replace" ) )
{
char *psz_to = SSPop( st );
char *psz_from = SSPop( st );
char *psz_in = SSPop( st );
char *psz_in_current = psz_in;
char *psz_out = malloc( strlen(psz_in) * strlen(psz_to) + 1 );
char *psz_out_current = psz_out;
while( (p = strstr( psz_in_current, psz_from )) != NULL )
{
memcpy( psz_out_current, psz_in_current, p - psz_in_current );
psz_out_current += p - psz_in_current;
strcpy( psz_out_current, psz_to );
psz_out_current += strlen(psz_to);
psz_in_current = p + strlen(psz_from);
}
strcpy( psz_out_current, psz_in_current );
psz_out_current += strlen(psz_in_current);
*psz_out_current = '\0';
SSPush( st, psz_out );
free( psz_to );
free( psz_from );
free( psz_in );
free( psz_out );
}
else if( !strcmp( s, "url_extract" ) )
{
const char *url = mvar_GetValue( vars, "url_value" );
char *name = SSPop( st );
char *value = ExtractURIString( url, name );
if( value != NULL )
{
decode_URI( value );
SSPush( st, value );
free( value );
}
else
SSPush( st, "" );
free( name );
}
else if( !strcmp( s, "url_encode" ) )
{
char *url = SSPop( st );
char *value = encode_URI_component( url );
free( url );
SSPush( st, value );
free( value );
}
else if( !strcmp( s, "xml_encode" )
|| !strcmp( s, "htmlspecialchars" ) )
{
char *url = SSPop( st );
char *value = convert_xml_special_chars( url );
free( url );
SSPush( st, value );
free( value );
}
else if( !strcmp( s, "addslashes" ) )
{
char *psz_src = SSPop( st );
char *psz_dest;
char *str = psz_src;
p = psz_dest = malloc( strlen( str ) * 2 + 1 );
while( *str != '\0' )
{
if( *str == '"' || *str == '\'' || *str == '\\' )
{
*p++ = '\\';
}
*p++ = *str;
str++;
}
*p = '\0';
SSPush( st, psz_dest );
free( psz_src );
free( psz_dest );
}
else if( !strcmp( s, "stripslashes" ) )
{
char *psz_src = SSPop( st );
char *psz_dest;
char *str = psz_src;
p = psz_dest = strdup( psz_src );
while( *str )
{
if( *str == '\\' && *(str + 1) )
{
str++;
}
*p++ = *str++;
}
*p = '\0';
SSPush( st, psz_dest );
free( psz_src );
free( psz_dest );
}
else if( !strcmp( s, "realpath" ) )
{
char *psz_src = SSPop( st );
char *psz_dir = RealPath( psz_src );
SSPush( st, psz_dir );
free( psz_src );
free( psz_dir );
}
/* 4. stack functions */
else if( !strcmp( s, "dup" ) )
{
char *str = SSPop( st );
SSPush( st, str );
SSPush( st, str );
free( str );
}
else if( !strcmp( s, "drop" ) )
{
char *str = SSPop( st );
free( str );
}
else if( !strcmp( s, "swap" ) )
{
char *s1 = SSPop( st );
char *s2 = SSPop( st );
SSPush( st, s1 );
SSPush( st, s2 );
free( s1 );
free( s2 );
}
else if( !strcmp( s, "flush" ) )
{
SSClean( st );
SSInit( st );
}
else if( !strcmp( s, "store" ) )
{
char *value = SSPop( st );
char *name = SSPop( st );
mvar_PushNewVar( vars, name, value );
free( name );
free( value );
}
else if( !strcmp( s, "value" ) )
{
char *name = SSPop( st );
const char *value = mvar_GetValue( vars, name );
SSPush( st, value );
free( name );
}
/* 5. player control */
else if( !strcmp( s, "vlc_play" ) )
{
int i_id = SSPopN( st, vars );
int i_ret;
playlist_Lock( p_sys->p_playlist );
i_ret = playlist_Control( p_sys->p_playlist, PLAYLIST_VIEWPLAY,
pl_Locked, NULL,
playlist_ItemGetById( p_sys->p_playlist,
i_id ) );
playlist_Unlock( p_sys->p_playlist );
msg_Dbg( p_intf, "requested playlist item: %i", i_id );
SSPushN( st, i_ret );
}
else if( !strcmp( s, "vlc_stop" ) )
{
playlist_Control( p_sys->p_playlist, PLAYLIST_STOP, pl_Unlocked );
msg_Dbg( p_intf, "requested playlist stop" );
}
else if( !strcmp( s, "vlc_pause" ) )
{
playlist_Control( p_sys->p_playlist, PLAYLIST_PAUSE, pl_Unlocked );
msg_Dbg( p_intf, "requested playlist pause" );
}
else if( !strcmp( s, "vlc_next" ) )
{
playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP, pl_Unlocked, 1 );
msg_Dbg( p_intf, "requested playlist next" );
}
else if( !strcmp( s, "vlc_previous" ) )
{
playlist_Control( p_sys->p_playlist, PLAYLIST_SKIP, pl_Unlocked, -1 );
msg_Dbg( p_intf, "requested playlist previous" );
}
else if( !strcmp( s, "vlc_seek" ) )
{
char *psz_value = SSPop( st );
HandleSeek( p_intf, psz_value );
msg_Dbg( p_intf, "requested playlist seek: %s", psz_value );
free( psz_value );
}
else if( !strcmp( s, "vlc_var_type" )
|| !strcmp( s, "vlc_config_type" ) )
{
vlc_object_t *p_object;
const char *psz_type = NULL;
int i_type = 0;
if( !strcmp( s, "vlc_var_type" ) )
{
char *psz_object = SSPop( st );
char *psz_variable = SSPop( st );
bool b_need_release;
p_object = GetVLCObject( p_intf, psz_object, &b_need_release );
if( p_object != NULL )
i_type = var_Type( p_object, psz_variable );
free( psz_variable );
free( psz_object );
if( b_need_release && p_object != NULL )
vlc_object_release( p_object );
}
else
{
char *psz_variable = SSPop( st );
p_object = VLC_OBJECT(p_intf);
i_type = config_GetType( p_object, psz_variable );
free( psz_variable );
}
if( p_object != NULL )
{
switch( i_type & VLC_VAR_TYPE )
{
case VLC_VAR_BOOL:
psz_type = "VLC_VAR_BOOL";
break;
case VLC_VAR_INTEGER:
psz_type = "VLC_VAR_INTEGER";
break;
case VLC_VAR_HOTKEY:
psz_type = "VLC_VAR_HOTKEY";
break;
case VLC_VAR_STRING:
psz_type = "VLC_VAR_STRING";
break;
case VLC_VAR_VARIABLE:
psz_type = "VLC_VAR_VARIABLE";
break;
case VLC_VAR_FLOAT:
psz_type = "VLC_VAR_FLOAT";
break;
default:
psz_type = "UNDEFINED";
}
}
else
psz_type = "INVALID";
SSPush( st, psz_type );
}
else if( !strcmp( s, "vlc_var_set" ) )
{
char *psz_object = SSPop( st );
char *psz_variable = SSPop( st );
bool b_need_release;
vlc_object_t *p_object = GetVLCObject( p_intf, psz_object,
&b_need_release );
if( p_object != NULL )
{
bool b_error = false;
char *psz_value = NULL;
vlc_value_t val;
int i_type;
i_type = var_Type( p_object, psz_variable );
switch( i_type & VLC_VAR_TYPE )
{
case VLC_VAR_BOOL:
val.b_bool = SSPopN( st, vars );
msg_Dbg( p_intf, "requested %s var change: %s->%d",
psz_object, psz_variable, val.b_bool );
break;
case VLC_VAR_INTEGER:
case VLC_VAR_HOTKEY:
val.i_int = SSPopN( st, vars );
msg_Dbg( p_intf, "requested %s var change: %s->%"PRIu64,
psz_object, psz_variable, val.i_int );
break;
case VLC_VAR_STRING:
case VLC_VAR_VARIABLE:
val.psz_string = psz_value = SSPop( st );
msg_Dbg( p_intf, "requested %s var change: %s->%s",
psz_object, psz_variable, psz_value );
break;
case VLC_VAR_FLOAT:
psz_value = SSPop( st );
val.f_float = atof( psz_value );
msg_Dbg( p_intf, "requested %s var change: %s->%f",
psz_object, psz_variable, val.f_float );
break;
default:
SSPopN( st, vars );
msg_Warn( p_intf, "invalid %s variable type %d (%s)",
psz_object, i_type & VLC_VAR_TYPE, psz_variable );
b_error = true;
}
if( !b_error )
var_Set( p_object, psz_variable, val );
free( psz_value );
}
else
msg_Warn( p_intf, "vlc_var_set called without an object" );
free( psz_variable );
free( psz_object );
if( b_need_release && p_object != NULL )
vlc_object_release( p_object );
}
else if( !strcmp( s, "vlc_var_get" ) )
{
char *psz_object = SSPop( st );
char *psz_variable = SSPop( st );
bool b_need_release;
vlc_object_t *p_object = GetVLCObject( p_intf, psz_object,
&b_need_release );
if( p_object != NULL )
{
vlc_value_t val;
int i_type;
i_type = var_Type( p_object, psz_variable );
var_Get( p_object, psz_variable, &val );
switch( i_type & VLC_VAR_TYPE )
{
case VLC_VAR_BOOL:
SSPushN( st, val.b_bool );
break;
case VLC_VAR_INTEGER:
case VLC_VAR_HOTKEY:
SSPushN( st, val.i_int );
break;
case VLC_VAR_STRING:
case VLC_VAR_VARIABLE:
SSPush( st, val.psz_string );
free( val.psz_string );
break;
case VLC_VAR_FLOAT:
{
char psz_value[20];
lldiv_t value = lldiv( val.f_float * 1000000, 1000000 );
snprintf( psz_value, sizeof(psz_value), "%lld.%06u",
value.quot, (unsigned int)value.rem );
SSPush( st, psz_value );
break;
}
default:
msg_Warn( p_intf, "invalid %s variable type %d (%s)",
psz_object, i_type & VLC_VAR_TYPE, psz_variable );
SSPush( st, "" );
}
}
else
{
msg_Warn( p_intf, "vlc_var_get called without an object" );
SSPush( st, "" );
}
free( psz_variable );
free( psz_object );
if( b_need_release && p_object != NULL )
vlc_object_release( p_object );
}
else if( !strcmp( s, "vlc_object_exists" ) )
{
char *psz_object = SSPop( st );
bool b_need_release;
vlc_object_t *p_object = GetVLCObject( p_intf, psz_object,
&b_need_release );
if( b_need_release && p_object != NULL )
vlc_object_release( p_object );
if( p_object != NULL )
SSPush( st, "1" );
else
SSPush( st, "0" );
}
else if( !strcmp( s, "vlc_config_set" ) )
{
char *psz_variable = SSPop( st );
int i_type = config_GetType( p_intf, psz_variable );
switch( i_type & VLC_VAR_TYPE )
{
case VLC_VAR_BOOL:
case VLC_VAR_INTEGER:
config_PutInt( p_intf, psz_variable, SSPopN( st, vars ) );
break;
case VLC_VAR_STRING:
{
char *psz_string = SSPop( st );
config_PutPsz( p_intf, psz_variable, psz_string );
free( psz_string );
break;
}
case VLC_VAR_FLOAT:
{
char *psz_string = SSPop( st );
config_PutFloat( p_intf, psz_variable, atof(psz_string) );
free( psz_string );
break;
}
default:
msg_Warn( p_intf, "vlc_config_set called on unknown var (%s)",
psz_variable );
}
free( psz_variable );
}
else if( !strcmp( s, "vlc_config_get" ) )
{
char *psz_variable = SSPop( st );
int i_type = config_GetType( p_intf, psz_variable );
switch( i_type & VLC_VAR_TYPE )
{
case VLC_VAR_BOOL:
case VLC_VAR_INTEGER:
SSPushN( st, config_GetInt( p_intf, psz_variable ) );
break;
case VLC_VAR_STRING:
{
char *psz_string = config_GetPsz( p_intf, psz_variable );
SSPush( st, psz_string );
free( psz_string );
break;
}
case VLC_VAR_FLOAT:
{
char psz_string[20];
lldiv_t value = lldiv( config_GetFloat( p_intf, psz_variable )
* 1000000, 1000000 );
snprintf( psz_string, sizeof(psz_string), "%lld.%06u",
value.quot, (unsigned int)value.rem );
SSPush( st, psz_string );
break;
}
default:
msg_Warn( p_intf, "vlc_config_get called on unknown var (%s)",
psz_variable );
SSPush( st, "" );
}
free( psz_variable );
}
else if( !strcmp( s, "vlc_config_save" ) )
{
char *psz_module = SSPop( st );
int i_result;
if( !*psz_module )
{
free( psz_module );
psz_module = NULL;
}
i_result = config_SaveConfigFile( p_intf, psz_module );
free( psz_module );
SSPushN( st, i_result );
}
else if( !strcmp( s, "vlc_config_reset" ) )
{
config_ResetAll( p_intf );
}
/* 6. playlist functions */
else if( !strcmp( s, "playlist_add" ) )
{
char *psz_name = SSPop( st );
char *mrl = SSPop( st );
input_item_t *p_input;
int i_ret;
p_input = MRLParse( p_intf, mrl, psz_name );
char *psz_uri = input_item_GetURI( p_input );
if( !p_input || !psz_uri || !*psz_uri )
{
i_ret = VLC_EGENERIC;
msg_Dbg( p_intf, "invalid requested mrl: %s", mrl );
}
else
{
i_ret = playlist_AddInput( p_sys->p_playlist, p_input,
PLAYLIST_APPEND, PLAYLIST_END, true,
pl_Unlocked );
if( i_ret == VLC_SUCCESS )
{
playlist_item_t *p_item;
msg_Dbg( p_intf, "requested mrl add: %s", mrl );
playlist_Lock( p_sys->p_playlist );
p_item = playlist_ItemGetByInput( p_sys->p_playlist,
p_input );
if( p_item )
i_ret = p_item->i_id;
playlist_Unlock( p_sys->p_playlist );
}
else
msg_Warn( p_intf, "adding mrl %s failed", mrl );
vlc_gc_decref( p_input );
}
free( psz_uri );
SSPushN( st, i_ret );
free( mrl );
free( psz_name );
}
else if( !strcmp( s, "playlist_empty" ) )
{
playlist_Clear( p_sys->p_playlist, pl_Unlocked );
msg_Dbg( p_intf, "requested playlist empty" );
}
else if( !strcmp( s, "playlist_delete" ) )
{
int i_id = SSPopN( st, vars );
playlist_Lock( p_sys->p_playlist );
playlist_item_t *p_item = playlist_ItemGetById( p_sys->p_playlist,
i_id );
if( p_item )
{
playlist_DeleteFromInput( p_sys->p_playlist,
p_item->p_input, pl_Locked );
msg_Dbg( p_intf, "requested playlist delete: %d", i_id );
}
else
{
msg_Dbg( p_intf, "couldn't find playlist item to delete (%d)",
i_id );
}
playlist_Unlock( p_sys->p_playlist );
}
else if( !strcmp( s, "playlist_move" ) )
{
/*int i_newpos =*/ SSPopN( st, vars );
/*int i_pos =*/ SSPopN( st, vars );
/* FIXME FIXME TODO TODO XXX XXX
do not release before fixing this
if ( i_pos < i_newpos )
{
playlist_Move( p_sys->p_playlist, i_pos, i_newpos + 1 );
}
else
{
playlist_Move( p_sys->p_playlist, i_pos, i_newpos );
}
msg_Dbg( p_intf, "requested to move playlist item %d to %d",
i_pos, i_newpos);
FIXME FIXME TODO TODO XXX XXX */
msg_Err( p_intf, "moving using indexes is obsolete. We need to update this function" );
}
else if( !strcmp( s, "playlist_sort" ) )
{
int i_order = SSPopN( st, vars );
int i_sort = SSPopN( st, vars );
i_order = i_order % 2;
i_sort = i_sort % 9;
/* FIXME FIXME TODO TODO XXX XXX
do not release before fixing this
playlist_RecursiveNodeSort( p_sys->p_playlist,
p_sys->p_playlist->p_general,
i_sort, i_order );
msg_Dbg( p_intf, "requested sort playlist by : %d in order : %d",
i_sort, i_order );
FIXME FIXME TODO TODO XXX XXX */
msg_Err( p_intf, "this needs to be fixed to use the new playlist framework" );
}
else if( !strcmp( s, "services_discovery_add" ) )
{
char *psz_sd = SSPop( st );
playlist_ServicesDiscoveryAdd( p_sys->p_playlist, psz_sd );
free( psz_sd );
}
else if( !strcmp( s, "services_discovery_remove" ) )
{
char *psz_sd = SSPop( st );
playlist_ServicesDiscoveryRemove( p_sys->p_playlist, psz_sd );
free( psz_sd );
}
else if( !strcmp( s, "services_discovery_is_loaded" ) )
{
char *psz_sd = SSPop( st );
SSPushN( st,
playlist_IsServicesDiscoveryLoaded( p_sys->p_playlist, psz_sd ) );
free( psz_sd );
}
else if( !strcmp( s, "vlc_volume_set" ) )
{
char *psz_vol = SSPop( st );
int i_value;
audio_volume_t i_volume;
i_volume = aout_VolumeGet( p_sys->p_playlist );
if( psz_vol[0] == '+' )
{
i_value = atoi( psz_vol );
if( (i_volume + i_value) > AOUT_VOLUME_MAX )
aout_VolumeSet( p_sys->p_playlist, AOUT_VOLUME_MAX );
else
aout_VolumeSet( p_sys->p_playlist, i_volume + i_value );
}
else if( psz_vol[0] == '-' )
{
i_value = atoi( psz_vol );
if( (i_volume + i_value) < AOUT_VOLUME_MIN )
aout_VolumeSet( p_sys->p_playlist, AOUT_VOLUME_MIN );
else
aout_VolumeSet( p_sys->p_playlist, i_volume + i_value );
}
else if( strstr( psz_vol, "%") != NULL )
{
i_value = atoi( psz_vol );
if( i_value < 0 ) i_value = 0;
if( i_value > 400 ) i_value = 400;
aout_VolumeSet( p_sys->p_playlist, (i_value * (AOUT_VOLUME_MAX - AOUT_VOLUME_MIN))/400+AOUT_VOLUME_MIN);
}
else
{
i_value = atoi( psz_vol );
if( i_value > AOUT_VOLUME_MAX ) i_value = AOUT_VOLUME_MAX;
if( i_value < AOUT_VOLUME_MIN ) i_value = AOUT_VOLUME_MIN;
aout_VolumeSet( p_sys->p_playlist, i_value );
}
i_volume = aout_VolumeGet( p_sys->p_playlist );
free( psz_vol );
}
else if( !strcmp( s, "vlc_get_meta" ) )
{
char *psz_meta = SSPop( st );
char *psz_val = NULL;
if( p_sys->p_input && input_GetItem(p_sys->p_input) )
{
#define p_item input_GetItem( p_sys->p_input )
if( !strcmp( psz_meta, "ARTIST" ) )
{
psz_val = input_item_GetArtist( p_item );
}
else if( !strcmp( psz_meta, "TITLE" ) )
{
psz_val = input_item_GetTitle( p_item );
if( !psz_val )
psz_val = input_item_GetName( p_item );
}
else if( !strcmp( psz_meta, "ALBUM" ) )
{
psz_val = input_item_GetAlbum( p_item );
}
else if( !strcmp( psz_meta, "GENRE" ) )
{
psz_val = input_item_GetGenre( p_item );
}
else if( !strcmp( psz_meta, "COPYRIGHT" ) )
{
psz_val = input_item_GetCopyright( p_item );
}
else if( !strcmp( psz_meta, "TRACK_NUMBER" ) )
{
psz_val = input_item_GetTrackNum( p_item );
}
else if( !strcmp( psz_meta, "DESCRIPTION" ) )
{
psz_val = input_item_GetDescription( p_item );
}
else if( !strcmp( psz_meta, "RATING" ) )
{
psz_val = input_item_GetRating( p_item );
}
else if( !strcmp( psz_meta, "DATE" ) )
{
psz_val = input_item_GetDate( p_item );
}
else if( !strcmp( psz_meta, "URL" ) )
{
psz_val = input_item_GetURL( p_item );
}
else if( !strcmp( psz_meta, "LANGUAGE" ) )
{
psz_val = input_item_GetLanguage( p_item );
}
else if( !strcmp( psz_meta, "NOW_PLAYING" ) )
{
psz_val = input_item_GetNowPlaying( p_item );
}
else if( !strcmp( psz_meta, "PUBLISHER" ) )
{
psz_val = input_item_GetPublisher( p_item );
}
else if( !strcmp( psz_meta, "ENCODED_BY" ) )
{
psz_val = input_item_GetEncodedBy( p_item );
}
else if( !strcmp( psz_meta, "ART_URL" ) )
{
psz_val = input_item_GetEncodedBy( p_item );
}
else if( !strcmp( psz_meta, "TRACK_ID" ) )
{
psz_val = input_item_GetTrackID( p_item );
}
#undef p_item
}
if( psz_val == NULL ) psz_val = strdup( "" );
SSPush( st, psz_val );
free( psz_meta );
free( psz_val );
}
#ifdef ENABLE_VLM
else if( !strcmp( s, "vlm_command" ) || !strcmp( s, "vlm_cmd" ) )
{
char *psz_elt;
char *psz_cmd = strdup( "" );
char *psz_error;
vlm_message_t *vlm_answer;
/* make sure that we have a vlm object */
if( p_intf->p_sys->p_vlm == NULL )
p_intf->p_sys->p_vlm = vlm_New( p_intf );
/* vlm command uses the ';' delimiter
* (else we can't know when to stop) */
while( strcmp( psz_elt = SSPop( st ), "" )
&& strcmp( psz_elt, ";" ) )
{
char* psz_buf;
if( asprintf( &psz_buf, "%s %s", psz_cmd, psz_elt ) == -1 )
psz_buf = NULL;
free( psz_cmd );
free( psz_elt );
psz_cmd = psz_buf;
}
msg_Dbg( p_intf, "executing vlm command: %s", psz_cmd );
vlm_ExecuteCommand( p_intf->p_sys->p_vlm, psz_cmd, &vlm_answer );
if( vlm_answer->psz_value == NULL )
{
psz_error = strdup( "" );
}
else
{
if( asprintf( &psz_error , "%s : %s" , vlm_answer->psz_name,
vlm_answer->psz_value ) == -1 )
psz_error = NULL;
}
mvar_AppendNewVar( vars, "vlm_error", psz_error );
/* this is kind of a duplicate but we need to have the message
* without the command name for the "export" command */
mvar_AppendNewVar( vars, "vlm_value", vlm_answer->psz_value );
vlm_MessageDelete( vlm_answer );
free( psz_cmd );
free( psz_error );
}
#endif /* ENABLE_VLM */
else if( !strcmp( s, "snapshot" ) )
{
if( p_sys->p_input )
{
vout_thread_t *p_vout = input_GetVout( p_sys->p_input );
if( p_vout )
{
var_TriggerCallback( p_vout, "video-snapshot" );
vlc_object_release( p_vout );
msg_Dbg( p_intf, "requested snapshot" );
}
}
break;
}
else
{
SSPush( st, s );
}
}
}
/*****************************************************************************
* util.c : Utility functions for HTTP interface
*****************************************************************************
* Copyright (C) 2001-2005 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include "http.h"
#include <vlc_strings.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <vlc_fs.h>
/****************************************************************************
* File and directory functions
****************************************************************************/
/* ToUrl: create a good name for a url from filename */
static char *FileToUrl( const char *name, bool *pb_index )
{
*pb_index = false;
char *url = malloc( strlen( name ) + 2 );
if( unlikely(url == NULL) )
return NULL;
#if (DIR_SEP_CHAR == '/')
name += strspn( name, "/" );
#else
name += strspn( name, "/"DIR_SEP );
#endif
*url = '/';
strcpy( url + 1, name );
#if (DIR_SEP_CHAR != '/')
/* convert '\\' into '/' */
for( char *ptr = url; *ptr; ptr++ )
if( *ptr == DIR_SEP_CHAR )
*ptr = '/';
#endif
/* index.* -> / */
char *p = strrchr( url, '/' );
if( p != NULL && !strncmp( p, "/index.", 7 ) )
{
p[1] = '\0';
*pb_index = true;
}
return url;
}
/* Load a file */
int FileLoad( FILE *f, char **pp_data, int *pi_data )
{
int i_read;
/* just load the file */
*pi_data = 0;
*pp_data = xmalloc( 1025 ); /* +1 for \0 */
while( ( i_read = fread( &(*pp_data)[*pi_data], 1, 1024, f ) ) == 1024 )
{
*pi_data += 1024;
*pp_data = xrealloc( *pp_data, *pi_data + 1025 );
}
if( i_read > 0 )
{
*pi_data += i_read;
}
(*pp_data)[*pi_data] = '\0';
return VLC_SUCCESS;
}
/* Parse a directory and recursively add files */
int ParseDirectory( intf_thread_t *p_intf, char *psz_root,
char *psz_dir )
{
intf_sys_t *p_sys = p_intf->p_sys;
char dir[MAX_DIR_SIZE];
DIR *p_dir;
vlc_acl_t *p_acl;
FILE *file;
char *user = NULL;
char *password = NULL;
int i_dirlen;
if( ( p_dir = vlc_opendir( psz_dir ) ) == NULL )
{
if( errno != ENOENT && errno != ENOTDIR )
msg_Err( p_intf, "cannot open directory (%s)", psz_dir );
return VLC_EGENERIC;
}
i_dirlen = strlen( psz_dir );
if( i_dirlen + 10 > MAX_DIR_SIZE )
{
msg_Warn( p_intf, "skipping too deep directory (%s)", psz_dir );
closedir( p_dir );
return 0;
}
msg_Dbg( p_intf, "dir=%s", psz_dir );
snprintf( dir, sizeof( dir ), "%s"DIR_SEP".access", psz_dir );
if( ( file = vlc_fopen( dir, "r" ) ) != NULL )
{
char line[1024];
int i_size;
msg_Dbg( p_intf, "find .access in dir=%s", psz_dir );
i_size = fread( line, 1, 1023, file );
if( i_size > 0 )
{
char *p;
while( i_size > 0 && ( line[i_size-1] == '\n' ||
line[i_size-1] == '\r' ) )
{
i_size--;
}
line[i_size] = '\0';
p = strchr( line, ':' );
if( p )
{
*p++ = '\0';
user = strdup( line );
password = strdup( p );
}
}
msg_Dbg( p_intf, "using user=%s (read=%d)", user, i_size );
fclose( file );
}
snprintf( dir, sizeof( dir ), "%s"DIR_SEP".hosts", psz_dir );
p_acl = ACL_Create( p_intf, false );
if( ACL_LoadFile( p_acl, dir ) )
{
ACL_Destroy( p_acl );
struct stat st;
if( vlc_stat( dir, &st ) == 0 )
{
free( user );
free( password );
closedir( p_dir );
return VLC_EGENERIC;
}
p_acl = NULL;
}
for( ;; )
{
char *psz_filename;
/* parse psz_src dir */
if( ( psz_filename = vlc_readdir( p_dir ) ) == NULL )
{
break;
}
if( ( psz_filename[0] == '.' )
|| ( i_dirlen + strlen( psz_filename ) > MAX_DIR_SIZE ) )
{
free( psz_filename );
continue;
}
snprintf( dir, sizeof( dir ), "%s"DIR_SEP"%s", psz_dir, psz_filename );
free( psz_filename );
if( ParseDirectory( p_intf, psz_root, dir ) )
{
httpd_file_sys_t *f = NULL;
httpd_handler_sys_t *h = NULL;
bool b_index;
char *psz_name, *psz_ext;
psz_name = FileToUrl( &dir[strlen( psz_root )], &b_index );
psz_ext = strrchr( dir, '.' );
if( psz_ext != NULL )
{
int i;
psz_ext++;
for( i = 0; i < p_sys->i_handlers; i++ )
if( !strcmp( p_sys->pp_handlers[i]->psz_ext, psz_ext ) )
break;
if( i < p_sys->i_handlers )
{
f = malloc( sizeof( httpd_handler_sys_t ) );
h = (httpd_handler_sys_t *)f;
f->b_handler = true;
h->p_association = p_sys->pp_handlers[i];
}
}
if( f == NULL )
{
f = xmalloc( sizeof( httpd_file_sys_t ) );
f->b_handler = false;
}
f->p_intf = p_intf;
f->p_file = NULL;
f->p_redir = NULL;
f->p_redir2 = NULL;
f->file = strdup (dir);
f->name = psz_name;
f->b_html = strstr( &dir[strlen( psz_root )], ".htm" ) || strstr( &dir[strlen( psz_root )], ".xml" ) ? true : false;
if( !f->name )
{
msg_Err( p_intf , "unable to parse directory" );
closedir( p_dir );
free( f );
return( VLC_ENOMEM );
}
msg_Dbg( p_intf, "file=%s (url=%s)",
f->file, f->name );
if( !f->b_handler )
{
char *psz_type = strdup( "text/html; charset=UTF-8" );
if( strstr( &dir[strlen( psz_root )], ".xml" ) )
{
char *psz = strstr( psz_type, "html;" );
if( psz )
{
psz[0] = 'x';
psz[1] = 'm';
psz[2] = 'l';
psz[3] = ';';
psz[4] = ' ';
}
}
f->p_file = httpd_FileNew( p_sys->p_httpd_host,
f->name,
f->b_html ? psz_type : NULL,
user, password, p_acl,
HttpCallback, f );
free( psz_type );
if( f->p_file != NULL )
{
TAB_APPEND( p_sys->i_files, p_sys->pp_files, f );
}
}
else
{
h->p_handler = httpd_HandlerNew( p_sys->p_httpd_host,
f->name,
user, password, p_acl,
HandlerCallback, h );
if( h->p_handler != NULL )
{
TAB_APPEND( p_sys->i_files, p_sys->pp_files,
(httpd_file_sys_t *)h );
}
}
/* for url that ends by / add
* - a redirect from rep to rep/
* - in case of index.* rep/index.html to rep/ */
if( f && f->name[strlen(f->name) - 1] == '/' )
{
char *psz_redir = strdup( f->name );
char *p;
psz_redir[strlen( psz_redir ) - 1] = '\0';
msg_Dbg( p_intf, "redir=%s -> %s", psz_redir, f->name );
f->p_redir = httpd_RedirectNew( p_sys->p_httpd_host, f->name, psz_redir );
free( psz_redir );
if( b_index && ( p = strstr( f->file, "index." ) ) )
{
if( asprintf( &psz_redir, "%s%s", f->name, p ) != -1 )
{
msg_Dbg( p_intf, "redir=%s -> %s", psz_redir, f->name );
f->p_redir2 = httpd_RedirectNew( p_sys->p_httpd_host,
f->name, psz_redir );
free( psz_redir );
}
}
}
}
}
free( user );
free( password );
ACL_Destroy( p_acl );
closedir( p_dir );
return VLC_SUCCESS;
}
/*************************************************************************
* Playlist stuff
*************************************************************************/
void PlaylistListNode( intf_thread_t *p_intf, playlist_t *p_pl,
playlist_item_t *p_node, char *name, mvar_t *s,
int i_depth )
{
if( !p_node || !p_node->p_input )
return;
if( p_node->i_children == -1 )
{
char value[512];
char *psz;
playlist_item_t * p_item = playlist_CurrentPlayingItem( p_pl );
if( !p_item || !p_item->p_input )
return;
mvar_t *itm = mvar_New( name, "set" );
if( p_item->p_input == p_node->p_input )
mvar_AppendNewVar( itm, "current", "1" );
else
mvar_AppendNewVar( itm, "current", "0" );
sprintf( value, "%d", p_node->i_id );
mvar_AppendNewVar( itm, "index", value );
psz = input_item_GetName( p_node->p_input );
mvar_AppendNewVar( itm, "name", psz );
free( psz );
psz = input_item_GetURI( p_node->p_input );
mvar_AppendNewVar( itm, "uri", psz );
free( psz );
mvar_AppendNewVar( itm, "type", "Item" );
sprintf( value, "%d", i_depth );
mvar_AppendNewVar( itm, "depth", value );
if( p_node->i_flags & PLAYLIST_RO_FLAG )
mvar_AppendNewVar( itm, "ro", "ro" );
else
mvar_AppendNewVar( itm, "ro", "rw" );
sprintf( value, "%"PRId64, input_item_GetDuration( p_node->p_input ) );
mvar_AppendNewVar( itm, "duration", value );
//Adding extra meta-information to each playlist item
psz = input_item_GetTitle( p_node->p_input );
mvar_AppendNewVar( itm, "title", psz );
free( psz );
psz = input_item_GetArtist( p_node->p_input );
mvar_AppendNewVar( itm, "artist", psz );
free( psz );
psz = input_item_GetGenre( p_node->p_input );
mvar_AppendNewVar( itm, "genre", psz );
free( psz );
psz = input_item_GetCopyright( p_node->p_input );
mvar_AppendNewVar( itm, "copyright", psz );
free( psz );
psz = input_item_GetAlbum( p_node->p_input );
mvar_AppendNewVar( itm, "album", psz );
free( psz );
psz = input_item_GetTrackNum( p_node->p_input );
mvar_AppendNewVar( itm, "track", psz );
free( psz );
psz = input_item_GetDescription( p_node->p_input );
mvar_AppendNewVar( itm, "description", psz );
free( psz );
psz = input_item_GetRating( p_node->p_input );
mvar_AppendNewVar( itm, "rating", psz );
free( psz );
psz = input_item_GetDate( p_node->p_input );
mvar_AppendNewVar( itm, "date", psz );
free( psz );
psz = input_item_GetURL( p_node->p_input );
mvar_AppendNewVar( itm, "url", psz );
free( psz );
psz = input_item_GetLanguage( p_node->p_input );
mvar_AppendNewVar( itm, "language", psz );
free( psz );
psz = input_item_GetNowPlaying( p_node->p_input );
mvar_AppendNewVar( itm, "now_playing", psz );
free( psz );
psz = input_item_GetPublisher( p_node->p_input );
mvar_AppendNewVar( itm, "publisher", psz );
free( psz );
psz = input_item_GetEncodedBy( p_node->p_input );
mvar_AppendNewVar( itm, "encoded_by", psz );
free( psz );
psz = input_item_GetArtURL( p_node->p_input );
mvar_AppendNewVar( itm, "art_url", psz );
free( psz );
psz = input_item_GetTrackID( p_node->p_input );
mvar_AppendNewVar( itm, "track_id", psz );
free( psz );
mvar_AppendVar( s, itm );
}
else
{
char value[512];
int i_child;
mvar_t *itm = mvar_New( name, "set" );
mvar_AppendNewVar( itm, "name", p_node->p_input->psz_name );
mvar_AppendNewVar( itm, "uri", p_node->p_input->psz_name );
mvar_AppendNewVar( itm, "type", "Node" );
sprintf( value, "%d", p_node->i_id );
mvar_AppendNewVar( itm, "index", value );
sprintf( value, "%d", p_node->i_children);
mvar_AppendNewVar( itm, "i_children", value );
sprintf( value, "%d", i_depth );
mvar_AppendNewVar( itm, "depth", value );
if( p_node->i_flags & PLAYLIST_RO_FLAG )
mvar_AppendNewVar( itm, "ro", "ro" );
else
mvar_AppendNewVar( itm, "ro", "rw" );
mvar_AppendVar( s, itm );
for( i_child = 0 ; i_child < p_node->i_children ; i_child++ )
PlaylistListNode( p_intf, p_pl, p_node->pp_children[i_child],
name, s, i_depth + 1);
}
}
/****************************************************************************
* Seek command parsing handling
****************************************************************************/
void HandleSeek( intf_thread_t *p_intf, char *p_value )
{
intf_sys_t *p_sys = p_intf->p_sys;
vlc_value_t val;
int i_stock = 0;
uint64_t i_length;
int i_value = 0;
int i_relative = 0;
#define POSITION_ABSOLUTE 12
#define POSITION_REL_FOR 13
#define POSITION_REL_BACK 11
#define VL_TIME_ABSOLUTE 0
#define VL_TIME_REL_FOR 1
#define VL_TIME_REL_BACK -1
if( p_sys->p_input )
{
var_Get( p_sys->p_input, "length", &val );
i_length = val.i_time;
while( p_value[0] != '\0' )
{
switch(p_value[0])
{
case '+':
{
i_relative = VL_TIME_REL_FOR;
p_value++;
break;
}
case '-':
{
i_relative = VL_TIME_REL_BACK;
p_value++;
break;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
i_stock = strtol( p_value , &p_value , 10 );
break;
}
case '%': /* for percentage ie position */
{
i_relative += POSITION_ABSOLUTE;
i_value = i_stock;
i_stock = 0;
p_value[0] = '\0';
break;
}
case ':':
{
i_value = 60 * (i_value + i_stock) ;
i_stock = 0;
p_value++;
break;
}
case 'h': case 'H': /* hours */
{
i_value += 3600 * i_stock;
i_stock = 0;
/* other characters which are not numbers are not
* important */
while( ((p_value[0] < '0') || (p_value[0] > '9'))
&& (p_value[0] != '\0') )
{
p_value++;
}
break;
}
case 'm': case 'M': case '\'': /* minutes */
{
i_value += 60 * i_stock;
i_stock = 0;
p_value++;
while( ((p_value[0] < '0') || (p_value[0] > '9'))
&& (p_value[0] != '\0') )
{
p_value++;
}
break;
}
case 's': case 'S': case '"': /* seconds */
{
i_value += i_stock;
i_stock = 0;
while( ((p_value[0] < '0') || (p_value[0] > '9'))
&& (p_value[0] != '\0') )
{
p_value++;
}
break;
}
default:
{
p_value++;
break;
}
}
}
/* if there is no known symbol, I consider it as seconds.
* Otherwise, i_stock = 0 */
i_value += i_stock;
switch(i_relative)
{
case VL_TIME_ABSOLUTE:
{
if( (uint64_t)( i_value ) * 1000000 <= i_length )
val.i_time = (uint64_t)( i_value ) * 1000000;
else
val.i_time = i_length;
var_Set( p_sys->p_input, "time", val );
msg_Dbg( p_intf, "requested seek position: %dsec", i_value );
break;
}
case VL_TIME_REL_FOR:
{
var_Get( p_sys->p_input, "time", &val );
if( (uint64_t)( i_value ) * 1000000 + val.i_time <= i_length )
{
val.i_time = ((uint64_t)( i_value ) * 1000000) + val.i_time;
} else
{
val.i_time = i_length;
}
var_Set( p_sys->p_input, "time", val );
msg_Dbg( p_intf, "requested seek position forward: %dsec", i_value );
break;
}
case VL_TIME_REL_BACK:
{
var_Get( p_sys->p_input, "time", &val );
if( (int64_t)( i_value ) * 1000000 > val.i_time )
{
val.i_time = 0;
} else
{
val.i_time = val.i_time - ((uint64_t)( i_value ) * 1000000);
}
var_Set( p_sys->p_input, "time", val );
msg_Dbg( p_intf, "requested seek position backward: %dsec", i_value );
break;
}
case POSITION_ABSOLUTE:
{
val.f_float = __MIN( __MAX( ((float) i_value ) / 100.0 ,
0.0 ), 100.0 );
var_Set( p_sys->p_input, "position", val );
msg_Dbg( p_intf, "requested seek percent: %d%%", i_value );
break;
}
case POSITION_REL_FOR:
{
var_Get( p_sys->p_input, "position", &val );
val.f_float += __MIN( __MAX( ((float) i_value ) / 100.0,
0.0 ) , 100.0 );
var_Set( p_sys->p_input, "position", val );
msg_Dbg( p_intf, "requested seek percent forward: %d%%",
i_value );
break;
}
case POSITION_REL_BACK:
{
var_Get( p_sys->p_input, "position", &val );
val.f_float -= __MIN( __MAX( ((float) i_value ) / 100.0,
0.0 ) , 100.0 );
var_Set( p_sys->p_input, "position", val );
msg_Dbg( p_intf, "requested seek percent backward: %d%%",
i_value );
break;
}
default:
{
msg_Dbg( p_intf, "invalid seek request" );
break;
}
}
}
#undef POSITION_ABSOLUTE
#undef POSITION_REL_FOR
#undef POSITION_REL_BACK
#undef VL_TIME_ABSOLUTE
#undef VL_TIME_REL_FOR
#undef VL_TIME_REL_BACK
}
/****************************************************************************
* URI Parsing functions
****************************************************************************/
int TestURIParam( char *psz_uri, const char *psz_name )
{
char *p = psz_uri;
while( (p = strstr( p, psz_name )) )
{
/* Verify that we are dealing with a post/get argument */
if( (p == psz_uri || *(p - 1) == '&' || *(p - 1) == '\n')
&& p[strlen(psz_name)] == '=' )
{
return true;
}
p++;
}
return false;
}
static const char *FindURIValue( const char *psz_uri, const char *restrict psz_name,
size_t *restrict p_len )
{
const char *p = psz_uri, *end;
size_t len;
while( (p = strstr( p, psz_name )) )
{
/* Verify that we are dealing with a post/get argument */
if( (p == psz_uri || *(p - 1) == '&' || *(p - 1) == '\n')
&& p[strlen(psz_name)] == '=' )
break;
p++;
}
if( p == NULL )
{
*p_len = 0;
return NULL;
}
p += strlen( psz_name );
if( *p == '=' ) p++;
if( ( end = strchr( p, '\n' ) ) != NULL )
{
/* POST method */
if( ( end > p ) && ( end[-1] == '\r' ) )
end--;
len = end - p;
}
else
{
/* GET method */
if( ( end = strchr( p, '&' ) ) != NULL )
len = end - p;
else
len = strlen( p );
}
*p_len = len;
return p;
}
const char *ExtractURIValue( const char *restrict psz_uri,
const char *restrict psz_name,
char *restrict psz_buf, size_t bufsize )
{
size_t len;
const char *psz_value = FindURIValue( psz_uri, psz_name, &len );
const char *psz_next;
if( psz_value == NULL )
{
if( bufsize > 0 )
*psz_buf = '\0';
return NULL;
}
psz_next = psz_value + len;
if( len >= bufsize )
len = bufsize - 1;
if( len > 0 )
strncpy( psz_buf, psz_value, len );
if( bufsize > 0 )
psz_buf[len] = '\0';
return psz_next;
}
char *ExtractURIString( const char *restrict psz_uri,
const char *restrict psz_name )
{
size_t len;
const char *psz_value = FindURIValue( psz_uri, psz_name, &len );
if( psz_value == NULL )
return NULL;
char *res = malloc( len + 1 );
if( res == NULL )
return NULL;
memcpy( res, psz_value, len );
res[len] = '\0';
return res;
}
/* Since the resulting string is smaller we can work in place, so it is
* permitted to have psz == new. new points to the first word of the
* string, the function returns the remaining string. */
char *FirstWord( char *psz, char *new )
{
bool b_end;
while( *psz == ' ' )
psz++;
while( *psz != '\0' && *psz != ' ' )
{
if( *psz == '\'' )
{
char c = *psz++;
while( *psz != '\0' && *psz != c )
{
if( *psz == '\\' && psz[1] != '\0' )
psz++;
*new++ = *psz++;
}
if( *psz == c )
psz++;
}
else
{
if( *psz == '\\' && psz[1] != '\0' )
psz++;
*new++ = *psz++;
}
}
b_end = !*psz;
*new++ = '\0';
if( !b_end )
return psz + 1;
else
return NULL;
}
/**********************************************************************
* MRLParse: parse the MRL, find the MRL string and the options,
* create an item with all information in it, and return the item.
* return NULL if there is an error.
**********************************************************************/
/* Function analog to FirstWord except that it relies on colon instead
* of space to delimit option boundaries. */
static char *FirstOption( char *psz, char *new )
{
bool b_end, b_start = true;
while( *psz == ' ' )
psz++;
while( *psz != '\0' && (*psz != ' ' || psz[1] != ':') )
{
if( *psz == '\'' )
{
char c = *psz++;
while( *psz != '\0' && *psz != c )
{
if( *psz == '\\' && psz[1] != '\0' )
psz++;
*new++ = *psz++;
b_start = false;
}
if( *psz == c )
psz++;
}
else
{
if( *psz == '\\' && psz[1] != '\0' )
psz++;
*new++ = *psz++;
b_start = false;
}
}
b_end = !*psz;
if ( !b_start )
while (new[-1] == ' ')
new--;
*new++ = '\0';
if( !b_end )
return psz + 1;
else
return NULL;
}
input_item_t *MRLParse( intf_thread_t *p_intf, const char *mrl,
char *psz_name )
{
char *psz = strdup( mrl ), *s_mrl = psz, *s_temp;
if( psz == NULL )
return NULL;
/* extract the mrl */
s_temp = FirstOption( s_mrl, s_mrl );
if( s_temp == NULL )
{
s_temp = s_mrl + strlen( s_mrl );
}
input_item_t *p_input = input_item_New( p_intf, s_mrl, psz_name );
if( p_input == NULL )
return NULL;
s_mrl = s_temp;
/* now we can take care of the options */
while ( *s_mrl != '\0' )
{
s_temp = FirstOption( s_mrl, s_mrl );
if( s_mrl == '\0' )
break;
if( s_temp == NULL )
{
s_temp = s_mrl + strlen( s_mrl );
}
input_item_AddOption( p_input, s_mrl, VLC_INPUT_OPTION_TRUSTED );
s_mrl = s_temp;
}
return p_input;
}
/**********************************************************************
* RealPath: parse ../, ~ and path stuff
**********************************************************************/
char *RealPath( const char *psz_src )
{
char *psz_dir;
char *p;
int i_len = strlen(psz_src);
psz_dir = xmalloc( i_len + 2 );
strcpy( psz_dir, psz_src );
/* Add a trailing sep to ease the .. step */
psz_dir[i_len] = DIR_SEP_CHAR;
psz_dir[i_len + 1] = '\0';
#if (DIR_SEP_CHAR != '/')
/* Convert all / to native separator */
p = psz_dir;
while( (p = strchr( p, '/' )) != NULL )
{
*p = DIR_SEP_CHAR;
}
#endif
/* FIXME: this could be O(N) rather than O(N²)... */
/* Remove multiple separators and /./ */
p = psz_dir;
while( (p = strchr( p, DIR_SEP_CHAR )) != NULL )
{
if( p[1] == DIR_SEP_CHAR )
memmove( &p[1], &p[2], strlen(&p[2]) + 1 );
else if( p[1] == '.' && p[2] == DIR_SEP_CHAR )
memmove( &p[1], &p[3], strlen(&p[3]) + 1 );
else
p++;
}
if( psz_dir[0] == '~' )
{
char *home = config_GetUserDir( VLC_HOME_DIR ), *dir;
if( asprintf( &dir, "%s%s", home, psz_dir + 1 ) != -1 )
{
free( psz_dir );
psz_dir = dir;
}
free( home );
}
if( strlen(psz_dir) > 2 )
{
/* Fix all .. dir */
p = psz_dir + 3;
while( (p = strchr( p, DIR_SEP_CHAR )) != NULL )
{
if( p[-1] == '.' && p[-2] == '.' && p[-3] == DIR_SEP_CHAR )
{
char *q;
p[-3] = '\0';
if( (q = strrchr( psz_dir, DIR_SEP_CHAR )) != NULL )
{
memmove( q + 1, p + 1, strlen(p + 1) + 1 );
p = q + 1;
}
else
{
memmove( psz_dir, p, strlen(p) + 1 );
p = psz_dir + 3;
}
}
else
p++;
}
}
/* Remove trailing sep if there are at least 2 sep in the string
* (handles the C:\ stuff) */
p = strrchr( psz_dir, DIR_SEP_CHAR );
if( p != NULL && p[1] == '\0' && p != strchr( psz_dir, DIR_SEP_CHAR ) )
*p = '\0';
return psz_dir;
}
......@@ -400,13 +400,6 @@ modules/control/gestures.c
modules/control/globalhotkeys/win32.c
modules/control/globalhotkeys/xcb.c
modules/control/hotkeys.c
modules/control/http/http.c
modules/control/http/http.h
modules/control/http/macro.c
modules/control/http/macros.h
modules/control/http/mvar.c
modules/control/http/rpn.c
modules/control/http/util.c
modules/control/lirc.c
modules/control/motion.c
modules/control/netsync.c
......
......@@ -30,7 +30,6 @@ EXTRA_DIST = \
$(skins2_default_vlt_FILES) \
$(DIST_rsrc) \
$(DIST_skins2) \
$(DIST_http) \
$(DIST_http_lua) \
$(DIST_lua) \
$(DIST_osdmenu_default) \
......@@ -42,9 +41,6 @@ if BUILD_SKINS
nobase_vlcdata_DATA += skins2/default.vlt
nobase_vlcdata_DATA += $(DIST_skins2)
endif
if BUILD_HTTPD
nobase_vlcdata_DATA += $(DIST_http)
endif
if BUILD_OSDMENU
nobase_vlcdata_DATA += \
$(DIST_osdmenu_default)
......@@ -86,72 +82,6 @@ skins2/default.vlt: $(skins2_default_vlt_FILES)
LC_ALL=C sort -z | \
tar cvv --exclude .svn --no-recursion --null -T -) | \
gzip -n > skins2/default.vlt
DIST_http = \
http/.hosts \
http/dialogs/.hosts \
http/dialogs/browse \
http/dialogs/footer \
http/dialogs/input \
http/dialogs/main \
http/dialogs/mosaic \
http/dialogs/playlist \
http/dialogs/sout \
http/dialogs/vlm \
http/favicon.ico \
http/images/delete.png \
http/images/delete_small.png \
http/images/eject.png \
http/images/empty.png \
http/images/fullscreen.png \
http/images/help.png \
http/images/info.png \
http/images/loop.png \
http/images/minus.png \
http/images/next.png \
http/images/pause.png \
http/images/play.png \
http/images/playlist.png \
http/images/playlist_small.png \
http/images/plus.png \
http/images/prev.png \
http/images/refresh.png \
http/images/repeat.png \
http/images/sd.png \
http/images/shuffle.png \
http/images/slider_bar.png \
http/images/slider_left.png \
http/images/slider_point.png \
http/images/slider_right.png \
http/images/snapshot.png \
http/images/slow.png \
http/images/sort.png \
http/images/sout.png \
http/images/speaker.png \
http/images/speaker_mute.png \
http/images/stop.png \
http/images/vlc16x16.png \
http/images/volume_down.png \
http/images/volume_up.png \
http/images/white.png \
http/images/white_cross_small.png \
http/index.html \
http/js/functions.js \
http/js/mosaic.js \
http/js/vlm.js \
http/mosaic.html \
http/requests/browse.xml \
http/requests/playlist.xml \
http/requests/status.xml \
http/requests/vlm.xml \
http/requests/vlm_cmd.xml \
http/requests/README.txt \
http/style.css \
http/iehacks.css \
http/vlm.html \
http/vlm_export.html \
http/flash.html
DIST_osdmenu_default = \
osdmenu/default.cfg \
osdmenu/default/unselected.png \
......
#
# Access-list for VLC HTTP interface
# $Id$
#
# localhost
::1
127.0.0.1
# link-local addresses
#fe80::/64
# private addresses
#fc00::/7
#fec0::/10
#10.0.0.0/8
#172.16.0.0/12
#192.168.0.0/16
#169.254.0.0/16
# The world (uncommenting these 2 lines is not quite safe)
#::/0
#0.0.0.0/0
# This file is an empty access list. Leave it as is.
# You are not supposed to access files from this directory directly.
<vlc id="if" param1="0" />
vim:syntax=html
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< browse: VLC media player web interface - remote file browse dialog
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
This dialog needs the following dialogs to be fully functional: <none>
<vlc id="end" />
<div id="browse" class="popup" style="display: none;">
<div class="title">
Browse
<img class="close" src="images/white_cross_small.png" alt="Close" onclick="hide('browse');"/>
</div>
<div id="browser">
<a href="javascript:browse_dir(document.getElementById( 'browse_lastdir' ).value);">Click here to browse</a>
( or <a href="javascript:browse_dir('');">here</a> if it doesn't work )
</div>
<div class="controls">
<button id="btn_browse_close" onclick="hide('browse');">
Close
</button>
<input type="hidden" id="browse_lastdir" value="~" />
<input type="hidden" id="browse_dest" value="" />
</div>
</div>
<vlc id="if" param1="0" />
vim:syntax=html
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< footer: VLC media player web interface - VLC copyright footer
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
This dialog needs the following dialogs to be fully functional: <none>
<vlc id="end" />
<div id="footer" class="dialog" >
<a href="/">main VLC interface</a> -
<a href="/vlm.html">VLM interface</a> -
<a href="/mosaic.html">Mosaic wizard</a> -
<a href="/flash.html">Flash based remote playback</a> -
<a href="http://www.videolan.org">VideoLAN website</a>
<br />
<vlc id="value" param1="copyright" />
</div>
<vlc id="if" param1="0" />
vim:syntax=html
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< input: VLC media player web interface - input selection dialog
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
This dialog needs the following dialogs to be fully functional: browse
<vlc id="end" />
<div id="input" class="dialog" style="display: none">
<div class="title">
Input
<img class="close" src="images/white_cross_small.png" alt="Close" onclick="hide('input');"/>
</div>
<div class="controls">
<label for="input_mrl">Input (MRL)</label>
<vlc id="if" param1="page value 'vlm' strcmp 0 =" />
<input type="text" name="input_mrl" id="input_mrl" size="60" onkeypress="if( event.keyCode == 13 ) vlm_input_change();"/>
<input type="button" value="Ok" onclick="vlm_input_change();" />
<input type="button" value="Cancel" onclick="hide('input');" />
<input type="hidden" id="input_dest" value="" />
<vlc id="else" />
<input type="text" name="input_mrl" id="input_mrl" size="60" onkeypress="if( event.keyCode == 13 ) in_play();"/>
<input type="button" value="Play" onclick="in_play();" />
<input type="button" value="Enqueue" onclick="in_enqueue();" />
<vlc id="end" />
<br/>
<!--<button id="btn_inhide" onclick="hide_input();">
Hide
</button>-->
<button id="btn_file" onclick="hide_input();show('input_file');update_input_file();">
File
</button>
<button id="btn_disc" onclick="hide_input();show('input_disc');update_input_disc();">
Disc
</button>
<button id="btn_network" onclick="hide_input();show('input_network');update_input_net();">
Network
</button>
<button id="btn_fake" onclick="hide_input();show('input_fake');update_input_fake();">
Fixed image
</button>
</div>
<div id="input_helper" class="helper" >
<div id="input_file" style="display: block">
Open File
<hr/>
<label for="input_file_filename">File name</label>
<input type="text" id="input_file_filename" size="60" onchange="update_input_file();" onfocus="update_input_file();"/>
<input type="button" id="input_file_browse" value="Browse" onclick="browse( 'input_file_filename' );" />
<!-- <hr/>
<input type="checkbox" id="input_sub_options" />
<label for="input_sub_options">Subtitle options *TODO/FIXME/FIXHTTPD*</label>
<br/>
<label for="input_sub_file">Subtitles file</label>
<input type="text" id="input_sub_file" size="60" />
<br/>
<label for="input_sub_enc">Subtitles encoding</label>
<select id="input_sub_enc">
<option></option>
</select>
<br/>
<label for="input_sub_size">Font size</label>
<select id="input_sub_size">
<option></option>
</select>
<label for="input_sub_justification">Justification</label>
<select id="input_sub_justification">
<option></option>
</select>
<br/>
<label for="input_sub_fps">Frames per second</label>
<input type="text" id="input_sub_fps" />
<label for="input_sub_delay">Delay</label>
<input type="text" id="input_sub_delay" />-->
</div>
<div id="input_disc" style="display: none">
Open Disc
<hr/>
Disc type :
<input type="radio" name="input_disc_type" id="input_disc_dvdmenu" value="dvd" onchange="update_input_disc();" />
<label for="input_disc_dvdmenu">DVD (menus)</label>
<input type="radio" name="input_disc_type" id="input_disc_dvd" value="dvdsimple" onchange="update_input_disc();" />
<label for="input_disc_dvd">DVD</label>
<input type="radio" name="input_disc_type" id="input_disc_vcd" value="vcd" onchange="update_input_disc();" />
<label for="input_disc_vcd">VCD</label>
<input type="radio" name="input_disc_type" id="input_disc_cdda" value="cdda" onchange="update_input_disc();" />
<label for="input_disc_cdda">Audio CD</label>
<hr/>
<table>
<tr>
<td>
<label for="input_disc_dev">Device name</label>
</td>
<td>
<input type="text" id="input_disc_dev" onchange="update_input_disc();" />
</td>
</tr>
<tr>
<td>
<label for="input_disc_title">Title</label>
</td>
<td>
<input type="text" id="input_disc_title" onchange="update_input_disc();" />
</td>
</tr>
<tr>
<td>
<label for="input_disc_chapter">Chapter</label>
</td>
<td>
<input type="text" id="input_disc_chapter" onchange="update_input_disc();" />
</td>
</tr>
<tr>
<td>
<label for="input_disc_subtrack">Subtitles track</label>
</td>
<td>
<input type="text" id="input_disc_subtrack" onchange="update_input_disc();" />
</td>
</tr>
<tr>
<td>
<label for="input_disc_audiotrack">Audio track</label>
</td>
<td>
<input type="text" id="input_disc_audiotrack" onchange="update_input_disc();" />
</td>
</tr>
</table>
</div>
<div id="input_network" style="display: none">
Open Network
<hr/>
<table>
<tr>
<td>
<input type="radio" name="input_net_type" id="input_net_udp" value="udp" onchange="update_input_net();" />
<label for="input_net_udp">UDP/RTP</label>
</td>
<td>
<label for="input_net_udp_port">Port</label>
<input type="text" id="input_net_udp_port" size="6" onchange="update_input_net();" />
<input type="checkbox" id="input_net_udp_forceipv6" onchange="update_input_net();" />
<label for="input_net_udp_forceipv6">Force IPv6</label>
</td>
</tr>
<tr>
<td>
<input type="radio" name="input_net_type" id="input_net_udpmcast" value="udpmcast" onchange="update_input_net();" />
<label for="input_net_udpmcast">UDP/RTP Multicast</label>
</td>
<td>
<label for="input_net_udpmcast_address">Address</label>
<input type="text" id="input_net_udpmcast_address" onchange="update_input_net();" />
<label for="input_net_udpmcast_port">Port</label>
<input type="text" id="input_net_udpmcast_port" size="6" onchange="update_input_net();" />
</td>
</tr>
<tr>
<td>
<input type="radio" name="input_net_type" id="input_net_http" value="http" onchange="update_input_net();" />
<label for="input_net_http">HTTP/HTTPS/FTP/MMS</label>
</td>
<td>
<label for="input_net_http_url">URL</label>
<input type="text" id="input_net_http_url" onchange="update_input_net();" />
</td>
</tr>
<tr>
<td>
<input type="radio" name="input_net_type" id="input_net_rtsp" value="rtsp" onchange="update_input_net();" />
<label for="input_net_rtsp">RTSP</label>
</td>
<td>
<label for="input_net_rtsp_url">URL</label>
<input type="text" id="input_net_rtsp_url" value="rtsp://" onchange="update_input_net();" />
</td>
</tr>
<tr>
<td>
<input type="checkbox" id="input_net_timeshift" onchange="update_input_net();" />
<label for="input_net_timeshift">Allow timeshifting</label>
</td>
<td></td>
</tr>
</table>
</div>
<div id="input_fake" style="display: none">
Fixed image stream (fake)
<hr/>
<label for="input_fake_filename">Image file name</label>
<input type="text" id="input_fake_filename" size="60" onchange="update_input_fake();" onfocus="update_input_fake();"/>
<input type="button" id="input_fake_browse" value="Browse" onclick="browse( 'input_fake_filename' );" />
<hr/>
<label for="input_fake_width">Width</label>
<input type="text" id="input_fake_width" size="8" onchange="update_input_fake();" />
<label for="input_fake_height">Height</label>
<input type="text" id="input_fake_height" size="8" onchange="update_input_fake();" />
<label for="input_fake_ar">Aspect ratio</label>
<input type="text" id="input_fake_ar" size="8" onchange="update_input_fake();" />
</div>
</div>
</div>
<vlc id="if" param1="0" />
vim:syntax=html
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< main: VLC media player web interface - main VLC controler
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
This dialog needs the following dialogs to be fully functional: input,
sout and playlist .
<vlc id="end" />
<div id="main" class="dialog" >
<div class="title">
VLC media player
<button id="btn_toggle_text" onclick="toggle_btn_text();" title="Help" >
<img src="images/help.png" alt="Help" />
Help
</button>
</div>
<div class="controls">
<button id="btn_open" onclick="toggle_show('input');" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Open" >
<img src="images/eject.png" alt="Open" />
<span class="btn_text">Open</span>
</button>
&nbsp;
<button id="btn_stop" onclick="pl_stop();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Stop" >
<img src="images/stop.png" alt="Stop" />
<span class="btn_text">Stop</span>
</button>
<!--<button id="btn_play" onclick="alert('FIXME');" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Play" >
<img src="images/play.png" alt="Play" />
<span class="btn_text">Play</span>
</button>-->
<button id="btn_pause" onclick="pl_pause();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Pause" >
<img src="images/pause.png" alt="Pause" id="btn_pause_img" />
<span class="btn_text">Pause</span>
</button>
&nbsp;
<button id="btn_previous" onclick="pl_previous();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Previous" >
<img src="images/prev.png" alt="Previous" />
<span class="btn_text">Previous</span>
</button>
<button id="btn_next" onclick="pl_next();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Next" >
<img src="images/next.png" alt="Next" />
<span class="btn_text">Next</span>
</button>
&nbsp;
<button id="btn_sout" onclick="toggle_show('sout');" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Stream Output" >
<img src="images/sout.png" alt="Stream Output" />
<span class="btn_text">Stream Output</span>
</button>
<button id="btn_playlist" onclick="toggle_show('playlist');" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Playlist" >
<img src="images/playlist.png" alt="Playlist" />
<span class="btn_text">Playlist</span>
</button>
<button id="btn_info" onclick="toggle_show('info');" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Info" >
<img src="images/info.png" alt="Info" />
<span class="btn_text">Info</span>
</button>
&nbsp;
<button id="btn_fullscreen" onclick="fullscreen();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Fullscreen" >
<img src="images/fullscreen.png" alt="Fullscreen" />
<span class="btn_text">Fullscreen</span>
</button>
&nbsp;
<button id="btn_snapshot" onclick="snapshot();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Take video snapshot" >
<img src="images/snapshot.png" alt="Take video snapshot" />
<span class="btn_text">Take video snapshot</span>
</button>
&nbsp;
<button id="btn_volume_down" onclick="volume_down();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Decrease Volume" >
<img src="images/volume_down.png" alt="Decrease Volume" />
<span class="btn_text">Decrease Volume</span>
</button>
<button id="btn_volume_up" onclick="volume_up();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Increase Volume" >
<img src="images/volume_up.png" alt="Increase Volume" />
<span class="btn_text">Increase Volume</span>
</button>
<button id="btn_volume_mute" onclick="volume_mute();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Mute Volume" >
<img src="images/speaker_mute.png" alt="Mute Volume" />
<span class="btn_text">Mute Volume</span>
</button>
</div>
<div id="status">
<span id="state">(?)</span>
-
Time : <span id="time">(?)</span>/<span id="length">(?)</span>
-
Volume : <span id="volume">(?)</span>
<br/>
<!-- progress bar -->
<img src="images/slider_left.png" alt="slider left" /><span id="progressbar" style="background-image: url( 'images/slider_bar.png' ); width: 408px; height:16px; position:absolute;" onclick="slider_seek( event, this );" onmousemove="slider_move( event, this );"><img src="images/slider_point.png" alt="slider point" style="position:relative; left:0px;" id="main_slider_point" onmousedown="slider_down( event, this );" onmouseup="slider_up( event, this.parentNode );" onmouseout="slider_up( event, this.parentNode );"/></span><img src="images/slider_right.png" alt="slider right" style="position:relative;left:408px;" />
<br/>
<span id="nowplaying">(?)</span>
<img id="albumart" alt="" src="/art" style="float: right" onclick="refresh_albumart(true);"/>
</div>
</div>
<div id="info" class="dialog" style="display: none;" >
<div class="title">
Stream and media info
<img class="close" src="images/white_cross_small.png" alt="Close" onclick="hide('info');"/>
</div>
<div id="infotree">
</div>
</div>
<vlc id="if" param1="0" />
vim:syntax=html
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< mosaic: VLC media player web interface - mosaic wizard
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
This dialog needs the following dialogs to be fully functional: input and
sout.
<vlc id="end" />
<div id="mosaic" class="dialog">
<div class="title">
VLC media player - Mosaic wizard
<button id="btn_toggle_text" onclick="toggle_btn_text();">
<img src="images/help.png" alt="Help" />
Help
</button>
</div>
<div class="controls">
<b>Mosaic dimensions:</b><br/>
<table style="text-align: right;">
<tr>
<td>
<label for="bg_width">Background width*:</label> <input class="mosaic_bg" type="text" id="bg_width" value="400" size="8" onchange="mosaic_size_change();" />
</td>
<td>
<label for="bg_height">Background height*:</label> <input class="mosaic_bg" type="text" id="bg_height" value="300" size="8" onchange="mosaic_size_change();" />
</td>
</tr>
<tr>
<td>
<label for="mosaic_width">Width:</label> <input class="mosaic_tbl" type="text" id="mosaic_width" value="200" size="8" onchange="mosaic_size_change();" />
</td>
<td>
<label for="mosaic_height">Height:</label> <input class="mosaic_tbl" type="text" id="mosaic_height" value="200" size="8" onchange="mosaic_size_change();" />
</td>
</tr>
<tr>
<td>
<label for="mosaic_xoffset">X offset (left):</label> <input class="mosaic_tbl" type="text" id="mosaic_xoffset" value="10" size="8" onchange="mosaic_size_change();" />
</td>
<td>
<label for="mosaic_yoffset">Y offset (top):</label> <input class="mosaic_tbl" type="text" id="mosaic_yoffset" value="10" size="8" onchange="mosaic_size_change();" />
</td>
</tr>
<tr>
<td>
<label for="mosaic_cols">Columns:</label> <input class="mosaic_itm" type="text" id="mosaic_cols" value="2" size="8" onchange="mosaic_size_change();" />
</td>
<td>
<label for="mosaic_rows">Rows:</label> <input class="mosaic_itm" type="text" id="mosaic_rows" value="2" size="8" onchange="mosaic_size_change();" />
</td>
</tr>
<tr>
<td>
<label for="mosaic_hborder">Horizontal border:</label> <input class="mosaic_itm" type="text" id="mosaic_hborder" value="10" size="8" onchange="mosaic_size_change();" />
</td>
<td>
<label for="mosaic_vborder">Vertical border:</label> <input class="mosaic_itm" type="text" id="mosaic_vborder" value="5" size="8" onchange="mosaic_size_change();" />
</td>
</tr>
<tr>
<td colspan="2">
*: these values aren't used by the mosaic code.<br/> They're only here to adapt the preview's size.
</td>
</tr>
</table>
<b>Background:</b><br/>
<label for="mosaic_bg_input">Input:<label> <input type="text" id="mosaic_bg_input" class="mosaic_bg" value="" size="60" onblur="mosaic_code_update();" /> <input type="button" value="Edit" onclick="vlm_input_edit( 'mosaic_bg_input' );" /><br/>
<b>Item:</b><br/>
<label for="mosaic_input_name">Name:</label> <input type="text" id="mosaic_input_name" value="" class="mosaic_itm" />
<label for="mosaic_input">Input:</label> <input type="text" id="mosaic_input" value="" class="mosaic_itm" /> <input type="button" value="Edit" onclick="vlm_input_edit( 'mosaic_input' );" /> <input type="button" value="Add to input list" onclick="mosaic_add_input();" /><br/>
<b>Stream:</b> (leave this empty to display locally)<br/>
<label for="mosaic_output">Output:</label> <input type="text" id="mosaic_output" value="" size="60" onblur="mosaic_code_update();" /> <input type="button" value="Edit" onclick="vlm_output_edit( 'mosaic_output' );" /><br/>
<div id="mosaic_feedback"></div>
</div>
<div id="mosaic_list" class="popup">[<a href="javascript:hide('mosaic_list');">hide</a>] - Select a stream:<br/><div id="mosaic_list_content"></div></div>
<div class="controls">
Click on each of the cells to assign inputs. (<a href="javascript:document.getElementById('mosaic_list').value='';show('mosaic_list');">Show input list</a>)
</div>
</div>
<div id="mosaic_layout" class="mosaic_bg"></div>
<div class="dialog" style="overflow:visible;">
<div class="controls">
<input type="button" value="Let's go!" onclick="mosaic_batch(document.getElementById('mosaic_code').value);" />
<input type="button" value="Stop" onclick="mosaic_stop()" />
<input type="button" id="mosaic_code_show" value="Show VLM code" onclick="show('mosaic_code_div');hide('mosaic_code_show');showinline('mosaic_code_hide');" />
<input type="button" id="mosaic_code_hide" style="display:none" value="Hide VLM code" onclick="hide('mosaic_code_div');hide('mosaic_code_hide');showinline('mosaic_code_show');" />
<br/><br/>
</div>
<div id="mosaic_code_div" style="display:none;" >
Edit the following VLM command batch if you want to fine tune your mosaic settings:
<textarea id="mosaic_code" cols="80" rows="30"></textarea>
</div>
</div>
<vlc id="if" param1="0" />
vim:syntax=html
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< playlist: VLC media player web interface - playlist dialog
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
This dialog needs the following dialogs to be fully functional: <none>
<vlc id="end" />
<div id="playlist" class="dialog" >
<div class="title">
Playlist
<img class="close" src="images/white_cross_small.png" alt="Close" onclick="hide('playlist');"/>
</div>
<div class="controls">
<table>
<tr>
<td>
<!--<button id="btn_delete" onmouseover="button_over(this);" onmouseout="button_out(this);">
<img src="images/delete.png" alt="Delete" />
<span class="btn_text">Delete</span>
</button>-->
<button id="btn_empty" onclick="pl_empty();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Empty" >
<img src="images/empty.png" alt="Empty" />
<span class="btn_text">Empty</span>
</button>
<button id="btn_shuffle" onclick="pl_shuffle();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Shuffle" >
<img src="images/shuffle.png" alt="Shuffle" />
<span class="btn_text">Shuffle</span>
</button>
<button id="btn_loop" onclick="pl_loop();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Loop" >
<img src="images/loop.png" alt="Loop" />
<span class="btn_text">Loop</span>
</button>
<button id="btn_repeat" onclick="pl_repeat();" onmouseover="button_over(this);" onmouseout="button_out(this);" title="Repeat" >
<img src="images/repeat.png" alt="Repeat" />
<span class="btn_text">Repeat</span>
</button>
</td>
<td onmouseout="hide_menu('menu_sort');" onmouseover="show_menu('menu_sort');" >
<button id="btn_sort" title="Sort" >
<img src="images/sort.png" alt="Sort" />
<span class="btn_text">Sort</span>
</button>
<div id="menu_sort" class="menu" >
<button class="menuout" onclick="pl_sort(1,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Name ascending" >Name</button><br/>
<button class="menuout" onclick="pl_sort(1,1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Name descending" >Name reverse</button><br/>
<button class="menuout" onclick="pl_sort(3,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Author ascending" >Author</button><br/>
<button class="menuout" onclick="pl_sort(3,1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Author ascending" >Author reverse</button><br/>
<button class="menuout" onclick="pl_sort(5,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Randomize" >Random</button><br/>
<button class="menuout" onclick="pl_sort(7,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Track number" >Track number</button><br/>
<button class="menuout" onclick="pl_sort(0,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Id ascending" >Id</button><br/>
<button class="menuout" onclick="pl_sort(0,1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Id descending" >Id reverse</button><br/>
</div>
</td>
<td onmouseover="show_menu('menu_sd');" onmouseout="hide_menu('menu_sd');">
<button id="btn_sd" title="Services Discovery" >
<img src="images/sd.png" alt="Services Discovery" />
<span class="btn_text">Services Discovery</span>
</button>
<div id="menu_sd" class="menu" >
<vlc id="foreach" param1="sd" param2="services" />
<button onclick="pl_sd('<vlc id="value" param1="sd value url_encode" />');hide_menu('menu_sd');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" class="menuout" title="Toggle <vlc id="value" param1="sd.name" />" ><vlc id="value" param1="sd.name" /></button><br/>
<vlc id="end" />
</div>
</td>
</tr>
</table>
</div>
<div id="playtree">
(?)
</div>
</div>
<vlc id="if" param1="0" />
vim:syntax=html
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< sout: VLC media player web interface - stream output dialog
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
This dialog needs the following dialogs to be fully functional: <none>
Note that the sout chain is used and sent to VLC by the input dialog
<vlc id="end" />
<div id="sout" class="dialog" style="display: none">
<div class="title">
Stream Output
<img class="close" src="images/white_cross_small.png" alt="Close" onclick="hide('sout');"/>
</div>
<div class="controls">
<label for="sout_mrl">Destination (MRL)</label>
<vlc id="if" param1="page value 'vlm' strcmp 0 =" />
<input type="text" name="sout_mrl" id="sout_mrl" size="60" onkeypress="if( event.keyCode == 13 ) vlm_output_change();"/>
<br/>
<input type="button" value="Ok" onclick="vlm_output_change();" />
<input type="button" value="Cancel" onclick="hide('sout');" />
<input type="hidden" id="sout_dest" />
<vlc id="else" />
<input type="text" name="sout_mrl" id="sout_mrl" size="60" onkeypress="if( event.keyCode == 13 ) save_sout();" />
<br/>
<input type="button" value="Save" onclick="save_sout();" />
<vlc id="end" />
<input type="button" value="Reset" onclick="reset_sout();"/>
<input type="hidden" id="sout_old_mrl" value="" /> <!-- FIXME -->
<input type="button" id="sout_helper_toggle" onclick="toggle_show_sout_helper()" value="Hide sout interface" />
</div>
<div id="sout_helper" class="helper">
Stream Output Helper
<hr/>
<div id="sout_method">
<table>
<tr>
<td>
<input type="checkbox" id="sout_display" onchange="update_sout()"/>
<label for="sout_display">Display</label>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
<input type="checkbox" id="sout_file" onchange="update_sout()"/>
<label for="sout_file">File</label>
</td>
<td>
<label for="sout_file_filename">File name</label>
<input type="text" id="sout_file_filename" onchange="update_sout()"/>
</td>
<td></td>
</tr>
<tr>
<td>
<input type="checkbox" id="sout_http" onchange="update_sout()"/>
<label for="sout_http">HTTP</label>
</td>
<td>
<label for="sout_http_addr">Address</label>
<input type="text" id="sout_http_addr" onchange="update_sout()"/>
</td>
<td>
<label for="sout_http_port">Port</label>
<input type="text" id="sout_http_port" onchange="update_sout()"/>
</td>
</tr>
<tr>
<td>
<input type="checkbox" id="sout_mmsh" onchange="update_sout()"/>
<label for="sout_mmsh">MMSH</label>
</td>
<td>
<label for="sout_mmsh_addr">Address</label>
<input type="text" id="sout_mmsh_addr" onchange="update_sout()"/>
</td>
<td>
<label for="sout_mmsh_port">Port</label>
<input type="text" id="sout_mmsh_port" onchange="update_sout()"/>
</td>
</tr>
<tr>
<td>
<input type="checkbox" id="sout_rtp" onchange="update_sout()"/>
<label for="sout_rtp">RTP</label>
</td>
<td>
<label for="sout_rtp_addr">Address</label>
<input type="text" id="sout_rtp_addr" onchange="update_sout()"/>
</td>
<td>
<label for="sout_rtp_port">Port</label>
<input type="text" id="sout_rtp_port" onchange="update_sout()"/>
</td>
</tr>
<tr>
<td>
<input type="checkbox" id="sout_udp" onchange="update_sout()"/>
<label for="sout_udp">UDP</label>
</td>
<td>
<label for="sout_udp_addr">Address</label>
<input type="text" id="sout_udp_addr" onchange="update_sout()"/>
</td>
<td>
<label for="sout_udp_port">Port</label>
<input type="text" id="sout_udp_port" onchange="update_sout()"/>
</td>
</tr>
</table>
</div>
<hr/>
<div id="sout_muxh">
<input type="radio" name="sout_mux" id="sout_mux_default" value="" onchange="update_sout()" />
<label for="sout_mux_default">Default</label>
<input type="radio" name="sout_mux" id="sout_mux_ts" value="ts" onchange="update_sout()"/>
<label for="sout_mux_ts">MPEG TS</label>
<input type="radio" name="sout_mux" id="sout_mux_ps" value="ps" onchange="update_sout()"/>
<label for="sout_mux_ps">MPEG PS</label>
<input type="radio" name="sout_mux" id="sout_mux_mpeg1" value="mpeg1" onchange="update_sout()"/>
<label for="sout_mux_ts">MPEG 1</label>
<input type="radio" name="sout_mux" id="sout_mux_ogg" value="ogg" onchange="update_sout()"/>
<label for="sout_mux_ts">OGG</label>
<br/>
<input type="radio" name="sout_mux" id="sout_mux_asf" value="asf" onchange="update_sout()"/>
<label for="sout_mux_ts">ASF</label>
<input type="radio" name="sout_mux" id="sout_mux_mp4" value="mp4" onchange="update_sout()"/>
<label for="sout_mux_ts">MP4</label>
<input type="radio" name="sout_mux" id="sout_mux_mov" value="mov" onchange="update_sout()"/>
<label for="sout_mux_ts">MOV</label>
<input type="radio" name="sout_mux" id="sout_mux_wav" value="wav" onchange="update_sout()"/>
<label for="sout_mux_ts">WAV</label>
<input type="radio" name="sout_mux" id="sout_mux_raw" value="raw" onchange="update_sout()"/>
<label for="sout_mux_ts">Raw</label>
</div>
<hr/>
<div id="sout_transcode">
<input type="hidden" id="sout_transcode_extra" value="" />
<table>
<tr>
<td>
<input type="checkbox" id="sout_vcodec_s" onchange="update_sout()"/>
<label for="sout_vcodec_s">Video Codec</label>
</td>
<td>
<select id="sout_vcodec" onchange="update_sout()">
<option value="mp1v">mp1v</option>
<option value="mp2v">mp2v</option>
<option value="mp4v">mp4v</option>
<option value="DIV1">DIV1</option>
<option value="DIV2">DIV2</option>
<option value="DIV3">DIV3</option>
<option value="H263">H263</option>
<option value="H264">H264</option>
<option value="WMV1">WMV1</option>
<option value="WMV2">WMV2</option>
<option value="MJPG">MJPG</option>
<option value="theo">theo</option>
</select>
</td>
<td>
<label for="sout_vb">Bitrate (kb/s)</label>
<select id="sout_vb" onchange="update_sout()">
<option value="4096">4096</option>
<option value="3072">3072</option>
<option value="2048">2048</option>
<option value="1024">1024</option>
<option value="768">768</option>
<option value="512">512</option>
<option value="384">384</option>
<option value="256">256</option>
<option value="192">192</option>
<option value="128">128</option>
<option value="96">96</option>
<option value="64">64</option>
<option value="32">32</option>
<option value="16">16</option>
</select>
</td>
<td>
<label for="sout_scale">Scale</label>
<select id="sout_scale" onchange="update_sout()">
<option value="0.25">0.25</option>
<option value="0.5">0.5</option>
<option value="0.75">0.75</option>
<option value="1" selected="selected">1</option>
<option value="1.25">1.25</option>
<option value="1.5">1.5</option>
<option value="1.75">1.75</option>
<option value="2">2</option>
</select>
</td>
</tr>
<tr>
<td>
<input type="checkbox" id="sout_acodec_s" onchange="update_sout()"/>
<label for="sout_acodec_s">Audio Codec</label>
</td>
<td>
<select id="sout_acodec" onchange="update_sout()">
<option value="mpga">mpga</option>
<option value="mp2a">mp2a</option>
<option value="mp3">mp3</option>
<option value="mp4a">mp4a</option>
<option value="a52">a52</option>
<option value="vorb">vorb</option>
<option value="flac">flac</option>
<option value="spx">spx</option>
<option value="s16l">s16l</option>
<option value="fl32">fl32</option>
</select>
</td>
<td>
<label for="sout_ab">Bitrate (kb/s)</label>
<select id="sout_ab" onchange="update_sout()">
<option value="512">512</option>
<option value="384">384</option>
<option value="256">256</option>
<option value="192">192</option>
<option value="128">128</option>
<option value="96">96</option>
<option value="64">64</option>
<option value="32">32</option>
<option value="16">16</option>
</select>
</td>
<td>
<label for="sout_channels">Channels</label>
<select id="sout_channels" onchange="update_sout()">
<option value="">default</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="4">4</option>
<option value="6">6</option>
</select>
</td>
</tr>
<tr>
<td>
<input type="checkbox" id="sout_sub" onchange="update_sout()"/>
<label for="sout_sub">Subtitles Codec</label>
</td>
<td>
<select id="sout_scodec" onchange="update_sout()">
<option value="dvbs">dvbs</option>
</select>
</td>
<td colspan="2">
<input type="checkbox" id="sout_soverlay" onchange="update_sout()"/>
<label for="sout_soverlay">Subtitles overlay</label>
</td>
</tr>
</table>
</div>
<hr/>
<div id="sout_misc">
<input type="checkbox" id="sout_sap" onchange="update_sout()"/>
<label for="sout_sap">SAP announce</label>
<br/>
<label for="sout_sap_group">Group name</label>
<input type="text" id="sout_sap_group" onchange="update_sout()"/>
<label for="sout_sap_name">Channel name</label>
<input type="text" id="sout_sap_name" onchange="update_sout()"/>
<hr/>
<input type="checkbox" id="sout_all" onchange="update_sout()"/>
<label for="sout_all">Select all elementary streams</label>
<hr/>
<label for="sout_ttl">Time-To-Live (TTL)</label>
<input type="text" id="sout_ttl" onchange="update_sout()"/>
</div>
</div>
</div>
<vlc id="if" param1="0" />
vim:syntax=html
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< vlm: VLC media player web interface - VLM controler
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
This dialog needs the following dialogs to be fully functional: input,
sout and vlmelements .
<vlc id="end" />
<div id="vlm" class="dialog" >
<div class="title">
VLC media player - VLM interface
<!--
<button id="btn_toggle_text" onclick="toggle_btn_text();">
<img src="images/help.png" alt="Help" />
Help
</button>
-->
</div>
<div class="controls">
<label for="vlm_command">VLM command:</label>
<input type="text" id="vlm_command" size="60" onkeypress="if( event.keyCode == 13 ) vlm_send();" />
<input type="button" value="Send" onclick="vlm_send();" />
<br />
<span id="vlm_error"></span>
<br />
<span id="vlm_helper_controls">
<button id="btn_broadcast" onclick="hide_vlm_add();show('vlm_add_broadcast');update_vlm_add_broadcast();" onmouseover="button_over(this);" onmouseout="button_out(this);">
Broadcast
</button>
<button id="btn_vod" onclick="hide_vlm_add();show('vlm_add_vod');update_vlm_add_vod();" onmouseover="button_over(this);" onmouseout="button_out(this);">
Video on Demand
</button>
<button id="btn_schedule" onclick="hide_vlm_add();show('vlm_add_schedule');update_vlm_add_schedule();" onmouseover="button_over(this);" onmouseout="button_out(this);">
Schedule
</button>
<button id="btn_other" onclick="hide_vlm_add();show('vlm_add_other');update_vlm_add_other();" onmouseover="button_over(this);" onmouseout="button_out(this);">
Other
</button>
</span>
<button id="btn_vlm_helper_toggle" onclick="toggle_show_vlm_helper();" onmouseover="button_over(this);" onmouseout="button_out(this);">
Hide VLM helper
</button>
</div>
<div id="vlm_helper" class="helper" >
<div id="vlm_add_broadcast" style="display: block">
New broadcast element
<hr />
<label for="vlm_broadcast_name">Name</label>
<input type="text" id="vlm_broadcast_name" size="20" onchange="update_vlm_add_broadcast();" />
<input type="checkbox" id="vlm_broadcast_enabled" onchange="update_vlm_add_broadcast();" />
<label for="vlm_broadcast_enabled">Enable</label>
<input type="checkbox" id="vlm_broadcast_loop" onchange="update_vlm_add_broadcast();" />
<label for="vlm_broadcast_loop">Loop</label>
<br/>
<label for="vlm_broadcast_input">Input</label>
<input type="text" id="vlm_broadcast_input" size="60" onblur="update_vlm_add_broadcast();" />
<input type="button" value="Edit" onclick="vlm_input_edit('vlm_broadcast_input');" />
<br/>
<label for="vlm_broadcast_output">Output</label>
<input type="text" id="vlm_broadcast_output" size="60" onblur="update_vlm_add_broadcast();" />
<input type="button" value="Edit" onclick="vlm_output_edit('vlm_broadcast_output');" />
<br/>
</div>
<div id="vlm_add_vod" style="display: none">
New video on demand element
<hr />
<label for="vlm_vod_name">Name</label>
<input type="text" id="vlm_vod_name" size="20" onchange="update_vlm_add_vod();" />
<input type="checkbox" id="vlm_vod_enabled" onchange="update_vlm_add_vod();" />
<label for="vlm_vod_enabled">Enable</label>
<br/>
<label for="vlm_vod_input">Input</label>
<input type="text" id="vlm_vod_input" size="60" onblur="update_vlm_add_vod();" />
<input type="button" value="Edit" onclick="vlm_input_edit('vlm_vod_input');" />
<br/>
<label for="vlm_vod_output">Output (leave empty unless you want to transcode)</label>
<input type="text" id="vlm_vod_output" size="60" onblur="update_vlm_add_vod();" />
<input type="button" value="Edit" onclick="vlm_output_edit('vlm_vod_output');" />
<br/>
</div>
<div id="vlm_add_schedule" style="display: none">
New schedule
<hr />
<label for="vlm_schedule_name">Name</label>
<input type="text" id="vlm_schedule_name" size="20" onchange="update_vlm_add_schedule();" />
<input type="checkbox" id="vlm_schedule_enabled" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_enabled">Enable</label>
<br />
Schedule date:
<input type="checkbox" id="vlm_schedule_now" onchange="toggle_schedule_date();update_vlm_add_schedule();" />
<label for="vlm_schedule_now">Now</label>
<br/>
<label for="vlm_schedule_year">Year:</label>
<input type="text" id="vlm_schedule_year" value="1970" size="4" maxlength="4" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_month">Month:</label>
<input type="text" id="vlm_schedule_month" value="01" size="2" maxlength="2" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_day">Day:</label>
<input type="text" id="vlm_schedule_day" value="01" size="2" maxlength="2" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_hour">Hour:</label>
<input type="text" id="vlm_schedule_hour" value="00" size="2" maxlength="2" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_minute">Minute:</label>
<input type="text" id="vlm_schedule_minute" value="59" size="2" maxlength="2" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_second">Second:</label>
<input type="text" id="vlm_schedule_second" value="59" size="2" maxlength="2" onchange="update_vlm_add_schedule();" />
<br/>
Schedule period:<br/>
<input type="checkbox" id="vlm_schedule_repeat" onchange="toggle_schedule_repeat();update_vlm_add_schedule();" />
<label for="vlm_schedule_repeat">Repeat</label>
<br />
<label for="vlm_schedule_period_year">Year:</label>
<input type="text" id="vlm_schedule_period_year" value="0" size="4" disabled="disabled" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_period_month">Month:</label>
<input type="text" id="vlm_schedule_period_month" value="0" size="2" disabled="disabled" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_period_day">Day:</label>
<input type="text" id="vlm_schedule_period_day" value="0" size="2" disabled="disabled" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_period_hour">Hour:</label>
<input type="text" id="vlm_schedule_period_hour" value="0" size="2" disabled="disabled" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_period_minute">Minute:</label>
<input type="text" id="vlm_schedule_period_minute" value="0" size="4" disabled="disabled" onchange="update_vlm_add_schedule();" />
<label for="vlm_schedule_period_second">Second:</label>
<input type="text" id="vlm_schedule_period_second" value="0" size="4" disabled="disabled" onchange="update_vlm_add_schedule();" />
<br />
<label for="vlm_schedule_repeat_times">Number of repetitions (use 0 to repeat endlessly):</label>
<input type="text" id="vlm_schedule_repeat_times" size="8" disabled="disabled" value="0" onchange="update_vlm_add_schedule();" />
</div>
<div id="vlm_add_other" style="display: none">
<input type="button" id="btn_import" onclick="vlm_batch(document.getElementById('vlm_batch_text').value);" value="Send command batch" />
<input type="button" id="btn_export" onclick="document.location.assign('vlm_export.html');" value="Export VLM commands (new page)" />
<br/>
<textarea cols="70" rows="20" id="vlm_batch_text">#paste your VLM commands here</textarea>
</div>
</div>
</div>
<div id="vlm_broadcast" class="dialog" >
<div class="title">
Broadcast Elements
<button id="btn_refresh_broadcast" onclick="vlm_get_elements();" title="Refresh" >
<img src="images/refresh.png" alt="Refresh" />
</button>
</div>
<div id="vlm_broadcast_list" class="list"></div>
</div>
<div id="vlm_vod" class="dialog" >
<div class="title">
Video on Demand Elements
<button id="btn_refresh_vod" onclick="vlm_get_elements();" title="Refresh" >
<img src="images/refresh.png" alt="Refresh" />
</button>
</div>
<div id="vlm_vod_list" class="list"></div>
</div>
<div id="vlm_schedule" class="dialog" >
<div class="title">
Schedule Elements
<button id="btn_refresh_schedule" onclick="vlm_get_elements();" title="Refresh" >
<img src="images/refresh.png" alt="Refresh" />
</button>
</div>
<div id="vlm_schedule_list" class="list"></div>
</div>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>VLC media player - Web Interface with Flash Viewer</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="style.css" rel="stylesheet" type="text/css" />
<!--[if IE ]>
<link href="iehacks.css" rel="stylesheet" type="text/css" />
<![endif]-->
<script type="text/javascript" src="js/functions.js"></script>
<script type="text/javascript">
// <![CDATA[
host = document.location.toString().replace( /http:\/\//, '' ).replace( /[:/].*/, '' );
// ]]>
</script>
</head>
<body onload="hide('playlist');">
<vlc id="include" param1="dialogs/browse" />
<vlc id="include" param1="dialogs/main" />
<vlc id="include" param1="dialogs/input" />
<vlc id="include" param1="dialogs/playlist" />
<input id="sout_mrl" type="hidden" value=":sout=#transcode{vcodec=FLV1,acodec=mp3,channels=2,samplerate=44100}:std{access=http,mux=ffmpeg{mux=flv},dst=0.0.0.0:8081/stream.flv} :no-sout-keep" />
<div style='height: 100%; width: 100%; text-align: center;'>
<object type="application/x-shockwave-flash" data="http://flowplayer.sourceforge.net/video/FlowPlayer.swf" width="800px" height="600px" id="FlowPlayer" style="z-index: 0">
<param name="allowScriptAccess" value="sameDomain" />
<param name="movie" value="http://flowplayer.sourceforge.net/video/FlowPlayer.swf" />
<param name="quality" value="high" />
<!-- <param name="scale" value="noScale" />-->
<param name="wmode" value="transparent" />
<!-- <param name="flashvars" value="config={ loop: false, initialScale: \'fit\', autoPlay: false, configInject: true}" />-->
<script type="text/javascript">
// <![CDATA[
document.write( '' +
' <param name="flashvars" value="config={ loop: false, initialScale: \'fit\', autoPlay: false, playList: [{ url: \'http://' + host + ':8081/stream.flv\', controlEnabled: true}] }" />' );
// ]]>
</script>
</object>
<p style="font-size: small;">Uses the <a href="http://flowplayer.sourceforge.net/">Flow Player</a> free flash video player for playback (client side).</p>
</div>
<vlc id="include" param1="dialogs/footer" />
</body>
</html>
/*****************************************************************************
* iehacks.css: VLC media player web interface
*****************************************************************************
* Copyright (C) 2006 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
div.menu {
margin-left: -30px;
margin-top: 15px;
background: #fff;
}
div.menu button {
background: #fff;
}
div.menu button.menuout {
border: 1px solid #fff;
}
div#mosaic_list {
background: #fff;
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< index.html: VLC media player web interface
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>VLC media player - Web Interface</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="style.css" rel="stylesheet" type="text/css" />
<!--[if IE ]>
<link href="iehacks.css" rel="stylesheet" type="text/css" />
<![endif]-->
<script type="text/javascript" src="js/functions.js"></script>
<!-- in case people had scripts that sent commands to the default
index.html page -->
<vlc id="control" param1="stop,pause,previous,next,add,sout,play,delete,empty,seek,fullscreen,keep,volume,sort,move" />
<vlc id="set" param1="sout" param2="string" />
</head>
<body onload="loop_refresh();">
<noscript>
<hr/>
<p>
Warning: Your browser doesn't support JavaScript.
</p>
<hr/>
</noscript>
<vlc id="include" param1="dialogs/browse" />
<vlc id="include" param1="dialogs/main" />
<vlc id="include" param1="dialogs/input" />
<vlc id="include" param1="dialogs/sout" />
<vlc id="include" param1="dialogs/playlist" />
<vlc id="include" param1="dialogs/footer" />
</body>
</html>
/*****************************************************************************
* functions.js: VLC media player web interface
*****************************************************************************
* Copyright (C) 2005-2006 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/**********************************************************************
* Global variables
*********************************************************************/
var old_time = 0;
var pl_cur_id;
var albumart_id = -1;
var req = null;
/**********************************************************************
* Slider functions
*********************************************************************/
var slider_mouse_down = 0;
var slider_dx = 0;
/* findPosX() from http://www.quirksmode.rg/js/indpos.html */
function findPosX(obj)
{
var curleft = 0;
if (obj.offsetParent)
{
while (obj.offsetParent)
{
curleft += obj.offsetLeft
obj = obj.offsetParent;
}
}
else if (obj.x)
curleft += obj.x;
return curleft;
}
function slider_seek( e, bar )
{
seek(Math.floor(( e.clientX + document.body.scrollLeft - findPosX( bar )) / 4)+"%25");
}
function slider_down( e, point )
{
slider_mouse_down = 1;
slider_dx = e.clientX - findPosX( point );
}
function slider_up( e, bar )
{
slider_mouse_down = 0;
/* slider_seek( e, bar ); */
}
function slider_move( e, bar )
{
if( slider_mouse_down == 1 )
{
var slider_position = Math.floor( e.clientX - slider_dx + document.body.scrollLeft - findPosX( bar ));
document.getElementById( 'main_slider_point' ).style.left = slider_position+"px";
slider_seek( e, bar );
}
}
/**********************************************************************
* Misc utils
*********************************************************************/
/* XMLHttpRequest wrapper */
function loadXMLDoc( url, callback )
{
// branch for native XMLHttpRequest object
if ( window.XMLHttpRequest )
{
req = new XMLHttpRequest();
req.onreadystatechange = callback;
req.open( "GET", url, true );
req.send( null );
// branch for IE/Windows ActiveX version
}
else if ( window.ActiveXObject )
{
req = new ActiveXObject( "Microsoft.XMLHTTP" );
if ( req )
{
req.onreadystatechange = callback;
req.open( "GET", url, true );
req.send();
}
}
}
/* fomat time in second as hh:mm:ss */
function format_time( s )
{
var hours = Math.floor(s/3600);
var minutes = Math.floor((s/60)%60);
var seconds = Math.floor(s%60);
if( hours < 10 ) hours = "0"+hours;
if( minutes < 10 ) minutes = "0"+minutes;
if( seconds < 10 ) seconds = "0"+seconds;
return hours+":"+minutes+":"+seconds;
}
/* delete all a tag's children and add a text child node */
function set_text( id, val )
{
var elt = document.getElementById( id );
while( elt.hasChildNodes() )
elt.removeChild( elt.firstChild );
elt.appendChild( document.createTextNode( val ) );
}
/* set item's 'element' attribute to value */
function set_css( item, element, value )
{
for( var j = 0; j < document.styleSheets.length; j++ )
{
var cssRules = document.styleSheets[j].cssRules;
if( !cssRules ) cssRules = document.styleSheets[j].rules;
for( var i = 0; i < cssRules.length; i++)
{
if( cssRules[i].selectorText == item )
{
if( cssRules[i].style.setProperty )
cssRules[i].style.setProperty( element, value, null );
else
cssRules[i].style.setAttribute( toCamelCase( element ), value );
return;
}
}
}
}
/* get item's 'element' attribute */
function get_css( item, element )
{
for( var j = 0; j < document.styleSheets.length; j++ )
{
var cssRules = document.styleSheets[j].cssRules;
if( !cssRules ) cssRules = document.styleSheets[j].rules;
for( var i = 0; i < cssRules.length; i++)
{
if( cssRules[i].selectorText == item )
{
if( cssRules[i].style.getPropertyValue )
return cssRules[i].style.getPropertyValue( element );
else
return cssRules[i].style.getAttribute( toCamelCase( element ) );
}
}
}
}
function toggle_show( id )
{
var element = document.getElementById( id );
if( element.style.display == 'block' || element.style.display == '' )
{
element.style.display = 'none';
}
else
{
element.style.display = 'block';
}
}
function toggle_show_node( id )
{
var element = document.getElementById( 'pl_'+id );
var img = document.getElementById( 'pl_img_'+id );
if( element.style.display == 'block' || element.style.display == '' )
{
element.style.display = 'none';
img.setAttribute( 'src', 'images/plus.png' );
img.setAttribute( 'alt', '[+]' );
}
else
{
element.style.display = 'block';
img.setAttribute( 'src', 'images/minus.png' );
img.setAttribute( 'alt', '[-]' );
}
}
function show( id ){ document.getElementById( id ).style.display = 'block'; }
function showinline( id ){ document.getElementById( id ).style.display = 'inline'; }
function hide( id ){ document.getElementById( id ).style.display = 'none'; }
function checked( id ){ return document.getElementById( id ).checked; }
function value( id ){ return document.getElementById( id ).value; }
function setclass( obj, value )
{
obj.setAttribute( 'class', value ); /* Firefox */
obj.setAttribute( 'className', value ); /* IE */
}
function radio_value( name )
{
var radio = document.getElementsByName( name );
for( var i = 0; i < radio.length; i++ )
{
if( radio[i].checked )
{
return radio[i].value;
}
}
return "";
}
function check_and_replace_int( id, val )
{
var objRegExp = /^\d+$/;
if( value( id ) != ''
&& ( !objRegExp.test( value( id ) )
|| parseInt( value( id ) ) < 1 ) )
return document.getElementById( id ).value = val;
return document.getElementById( id ).value;
}
function addslashes( str ){ return str.replace(/\'/g, '\\\''); }
function escapebackslashes( str ){ return str.replace(/\\/g, '\\\\'); }
function toCamelCase( str )
{
str = str.split( '-' );
var cml = str[0];
for( var i=1; i<str.length; i++)
cml += str[i].charAt(0).toUpperCase()+str[i].substring(1);
return cml;
}
function disable( id ){ document.getElementById( id ).disabled = true; }
function enable( id ){ document.getElementById( id ).disabled = false; }
function button_over( element ){ element.style.border = "1px solid #000"; }
function button_out( element ){ element.style.border = "1px solid #fff"; }
function button_out_menu( element ){ element.style.border = "1px solid transparent"; }
function show_menu( id ){ document.getElementById(id).style.display = 'block'; }
function hide_menu( id ){ document.getElementById(id).style.display = 'none'; }
/* toggle show help under the buttons */
function toggle_btn_text()
{
if( get_css( '.btn_text', 'display' ) == 'none' )
{
set_css( '.btn_text', 'display', 'block' );
}
else
{
set_css( '.btn_text', 'display', 'none' );
}
}
function clear_children( elt )
{
if( elt )
while( elt.hasChildNodes() )
elt.removeChild( elt.firstChild );
}
function playlist_populated()
{
if( document.getElementById( 'playtree' ) != null && document.getElementById( 'playtree' ).childElementCount > 0 )
{
return true;
}
return false;
}
/**********************************************************************
* Interface actions
*********************************************************************/
/* input actions */
function in_play()
{
var input = value('input_mrl');
if( value('sout_mrl') != '' )
input += ' '+value('sout_mrl');
var url = 'requests/status.xml?command=in_play&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
loadXMLDoc( url, parse_status );
setTimeout( 'update_playlist()', 1000 );
}
function in_enqueue()
{
var input = value('input_mrl');
if( value('sout_mrl') != '' )
input += ' '+value('sout_mrl');
var url = 'requests/status.xml?command=in_enqueue&input='+encodeURIComponent( addslashes(escapebackslashes(input)) );
loadXMLDoc( url, parse_status );
setTimeout( 'update_playlist()', 1000 );
}
/* playlist actions */
function pl_play( id )
{
loadXMLDoc( 'requests/status.xml?command=pl_play&id='+id, parse_status );
pl_cur_id = id;
setTimeout( 'update_playlist()', 1000 );
}
function pl_pause()
{
loadXMLDoc( 'requests/status.xml?command=pl_pause&id='+pl_cur_id, parse_status );
}
function pl_stop()
{
loadXMLDoc( 'requests/status.xml?command=pl_stop', parse_status );
setTimeout( 'update_playlist()', 1000 );
}
function pl_next()
{
loadXMLDoc( 'requests/status.xml?command=pl_next', parse_status );
setTimeout( 'update_playlist()', 1000 );
}
function pl_previous()
{
loadXMLDoc( 'requests/status.xml?command=pl_previous', parse_status );
setTimeout( 'update_playlist()', 1000 );
}
function pl_delete( id )
{
loadXMLDoc( 'requests/status.xml?command=pl_delete&id='+id, parse_status );
setTimeout( 'update_playlist(true)', 1000 );
}
function pl_empty()
{
loadXMLDoc( 'requests/status.xml?command=pl_empty', parse_status );
setTimeout( 'update_playlist(true)', 1000 );
}
function pl_sort( sort, order )
{
loadXMLDoc( 'requests/status.xml?command=pl_sort&id='+order+'&val='+sort, parse_status );
setTimeout( 'update_playlist(true)', 1000 );
}
function pl_shuffle()
{
loadXMLDoc( 'requests/status.xml?command=pl_random', parse_status );
setTimeout( 'update_playlist(true)', 1000 );
}
function pl_loop()
{
loadXMLDoc( 'requests/status.xml?command=pl_loop', parse_status );
}
function pl_repeat()
{
loadXMLDoc( 'requests/status.xml?command=pl_repeat', parse_status );
}
function pl_sd( value )
{
loadXMLDoc( 'requests/status.xml?command=pl_sd&val='+value, parse_status );
}
/* misc actions */
function volume_down()
{
loadXMLDoc( 'requests/status.xml?command=volume&val=-20', parse_status );
}
function volume_up()
{
loadXMLDoc( 'requests/status.xml?command=volume&val=%2B20', parse_status );
}
function volume_mute()
{
loadXMLDoc( 'requests/status.xml?command=volume&val=0', parse_status );
}
function seek( pos )
{
loadXMLDoc( 'requests/status.xml?command=seek&val='+pos, parse_status );
}
function fullscreen()
{
loadXMLDoc( 'requests/status.xml?command=fullscreen', parse_status );
}
function snapshot()
{
loadXMLDoc( 'requests/status.xml?command=snapshot', parse_status );
}
function hotkey( str )
{
/* Use hotkey name (without the "key-" part) as the argument to simulate a hotkey press */
loadXMLDoc( 'requests/status.xml?command=key&val='+str, parse_status );
}
function update_status()
{
if( req == null || req.readyState == 0 || req.readyState == 4 )
{
loadXMLDoc( 'requests/status.xml', parse_status );
}
}
function update_playlist(force_refresh)
{
if( force_refresh || !playlist_populated() )
{
loadXMLDoc( 'requests/playlist.xml', parse_playlist );
}
else
{
loadXMLDoc( 'requests/status.xml', update_playlist_view );
}
}
/**********************************************************************
* Parse xml replies to XMLHttpRequests
*********************************************************************/
/* parse request/status.xml */
function parse_status()
{
if( req.readyState == 4 )
{
if( req.status == 200 )
{
var status = req.responseXML.documentElement;
var timetag = status.getElementsByTagName( 'time' );
if( timetag.length > 0 )
{
var new_time = timetag[0].firstChild.data;
}
else
{
new_time = old_time;
}
var lengthtag = status.getElementsByTagName( 'length' );
var length;
if( lengthtag.length > 0 )
{
length = lengthtag[0].firstChild.data;
}
else
{
length = 0;
}
var slider_position;
positiontag = status.getElementsByTagName( 'position' );
if( length < 100 && positiontag.length > 0 )
{
slider_position = ( positiontag[0].firstChild.data * 4 ) + "px";
}
else if( length > 0 )
{
/* this is more precise if length > 100 */
slider_position = Math.floor( ( new_time * 400 ) / length ) + "px";
}
else
{
slider_position = 0;
}
if( old_time > new_time )
setTimeout('update_playlist()',50);
old_time = new_time;
set_text( 'time', format_time( new_time ) );
set_text( 'length', format_time( length ) );
if( status.getElementsByTagName( 'volume' ).length != 0 )
set_text( 'volume', Math.floor(status.getElementsByTagName( 'volume' )[0].firstChild.data/5.12)+'%' );
var statetag = status.getElementsByTagName( 'state' );
if( statetag.length > 0 )
{
set_text( 'state', statetag[0].firstChild.data );
}
else
{
set_text( 'state', '(?)' );
}
if( slider_mouse_down == 0 )
{
document.getElementById( 'main_slider_point' ).style.left = slider_position;
}
var statustag = status.getElementsByTagName( 'state' );
if( statustag.length > 0 ? statustag[0].firstChild.data == "playing" : 0 )
{
document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/pause.png' );
document.getElementById( 'btn_pause_img' ).setAttribute( 'alt', 'Pause' );
document.getElementById( 'btn_pause' ).setAttribute( 'title', 'Pause' );
}
else
{
document.getElementById( 'btn_pause_img' ).setAttribute( 'src', 'images/play.png' );
document.getElementById( 'btn_pause_img' ).setAttribute( 'alt', 'Play' );
document.getElementById( 'btn_pause' ).setAttribute( 'title', 'Play' );
}
var randomtag = status.getElementsByTagName( 'random' );
if( randomtag.length > 0 ? randomtag[0].firstChild.data == "1" : 0)
setclass( document.getElementById( 'btn_shuffle'), 'on' );
else
setclass( document.getElementById( 'btn_shuffle'), 'off' );
var looptag = status.getElementsByTagName( 'loop' );
if( looptag.length > 0 ? looptag[0].firstChild.data == "1" : 0)
setclass( document.getElementById( 'btn_loop'), 'on' );
else
setclass( document.getElementById( 'btn_loop'), 'off' );
var repeattag = status.getElementsByTagName( 'repeat' );
if( repeattag.length > 0 ? repeattag[0].firstChild.data == "1" : 0 )
setclass( document.getElementById( 'btn_repeat'), 'on' );
else
setclass( document.getElementById( 'btn_repeat'), 'off' );
var tree = document.createElement( "ul" );
var categories = status.getElementsByTagName( 'category' );
var i;
for( i = 0; i < categories.length; i++ )
{
var item = document.createElement( "li" );
item.appendChild( document.createTextNode( categories[i].getAttribute( 'name' ) ) );
var subtree = document.createElement( "dl" );
var infos = categories[i].getElementsByTagName( 'info' );
var j;
for( j = 0; j < infos.length; j++ )
{
var subitem = document.createElement( "dt" );
subitem.appendChild( document.createTextNode( infos[j].getAttribute( 'name' ) ) );
subtree.appendChild( subitem );
if( infos[j].hasChildNodes() )
{
var subitem = document.createElement( "dd" );
subitem.appendChild( document.createTextNode( infos[j].firstChild.data ) );
subtree.appendChild( subitem );
}
}
item.appendChild( subtree );
tree.appendChild( item );
}
var infotree = document.getElementById('infotree' );
clear_children( infotree );
infotree.appendChild( tree );
}
else
{
/*alert( 'Error! HTTP server replied: ' + req.status );*/
}
}
}
/* parse playlist.xml */
function parse_playlist()
{
if( req.readyState == 4 )
{
if( req.status == 200 )
{
var answer = req.responseXML.documentElement;
var playtree = document.getElementById( 'playtree' );
var pos = document.createElement( "div" );
pos.style.height = document.body.clientHeight - 100 + "px";
pos.style.overflow = "auto";
var pos_top = pos;
var elt = answer.firstChild;
pl_cur_id = 0; /* changed to the current id is there actually
* is a current id */
while( elt )
{
if( elt.nodeName == "node" )
{
if( pos.hasChildNodes() )
pos.appendChild( document.createElement( "br" ) );
var nda = document.createElement( 'a' );
nda.setAttribute( 'href', 'javascript:toggle_show_node(\''+elt.getAttribute( 'id' )+'\');' );
var ndai = document.createElement( 'img' );
ndai.setAttribute( 'src', 'images/minus.png' );
ndai.setAttribute( 'alt', '[-]' );
ndai.setAttribute( 'id', 'pl_img_'+elt.getAttribute( 'id' ) );
nda.appendChild( ndai );
pos.appendChild( nda );
pos.appendChild( document.createTextNode( ' ' + elt.getAttribute( 'name' ) ) );
if( elt.getAttribute( 'ro' ) == 'rw' )
{
pos.appendChild( document.createTextNode( ' ' ) );
var del = document.createElement( "a" );
del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
var delimg = document.createElement( "img" );
delimg.setAttribute( 'src', 'images/delete_small.png' );
delimg.setAttribute( 'alt', '(delete)' );
del.appendChild( delimg );
pos.appendChild( del );
}
var nd = document.createElement( "div" );
setclass( nd, 'pl_node' );
nd.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
pos.appendChild( nd );
}
else if( elt.nodeName == "leaf" )
{
if( pos.hasChildNodes() )
pos.appendChild( document.createElement( "br" ) );
var pl = document.createElement( "a" );
setclass( pl, 'pl_leaf' );
pl.setAttribute( 'href', 'javascript:pl_play('+elt.getAttribute( 'id' )+');' );
pl.setAttribute( 'id', 'pl_'+elt.getAttribute( 'id' ) );
if( elt.getAttribute( 'current' ) == 'current' )
{
pl.style.fontWeight = 'bold';
var nowplaying = document.getElementById( 'nowplaying' );
clear_children( nowplaying );
nowplaying.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
pl.appendChild( document.createTextNode( '' ));
pl_cur_id = elt.getAttribute( 'id' );
}
pl.setAttribute( 'title', elt.getAttribute( 'uri' ));
pl.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
var duration = elt.getAttribute( 'duration' );
if( duration > 0 )
pl.appendChild( document.createTextNode( " (" + format_time( elt.getAttribute( 'duration' ) / 1000000 ) + ")" ) );
pos.appendChild( pl );
if( elt.getAttribute( 'ro' ) == 'rw' )
{
pos.appendChild( document.createTextNode( ' ' ) );
var del = document.createElement( "a" );
del.setAttribute( 'href', 'javascript:pl_delete('+elt.getAttribute( 'id' )+')' );
var delimg = document.createElement( "img" );
delimg.setAttribute( 'src', 'images/delete_small.png' );
delimg.setAttribute( 'alt', '(delete)' );
del.appendChild( delimg );
pos.appendChild( del );
}
}
if( elt.firstChild )
{
elt = elt.firstChild;
pos = pos.lastChild;
}
else if( elt.nextSibling )
{
elt = elt.nextSibling;
pos = pos;
}
else
{
while( ! elt.parentNode.nextSibling )
{
elt = elt.parentNode;
if( ! elt.parentNode ) break;
pos = pos.parentNode;
}
if( ! elt.parentNode ) break;
elt = elt.parentNode.nextSibling;
pos = pos.parentNode;
}
}
clear_children( playtree );
playtree.appendChild( pos_top );
}
else
{
/*alert( 'Error! HTTP server replied: ' + req.status );*/
}
}
}
/* parse browse.xml */
function parse_browse_dir( )
{
if( req.readyState == 4 )
{
if( req.status == 200 )
{
var answer = req.responseXML.documentElement;
if( !answer ) return;
var browser = document.getElementById( 'browser' );
var pos = document.createElement( "div" );
var elt = answer.firstChild;
while( elt )
{
if( elt.nodeName == "element" )
{
var item = document.createElement( "a" );
setclass( item, 'browser' );
if( elt.getAttribute( 'type' ) == 'directory' )
{
item.setAttribute( 'href', 'javascript:browse_dir(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');');
}
else
{
item.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');' );
}
item.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
pos.appendChild( item );
if( elt.getAttribute( 'type' ) == 'directory' )
{
pos.appendChild( document.createTextNode( ' ' ) );
var item = document.createElement( "a" );
setclass( item, 'browser' );
item.setAttribute( 'href', 'javascript:browse_path(\''+addslashes(escapebackslashes(elt.getAttribute( 'path' )))+'\');');
item.appendChild( document.createTextNode( '(select)' ) );
pos.appendChild( item );
}
pos.appendChild( document.createElement( "br" ) );
}
elt = elt.nextSibling;
}
clear_children( browser );
browser.appendChild( pos );
}
else
{
/*alert( 'Error! HTTP server replied: ' + req.status );*/
}
}
}
/* updates playlist to display active entry */
function update_playlist_view ()
{
if( req.readyState == 4 ) {
if( req.status == 200 ) {
var status = req.responseXML.documentElement;
var title = status.getElementsByTagName( 'title' );
if( title.length > 0 ) {
title = title[0].firstChild.data;
//update now-playing..
var nowplaying = document.getElementById( 'nowplaying' );
clear_children( nowplaying );
nowplaying.appendChild( document.createTextNode( title ) );
//update playlist..
var playtree = document.getElementById( 'playtree' );
if( playtree.hasChildNodes() )
{
var root = playtree.firstChild; //root div
if( root.hasChildNodes() )
{
for( var i = 0; i < root.childNodes.length - 1; i++ )
{
if ( root.childNodes[i].className == "pl_node" && root.childNodes[i].hasChildNodes() )
{
var node = root.childNodes[i]; //pl_node
if( node.className == "pl_node" && node.hasChildNodes() )
{
for( var j = 0; j < node.childNodes.length - 1; j++ )
{
if( node.childNodes[j].className == "pl_leaf" )
{
var leaf = node.childNodes[j]; //pl_leaf
var pl_title = leaf.textContent.substring( 0, leaf.textContent.length - leaf.text.length )
//if( leaf.style.fontWeight == "bold" && pl_title.substring(0, 2) == "* " ) //handle leaf currently identified as playing..
//{
// pl_title = pl_title.substring(2);
//}
if( pl_title == title )
{
leaf.style.fontWeight = "bold";
}
else
{
leaf.style.fontWeight = "";
}
}
}
}
}
}
}
}
}
}
}
}
/**********************************************************************
* Input dialog functions
*********************************************************************/
function hide_input( )
{
document.getElementById( 'input_file' ).style.display = 'none';
document.getElementById( 'input_disc' ).style.display = 'none';
document.getElementById( 'input_network' ).style.display = 'none';
document.getElementById( 'input_fake' ).style.display = 'none';
}
/* update the input MRL using data from the input file helper */
/* FIXME ... subs support */
function update_input_file()
{
var mrl = document.getElementById( 'input_mrl' );
mrl.value = value( 'input_file_filename' );
}
/* update the input MRL using data from the input disc helper */
function update_input_disc()
{
var mrl = document.getElementById( 'input_mrl' );
var type = radio_value( "input_disc_type" );
var device = value( "input_disc_dev" );
var title = check_and_replace_int( 'input_disc_title', 0 );
var chapter = check_and_replace_int( 'input_disc_chapter', 0 );
var subs = check_and_replace_int( 'input_disc_subtrack', '' );
var audio = check_and_replace_int( 'input_disc_audiotrack', 0 );
mrl.value = "";
if( type == "dvd" )
{
mrl.value += "dvd://";
}
else if( type == "dvdsimple" )
{
mrl.value += "dvdsimple://";
}
else if( type == "vcd" )
{
mrl.value += "vcd://";
}
else if( type == "cdda" )
{
mrl.value += "cdda://";
}
mrl.value += device;
if( title )
{
mrl.value += "@"+title;
if( chapter && type != "cdda" )
mrl.value += ":"+chapter;
}
if( type != "cdda" )
{
if( subs != '' )
mrl.value += " :sub-track="+subs;
if( audio != '' )
mrl.value += " :audio-track="+audio;
}
}
/* update the input MRL using data from the input network helper */
function update_input_net()
{
var mrl = document.getElementById( 'input_mrl' );
var type = radio_value( "input_net_type" );
check_and_replace_int( 'input_net_udp_port', 1234 );
check_and_replace_int( 'input_net_udpmcast_port', 1234 );
mrl.value = "";
if( type == "udp" )
{
mrl.value += "udp://";
if( checked( 'input_net_udp_forceipv6' ) )
mrl.value += "[::]";
if( value( 'input_net_udp_port' ) )
mrl.value += ":"+value( 'input_net_udp_port' );
}
else if( type == "udpmcast" )
{
mrl.value += "udp://@"+value( 'input_net_udpmcast_address');
if( value( 'input_net_udpmcast_port' ) )
mrl.value += ":"+value( 'input_net_udpmcast_port' );
}
else if( type == "http" )
{
var url = value( 'input_net_http_url' );
if( url.substring(0,7) != "http://"
&& url.substring(0,8) != "https://"
&& url.substring(0,6) != "ftp://"
&& url.substring(0,6) != "mms://"
&& url.substring(0,7) != "mmsh://" )
mrl.value += "http://";
mrl.value += url;
}
else if( type == "rtsp" )
{
var url = value( 'input_net_rtsp_url' );
if( url.substring(0,7) != "rtsp://" )
mrl.value += "rtsp://";
mrl.value += url;
}
if( checked( "input_net_timeshift" ) )
mrl.value += " :access-filter=timeshift";
}
/* update the input MRL using data from the input fake helper */
function update_input_fake()
{
var mrl = document.getElementById( 'input_mrl' );
mrl.value = "fake://";
mrl.value += " :fake-file=" + value( "input_fake_filename" );
if( value( "input_fake_width" ) )
mrl.value += " :fake-width=" + value( "input_fake_width" );
if( value( "input_fake_height" ) )
mrl.value += " :fake-height=" + value( "input_fake_height" );
if( value( "input_fake_ar" ) )
mrl.value += " :fake-ar=" + value( "input_fake_ar" );
}
/**********************************************************************
* Sout dialog functions
*********************************************************************/
/* toggle show the full sout interface */
function toggle_show_sout_helper()
{
var element = document.getElementById( "sout_helper" );
if( element.style.display == 'block' )
{
element.style.display = 'none';
document.getElementById( "sout_helper_toggle" ).value = 'Full sout interface';
}
else
{
element.style.display = 'block';
document.getElementById( "sout_helper_toggle" ).value = 'Hide sout interface';
}
}
/* update the sout MRL using data from the sout_helper */
function update_sout()
{
var mrl = document.getElementById( 'sout_mrl' );
mrl.value = "";
check_and_replace_int( 'sout_http_port', 8080 );
check_and_replace_int( 'sout_mmsh_port', 8080 );
check_and_replace_int( 'sout_rtp_port', 1234 );
check_and_replace_int( 'sout_udp_port', 1234 );
check_and_replace_int( 'sout_ttl', 1 );
if( checked( 'sout_soverlay' ) )
{
disable( 'sout_scodec' );
disable( 'sout_sub' );
}
else
{
enable( 'sout_scodec' );
enable( 'sout_sub' );
}
var transcode = checked( 'sout_vcodec_s' ) || checked( 'sout_acodec_s' )
|| checked( 'sout_sub' ) || checked( 'sout_soverlay' );
if( transcode )
{
mrl.value += ":sout=#transcode{";
var alot = false; /* alot == at least one transcode */
if( checked( 'sout_vcodec_s' ) )
{
mrl.value += "vcodec="+value( 'sout_vcodec' )+",vb="+value( 'sout_vb' )+",scale="+value( 'sout_scale' );
alot = true;
}
if( checked( 'sout_acodec_s' ) )
{
if( alot ) mrl.value += ",";
mrl.value += "acodec="+value( 'sout_acodec' )+",ab="+value( 'sout_ab' );
if( value( 'sout_channels' ) )
mrl.value += ",channels="+value( 'sout_channels' );
alot = true;
}
if( checked( 'sout_soverlay' ) )
{
if( alot ) mrl.value += ",";
mrl.value += "soverlay";
alot = true;
}
else if( checked( 'sout_sub' ) )
{
if( alot ) mrl.value += ",";
mrl.value += "scodec="+value( 'sout_scodec' );
alot = true;
}
mrl.value += value( 'sout_transcode_extra' );
mrl.value += "}";
}
var output = checked( 'sout_display' ) + checked( 'sout_file' )
+ checked( 'sout_http' ) + checked( 'sout_mmsh' )
+ checked( 'sout_rtp' ) + checked( 'sout_udp' );
if( output )
{
if( transcode )
mrl.value += ":";
else
mrl.value += ":sout=#";
var aloo = false; /* aloo == at least one output */
var mux = radio_value( 'sout_mux' );
var ttl = parseInt( value( 'sout_ttl' ) );
if( output > 1 ) mrl.value += "duplicate{";
if( checked( 'sout_display' ) )
{
if( output > 1 ) mrl.value += "dst="
mrl.value += "display";
aloo = true;
}
if( checked( 'sout_file' ) )
{
if( aloo ) mrl.value += ",";
if( output > 1 ) mrl.value += "dst="
mrl.value += "std{access=file,mux="+mux+",dst="+value( 'sout_file_filename' )+"}";
aloo = true;
}
if( checked( 'sout_http' ) )
{
if( aloo ) mrl.value += ",";
if( output > 1 ) mrl.value += "dst="
mrl.value += "std{access=http,mux="+mux+",dst="+value( 'sout_http_addr' );
if( value( 'sout_http_port' ) )
mrl.value += ":"+value( 'sout_http_port' );
mrl.value += "}";
aloo = true;
}
if( checked( 'sout_mmsh' ) )
{
if( aloo ) mrl.value += ",";
if( output > 1 ) mrl.value += "dst="
mrl.value += "std{access=mmsh,mux="+mux+",dst="+value( 'sout_mmsh_addr' );
if( value( 'sout_mmsh_port' ) )
mrl.value += ":"+value( 'sout_mmsh_port' );
mrl.value += "}";
aloo = true;
}
if( checked( 'sout_rtp' ) )
{
if( aloo ) mrl.value += ",";
if( output > 1 ) mrl.value += "dst="
mrl.value += "std{access=rtp";
if( ttl ) mrl.value += "{ttl="+ttl+"}";
mrl.value += ",mux="+mux+",dst="+value( 'sout_rtp_addr' );
if( value( 'sout_rtp_port' ) )
mrl.value += ":"+value( 'sout_rtp_port' );
if( checked( 'sout_sap' ) )
{
mrl.value += ",sap";
if( value( 'sout_sap_group' ) != '' )
{
mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
}
mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
}
mrl.value += "}";
aloo = true;
}
if( checked( 'sout_udp' ) )
{
if( aloo ) mrl.value += ",";
if( output > 1 ) mrl.value += "dst="
mrl.value += "std{access=udp";
if( ttl ) mrl.value += "{ttl="+ttl+"}";
mrl.value += ",mux="+mux+",dst="+value( 'sout_udp_addr' );
if( value('sout_udp_port' ) )
mrl.value += ":"+value( 'sout_udp_port' );
if( checked( 'sout_sap' ) )
{
mrl.value += ",sap";
if( value( 'sout_sap_group' ) != '' )
{
mrl.value += ",group=\""+value( 'sout_sap_group' )+"\"";
}
mrl.value += ",name=\""+value( 'sout_sap_name' )+"\"";
}
mrl.value += "}";
aloo = true;
}
if( output > 1 ) mrl.value += "}";
}
if( ( transcode || output ) && checked( 'sout_all' ) )
mrl.value += " :sout-all";
}
/* reset sout mrl value */
function reset_sout()
{
document.getElementById('sout_mrl').value = value('sout_old_mrl');
}
/* save sout mrl value */
function save_sout()
{
document.getElementById('sout_old_mrl').value = value('sout_mrl');
}
/**********************************************************************
* Browser dialog functions
*********************************************************************/
/* only browse() should be called directly */
function browse( dest )
{
document.getElementById( 'browse_dest' ).value = dest;
document.getElementById( 'browse_lastdir' ).value;
browse_dir( document.getElementById( 'browse_lastdir' ).value );
show( 'browse' );
}
function browse_dir( dir )
{
document.getElementById( 'browse_lastdir' ).value = dir;
loadXMLDoc( 'requests/browse.xml?dir='+encodeURIComponent(dir), parse_browse_dir );
}
function browse_path( p )
{
document.getElementById( value( 'browse_dest' ) ).value = p;
hide( 'browse' );
document.getElementById( value( 'browse_dest' ) ).focus();
}
function refresh_albumart( force )
{
if( albumart_id != pl_cur_id || force )
{
var now = new Date();
var albumart = document.getElementById( 'albumart' );
albumart.src = '/art?timestamp=' + now.getTime();
albumart_id = pl_cur_id;
}
}
/**********************************************************************
* Periodically update stuff in the interface
*********************************************************************/
function loop_refresh_status()
{
setTimeout( 'loop_refresh_status()', 1000 );
update_status();
}
function loop_refresh_playlist()
{
/* setTimeout( 'loop_refresh_playlist()', 10000 ); */
update_playlist();
}
function loop_refresh_albumart()
{
setTimeout( 'loop_refresh_albumart()', 1000 );
refresh_albumart( false );
}
function loop_refresh()
{
setTimeout( 'loop_refresh_status()', 1 );
setTimeout( 'loop_refresh_playlist()', 1 );
setTimeout( 'loop_refresh_albumart()', 1 );
}
/*****************************************************************************
* mosaic.js: VLC media player web interface - Mosaic specific functions
*****************************************************************************
* Copyright (C) 2005-2006 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/**********************************************************************
*
*********************************************************************/
var mosaic_alpha = 255;
var mosaic_height = 0;
var mosaic_width = 0;
var mosaic_align = 5;
var mosaic_xoffset = 0;
var mosaic_yoffset = 0;
var mosaic_vborder = 0;
var mosaic_hborder = 0;
var mosaic_position = 1;
var mosaic_rows = 0;
var mosaic_cols = 0;
var mosaic_delay = 0;
var cell_width = 0;
var cell_height = 0;
var streams = Object();
var cells = Object();
function mosaic_init()
{
document.getElementById( 'sout_transcode_extra' ).value = ",sfilter=mosaic}:bridge-in{offset=100";
mosaic_size_change();
/* Force usage of transcode in sout */
document.getElementById( 'sout_vcodec_s' ).checked = 'checked';
disable( 'sout_vcodec_s' );
update_sout();
}
function mosaic_size_change()
{
var x,y;
var bg_width = check_and_replace_int( "bg_width", "400" );
var bg_height = check_and_replace_int( "bg_height", "300" );
mosaic_height = check_and_replace_int( "mosaic_height", "100" );
mosaic_width = check_and_replace_int( "mosaic_width", "100" );
mosaic_xoffset = check_and_replace_int( "mosaic_xoffset", "10" );
mosaic_yoffset = check_and_replace_int( "mosaic_yoffset", "10" );
mosaic_vborder = check_and_replace_int( "mosaic_vborder", "5" );
mosaic_hborder = check_and_replace_int( "mosaic_hborder", "10" );
mosaic_rows = check_and_replace_int( "mosaic_rows", "1" );
mosaic_cols = check_and_replace_int( "mosaic_cols", "1" );
cell_width = Math.floor((mosaic_width-(mosaic_cols-1)*mosaic_hborder)/mosaic_cols);
cell_height = Math.floor((mosaic_height-(mosaic_rows-1)*mosaic_vborder)/mosaic_rows);
var mlayout = document.getElementById( "mosaic_layout" );
while( mlayout.hasChildNodes() )
mlayout.removeChild( mlayout.firstChild );
mlayout.style.width = bg_width + "px";
mlayout.style.height = bg_height + "px";
if( mosaic_cols && mosaic_rows )
{
var mdt = document.createElement( 'div' );
mdt.setAttribute( 'id', 'mosaic_dt' );
setclass( mdt, 'mosaic_tbl' );
mdt.style.width = mosaic_width + "px";
mdt.style.height = mosaic_height + "px";
mdt.style.top = mosaic_yoffset + "px";
mdt.style.left = mosaic_xoffset + "px";
var mtable = document.createElement( 'table' );
mtable.setAttribute( 'id', 'mosaic_table' );
mtable.style.top = "-" + mosaic_vborder + "px";
mtable.style.left = "-" + mosaic_hborder + "px";
mtable.style.width = (1*mosaic_width +2*mosaic_hborder) + "px";
mtable.style.height = (1*mosaic_height+2*mosaic_vborder) + "px";
mtable.style.borderSpacing = mosaic_hborder + "px " +
mosaic_vborder + "px";
var mtbody = document.createElement( 'tbody' );
for( y = 0; y < mosaic_rows; y++ )
{
var mrow = document.createElement( 'tr' );
for( x = 0; x < mosaic_cols; x++ )
{
var mcell = document.createElement( 'td' );
setclass( mcell, 'mosaic_itm' );
mcell.style.width = cell_width + "px";
mcell.style.height = cell_height + "px";
var id = x+'_'+y;
var melt = create_button( cells[id] ? cells[id] : '?', 'mosaic_elt_choose(\"'+id+'\");' );
melt.setAttribute( 'id', id );
melt.setAttribute( 'title', 'Click to choose stream' );
mcell.appendChild( melt );
mrow.appendChild( mcell );
}
mtbody.appendChild( mrow );
}
mtable.appendChild( mtbody );
mdt.appendChild( mtable );
mlayout.appendChild( mdt );
}
mosaic_code_update();
}
function mosaic_add_input()
{
streams[ addunderscores( value('mosaic_input_name') ) ] =
value('mosaic_input');
mosaic_feedback( addunderscores( value('mosaic_input_name') ) + " ( " + value('mosaic_input') + " ) added to input list.", true );
var mlist = document.getElementById( "mosaic_list_content" );
while( mlist.hasChildNodes() )
mlist.removeChild( mlist.firstChild );
for( var name in streams )
{
var mrl = streams[name];
var minput = document.createElement( 'a' );
minput.setAttribute( 'href', 'javascript:mosaic_elt_select(\''+name+'\');');
minput.setAttribute( 'id', name );
minput.setAttribute( 'value', mrl );
var minputtxt = document.createTextNode( name );
minput.appendChild( minputtxt );
mlist.appendChild( minput );
mlist.appendChild( document.createTextNode( " ( "+mrl+" )" ) );
mlist.appendChild( document.createElement( 'br' ) );
}
}
function mosaic_elt_select( id )
{
hide( 'mosaic_list' );
var ml = document.getElementById( 'mosaic_list' ).value;
if( ml )
{
document.getElementById( ml ).value = id;
cells[ ml ] = id;
mosaic_code_update();
}
}
function mosaic_elt_choose( id )
{
document.getElementById( 'mosaic_list' ).value = id;
show( 'mosaic_list' );
}
function mosaic_code_update()
{
var code = document.getElementById( 'mosaic_code' );
code.value =
"##################################\n"+
"## HTTP interface mosaic wizard ##\n"+
"##################################\n"+
"\n"+
"# Comment the following line if you don't want to reset your VLM configuration\n"+
"del all\n"+
"\n"+
"# Background options\n"+
"new bg broadcast enabled\n"+
"setup bg input " + sanitize_input( value( 'mosaic_bg_input' ) ) + "\n";
if( value( 'mosaic_output' ) )
{
code.value +=
"setup bg output " + value( 'mosaic_output' )+ "\n";
}
var o = /.*transcode.*/;
if(! o.test( value( 'mosaic_output' ) ) )
{
code.value +=
"setup bg option sub-source=mosaic\n"+
"setup bg output #bridge-in{offset=100}:display\n";
}
code.value+=
"\n"+
"# Mosaic options\n"+
"setup bg option mosaic-alpha=" + mosaic_alpha + "\n"+
"setup bg option mosaic-height=" + mosaic_height + "\n"+
"setup bg option mosaic-width=" + mosaic_width + "\n"+
"setup bg option mosaic-align=" + mosaic_align + "\n"+
"setup bg option mosaic-xoffset=" + mosaic_xoffset + "\n"+
"setup bg option mosaic-yoffset=" + mosaic_yoffset + "\n"+
"setup bg option mosaic-vborder=" + mosaic_vborder + "\n"+
"setup bg option mosaic-hborder=" + mosaic_hborder + "\n"+
"setup bg option mosaic-position=" + mosaic_position + "\n"+
"setup bg option mosaic-rows=" + mosaic_rows + "\n"+
"setup bg option mosaic-cols=" + mosaic_cols + "\n"+
"setup bg option mosaic-order=";
for( y = 0; y < mosaic_rows; y++ )
{
for( x = 0; x < mosaic_cols; x++ )
{
var id = x+'_'+y;
if( cells[id] )
code.value += cells[id];
else
code.value += '_';
if( y != mosaic_rows - 1 || x != mosaic_cols - 1 )
code.value += ',';
}
}
code.value += "\n"+
"setup bg option mosaic-delay=" + mosaic_delay + "\n"+
"setup bg option mosaic-keep-picture\n"+
"\n"+
"# Input options\n";
var x, y;
for( y = 0; y < mosaic_rows; y++ )
{
for( x = 0; x < mosaic_cols; x++ )
{
var id = x+'_'+y;
if( cells[id] )
{
var s = cells[id];
code.value +=
"new " + s + " broadcast enabled\n"+
"setup " + s + " input " + sanitize_input( streams[s] ) + "\n"+
"setup " + s + " output #duplicate{dst=mosaic-bridge{id=" + s + ",width="+cell_width+",height="+cell_height+"},select=video,dst=bridge-out{id="+(y*mosaic_cols+x)+"},select=audio}\n"+
"\n";
}
}
}
code.value +=
"# Launch everything\n"+
"control bg play\n";
for( y = 0; y < mosaic_rows; y++ )
{
for( x = 0; x < mosaic_cols; x++ )
{
var id = x+'_'+y;
if( cells[id] )
{
var s = cells[id];
code.value +=
"control " + s + " play\n";
}
}
}
code.value +=
"\n"+
"# end of mosaic batch\n";
}
function mosaic_batch( batch )
{
var i;
var commands = batch.split( '\n' );
for( i = 0; i < commands.length; i++ )
{
mosaic_cmd( commands[i] );
}
}
function mosaic_cmd( cmd )
{
loadXMLDoc( 'requests/vlm_cmd.xml?command='+cmd.replace(/\#/g, '%23'), parse_mosaic_cmd );
}
function parse_mosaic_cmd()
{
/* TODO */
}
function mosaic_stop()
{
var cmd;
cmd = "control bg stop\n";
var x,y;
for( y = 0; y < mosaic_rows; y++ )
{
for( x = 0; x < mosaic_cols; x++ )
{
var id = x+'_'+y;
if( cells[id] )
{
var s = cells[id];
cmd += "control " + s + " stop\n";
}
}
}
mosaic_batch( cmd );
}
function mosaic_feedback( msg, ok )
{
var f = document.getElementById( "mosaic_feedback" );
while( f.hasChildNodes() )
f.removeChild( f.firstChild );
f.style.fontWeight = "bold";
if( ok )
f.style.color = "#0f0";
else
f.style.color = "#f00";
var t = document.createTextNode( ( ok ? "Info: " : "Error: " ) + msg );
f.appendChild( t );
}
/*****************************************************************************
* vlm.js: VLC media player web interface
*****************************************************************************
* Copyright (C) 2005-2006 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/* replace quotes and spaces by underscores */
function addunderscores( str ){ return str.replace(/\'|\"| /g, '_'); }
/**********************************************************************
* Input dialog functions
*********************************************************************/
function toggle_show_vlm_helper()
{
var vlmh = document.getElementById( "vlm_helper" );
var vlmhctrl = document.getElementById( "vlm_helper_controls" );
var btn = document.getElementById( "btn_vlm_helper_toggle" );
if( vlmh.style.display == 'block' || vlmh.style.display == '')
{
vlmh.style.display = 'none';
vlmhctrl.style.display = 'none';
btn.removeChild( btn.firstChild );
btn.appendChild( document.createTextNode( 'Show VLM helper' ) );
}
else
{
vlmh.style.display = 'block';
vlmhctrl.style.display = 'inline';
btn.removeChild( btn.firstChild );
btn.appendChild( document.createTextNode( 'Hide VLM helper' ) );
}
}
function vlm_input_edit( dest )
{
document.getElementById( 'input_dest' ).value = dest;
show( 'input' );
}
function vlm_input_change()
{
document.getElementById( value( 'input_dest' ) ).value = value( 'input_mrl' ).replace( /\ :/g, " option " );
hide( 'input' );
document.getElementById( value( 'input_dest' ) ).focus();
}
function vlm_output_edit( dest )
{
document.getElementById( 'sout_dest' ).value = dest;
show( 'sout' );
}
function vlm_output_change()
{
document.getElementById( value( 'sout_dest' ) ).value = value( 'sout_mrl' ).substr(6).replace( /\ :/g, " option " ); /* substr <-> remove :sout= */
hide( 'sout' );
document.getElementById( value( 'sout_dest' ) ).focus();
}
function hide_vlm_add()
{
document.getElementById( 'vlm_add_broadcast' ).style.display = 'none';
document.getElementById( 'vlm_add_vod' ).style.display = 'none';
document.getElementById( 'vlm_add_schedule' ).style.display = 'none';
document.getElementById( 'vlm_add_other' ).style.display = 'none';
}
function toggle_schedule_date()
{
if( checked( 'vlm_schedule_now' ) )
{
disable( 'vlm_schedule_year' );
disable( 'vlm_schedule_month' );
disable( 'vlm_schedule_day' );
disable( 'vlm_schedule_hour' );
disable( 'vlm_schedule_minute' );
disable( 'vlm_schedule_second' );
}
else
{
enable( 'vlm_schedule_year' );
enable( 'vlm_schedule_month' );
enable( 'vlm_schedule_day' );
enable( 'vlm_schedule_hour' );
enable( 'vlm_schedule_minute' );
enable( 'vlm_schedule_second' );
}
}
function toggle_schedule_repeat()
{
if( checked( 'vlm_schedule_repeat' ) )
{
enable( 'vlm_schedule_period_year' );
enable( 'vlm_schedule_period_month' );
enable( 'vlm_schedule_period_day' );
enable( 'vlm_schedule_period_hour' );
enable( 'vlm_schedule_period_minute' );
enable( 'vlm_schedule_period_second' );
enable( 'vlm_schedule_repeat_times' );
}
else
{
disable( 'vlm_schedule_period_year' );
disable( 'vlm_schedule_period_month' );
disable( 'vlm_schedule_period_day' );
disable( 'vlm_schedule_period_hour' );
disable( 'vlm_schedule_period_minute' );
disable( 'vlm_schedule_period_second' );
disable( 'vlm_schedule_repeat_times' );
}
}
function vlm_schedule_type_change( name )
{
var act = document.getElementById( 'vlm_elt_' + name + '_action' ).value;
var itemname = document.getElementById( 'vlm_elt_' + name + '_name' );
var opt = document.getElementById( 'vlm_elt_' + name + '_opt' );
if( act == "play" || act == "pause" || act == "stop" )
{
itemname.style.display = "";
opt.style.display = "none";
}
else if( act == "seek" )
{
itemname.style.display = "";
opt.style.display = "";
}
else
{
itemname.style.display = "none";
opt.style.display = "";
}
}
function sanitize_input( str )
{
return str.replace( /\"/g, '\\\"' ).replace( /^/, '"' ).replace( /$/, '"' ).replace( /\ option\ /g, '" option "' );
}
function update_vlm_add_broadcast()
{
var cmd = document.getElementById( 'vlm_command' );
if( value( 'vlm_broadcast_name' ) )
{
cmd.value = "new " + addunderscores( value( 'vlm_broadcast_name' ) )
+ " broadcast";
if( checked( 'vlm_broadcast_enabled' ) )
{
cmd.value += " enabled";
}
if( checked( 'vlm_broadcast_loop' ) )
{
cmd.value += " loop";
}
if( value( 'vlm_broadcast_input' ) )
{
cmd.value += " input " + sanitize_input( value( 'vlm_broadcast_input' ) );
}
if( value( 'vlm_broadcast_output' ) )
{
cmd.value += " output " + value( 'vlm_broadcast_output' );
}
}
else
{
cmd.value = "";
}
}
function update_vlm_add_vod()
{
var cmd = document.getElementById( 'vlm_command' );
if( value( 'vlm_vod_name' ) )
{
cmd.value = "new " + addunderscores( value( 'vlm_vod_name' ) )
+ " vod";
if( checked( 'vlm_vod_enabled' ) )
{
cmd.value += " enabled";
}
if( value( 'vlm_vod_input' ) )
{
cmd.value += " input " + sanitize_input( value( 'vlm_vod_input' ) );
}
if( value( 'vlm_vod_output' ) )
{
cmd.value += " output " + value( 'vlm_vod_output' );
}
}
else
{
cmd.value = "";
}
}
function update_vlm_add_schedule()
{
var cmd = document.getElementById( 'vlm_command' );
check_and_replace_int( 'vlm_schedule_year', '0000' );
check_and_replace_int( 'vlm_schedule_month', '00' );
check_and_replace_int( 'vlm_schedule_day', '00' );
check_and_replace_int( 'vlm_schedule_hour', '00' );
check_and_replace_int( 'vlm_schedule_minute', '00' );
check_and_replace_int( 'vlm_schedule_second', '00' );
check_and_replace_int( 'vlm_schedule_period_year', '0000' );
check_and_replace_int( 'vlm_schedule_period_month', '00' );
check_and_replace_int( 'vlm_schedule_period_day', '00' );
check_and_replace_int( 'vlm_schedule_period_hour', '00' );
check_and_replace_int( 'vlm_schedule_period_minute', '00' );
check_and_replace_int( 'vlm_schedule_period_second', '00' );
if( value( 'vlm_schedule_name' ) )
{
cmd.value = "new " + addunderscores( value( 'vlm_schedule_name' ) ) + " schedule";
if( checked( 'vlm_schedule_enabled' ) )
{
cmd.value += " enabled";
}
if( checked( 'vlm_schedule_now' ) )
{
cmd.value += " date now";
}
else
{
cmd.value += " date " + value( 'vlm_schedule_year' ) + "/" + value( 'vlm_schedule_month' ) + "/" + value( 'vlm_schedule_day' ) + '-' + value( 'vlm_schedule_hour' ) + ':' + value( 'vlm_schedule_minute' ) + ':' + value( 'vlm_schedule_second' );
}
if( checked( 'vlm_schedule_repeat' ) )
{
cmd.value += " period " + value( 'vlm_schedule_period_year' ) + "/" + value( 'vlm_schedule_period_month' ) + "/" + value( 'vlm_schedule_period_day' ) + '-' + value( 'vlm_schedule_period_hour' ) + ':' + value( 'vlm_schedule_period_minute' ) + ':' + value( 'vlm_schedule_period_second' );
if( value( 'vlm_schedule_repeat_times' ) != 0 )
{
cmd.value += " repeat " + (value( 'vlm_schedule_repeat_times' ) - 1 );
}
}
}
else
{
cmd.value = "";
}
}
function update_vlm_add_other()
{
var cmd = document.getElementById( 'vlm_command' );
cmd.value = "";
}
function clear_vlm_add()
{
document.getElementById( 'vlm_command' ).value = "";
document.getElementById( 'vlm_broadcast_name' ).value = "";
document.getElementById( 'vlm_vod_name' ).value = "";
}
function create_button( caption, action )
{
/* var link = document.createElement( "input" );
link.setAttribute( 'type', 'button' );*/
/* link.setAttribute( 'onclick', action ); */
/* Above doesn't work on ie. You need to use something like
* link.onclick = function() { alert( 'pouet' ); };
* instead ... conclusion: IE is crap */
/* link.setAttribute( 'value', caption );*/
var d = document.createElement( 'div' );
d.innerHTML = "<input type='button' onclick='"+action+"' value='"+caption+"' />"; /* other IE work around ... still crap. Use double quotes only in action */
var link = d.firstChild;
return link;
}
function create_option( caption, value )
{
var opt = document.createElement( 'option' );
opt.setAttribute( 'value', value );
opt.appendChild( document.createTextNode( caption ) );
return opt;
}
function parse_vlm_cmd()
{
if( req.readyState == 4 )
{
if( req.status == 200 )
{
var vlm_answer = req.responseXML.documentElement;
var error_tag = vlm_answer.getElementsByTagName( 'error' )[0];
var vlme = document.getElementById( 'vlm_error' );
clear_children( vlme );
if( error_tag.hasChildNodes() )
{
vlme.appendChild( document.createTextNode( 'Error: ' + error_tag.firstChild.data ) );
vlme.style.color = "#f00";
}
else
{
vlme.appendChild( document.createTextNode( 'Command successful (' + value( 'vlm_command' ) + ') ' ) );
vlme.style.color = "#0f0";
clear_vlm_add();
}
vlme.appendChild( create_button( 'clear', 'clear_children( document.getElementById( "vlm_error" ) );' ) );
vlm_get_elements();
}
}
}
function parse_vlm_elements()
{
if( req.readyState == 4 )
{
if( req.status == 200 )
{
var vlmb = document.getElementById( 'vlm_broadcast_list' );
var vlmv = document.getElementById( 'vlm_vod_list' );
var vlms = document.getElementById( 'vlm_schedule_list' );
clear_children( vlmb );
clear_children( vlmv );
clear_children( vlms );
answer = req.responseXML.documentElement;
var elt = answer.firstChild;
while( elt )
{
if( elt.nodeName == "broadcast" || elt.nodeName == "vod" )
{
var nb = document.createElement( 'div' );
setclass( nb, 'list_element' );
if( elt.nodeName == "broadcast" )
{
vlmb.appendChild( nb );
}
else
{
vlmv.appendChild( nb );
}
var nbname = document.createElement( 'b' );
nbname.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
nb.appendChild( nbname );
if( elt.getAttribute( 'enabled' ) == 'yes' )
{
nb.appendChild( document.createTextNode( " enabled " ) );
nb.appendChild( create_button( "Disable", 'vlm_disable("'+elt.getAttribute( 'name' ) + '");' ) );
}
else
{
nb.appendChild( document.createTextNode( " disabled " ) );
nb.appendChild( create_button( "Enable", 'vlm_enable("'+elt.getAttribute( 'name' ) + '");' ) );
}
if( elt.nodeName == "broadcast" )
{
if( elt.getAttribute( 'loop' ) == 'yes' )
{
nb.appendChild( document.createTextNode( " loop " ) );
nb.appendChild( create_button( 'Un-loop', 'vlm_unloop("'+elt.getAttribute( 'name' ) + '");' ) );
}
else
{
nb.appendChild( document.createTextNode( " play once " ) );
nb.appendChild( create_button( 'Loop', 'vlm_loop("'+elt.getAttribute( 'name' ) + '");' ) );
}
if( elt.getAttribute( 'enabled' ) == 'yes' )
{
nb.appendChild( document.createTextNode( " " ) );
nb.appendChild( create_button( 'Play', 'vlm_play("'+elt.getAttribute('name')+'");' ) );
}
nb.appendChild( document.createTextNode( " " ) );
nb.appendChild( create_button( 'Pause', 'vlm_pause("'+elt.getAttribute('name')+'");' ) );
nb.appendChild( document.createTextNode( " " ) );
nb.appendChild( create_button( 'Stop', 'vlm_stop("'+elt.getAttribute('name')+'");' ) );
}
nb.appendChild( document.createTextNode( " " ) );
nb.appendChild( create_button( 'Delete', 'vlm_delete("'+elt.getAttribute( 'name' ) + '");' ) );
var list = document.createElement( "ul" );
/* begin input list */
var item = document.createElement( "li" );
list.appendChild( item );
item.appendChild( document.createTextNode( "Inputs: " ) );
var text = document.createElement( "input" );
text.setAttribute( 'type', 'text' );
text.setAttribute( 'size', '40' );
text.setAttribute( 'id', 'vlm_elt_'+elt.getAttribute('name')+'_input' );
text.setAttribute( 'onkeypress', 'if( event.keyCode == 13 ) vlm_add_input("'+elt.getAttribute('name')+'",document.getElementById("vlm_elt_'+elt.getAttribute('name')+'_input").value );' );
item.appendChild( text );
item.appendChild( document.createTextNode( ' ' ) );
item.appendChild( create_button( 'Edit', 'vlm_input_edit("vlm_elt_'+elt.getAttribute('name')+'_input");') );
item.appendChild( document.createTextNode( ' ' ) );
item.appendChild( create_button( 'Add input', 'vlm_add_input("'+elt.getAttribute('name')+'",document.getElementById("vlm_elt_'+elt.getAttribute('name')+'_input").value );' ) );
var inputs = elt.getElementsByTagName( 'input' );
if( inputs.length > 0 )
{
var ilist = document.createElement( "ol" );
ilist.setAttribute( 'start', '1' );
item.appendChild( ilist );
for( i = 0; i < inputs.length; i++ )
{
var item = document.createElement( "li" );
item.appendChild( document.createTextNode( inputs[i].firstChild.data + " " ) );
item.appendChild( create_button( "Delete", 'vlm_delete_input("' + elt.getAttribute( 'name' ) + '", '+(i+1)+' );' ) );
ilist.appendChild( item );
}
}
/* end of input list */
/* output */
var item = document.createElement( "li" );
outputelt = elt.getElementsByTagName( 'output' )[0];
if( outputelt.hasChildNodes() )
{
output = outputelt.firstChild.data;
}
else
{
output = "";
}
item.appendChild( document.createTextNode( 'Output: ' ) );
var text = document.createElement( "input" );
text.setAttribute( 'type', 'text' );
text.setAttribute( 'id', 'vlm_elt_'+elt.getAttribute('name')+'_output' );
text.setAttribute( 'value', output );
text.setAttribute( 'onkeypress', 'if( event.keyCode == 13 ) vlm_output("'+elt.getAttribute( 'name' )+ '",document.getElementById("vlm_elt_'+elt.getAttribute( 'name' )+'_output").value);' );
item.appendChild( text );
item.appendChild( document.createTextNode( ' ' ) );
item.appendChild( create_button( 'Edit', 'vlm_output_edit("vlm_elt_'+elt.getAttribute('name')+'_output");' ) );
item.appendChild( document.createTextNode( ' ' ) );
item.appendChild( create_button( 'Change output', 'vlm_output("'+elt.getAttribute( 'name' )+ '",document.getElementById("vlm_elt_'+elt.getAttribute( 'name' )+'_output").value);' ) );
list.appendChild( item );
/* end of output */
/* begin options list */
var item = document.createElement( "li" );
list.appendChild( item );
item.appendChild( document.createTextNode( "Options: " ) );
/* Add option */
var text = document.createElement( "input" );
text.setAttribute( 'type', 'text' );
text.setAttribute( 'size', '40' );
text.setAttribute( 'id', 'vlm_elt_'+elt.getAttribute('name')+'_option' );
text.setAttribute( 'onkeypress', 'if( event.keyCode == 13 ) vlm_option("'+elt.getAttribute('name')+'",document.getElementById("vlm_elt_'+elt.getAttribute('name')+'_option").value );' );
item.appendChild( text );
item.appendChild( document.createTextNode( ' ' ) );
item.appendChild( create_button( 'Add option', 'vlm_option("'+elt.getAttribute('name')+'",document.getElementById("vlm_elt_'+elt.getAttribute('name')+'_option").value );' ) );
var options = elt.getElementsByTagName( 'option' );
if( options.length > 0 )
{
var olist = document.createElement( "ul" );
item.appendChild( olist );
for( i = 0; i < options.length; i++ )
{
var item = document.createElement( "li" );
item.appendChild( document.createTextNode( options[i].firstChild.data ) );
olist.appendChild( item );
}
}
/* end of options */
/* Instances list */
var instances = elt.getElementsByTagName( 'instance' );
if( instances.length > 0 )
{
var item = document.createElement("li");
var ilist = document.createElement("ul");
list.appendChild( item );
item.appendChild(document.createTextNode("Instances:"));
item.appendChild( ilist );
for( i = 0; i < instances.length; i++ )
{
var iname = instances[i].getAttribute( 'name' );
var istate = instances[i].getAttribute( 'state' );
var iposition = Number( instances[i].getAttribute( 'position' ) * 100);
var itime = Math.floor( instances[i].getAttribute( 'time' ) / 1000000);
var ilength = Math.floor( instances[i].getAttribute( 'length' ) / 1000000);
var irate = instances[i].getAttribute( 'rate' );
var ititle = instances[i].getAttribute( 'title' );
var ichapter = instances[i].getAttribute( 'chapter' );
var iseekable = instances[i].getAttribute( 'seekable' );
var iplaylistindex = instances[i].getAttribute( 'playlistindex' );
var item = document.createElement( "li" );
item.appendChild( document.createTextNode( iname + ": " + istate + " (" + iplaylistindex + ") " + (iposition.toFixed(2)) + "%" + " " + format_time( itime ) + "/" + format_time( ilength ) ) );
ilist.appendChild( item );
}
}
/* end of instances list */
nb.appendChild( list );
}
else if( elt.nodeName == "schedule" )
{
var nb = document.createElement( 'div' );
setclass( nb, 'list_element' );
vlms.appendChild( nb );
var nbname = document.createElement( 'b' );
nbname.appendChild( document.createTextNode( elt.getAttribute( 'name' ) ) );
nb.appendChild( nbname );
if( elt.getAttribute( 'enabled' ) == 'yes' )
{
nb.appendChild( document.createTextNode( " enabled " ) );
nb.appendChild( create_button( "Disable", 'vlm_disable("'+elt.getAttribute( 'name' ) + '");' ) );
}
else
{
nb.appendChild( document.createTextNode( " disabled " ) );
nb.appendChild( create_button( "Enable", 'vlm_enable("'+elt.getAttribute( 'name' ) + '");' ) );
}
nb.appendChild( document.createTextNode( " " ) );
nb.appendChild( create_button( "Delete", 'vlm_delete("'+elt.getAttribute( 'name' ) + '");' ) );
var list = document.createElement( 'ul' );
var item = document.createElement( 'li' );
item.appendChild( document.createTextNode( "Date: " + elt.getAttribute( 'date' ) ) );
list.appendChild( item );
var item = document.createElement( 'li' );
item.appendChild( document.createTextNode( "Period (in seconds): " + elt.getAttribute( 'period' ) ) );
list.appendChild( item );
var item = document.createElement( 'li' );
if( elt.getAttribute( 'repeat' ) == -1 )
{
item.appendChild( document.createTextNode( "Number of repeats left: for ever" ) );
}
else
{
item.appendChild( document.createTextNode( "Number of repeats left: " + elt.getAttribute( 'repeat' ) ) );
}
list.appendChild( item );
var commands = elt.getElementsByTagName( 'command' );
for( i = 0; i < commands.length; i++ )
{
var item = document.createElement( "li" );
item.appendChild( document.createTextNode( "Command: " + commands[i].firstChild.data + " " ) );
list.appendChild( item );
}
var item = document.createElement( 'li' );
var sel = document.createElement( 'select' );
sel.setAttribute( 'id', 'vlm_elt_'+elt.getAttribute('name')+'_action' );
sel.setAttribute( 'onchange', 'vlm_schedule_type_change("'+elt.getAttribute('name')+'");');
sel.appendChild( create_option( 'play', 'play' ) );
sel.appendChild( create_option( 'pause', 'pause' ) );
sel.appendChild( create_option( 'stop', 'stop' ) );
sel.appendChild( create_option( 'seek', 'seek' ) );
sel.appendChild( create_option( '(other)', '' ) );
item.appendChild( sel );
item.appendChild( document.createTextNode( " " ) );
var text = document.createElement( 'input' );
text.setAttribute( 'type', 'text' );
text.setAttribute( 'id', 'vlm_elt_'+elt.getAttribute('name')+'_name' );
text.setAttribute( 'size', '10' );
text.setAttribute( 'value', '(name)' );
text.setAttribute( 'onfocus', 'if( this.value == "(name)" ) this.value = "";' );
text.setAttribute( 'onblur', 'if( this.value == "" ) this.value = "(name)";' );
item.appendChild( text );
item.appendChild( document.createTextNode( " " ) );
text = document.createElement( 'input' );
text.setAttribute( 'type', 'text' );
text.setAttribute( 'id', 'vlm_elt_'+elt.getAttribute('name')+'_opt' );
text.setAttribute( 'size', '30' );
text.setAttribute( 'value', '(options)' );
text.setAttribute( 'onfocus', 'if( this.value == "(options)" ) this.value = "";' );
text.setAttribute( 'onblur', 'if( this.value == "" ) this.value = "(options)";' );
item.appendChild( text );
item.appendChild( document.createTextNode( " " ) );
item.appendChild( create_button( "Append command", 'vlm_schedule_append("' + elt.getAttribute( 'name' ) + '");') );
list.appendChild( item );
nb.appendChild( list );
vlm_schedule_type_change( elt.getAttribute('name') );
}
elt = elt.nextSibling;
}
}
}
}
function vlm_cmd( cmd )
{
loadXMLDoc( 'requests/vlm_cmd.xml?command='+encodeURIComponent(cmd), parse_vlm_cmd );
}
function vlm_get_elements( )
{
loadXMLDoc( 'requests/vlm.xml', parse_vlm_elements );
}
/* helper functions */
function vlm_disable( name )
{
document.getElementById( 'vlm_command' ).value = "setup "+name+" disabled";
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_enable( name )
{
document.getElementById( 'vlm_command' ).value = "setup "+name+" enabled";
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_loop( name )
{
document.getElementById( 'vlm_command' ).value = "setup "+name+" loop";
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_unloop( name )
{
document.getElementById( 'vlm_command' ).value = "setup "+name+" unloop";
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_play( name )
{
document.getElementById( 'vlm_command' ).value = "control "+name+" play";
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_pause( name )
{
document.getElementById( 'vlm_command' ).value = "control "+name+" pause";
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_stop( name )
{
document.getElementById( 'vlm_command' ).value = "control "+name+" stop";
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_delete( name )
{
document.getElementById( 'vlm_command' ).value = "del "+name;
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_delete_input( name, num )
{
document.getElementById( 'vlm_command' ).value = "setup "+name+" inputdeln "+num;
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_add_input( name, input )
{
document.getElementById( 'vlm_command' ).value = "setup "+name+" input "+sanitize_input( input );
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_output( name, output )
{
document.getElementById( 'vlm_command' ).value = "setup "+name+" output "+output;
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_option( name, option )
{
document.getElementById( 'vlm_command' ).value = "setup "+name+" option "+option;
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_batch( batch )
{
var i;
var commands = batch.split( '\n' );
for( i = 0; i < commands.length; i++ )
{
document.getElementById( 'vlm_command' ).value = commands[i];
vlm_cmd( value( 'vlm_command' ) );
}
}
function vlm_schedule_append( name )
{
var act = document.getElementById( 'vlm_elt_' + name + '_action' ).value;
document.getElementById( 'vlm_command' ).value = "setup " + name + " append ";
var itemname = document.getElementById( 'vlm_elt_' + name + '_name' ).value;
if( itemname == "(name)" ) itemname = "";
var opt = document.getElementById( 'vlm_elt_' + name + '_opt' ).value;
if( opt == "(options)" ) opt = "";
if( act == '' )
{
document.getElementById( 'vlm_command' ).value += opt;
}
else
{
document.getElementById( 'vlm_command' ).value += 'control ' + itemname + " " + act + " " + opt;
}
vlm_cmd( value( 'vlm_command' ) );
}
function vlm_send( )
{
vlm_cmd( value( 'vlm_command' ) );
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< vlm.html: VLC media player web interface - VLM
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>VLC media player - Web Interface - Mosaic Wizard</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="js/functions.js"></script>
<script type="text/javascript" src="js/vlm.js"></script>
<script type="text/javascript" src="js/mosaic.js"></script>
</head>
<body onload="mosaic_init();">
<h1>Mosaic wizard</h1>
<vlc id="rpn" param1="page vlm store" />
<!-- do we need to browse in order to setup a mosaic ? for the background image maybe ... -->
<vlc id="include" param1="dialogs/browse" />
<!-- used to select background and sub streams -->
<vlc id="include" param1="dialogs/input" />
<!-- select final output -->
<vlc id="include" param1="dialogs/sout" />
<!-- the actual mosaic stuff -->
<vlc id="include" param1="dialogs/mosaic" />
<vlc id="include" param1="dialogs/footer" />
</body>
</html>
$Id$
This file describes commands available through the requests/ file:
Lines starting with < describe what the page sends back
Lines starting with > describe what you can send to the page
All parameters need to be URL encoded.
Examples:
# -> %23
% -> %25
+ -> %2B
space -> +
...
status.xml:
===========
< Get VLC status information, current item info and meta.
> add <mrl> to playlist and start playback:
?command=in_play&input=<mrl>
> add <mrl> to playlist:
?command=in_enqueue&input=<mrl>
> pause playback, do nothing if paused:
?command=pl_forcepause
> resume playback, do nothing if playing:
?command=pl_resume
> Start playback if in stopped or paused mode, if paused will resume, not restart playback:
?command=pl_forceplay
> play playlist item <id>:
?command=pl_play&id=<id>
> toggle pause. If current state was 'stop', play item <id>:
?command=pl_pause&id=<id>
> stop playback:
?command=pl_stop
> jump to next item:
?command=pl_next
> jump to previous item:
?command=pl_previous
> delete item <id> from playlist:
?command=pl_delete&id=<id>
> empty playlist:
?command=pl_empty
> sort playlist using sort mode <val> and order <id>:
?command=pl_sort&id=<id>&val=<val>
If id=0 then items will be sorted in normal order, if id=1 they will be
sorted in reverse order
A non exhaustive list of sort modes:
0 Id
1 Name
3 Author
5 Random
7 Track number
> toggle random playback:
?command=pl_random
> toggle loop:
?command=pl_loop
> toggle repeat:
?command=pl_repeat
> toggle enable service discovery module <val>:
?command=pl_sd&val=<val>
Typical values are:
sap
shoutcast
podcast
hal
> toggle fullscreen:
?command=fullscreen
> set volume level to <val> (can be absolute integer, percent or +/- relative value):
?command=volume&val=<val>
Allowed values are of the form:
+<int>, -<int>, <int> or <int>%
> seek to <val>:
?command=seek&val=<val>
Allowed values are of the form:
[+ or -][<int><H or h>:][<int><M or m or '>:][<int><nothing or S or s or ">]
or [+ or -]<int>%
(value between [ ] are optional, value between < > are mandatory)
examples:
1000 -> seek to the 1000th second
+1H:2M -> seek 1 hour and 2 minutes forward
-10% -> seek 10% back
playlist.xml:
=============
< get the full playlist tree
browse.xml:
===========
< ?dir=<dir>
> get <dir>'s filelist
vlm.xml:
========
< get the full list of VLM elements
vlm_cmd.xml:
============
< execute VLM command <cmd>
?command=<cmd>
> get the error message from <cmd>
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<vlc id="if" param1="0"/>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< browse.xml: VLC media player web interface
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<vlc id="end" />
<root>
<vlc id="if" param1="url_param 1 =" />
<vlc id="rpn" param1="'dir' url_extract" />
<vlc id="foreach" param1="file" param2="directory" />
<vlc id="if" param1="file.basename value '.' 1 strncmp 0 != file.basename value '..' 2 strncmp 0 = |" />
<element type="<vlc id="value" param1="file.type" />" size="<vlc id="value" param1="file.size" />" date="<vlc id="value" param1="file.date" />" path="<vlc id="value" param1="file.name value xml_encode" />" name="<vlc id="value" param1="file.basename value xml_encode" />" extension="<vlc id="value" param1="file.ext value xml_encode" />" />
<vlc id="end" />
<vlc id="end" />
<vlc id="end" />
</root>
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<vlc id="if" param1="0"/>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< playlist.xml: VLC media player web interface
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<vlc id="end"/>
<vlc id="rpn" param1="first_item 0 store" />
<vlc id="rpn" param1="last_depth 0 store" />
<vlc id="foreach" param1="pl" param2="playlist" />
<vlc id="if" param1="pl.depth value last_depth value <" />
<vlc id="rpn" param1="pl.depth value ':' last_depth value 1 - ':' 1 strcat strcat strcat strcat" />
<vlc id="foreach" param1="the_final_countdown" param2="integer" />
</node>
<vlc id="end" />
<vlc id="end" />
<vlc id="if" param1="pl.type value 'Node' strcmp" />
<vlc id="rpn" param1="1 +" />
<leaf id="<vlc id="value" param1="pl.index" />" <vlc id="if" param1="pl.current" /> current="current" <vlc id="end" /> uri="<vlc id="value" param1="pl.uri value xml_encode" />" name="<vlc id="value" param1="pl.name value xml_encode" />" ro="<vlc id="value" param1="pl.ro" />" duration="<vlc id="value" param1="pl.duration" />">
<title><![CDATA[<vlc id="value" param1="pl.title value xml_encode" />]]></title>
<artist><![CDATA[<vlc id="value" param1="pl.artist value xml_encode" />]]></artist>
<genre><![CDATA[<vlc id="value" param1="pl.genre value xml_encode" />]]></genre>
<copyright><![CDATA[<vlc id="value" param1="pl.copyright value xml_encode" />]]></copyright>
<album><![CDATA[<vlc id="value" param1="pl.album value xml_encode" />]]></album>
<track><![CDATA[<vlc id="value" param1="pl.track value xml_encode" />]]></track>
<description><![CDATA[<vlc id="value" param1="pl.description value xml_encode" />]]></description>
<rating><![CDATA[<vlc id="value" param1="pl.rating value xml_encode" />]]></rating>
<date><![CDATA[<vlc id="value" param1="pl.date value xml_encode" />]]></date>
<url><![CDATA[<vlc id="value" param1="pl.url value xml_encode" />]]></url>
<language><![CDATA[<vlc id="value" param1="pl.language value xml_encode" />]]></language>
<now_playing><![CDATA[<vlc id="value" param1="pl.now_playing value xml_encode" />]]></now_playing>
<publisher><![CDATA[<vlc id="value" param1="pl.publisher value xml_encode" />]]></publisher>
<encoded_by><![CDATA[<vlc id="value" param1="pl.encoded_by value xml_encode" />]]></encoded_by>
<art_url><![CDATA[<vlc id="value" param1="pl.art_url value xml_encode" />]]></art_url>
<track_id><![CDATA[<vlc id="value" param1="pl.track_id value xml_encode" />]]></track_id>
</leaf>
<vlc id="else" />
<node id="<vlc id="value" param1="pl.index" />" name="<vlc id="value" param1="pl.name value xml_encode" />" ro="<vlc id="value" param1="pl.ro" />" >
<vlc id="if" param1="first_item value 0 ="/>
<vlc id="rpn" param1="first_item 1 store" />
<vlc id="end"/>
<vlc id="if" param1="pl.i_children 0 !=" />
<vlc id="else" />
</node>
<vlc id="end" />
<vlc id="end" />
<vlc id="rpn" param1="last_depth pl.depth value store" />
<vlc id="end" />
<vlc id="rpn" param1="0 ':' last_depth value 1 - ':' 1 strcat strcat strcat strcat" />
<vlc id="foreach" param1="the_final_countdown" param2="integer" />
</node>
<vlc id="end" />
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<vlc id="if" param1="0"/>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< status.xml: VLC media player web interface
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<vlc id="end"/>
<vlc id="if" param1="url_param 1 =" />
<vlc id="rpn" param1="input 'input' url_extract store" />
<vlc id="rpn" param1="command 'command' url_extract store" />
<vlc id="rpn" param1="id 'id' url_extract store" />
<vlc id="rpn" param1="val 'val' url_extract store" />
<!-- input commands -->
<vlc id="if" param1="command value 'in_play' strcmp 0 =" />
<vlc id="rpn" param1="input value dup stripslashes playlist_add vlc_play" />
<vlc id="end" />
<vlc id="if" param1="command value 'in_enqueue' strcmp 0 =" />
<vlc id="rpn" param1="input value dup stripslashes playlist_add" />
<vlc id="end" />
<!-- playlist commands -->
<vlc id="if" param1="command value 'pl_forceplay' strcmp 0 =" />
<vlc id="if" param1="stream_state value 'stop' strcmp 0 =" />
<vlc id="rpn" param1="id value vlc_play"/>
<vlc id="else" />
<vlc id="if" param1="stream_state value 'paused' strcmp 0 =" />
<vlc id="rpn" param1="vlc_pause"/>
<vlc id="end" />
<vlc id="end" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_forcepause' strcmp 0 =" />
<vlc id="if" param1="stream_state value 'playing' strcmp 0 =" />
<vlc id="rpn" param1="vlc_pause"/>
<vlc id="end" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_resume' strcmp 0 =" />
<vlc id="if" param1="stream_state value 'paused' strcmp 0 =" />
<vlc id="rpn" param1="vlc_pause"/>
<vlc id="end" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_play' strcmp 0 =" />
<vlc id="rpn" param1="id value vlc_play" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_pause' strcmp 0 =" />
<vlc id="if" param1="stream_state value 'stop' strcmp 0 = id value 0 = ! &" />
<vlc id="rpn" param1="id value vlc_play"/>
<vlc id="else" />
<vlc id="rpn" param1="vlc_pause" />
<vlc id="end" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_stop' strcmp 0 =" />
<vlc id="rpn" param1="vlc_stop" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_next' strcmp 0 =" />
<vlc id="rpn" param1="vlc_next" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_previous' strcmp 0 =" />
<!-- FIXME -->
<vlc id="rpn" param1="vlc_previous" />
<vlc id="rpn" param1="vlc_previous" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_delete' strcmp 0 =" />
<vlc id="rpn" param1="id value playlist_delete" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_empty' strcmp 0 =" />
<vlc id="rpn" param1="playlist_empty" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_sort' strcmp 0 =" />
<vlc id="rpn" param1="val value id value playlist_sort" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_random' strcmp 0 =" />
<vlc id="rpn" param1="'random' 'VLC_OBJECT_PLAYLIST' vlc_var_get 1 + 2 % 'random' 'VLC_OBJECT_PLAYLIST' vlc_var_set" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_loop' strcmp 0 =" />
<vlc id="rpn" param1="'loop' 'VLC_OBJECT_PLAYLIST' vlc_var_get 1 + 2 % 'loop' 'VLC_OBJECT_PLAYLIST' vlc_var_set" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_repeat' strcmp 0 =" />
<vlc id="rpn" param1="'repeat' 'VLC_OBJECT_PLAYLIST' vlc_var_get 1 + 2 % 'repeat' 'VLC_OBJECT_PLAYLIST' vlc_var_set" />
<vlc id="end" />
<vlc id="if" param1="command value 'pl_sd' strcmp 0 =" />
<vlc id="if" param1="val value services_discovery_is_loaded" />
<vlc id="rpn" param1="val value services_discovery_remove" />
<vlc id="else" />
<vlc id="rpn" param1="val value services_discovery_add" />
<vlc id="end" />
<vlc id="end" />
<!-- misc commands -->
<vlc id="if" param1="command value 'fullscreen' strcmp 0 =" />
<vlc id="if" param1="'VLC_OBJECT_VOUT' vlc_object_exists" />
<vlc id="rpn" param1="'fullscreen' 'VLC_OBJECT_VOUT' vlc_var_get ! 'fullscreen' 'VLC_OBJECT_VOUT' vlc_var_set" />
<vlc id="end" />
<vlc id="end" />
<vlc id="if" param1="command value 'snapshot' strcmp 0 =" />
<vlc id="rpn" param1="snapshot" />
<vlc id="end" />
<vlc id="if" param1="command value 'volume' strcmp 0 =" />
<vlc id="rpn" param1="val value vlc_volume_set" />
<vlc id="end"/>
<vlc id="if" param1="command value 'seek' strcmp 0 =" />
<vlc id="rpn" param1="val value vlc_seek" />
<vlc id="end"/>
<vlc id="if" param1="command value 'key' strcmp 0 =" />
<vlc id="rpn" param1="'key-' val value strcat 'VLC_OBJECT_LIBVLC' vlc_var_get key-pressed 'VLC_OBJECT_LIBVLC' vlc_var_set" />
<vlc id="end"/>
<vlc id="end" />
<root>
<volume><vlc id="value" param1="volume" /></volume>
<length><vlc id="value" param1="stream_length" /></length>
<time><vlc id="value" param1="stream_time" /></time>
<state><vlc id="value" param1="stream_state" /></state>
<position><vlc id="value" param1="stream_position" /></position>
<fullscreen><vlc id="if" param1="'VLC_OBJECT_VOUT' vlc_obj_exists" /><vlc id="value" param1="'fullscreen' 'VLC_OBJECT_VOUT' vlc_var_get" /><vlc id="end" /></fullscreen>
<random><vlc id="value" param1="'random' 'VLC_OBJECT_PLAYLIST' vlc_var_get" /></random>
<loop><vlc id="value" param1="'loop' 'VLC_OBJECT_PLAYLIST' vlc_var_get" /></loop>
<repeat><vlc id="value" param1="'repeat' 'VLC_OBJECT_PLAYLIST' vlc_var_get" /></repeat>
<information>
<vlc id="foreach" param1="inf" param2="information" />
<category name="<vlc id="value" param1="inf.name value xml_encode" />">
<vlc id="foreach" param1="subinf" param2="inf.info" />
<info name="<vlc id="value" param1="subinf.name value xml_encode" />"><vlc id="value" param1="subinf.value value xml_encode" /></info>
<vlc id="end" />
</category>
<vlc id="end" />
<meta-information>
<title><![CDATA[<vlc id="value" param1="'TITLE' vlc_get_meta xml_encode" />]]></title>
<artist><![CDATA[<vlc id="value" param1="'ARTIST' vlc_get_meta xml_encode" />]]></artist>
<genre><![CDATA[<vlc id="value" param1="'GENRE' vlc_get_meta xml_encode" />]]></genre>
<copyright><![CDATA[<vlc id="value" param1="'COPYRIGHT' vlc_get_meta xml_encode" />]]></copyright>
<album><![CDATA[<vlc id="value" param1="'ALBUM' vlc_get_meta xml_encode" />]]></album>
<track><![CDATA[<vlc id="value" param1="'TRACK_NUMBER' vlc_get_meta xml_encode" />]]></track>
<description><![CDATA[<vlc id="value" param1="'DESCRIPTION' vlc_get_meta xml_encode" />]]></description>
<rating><![CDATA[<vlc id="value" param1="'RATING' vlc_get_meta xml_encode" />]]></rating>
<date><![CDATA[<vlc id="value" param1="'DATE' vlc_get_meta xml_encode" />]]></date>
<url><![CDATA[<vlc id="value" param1="'URL' vlc_get_meta xml_encode" />]]></url>
<language><![CDATA[<vlc id="value" param1="'LANGUAGE' vlc_get_meta xml_encode" />]]></language>
<now_playing><![CDATA[<vlc id="value" param1="'NOW_PLAYING' vlc_get_meta xml_encode" />]]></now_playing>
<publisher><![CDATA[<vlc id="value" param1="'PUBLISHER' vlc_get_meta xml_encode" />]]></publisher>
<encoded_by><![CDATA[<vlc id="value" param1="'ENCODED_BY' vlc_get_meta xml_encode" />]]></encoded_by>
<art_url><![CDATA[<vlc id="value" param1="'ART_URL' vlc_get_meta xml_encode" />]]></art_url>
<track_id><![CDATA[<vlc id="value" param1="'TRACK_ID' vlc_get_meta xml_encode" />]]></track_id>
</meta-information>
</information>
<stats>
<readbytes><vlc id="value" param1="read_bytes" /></readbytes>
<inputbitrate><vlc id="value" param1="input_bitrate" /></inputbitrate>
<demuxreadbytes><vlc id="value" param1="demux_read_bytes" /></demuxreadbytes>
<demuxbitrate><vlc id="value" param1="demux_bitrate" /></demuxbitrate>
<decodedvideo><vlc id="value" param1="decoded_video" /></decodedvideo>
<displayedpictures><vlc id="value" param1="displayed_pictures" /></displayedpictures>
<lostpictures><vlc id="value" param1="lost_pictures" /></lostpictures>
<decodedaudio><vlc id="value" param1="decoded_audio" /></decodedaudio>
<playedabuffers><vlc id="value" param1="played_abuffers" /></playedabuffers>
<lostabuffers><vlc id="value" param1="lost_abuffers" /></lostabuffers>
<sentpackets><vlc id="value" param1="sent_packets" /></sentpackets>
<sentbytes><vlc id="value" param1="sent_bytes" /></sentbytes>
<sendbitrate><vlc id="value" param1="send_bitrate" /></sendbitrate>
</stats>
</root>
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<vlc id="if" param1="0"/>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< vlm.xml: VLC media player web interface
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<vlc id="end"/>
<vlm>
<vlc id="foreach" param1="el" param2="vlm" />
<vlc id="if" param1="el.type value 'broadcast' strcmp 0 =" />
<broadcast name="<vlc id="value" param1="el.name"/>" enabled="<vlc id="value" param1="el.enabled" />" loop="<vlc id="value" param1="el.loop"/>">
<output><vlc id="value" param1="el.output" /></output>
<inputs>
<vlc id="foreach" param1="in" param2="el.inputs" />
<input><vlc id="value" param1="in value xml_encode" /></input>
<vlc id="end" />
</inputs>
<options>
<vlc id="foreach" param1="opt" param2="el.options" />
<option><vlc id="value" param1="opt" /></option>
<vlc id="end" />
</options>
<instances>
<vlc id="foreach" param1="inst" param2="el.instances" />
<instance name="<vlc id="value" param1="inst.name"/>" state="<vlc id="value" param1="inst.state"/>" position="<vlc id="value" param1="inst.position"/>" time="<vlc id="value" param1="inst.time"/>" length="<vlc id="value" param1="inst.length"/>" rate="<vlc id="value" param1="inst.rate"/>" title="<vlc id="value" param1="inst.title"/>" chapter="<vlc id="value" param1="inst.chapter"/>" seekable="<vlc id="value" param1="inst.seekable"/>" playlistindex="<vlc id="value" param1="inst.playlistindex"/>" />
<vlc id="end" />
</instances>
</broadcast>
<vlc id="else" />
<vlc id="if" param1="el.type value 'vod' strcmp 0 =" />
<vod name="<vlc id="value" param1="el.name"/>" enabled="<vlc id="value" param1="el.enabled" />">
<output><vlc id="value" param1="el.output" /></output>
<inputs>
<vlc id="foreach" param1="in" param2="el.inputs" />
<input><vlc id="value" param1="in value xml_encode" /></input>
<vlc id="end" />
</inputs>
<options>
<vlc id="foreach" param1="opt" param2="el.options" />
<option><vlc id="value" param1="opt" /></option>
<vlc id="end" />
</options>
<instances>
<vlc id="foreach" param1="inst" param2="el.instances" />
<instance name="<vlc id="value" param1="inst.name"/>" state="<vlc id="value" param1="inst.state"/>" position="<vlc id="value" param1="inst.position"/>" time="<vlc id="value" param1="inst.time"/>" length="<vlc id="value" param1="inst.length"/>" rate="<vlc id="value" param1="inst.rate"/>" title="<vlc id="value" param1="inst.title"/>" chapter="<vlc id="value" param1="inst.chapter"/>" seekable="<vlc id="value" param1="inst.seekable"/>" playlistindex="<vlc id="value" param1="inst.playlistindex"/>" />
<vlc id="end" />
</instances>
</vod>
<vlc id="else" />
<schedule name="<vlc id="value" param1="el.name"/>" enabled="<vlc id="value" param1="el.enabled" />" date="<vlc id="value" param1="el.date"/>" period="<vlc id="value" param1="el.period"/>" repeat="<vlc id="value" param1="el.repeat"/>">
<commands>
<vlc id="foreach" param1="com" param2="el.commands" />
<command><vlc id="value" param1="com" /></command>
<vlc id="end" />
</commands>
</schedule>
<vlc id="end" />
<vlc id="end" />
<vlc id="end" />
</vlm>
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<vlc id="if" param1="0"/>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< vlm_cmd.xml: VLC media player web interface
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<vlc id="end"/>
<vlc id="if" param1="url_param 1 =" />
<vlc id="rpn" param1="; 'command' url_extract vlm_cmd" />
<vlc id="end" />
<vlm>
<error><vlc id="value" param1="vlm_error" /></error>
</vlm>
/*****************************************************************************
* style.css: VLC media player web interface
*****************************************************************************
* Copyright (C) 2005-2006 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
body {
background-color: #eee;
font-family: Arial, sans-serif;
font-size: 12pt;
text-align: center; /* Center on page - IE */
padding: 0px;
margin: 0px;
}
div {
padding: 0px;
margin: 0px;
text-align: left;
}
div.dialog {
width: 440pt;
background: #fff;
border: solid #000 1px;
margin: 10px auto; /* Center on page - Firefox */
padding: 0px;
overflow: hidden; /* so that the title bar doesn't overflow on
* firefox but still takes all the div's width
* in IE */
}
div#footer {
font-size: 8pt;
text-align: center;
}
.btn_text {
display: none;
}
form {
display: inline;
}
input, textarea {
border: solid #000 1px;
background-color: #fff;
}
div.helper {
margin: 10px;
padding: 10px 0px;
border: solid 1px #000;
}
div.helper hr {
border: solid 1px #000;
}
div.title {
width: 100%/*576px*/; /* see overflow:hidden several lines
* before for explanation */
background: #000 url('images/vlc16x16.png') no-repeat top left;
padding-left: 24px;
color: #fff;
font-weight: bold;
}
div.title button {
border: 1px none #000;
padding: 0px;
background-color: #000;
color: #fff;
}
div.controls {
width: 100%;
padding: 3px 5px;
}
div.controls button {
border: 1px solid #fff;
padding: 0px;
background-color: #fff;
}
div.list {
padding: 1em;
}
div.list_element {
padding-bottom: 0.3em;
}
div.list_element ul {
margin: 0px;
}
div#infotree ul {
padding: 0.4em;
margin: 0em;
}
div#infotree li {
font-weight: bold;
font-size: 0.8em;
}
div#infotree dl {
font-weight: normal;
padding: 0em 1em;
}
div#infotree dt {
text-decoration: underline;
}
div#playtree {
min-height: 150px;
}
div.pl_node {
padding-left: 20px;
font-style: italic;
}
a.pl_leaf {
font-style: normal;
}
a.pl_leaf:hover {
color: #f00;
}
img {
border: 0px none black;
}
div.popup {
background-color: #fff;
overflow: hidden;
border: solid #888 1px;
margin: 10px auto; /* Center on page - Firefox */
position: absolute;
z-index: 2;
font-size: 0.8em;
}
div#browse {
width: 70%;
left: 15%;
}
div#browse div.title {
background-color: #008;
}
div#browser {
padding: 20px;
}
div#mosaic_list {
width: 50%;
left: 25%;
background: url('images/white.png') repeat;
display: none;
}
.mosaic_bg {
background-color: #aaf;
}
.mosaic_tbl {
background-color: #faa;
}
.mosaic_itm {
background-color: #afa;
}
div#mosaic_layout {
border: 0px solid #000;
padding: 0px;
margin: 10px auto;
}
div#mosaic_dt {
border: 0px solid #000;
position: relative;
}
table#mosaic_table {
border-spacing: 0px 0px;
position: relative;
}
table#mosaic_table tr {
padding: 0px;
margin: 0px;
}
table#mosaic_table td {
border: 0px solid #000;
text-align: center;
padding: 0px;
margin: 0px;
}
table#mosaic_table input {
border: 0px;
background: transparent;
text-align: center;
}
textarea#mosaic_code {
padding: 0px;
display: block;
margin: 10px auto;
}
div.controls button.on {
background-color: #aaa;
}
div.controls button.off {
background-color: #fff;
}
div.menubtn {
display: inline;
}
div.menu {
position: absolute;
border: 1px solid #ccc;
padding: 5px;
margin-top: -5px;
background: url('images/white.png') repeat;
z-index: 2;
display: none;
}
div.menu button {
background: transparent;
}
div.menu button.menuout {
border: 1px solid transparent;
}
div.menu button.menuover {
border: 1px solid #000;
}
div.popup img.close {
position: absolute;
right: 2px;
top: 2px;
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< vlm.html: VLC media player web interface - VLM
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
< Copyright (C) 2005-2006 the VideoLAN team
< $Id$
<
< Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
<
< This program is free software; you can redistribute it and/or modify
< it under the terms of the GNU General Public License as published by
< the Free Software Foundation; either version 2 of the License, or
< (at your option) any later version.
<
< This program is distributed in the hope that it will be useful,
< but WITHOUT ANY WARRANTY; without even the implied warranty of
< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
< GNU General Public License for more details.
<
< You should have received a copy of the GNU General Public License
< along with this program; if not, write to the Free Software
< Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>VLC media player - Web Interface - VLM</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="js/functions.js"></script>
<script type="text/javascript" src="js/vlm.js"></script>
</head>
<body onload="vlm_get_elements();">
<vlc id="rpn" param1="page vlm store" />
<vlc id="include" param1="dialogs/browse" />
<vlc id="include" param1="dialogs/input" />
<vlc id="include" param1="dialogs/sout" />
<vlc id="include" param1="dialogs/vlm" />
<vlc id="include" param1="dialogs/footer" />
</body>
</html>
## <pre>
##
## <a href="vlm.html">VLM HTTP interface</a>
## This file can be loaded as is in VLM.
## Comments starting with "##" were added by the HTTP interface.
## You can remove them if you want to.
##
<vlc id="value" param1="; export vlm_cmd vlm_value" />
##
## end of export
## </pre>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment