#include <vlc_demux.h>
#include <vlc_url.h>
#include <vlc_strings.h>
+#include <vlc_charset.h>
#include <errno.h> /* ENOMEM */
#include "playlist.h"
n = lua_tonumber( p_state, 1 );
lua_pop( p_state, i );
i_peek = stream_Peek( p_demux->s, &p_peek, n );
- lua_pushnumber( p_state, i_peek );
lua_pushlstring( p_state, (const char *)p_peek, i_peek );
- return 2;
+ return 1;
}
static int vlclua_readline( lua_State *p_state )
return 1;
}
+static int vlclua_resolve_xml_special_chars( lua_State *p_state )
+{
+ int i = lua_gettop( p_state );
+ if( !i ) return 0;
+ const char *psz_cstring = lua_tostring( p_state, 1 );
+ if( !psz_cstring ) return 0;
+ char *psz_string = strdup( psz_cstring );
+ lua_pop( p_state, i );
+ resolve_xml_special_chars( psz_string );
+ lua_pushstring( p_state, psz_string );
+ free( psz_string );
+ return 1;
+}
+
+static int file_select( const char *file )
+{
+ int i = strlen( file );
+ return i > 4 && !strcmp( file+i-4, ".lua" );
+}
+
+static int file_compare( const char **a, const char **b )
+{
+ return strcmp( *a, *b );
+}
+
/*****************************************************************************
* Import_LuaPlaylist: main import function
*****************************************************************************/
{
demux_t *p_demux = (demux_t *)p_this;
lua_State *p_state;
+ int i_ret = VLC_EGENERIC;
+ char **ppsz_filelist = NULL;
+ char **ppsz_fileend = NULL;
+ char **ppsz_file;
+ DIR *dir;
+ char *psz_filename = NULL;
+ int i_files;
+ const char psz_dir[] = "share/luaplaylist"; /* FIXME */
+
+ static luaL_Reg p_reg[] =
+ {
+ { "readline", vlclua_readline },
+ { "peek", vlclua_peek },
+ { "decode_uri", vlclua_decode_uri },
+ { "resolve_xml_special_chars", vlclua_resolve_xml_special_chars }
+ };
p_demux->p_sys = (demux_sys_t*)malloc( sizeof( demux_sys_t ) );
if( !p_demux->p_sys )
/* Load Lua libraries */
luaL_openlibs( p_state ); /* FIXME: Don't open all the libs? */
- static luaL_Reg p_reg[] =
- {
- { "readline", vlclua_readline },
- { "peek", vlclua_peek },
- { "decode_uri", vlclua_decode_uri }
- };
-
luaL_register( p_state, "vlc", p_reg );
lua_pushlightuserdata( p_state, p_demux );
lua_setfield( p_state, lua_gettop( p_state ) - 1, "private" );
lua_pop( p_state, 1 );
+ dir = utf8_opendir( psz_dir );
+ if( !dir ) goto error;
+ i_files = utf8_loaddir( dir, &ppsz_filelist, file_select, file_compare );
+ if( i_files < 1 ) goto error;
+ ppsz_fileend = ppsz_filelist + i_files;
+
+ for( ppsz_file = ppsz_filelist; ppsz_file < ppsz_fileend; ppsz_file++ )
{
- const char *psz_filename = "share/luaplaylist/test.lua";
- int i_ret;
+ free( psz_filename ); psz_filename = NULL;
+ asprintf( &psz_filename, "%s/%s", psz_dir, *ppsz_file );
+ msg_Dbg( p_demux, "Trying Lua playlist script %s", psz_filename );
+
+ /* Ugly hack to delete previous versions of the probe() and parse()
+ * functions. */
+ lua_pushnil( p_state );
+ lua_pushnil( p_state );
+ lua_setglobal( p_state, "probe" );
+ lua_setglobal( p_state, "parse" );
/* Load and run the script(s) */
if( luaL_dofile( p_state, psz_filename ) )
{
- msg_Warn( p_demux, "Error while runing script %s: %s", psz_filename, lua_tostring( p_state, lua_gettop( p_state ) ) );
- return VLC_EGENERIC;
+ msg_Warn( p_demux, "Error loading script %s: %s", psz_filename,
+ lua_tostring( p_state, lua_gettop( p_state ) ) );
+ lua_pop( p_state, 1 );
+ continue;
}
- if( lua_gettop( p_state ) )
- {
- i_ret = lua_toboolean( p_state, 1 );
- printf( "Script returned %d: %d\n", 1, i_ret );
+ lua_getglobal( p_state, "probe" );
- while( lua_gettop( p_state ) != 1 )
- {
- printf( "Script returned %d: %s\n", lua_gettop( p_state ),
- lua_tostring( p_state, lua_gettop( p_state ) ) );
- lua_pop( p_state, 1 );
- }
+ if( !lua_isfunction( p_state, lua_gettop( p_state ) ) )
+ {
+ msg_Warn( p_demux, "Error while runing script %s, "
+ "function probe() not found", psz_filename );
+ lua_pop( p_state, 1 );
+ continue;
+ }
+ if( lua_pcall( p_state, 0, 1, 0 ) )
+ {
+ msg_Warn( p_demux, "Error while runing script %s, "
+ "function probe(): %s", psz_filename,
+ lua_tostring( p_state, lua_gettop( p_state ) ) );
lua_pop( p_state, 1 );
+ continue;
+ }
- if( !i_ret )
+ if( lua_gettop( p_state ) )
+ {
+ if( lua_toboolean( p_state, 1 ) )
{
- E_(Close_LuaPlaylist)( p_this );
- return VLC_EGENERIC;
+ msg_Dbg( p_demux, "Lua playlist script %s's "
+ "probe() function was successful", psz_filename );
+ i_ret = VLC_SUCCESS;
}
+ lua_pop( p_state, 1 );
+
+ if( i_ret == VLC_SUCCESS ) break;
}
- else
+ }
+
+ error:
+ free( psz_filename );
+
+ if( ppsz_filelist )
{
- E_(Close_LuaPlaylist)( p_this );
- return VLC_EGENERIC;
+ for( ppsz_file = ppsz_filelist; ppsz_file < ppsz_fileend;
+ ppsz_file++ )
+ free( *ppsz_file );
+ free( ppsz_filelist );
}
- }
- return VLC_SUCCESS;
+ if( dir ) closedir( dir );
+ if( i_ret != VLC_SUCCESS )
+ E_(Close_LuaPlaylist)( p_this );
+ return i_ret;
}
/*****************************************************************************
static int Demux( demux_t *p_demux )
{
- /*input_item_t *p_input;*/
+ input_item_t *p_input;
+ lua_State *p_state = p_demux->p_sys->p_state;
+ char psz_filename[] = "FIXME";
INIT_PLAYLIST_STUFF;
-#if 0
- p_input = input_ItemNewExt( p_playlist, psz_url, psz_title, 0, NULL, -1 );
- playlist_BothAddInput( p_playlist, p_input,
- p_item_in_category,
- PLAYLIST_APPEND | PLAYLIST_SPREPARSE,
- PLAYLIST_END, NULL, NULL, VLC_FALSE );
-#endif
+ lua_getglobal( p_state, "parse" );
+
+ if( !lua_isfunction( p_state, lua_gettop( p_state ) ) )
+ {
+ msg_Warn( p_demux, "Error while runing script %s, "
+ "function parse() not found", psz_filename );
+ E_(Close_LuaPlaylist)( VLC_OBJECT( p_demux ) );
+ return VLC_EGENERIC;
+ }
+
+ if( lua_pcall( p_state, 0, 1, 0 ) )
+ {
+ msg_Warn( p_demux, "Error while runing script %s, "
+ "function parse(): %s", psz_filename,
+ lua_tostring( p_state, lua_gettop( p_state ) ) );
+ E_(Close_LuaPlaylist)( VLC_OBJECT( p_demux ) );
+ return VLC_EGENERIC;
+ }
+
+ if( lua_gettop( p_state ) )
+ {
+ int t = lua_gettop( p_state );
+ if( lua_istable( p_state, t ) )
+ {
+ lua_pushnil( p_state );
+ while( lua_next( p_state, t ) )
+ {
+ if( lua_istable( p_state, t+2 ) )
+ {
+ const char *psz_url = NULL;
+ const char *psz_title = NULL;
+ lua_getfield( p_state, t+2, "url" );
+ if( lua_isstring( p_state, t+3 ) )
+ {
+ psz_url = lua_tostring( p_state, t+3 );
+ printf("URL: %s\n", psz_url );
+ lua_getfield( p_state, t+2, "title" );
+ if( lua_isstring( p_state, t+4 ) )
+ {
+ psz_title = lua_tostring( p_state, t+4 );
+ printf("Title: %s\n", psz_title );
+ }
+ else
+ {
+ psz_title = psz_url;
+ }
+ p_input = input_ItemNewExt( p_playlist, psz_url,
+ psz_title, 0, NULL, -1 );
+ playlist_BothAddInput(
+ p_playlist, p_input,
+ p_item_in_category,
+ PLAYLIST_APPEND | PLAYLIST_SPREPARSE,
+ PLAYLIST_END, NULL, NULL, VLC_FALSE );
+ lua_pop( p_state, 1 ); /* pop "title" */
+ }
+ else
+ {
+ printf("URL isn't a string\n");
+ }
+ lua_pop( p_state, 1 ); /* pop "url" */
+ }
+ else
+ {
+ printf("This isn't a table !!!\n" );
+ }
+ lua_pop( p_state, 1 ); /* pop the value, keep the key for
+ * the next lua_next() call */
+ }
+ lua_pop( p_state, 1 ); /* pop the last key */
+ }
+ else
+ {
+ msg_Warn( p_demux, "Script didn't return a table" );
+ }
+ }
+ else
+ {
+ msg_Err( p_demux, "Script went completely foobar" );
+ }
HANDLE_PLAY_AND_RELEASE;
+++ /dev/null
--- $Id$
-
-if vlc.access ~= "http"
-then
- return false
-end
-
-url = nil
-title = nil
-
-function get_url_param( url, name )
- return string.gsub( vlc.path, "^.*"..name.."=([^&]*).*$", "%1" )
-end
-
-if string.match( vlc.path, "youtube.com" )
-then
- if string.match( vlc.path, "watch%?v=" )
- then
- url = string.gsub( vlc.path, "^(.*)watch%?v=([^&]*).*$", "http://%1v/%2" )
- while not title
- do
- line = vlc.readline()
- if not line
- then
- break
- end
- if string.match( line, "<meta name=\"title\"" )
- then
- title = string.gsub( line, "^.*content=\"([^\"]*).*$", "%1" )
- end
- end
- elseif string.match( vlc.path, "watch_fullscreen%?video_id=" ) or string.match( vlc.path, "p.swf" ) or string.match( vlc.path, "player2.swf" )
- then
- video_id = get_url_param( vlc.path, "video_id" )
- t = get_url_param( vlc.path, "t" )
- url = "http://www.youtube.com/get_video.php?video_id="..video_id.."&t="..t
- if string.match( vlc.path, "title=" )
- then
- title = get_url_param( vlc.path, "title" )
- end
- end
-elseif string.match( vlc.path, "dailymotion.com" )
-then
- len, str = vlc.peek( 9 )
- if str == "<!DOCTYPE"
- then
- while not url
- do
- line = vlc.readline()
- if string.match( line, "param name=\"flashvars\" value=\"url=" )
- then
- url = vlc.decode_uri( string.gsub( line, "^.*param name=\"flashvars\" value=\"url=([^&]*).*$", "%1" ) )
- end
- end
- end
-elseif string.match( vlc.path, "video.google.com" ) and string.match( vlc.path, "videoplay" )
-then
- url = string.gsub( vlc.path, "^.*(docid=[^&]*).*$", "http://video.google.com/videogvp?%1" )
-elseif string.match( vlc.path, "metacafe.com" )
-then
- if string.match( vlc.path, "watch/" )
- then
- url = string.gsub( vlc.path, "^.*watch/(.*[^/])/?$", "http://www.metacafe.com/fplayer/%1.swf" )
- elseif string.match( vlc.path, "mediaURL=" )
- then
- url = string.gsub( vlc.path, "^.*mediaURL=([^&]*).*$", "%1" )
- end
-end
-
-if url == nil
-then
- return false
-else
- return true, url, title
-end
--- /dev/null
+-- $Id$
+
+--[[
+VLC Lua playlist modules should define two functions:
+ * probe(): returns true if we want to handle the playlist in this script
+ * parse(): read the incoming data and return playlist item(s)
+ The playlist is a table of playlist objects.
+ A playlist object has the following members:
+ .url: the item's full URL
+ .title: the item's title (OPTIONAL)
+ Invalid playlist items will be discarded by VLC.
+
+VLC defines a global vlc object with the following members:
+ * vlc.path: the URL string (without the leading http:// or file:// element)
+ * vlc.access: the access used ("http" for http://, "file" for file://, etc.)
+ * vlc.peek( <int> ): return the first <int> characters from the playlist file.
+ * vlc.readline(): return a new line of playlist data on each call.
+ THIS FUNCTION SHOULD NOT BE USED IN peek().
+ * vlc.decode_uri( <string> ): decode %xy characters in a string.
+ * vlc.resolve_xml_special_chars( <string> ): decode &abc; characters in a string.
+
+Lua scripts are tried in alphabetical order in the luaplaylist/ directory.
+
+Lua documentation is available on http://www.lua.org .
+VLC uses Lua 5.1
+All the Lua standard libraries are available.
+--]]
+
+-- Helper function to get a parameter's value in a URL
+function get_url_param( url, name )
+ return string.gsub( vlc.path, "^.*"..name.."=([^&]*).*$", "%1" )
+end
+
+-- Probe function.
+function probe()
+ return vlc.access == "http"
+ and string.match( vlc.path, "youtube.com" )
+ and ( string.match( vlc.path, "watch%?v=" )
+ or string.match( vlc.path, "watch_fullscreen%?video_id=" )
+ or string.match( vlc.path, "p.swf" )
+ or string.match( vlc.path, "player2.swf" ) )
+end
+
+-- Parse function.
+function parse()
+ local p = {}
+ if string.match( vlc.path, "watch%?v=" )
+ then -- This is the HTML page's URL
+ p[1] = { url = string.gsub( vlc.path, "^(.*)watch%?v=([^&]*).*$", "http://%1v/%2" ) }
+ while true do
+ -- Try to find the video's title
+ line = vlc.readline()
+ if not line then break end
+ if string.match( line, "<meta name=\"title\"" ) then
+ p[1].title = string.gsub( line, "^.*content=\"([^\"]*).*$", "%1" )
+ break
+ end
+ end
+ else -- This is the flash player's URL
+ p[1] = { url = "http://www.youtube.com/get_video.php?video_id="..get_url_param( vlc.path, "video_id" ).."&t="..get_url_param( vlc.patch, "t" ) }
+ if string.match( vlc.path, "title=" ) then
+ p[1].title = get_url_param( vlc.path, "title" )
+ end
+ end
+ return p
+end