From 2c83bdf0d8b62c637aff052211b6e65c89488d20 Mon Sep 17 00:00:00 2001
From: Fabio Ritrovato <exsephiroth87@gmail.com>
Date: Wed, 22 Jul 2009 00:24:08 +0200
Subject: [PATCH] [GSoC] luasd: lua backed and first 2 scripts

---
 modules/misc/lua/Modules.am           |    1 +
 modules/misc/lua/libs/sd.c            |  143 +++++++++++
 modules/misc/lua/services_discovery.c |  276 ++++++++++++++++++++++
 modules/misc/lua/vlc.c                |   60 +++++-
 modules/misc/lua/vlc.h                |    3 +
 share/lua/sd/jamendo.lua              |  415 +++++++++++++++++++++++++++++++++
 share/lua/sd/youtube.lua              |  302 ++++++++++++++++++++++++
 7 files changed, 1199 insertions(+), 1 deletions(-)
 create mode 100644 modules/misc/lua/services_discovery.c
 create mode 100644 share/lua/sd/jamendo.lua
 create mode 100644 share/lua/sd/youtube.lua

diff --git a/modules/misc/lua/Modules.am b/modules/misc/lua/Modules.am
index 0b6b38b..ee91c9e 100644
--- a/modules/misc/lua/Modules.am
+++ b/modules/misc/lua/Modules.am
@@ -2,6 +2,7 @@ SOURCES_lua = \
 	intf.c \
 	meta.c \
 	demux.c \
+	services_discovery.c \
 	vlc.c \
 	vlc.h \
 	libs.h \
diff --git a/modules/misc/lua/libs/sd.c b/modules/misc/lua/libs/sd.c
index 491b682..92ca5bc 100644
--- a/modules/misc/lua/libs/sd.c
+++ b/modules/misc/lua/libs/sd.c
@@ -5,6 +5,7 @@
  * $Id$
  *
  * Authors: Antoine Cellerier <dionoea at videolan tod org>
+ *          Fabio Ritrovato <exsephiroth87@gmail.com>
  *
  * 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
@@ -97,6 +98,144 @@ static int vlclua_sd_is_loaded( lua_State *L )
     return 1;
 }
 
+static int vlclua_sd_add_node( lua_State *L )
+{
+    services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
+    if( lua_istable( L, -1 ) )
+    {
+        lua_getfield( L, -1, "title" );
+        if( lua_isstring( L, -1 ) )
+        {
+            input_item_t *p_input = input_item_New( p_sd,
+                                                    "vlc://nop",
+                                                    strdup( lua_tostring( L, -1 ) ) );
+            lua_pop( L, 1 );
+
+            lua_getfield( L, -1, "parent" );
+            if( !lua_isnil( L, -1 ) )
+            {
+                input_item_t **pp_parent = luaL_checkudata( L, -1, "input_item_t" );
+                if( *pp_parent )
+                    input_item_AddSubItem( *pp_parent, p_input );
+                else
+                    services_discovery_AddItem( p_sd, p_input, NULL );
+            }
+            else
+                services_discovery_AddItem( p_sd, p_input, NULL );
+            input_item_t **udata = (input_item_t **)
+                                   lua_newuserdata( L, sizeof( input_item_t * ) );
+            *udata = p_input;
+            if( luaL_newmetatable( L, "input_item_t" ) )
+            {
+                lua_pushstring( L, "none of your business" );
+                lua_setfield( L, -2, "__metatable" );
+            }
+            lua_setmetatable( L, -2 );
+        }
+        else
+            msg_Err( p_sd, "vlc.sd.add_node: the \"title\" parameter can't be empty" );
+    }
+    else
+        msg_Err( p_sd, "Error parsing add_node arguments" );
+    return 1;
+}
+
+static int vlclua_sd_add_item( lua_State *L )
+{
+    services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
+    if( lua_istable( L, -1 ) )
+    {
+        lua_getfield( L, -1, "url" );
+        if( lua_isstring( L, -1 ) )
+        {
+            input_item_t *p_input = input_item_New( p_sd,
+                                                    strdup( lua_tostring( L, -1 ) ),
+                                                    strdup( lua_tostring( L, -1 ) ) );
+            lua_pop( L, 1 );
+            vlclua_read_meta_data( p_sd, L, p_input );
+            /* This one is to be tested... */
+            vlclua_read_custom_meta_data( p_sd, L, p_input );
+            lua_getfield( L, -1, "duration" );
+            if( lua_isnumber( L, -1 ) )
+               input_item_SetDuration( p_input, (lua_tonumber( L, -1 )*1e6) );
+            else if( !lua_isnil( L, -1 ) )
+                msg_Warn( p_sd, "Item duration should be a number (in seconds)." );
+            lua_pop( L, 1 );
+            lua_getfield( L, -1, "parent" );
+            if( !lua_isnil( L, -1 ) )
+            {
+                input_item_t **pp_parent = luaL_checkudata( L, -1, "input_item_t" );
+                if( *pp_parent )
+                    input_item_AddSubItem( *pp_parent, p_input );
+                else
+                    services_discovery_AddItem( p_sd, p_input, NULL );
+            }
+            else
+                services_discovery_AddItem( p_sd, p_input, NULL );
+            input_item_t **udata = (input_item_t **)
+                                   lua_newuserdata( L, sizeof( input_item_t * ) );
+            *udata = p_input;
+            if( luaL_newmetatable( L, "input_item_t" ) )
+            {
+                lua_pushstring( L, "none of your business" );
+                lua_setfield( L, -2, "__metatable" );
+            }
+            lua_setmetatable( L, -2 );
+        }
+        else
+            msg_Err( p_sd, "vlc.sd.add_item: the \"url\" parameter can't be empty" );
+    }
+    else
+        msg_Err( p_sd, "Error parsing add_item arguments" );
+    return 1;
+}
+
+static int vlclua_sd_remove_item( lua_State *L )
+{
+    services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
+    if( !lua_isnil( L, -1 ) )
+    {
+        input_item_t **pp_input = luaL_checkudata( L, -1, "input_item_t" );
+        if( *pp_input )
+            services_discovery_RemoveItem( p_sd, *pp_input );
+    }
+    return 1;
+}
+
+static int vlclua_sd_add_parameter_value( lua_State *L )
+{
+    services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
+    if( lua_istable( L, -1 ) )
+    {
+        lua_getfield( L, -1, "parameter" );
+        if( lua_isstring( L, -1 ) )
+        {
+            char *parameter = lua_tostring( L, -1 );
+            lua_pop( L, 1 );
+            lua_getfield( L, -1, "name" );
+            if( lua_isstring( L, -1 ) )
+            {
+                char *name = lua_tostring( L, -1 );
+                lua_pop( L, 1 );
+                lua_getfield( L, -1, "value" );
+                if( lua_isstring( L, -1 ) )
+                {
+                    char *value = lua_tostring( L, -1 );
+                    lua_pop( L, 1 );
+                    services_discovery_AddParameterValue( p_sd, parameter, name, "%s", value );
+                    return 1;
+                }
+            }
+            services_discovery_AddParameterValue( p_sd, parameter, NULL, NULL );
+        }
+        else
+            msg_Err( p_sd, "vlc.sd.add_parameter_value: the \"parameter\" parameter can't be empty" );
+    }
+    else
+        msg_Err( p_sd, "Error parsing add_item arguments" );
+    return 1;
+}
+
 /*****************************************************************************
  *
  *****************************************************************************/
@@ -105,6 +244,10 @@ static const luaL_Reg vlclua_sd_reg[] = {
     { "add", vlclua_sd_add },
     { "remove", vlclua_sd_remove },
     { "is_loaded", vlclua_sd_is_loaded },
+    { "add_node", vlclua_sd_add_node },
+    { "add_item", vlclua_sd_add_item },
+    { "remove_item", vlclua_sd_remove_item },
+    { "add_parameter_value", vlclua_sd_add_parameter_value },
     { NULL, NULL }
 };
 
diff --git a/modules/misc/lua/services_discovery.c b/modules/misc/lua/services_discovery.c
new file mode 100644
index 0000000..78e78df
--- /dev/null
+++ b/modules/misc/lua/services_discovery.c
@@ -0,0 +1,276 @@
+/*****************************************************************************
+ * services_discovery.c : Services discovery using lua scripts
+ *****************************************************************************
+ * Copyright (C) 2009 the VideoLAN team
+ *
+ * Authors: Fabio Ritrovato <exsephiroth87@gmail.com>
+ *
+ * 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 <vlc_services_discovery.h>
+#include <vlc_playlist.h>
+
+#include "vlc.h"
+#include "libs.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+static void Started( const vlc_event_t *, void * );
+static void *Run( void * );
+static void ItemPut( const vlc_event_t * , void * );
+static void ItemGet( const vlc_event_t * , void * );
+static void ItemDelete( const vlc_event_t * , void * );
+
+/*****************************************************************************
+ * Local structures
+ *****************************************************************************/
+
+struct services_discovery_sys_t
+{
+    lua_State *L;
+    vlc_thread_t thread;
+};
+static const luaL_Reg p_reg[] = { { NULL, NULL } };
+
+/*****************************************************************************
+ * Open: initialize and create stuff
+ *****************************************************************************/
+int Open_LuaSD( vlc_object_t *p_this )
+{
+    services_discovery_t *p_sd = ( services_discovery_t * )p_this;
+    services_discovery_sys_t *p_sys;
+
+    if( !( p_sys = malloc( sizeof( services_discovery_sys_t ) ) ) )
+        return VLC_ENOMEM;
+    p_sd->p_sys = p_sys;
+    vlc_event_manager_register_event_type( &p_sd->event_manager,
+                                           vlc_ServicesDiscoveryStarted );
+    vlc_event_attach( services_discovery_EventManager( p_sd ),
+                      vlc_ServicesDiscoveryStarted, Started, p_sd );
+    vlc_event_manager_register_event_type( &p_sd->event_manager,
+            vlc_ServicesDiscoveryItemPut );
+    vlc_event_manager_register_event_type( &p_sd->event_manager,
+            vlc_ServicesDiscoveryItemGet );
+    vlc_event_manager_register_event_type( &p_sd->event_manager,
+            vlc_ServicesDiscoveryItemDelete );
+    return VLC_SUCCESS;
+}
+
+static void Started( const vlc_event_t * p_event, void * user_data )
+{
+    services_discovery_t *p_sd = ( services_discovery_t * )user_data;
+    VLC_UNUSED( p_event );
+
+    if( vlc_clone (&p_sd->p_sys->thread, Run, p_sd, VLC_THREAD_PRIORITY_LOW) )
+        msg_Err( p_sd, "Error creating service discovery thread" );
+}
+
+/*****************************************************************************
+ * Close: cleanup
+ *****************************************************************************/
+void Close_LuaSD( vlc_object_t *p_this )
+{
+    services_discovery_t *p_sd = ( services_discovery_t * )p_this;
+
+    vlc_cancel (p_sd->p_sys->thread);
+    vlc_join (p_sd->p_sys->thread, NULL);
+    vlc_event_detach( services_discovery_EventManager( p_sd ),
+              vlc_ServicesDiscoveryItemPut, ItemPut, p_sd );
+    vlc_event_detach( services_discovery_EventManager( p_sd ),
+              vlc_ServicesDiscoveryItemGet, ItemGet, p_sd );
+    vlc_event_detach( services_discovery_EventManager( p_sd ),
+              vlc_ServicesDiscoveryItemDelete, ItemDelete, p_sd );
+    free( p_sd->p_sys );
+}
+
+/*****************************************************************************
+ * Run: Thread entry-point
+ ****************************************************************************/
+static void* Run( void *data )
+{
+    services_discovery_t *p_sd = ( services_discovery_t * )data;
+    services_discovery_sys_t *p_sys = p_sd->p_sys;
+    lua_State *L;
+
+    msg_Info( p_sd, "Running LuaSD: %s", module_get_name( p_sd->p_module, false ) );  
+    char *psz_filename;
+    if( asprintf( &psz_filename, "%s" DIR_SEP "lua" DIR_SEP "sd" DIR_SEP "%s.lua",
+                   config_GetUserDataDir(),
+                   module_get_name( p_sd->p_module, false ) ) < 0 )
+    {
+        return NULL;
+    }
+    L = luaL_newstate();
+    if( !L )
+    {
+        msg_Err( p_sd, "Could not create new Lua State" );
+        free( psz_filename );
+        return NULL;
+    }
+    luaL_openlibs( L );
+    luaL_register( L, "vlc", p_reg );
+    lua_pushlightuserdata( L, p_sd );
+    lua_setfield( L, -2, "private" );
+    luaopen_input( L );
+    luaopen_msg( L );
+    luaopen_misc( L );
+    luaopen_net( L );
+    luaopen_object( L );
+    luaopen_playlist( L );
+    luaopen_sd( L );
+    luaopen_strings( L );
+    luaopen_variables( L );
+    luaopen_stream( L );
+    lua_pop( L, 1 );
+    if( luaL_dofile( L, psz_filename ) )
+    {
+
+        msg_Err( p_sd, "Error loading script %s: %s", psz_filename,
+                  lua_tostring( L, lua_gettop( L ) ) );
+        lua_pop( L, 1 );
+        free( psz_filename );
+        return NULL;
+    }
+    lua_getglobal( L, "item_put" );
+    if( lua_isfunction( L, lua_gettop( L ) ) )
+        p_sd->b_can_put = true;
+    lua_getglobal( L, "item_get" );
+    if( lua_isfunction( L, lua_gettop( L ) ) )
+        p_sd->b_can_get = true;
+    lua_getglobal( L, "item_delete" );
+    if( lua_isfunction( L, lua_gettop( L ) ) )
+        p_sd->b_can_delete = true;
+    vlc_event_attach( services_discovery_EventManager( p_sd ),
+                      vlc_ServicesDiscoveryItemPut, ItemPut, p_sd );
+    vlc_event_attach( services_discovery_EventManager( p_sd ),
+                      vlc_ServicesDiscoveryItemGet, ItemGet, p_sd );
+    vlc_event_attach( services_discovery_EventManager( p_sd ),
+                      vlc_ServicesDiscoveryItemDelete, ItemDelete, p_sd );
+    lua_getglobal( L, "main" );
+    if( !lua_isfunction( L, lua_gettop( L ) ) )
+    {
+        msg_Err( p_sd, "Error while runing script %s, "
+                  "function main() not found", psz_filename );
+        lua_pop( L, 1 );
+        free( psz_filename );
+        return NULL;
+    }
+    if( lua_pcall( L, 0, 1, 0 ) )
+    {
+        msg_Err( p_sd, "Error while runing script %s, "
+                  "function main(): %s", psz_filename,
+                  lua_tostring( L, lua_gettop( L ) ) );
+        lua_pop( L, 1 );
+        free( psz_filename );
+        return NULL;
+    }
+    free( psz_filename );
+    p_sys->L = L;
+
+    return NULL;
+}
+
+/*****************************************************************************
+ * Events callbacks
+ ****************************************************************************/
+static void ItemPut( const vlc_event_t * p_event, void * user_data )
+{
+    services_discovery_t *p_sd = ( services_discovery_t * )user_data;
+    lua_State *L = p_sd->p_sys->L;
+
+    lua_getglobal( L, "item_put" );
+    if( !lua_isfunction( L, lua_gettop( L ) ) )
+    {
+        msg_Err( p_sd, "Error while runing script %s, "
+                  "function item_put() not found", module_get_name( p_sd->p_module, false ) );
+        lua_pop( L, 1 );
+        return;
+    }
+    lua_pushstring( L, p_event->u.services_discovery_item_put.psz_string );
+    if( lua_pcall( L, 1, 1, 0 ) )
+    {
+        msg_Err( p_sd, "Error while runing script %s, "
+                  "function item_put(): %s", module_get_name( p_sd->p_module, false ),
+                  lua_tostring( L, lua_gettop( L ) ) );
+        lua_pop( L, 1 );
+        return;
+    }
+}
+
+static void ItemGet( const vlc_event_t * p_event, void * user_data )
+{
+    services_discovery_t *p_sd = ( services_discovery_t * )user_data;
+    lua_State *L = p_sd->p_sys->L;
+
+    lua_getglobal( L, "item_get" );
+    if( !lua_isfunction( L, lua_gettop( L ) ) )
+    {
+        msg_Err( p_sd, "Error while runing script %s, "
+                  "function item_get() not found", module_get_name( p_sd->p_module, false ) );
+        lua_pop( L, 1 );
+        return;
+    }
+    /* TODO: is this the best way to do it? */
+    lua_pushstring( L, input_item_GetURL( p_event->u.services_discovery_item_get.p_item ) );
+    lua_pushstring( L, p_event->u.services_discovery_item_get.psz_string );
+    if( lua_pcall( L, 2, 1, 0 ) )
+    {
+        msg_Err( p_sd, "Error while runing script %s, "
+                  "function item_get(): %s", module_get_name( p_sd->p_module, false ),
+                  lua_tostring( L, lua_gettop( L ) ) );
+        lua_pop( L, 1 );
+        return ;
+    }
+}
+
+static void ItemDelete( const vlc_event_t * p_event, void * user_data )
+{
+    services_discovery_t *p_sd = ( services_discovery_t * )user_data;
+    lua_State *L = p_sd->p_sys->L;
+
+    lua_getglobal( L, "item_delete" );
+    if( !lua_isfunction( L, lua_gettop( L ) ) )
+    {
+        msg_Err( p_sd, "Error while runing script %s, "
+                  "function item_delete() not found", module_get_name( p_sd->p_module, false ) );
+        lua_pop( L, 1 );
+        return;
+    }
+    input_item_t **udata = (input_item_t **)
+                           lua_newuserdata( L, sizeof( input_item_t * ) );
+    *udata = p_event->u.services_discovery_item_delete.p_item;
+    if( luaL_newmetatable( L, "input_item_t" ) )
+    {
+        lua_pushstring( L, "none of your business" );
+        lua_setfield( L, -2, "__metatable" );
+    }
+    lua_setmetatable( L, -2 );
+    if( lua_pcall( L, 1, 1, 0 ) )
+    {
+        msg_Err( p_sd, "Error while runing script %s, "
+                  "function item_delete(): %s", module_get_name( p_sd->p_module, false ),
+                  lua_tostring( L, lua_gettop( L ) ) );
+        lua_pop( L, 1 );
+        return;
+    }
+}
diff --git a/modules/misc/lua/vlc.c b/modules/misc/lua/vlc.c
index f59c391..04c21b4 100644
--- a/modules/misc/lua/vlc.c
+++ b/modules/misc/lua/vlc.c
@@ -50,7 +50,6 @@
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-
 #define INTF_TEXT N_("Lua interface")
 #define INTF_LONGTEXT N_("Lua interface module to load")
 
@@ -62,6 +61,7 @@ vlc_module_begin ()
         set_description( N_("Fetch artwork using lua scripts") )
         set_capability( "art finder", 10 )
         set_callbacks( FindArt, NULL )
+        set_not_cacheable( )
 
     add_submodule ()
         add_shortcut( "luaplaylist" )
@@ -89,6 +89,64 @@ vlc_module_begin ()
         add_string( "lua-config", "", NULL,
                     CONFIG_TEXT, CONFIG_LONGTEXT, false )
         set_callbacks( Open_LuaIntf, Close_LuaIntf )
+
+    char *psz_file;
+    char *psz_dir;
+    int    i_dirlen;
+    DIR *  dir;
+    struct dirent * file;
+    if( asprintf( &psz_dir, "%s" DIR_SEP "lua" DIR_SEP "sd", config_GetUserDataDir() ) >= 0 )
+    {
+        dir = opendir( psz_dir );
+        if( dir )
+        {
+            i_dirlen = strlen( psz_dir );
+            while( ( file = readdir( dir ) ) )
+            {
+                unsigned int i_len;
+                if( *file->d_name )
+                {
+                    i_len = strlen( file->d_name );
+                    if( !strcmp( file->d_name + ( i_len - 4 ), ".lua" ) )
+                    {
+                        psz_file = malloc( i_dirlen + 1 + i_len + 1 );
+                        sprintf( psz_file, "%s"DIR_SEP"%s", psz_dir, file->d_name );
+                        FILE *fd = fopen( psz_file, "r" );
+                        if( fd )
+                        {
+                            char description[256];
+                            if( fgets( description, 256, fd ) != NULL )
+                            {
+                                char *temp = strchr( description, '\n' );
+                                if( temp )
+                                    *temp = '\0';
+                                file->d_name[ i_len - 4 ] = '\0';
+                                add_submodule ()
+                                    set_shortname( strdup( file->d_name ) )
+                                    add_shortcut( strdup( file->d_name ) )
+                                    if( !strncmp( description, "--SD_Description=", 17 ) )
+                                    {
+                                        set_description( strdup( description + 17 ) )
+                                    }
+                                    else
+                                    {
+                                        set_description( strdup(file->d_name ) )
+                                    }
+                                    set_category( CAT_PLAYLIST )
+                                    set_subcategory( SUBCAT_PLAYLIST_SD )
+                                    set_capability( "services_discovery", 0 )
+                                    set_callbacks( Open_LuaSD, Close_LuaSD )
+                            }
+                            fclose( fd );
+                        }
+                        free( psz_file );
+                    }
+                }
+            }
+            closedir( dir );
+        }
+        free( psz_dir );
+    }
 vlc_module_end ()
 
 /*****************************************************************************
diff --git a/modules/misc/lua/vlc.h b/modules/misc/lua/vlc.h
index 94d69f6..60839f8 100644
--- a/modules/misc/lua/vlc.h
+++ b/modules/misc/lua/vlc.h
@@ -56,6 +56,9 @@ void Close_LuaPlaylist( vlc_object_t * );
 int Open_LuaIntf( vlc_object_t * );
 void Close_LuaIntf( vlc_object_t * );
 
+int Open_LuaSD( vlc_object_t * );
+void Close_LuaSD( vlc_object_t * );
+
 
 /*****************************************************************************
  * Lua debug
diff --git a/share/lua/sd/jamendo.lua b/share/lua/sd/jamendo.lua
new file mode 100644
index 0000000..370b499
--- /dev/null
+++ b/share/lua/sd/jamendo.lua
@@ -0,0 +1,415 @@
+--SD_Description=Jamendo
+--[[
+ $Id$
+
+ Copyright © 2007 the VideoLAN team
+ 
+ Authors: Fabio Ritrovato <exsephiroth87@gmail.com>
+
+ 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.
+--]]
+function main()
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Most populars",value="album=\"rating_desc\""} )
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Most populars this month",value="album=\"ratingmonth_desc\""} )
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Most populars this week",value="album=\"ratingweek_desc\""} )
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Latest releases",value="album=\"releasedate_desc\""} )
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Most downloaded",value="album=\"downloaded_desc\""} )
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Most listened to",value="album=\"listened_desc\""} )
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Most starred",value="album=\"starred_desc\""} )
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Most playlisted",value="album=\"playlisted_desc\""} )
+    vlc.sd.add_parameter_value( {parameter="Albums",name="Requires reviews",value="album=\"needreviews_desc\""} )
+    local fd = vlc.stream( "http://api.jamendo.com/get2/idstr + name/artist/plain?n=all&hasalbums=1&order=name_asc" )
+    local page = fd:read( 65653 )
+    local skipId = false, name, id
+    while( page ~= nil and page ~= "\n" ) do
+        local oldidxEnd = 0
+        while true do
+            local idxEnd
+            if skipId == false then
+                local _, idxEnd = string.find( page, "	", oldidxEnd )
+                if idxEnd ~= nil and idxEnd < 65653 then
+                    id = string.sub( page, oldidxEnd, idxEnd-1 )
+                    oldidxEnd = idxEnd+1
+                    skipId = true 
+                else
+                    break
+                end
+            end
+            _, idxEnd = string.find( page, "\n", oldidxEnd )
+            if idxEnd ~= nil and idxEnd < 65653 then
+                name = string.sub( page, oldidxEnd, idxEnd-1 )
+                oldidxEnd = idxEnd+1
+                skipId = false
+                vlc.sd.add_parameter_value( {parameter="Artist",name=name,value="artist_idstr=\"" .. id .. "\""} )
+            else
+                break
+            end
+        end
+        local newPage = fd:read( 65653 )
+        if newPage == nil or newPage == "" then
+            newPage = "\n"
+        end
+        page = string.sub( page, oldidxEnd, 65653 ) .. newPage
+    end
+    vlc.sd.add_parameter_value( {parameter="Radio",name="Rock",value="radio=\"9\""} )
+    vlc.sd.add_parameter_value( {parameter="Radio",name="Pop / Songwriting",value="radio=\"8\""} )
+    vlc.sd.add_parameter_value( {parameter="Radio",name="Jazz",value="radio=\"6\""} )
+    vlc.sd.add_parameter_value( {parameter="Radio",name="Hip-Hop",value="radio=\"5\""} )
+    vlc.sd.add_parameter_value( {parameter="Radio",name="Lounge",value="radio=\"7\""} )
+    vlc.sd.add_parameter_value( {parameter="Radio",name="Dance / Electro",value="radio=\"4\""} )
+    fd = nil
+    fd = vlc.stream( "http://www.jamendo.com/en/tags" )
+    page = fd:read( 131270 )
+    fd = nil
+    if page ~= nil then
+        local _, oldidxEnd = string.find( page, "tagscloud" )
+        if oldidxEnd ~= nil then
+            while true do
+                local idxEnd, tag_name
+                _, idxEnd, tag_name = string.find( page, "http://www.jamendo.com/en/tag/([^\"]+)\"", oldidxEnd )
+                if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and id then
+                    oldidxEnd = idxEnd+1
+                else
+                    break
+                end
+                vlc.sd.add_parameter_value( {parameter="Tags",name=tag_name,value="tag=\"" .. tag_name .. "\""} )
+            end
+        end
+    end
+    vlc.sd.add_parameter_value( {parameter="Album search"} )
+    vlc.sd.add_parameter_value( {parameter="Artist search"} )
+    vlc.sd.add_parameter_value( {parameter="Max results"} )
+end
+
+function item_put( string )
+    local _, _, artist = string.find( string, "artist_idstr=\"([^\"]+)\"" )
+    if artist ~= nil then
+        get_artist_from_idstr( artist, nil )
+        return
+    end
+    local _, _, album_order = string.find( string, "album=\"([^\"]+)\"" )
+    local _, _, tag = string.find( string, "tag=\"([^\"]+)\"" )
+    if album_order ~= nil or tag ~= nil then
+        if album_order == nil then
+            album_order = "ratingmonth_desc"
+        end
+        local _, _, max_results = string.find( string, "max_results=\"([^\"]+)\"" )
+        if max_results == nil then
+            max_results = "20"
+        end
+        get_top_albums( album_order, tag, max_results )
+        return
+    end
+    local _, _, radio = string.find( string, "radio=\"([^\"]+)\"" )
+    if radio ~= nil then
+        local _, _, max_results = string.find( string, "max_results=\"([^\"]+)\"" )
+        if max_results == nil then
+            max_results = "20"
+        end
+        get_radio_from_id( radio, max_results )
+        return
+    end
+    local _, _, search = string.find( string, "album_search=\"([^\"]+)\"" )
+    if search ~= nil then
+        local _, _, max_results = string.find( string, "max_results=\"([^\"]+)\"" )
+        if max_results == nil then
+            max_results = "20"
+        end
+        album_search( search, max_results )
+        return
+    end
+    local _, _, search = string.find( string, "artist_search=\"([^\"]+)\"" )
+    if search ~= nil then
+        local _, _, max_results = string.find( string, "max_results=\"([^\"]+)\"" )
+        if max_results == nil then
+            max_results = "20"
+        end
+        artist_search( search, max_results )
+        return
+    end
+end
+
+function get_artist_from_idstr( artist, parent )
+    local fd = vlc.stream( "http://api.jamendo.com/get2/name/artist/plain/?idstr=" .. artist )
+    local artist_name = fd:read( 65653 )
+    fd = nil
+    if artist_name == nil then
+        return false
+    end
+    local node = vlc.sd.add_node( {title=artist_name,arturl="http://img.jamendo.com/artists/" .. string.sub( artist, 1, 1 ) .. "/" .. artist .. ".jpg ",parent=parent} )
+    local albums = get_albums_from_artist( artist )
+    local i = 0
+    while albums[i] ~= nil do
+        local album_node = vlc.sd.add_node( {title=albums[i].title,arturl="http://imgjam.com/albums/".. albums[i].id .. "/covers/1.200.jpg",parent=node} )
+        local tracks = get_tracks_from_album( albums[i].id )
+        local j = 0
+        while tracks[j] ~= nil do
+            vlc.sd.add_item( {url="http://api.jamendo.com/get2/stream/track/redirect/?id=" .. tracks[j].id,title=tracks[j].title,artist=artist_name,album=albums[i].title,genre=tracks[j].genre,tracknum=j+1,date=tracks[j].date,arturl="http://imgjam.com/albums/".. albums[i].id .. "/covers/1.200.jpg",duration=tracks[j].duration,parent=album_node} )
+            j = j+1
+        end
+        i = i+1
+    end
+end
+
+function get_top_albums( album_order, tag, max_results )
+    local url = "http://api.jamendo.com/get2/id+name+artist_name/album/json/?order=" .. album_order .. "&n=" .. max_results
+    if tag ~= nil then
+        url = url .. "&tag_idstr=" .. tag
+    end
+    local fd = vlc.stream( url )
+    local page = fd:read( 65653 )
+    fd = nil
+    if page == nil then
+        return nil
+    end
+    local node_name
+    if album_order == "rating_desc" then node_name = "Most populars"
+    elseif album_order == "ratingmonth_desc" then node_name = "Most populars this month"
+    elseif album_order == "ratingweek_desc" then node_name = "Most populars this week"
+    elseif album_order == "releasedate_desc" then node_name = "Latest releases"
+    elseif album_order == "downloaded_desc" then node_name = "Most downloaded"
+    elseif album_order == "listened_desc" then node_name = "Most listened to"
+    elseif album_order == "starred_desc" then node_name = "Most starred"
+    elseif album_order == "playlisted_desc" then node_name = "Most playlisted"
+    elseif album_order == "needreviews_desc" then node_name = "Requires reviews"
+    end
+    if tag ~= nil then
+        node_name = tag .. " - " .. node_name
+    end
+    local node = vlc.sd.add_node( {title=node_name} )
+    local oldidxEnd = 0
+    while true do
+        local idxEnd, id, name, artist_name
+        _, idxEnd, id = string.find( page, "\"id\":([^\"]+),", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and id then
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, name = string.find( page, "\"name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and name then
+            name = vlc.strings.resolve_xml_special_chars( name )
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, artist_name = string.find( page, "\"artist_name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and artist_name then
+            artist_name = vlc.strings.resolve_xml_special_chars( artist_name )
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        local album_node = vlc.sd.add_node( {title=artist_name .. " - " .. name,arturl="http://imgjam.com/albums/".. id .. "/covers/1.200.jpg",parent=node} )
+        local tracks = get_tracks_from_album( id )
+        local i = 0
+        while tracks[i] ~= nil do
+            vlc.sd.add_item( {url="http://api.jamendo.com/get2/stream/track/redirect/?id=" .. tracks[i].id,title=tracks[i].title,artist=artist_name,album=name,genre=tracks[i].genre,tracknum=i+1,date=tracks[i].date,arturl="http://imgjam.com/albums/".. id .. "/covers/1.200.jpg",duration=tracks[i].duration,parent=album_node} )
+            i = i+1
+        end
+    end
+end
+
+function get_albums_from_artist( artist )
+    local fd = vlc.stream( "http://api.jamendo.com/get2/id+name/album/json/?artist_idstr=" .. artist .. "&n=all&order=name_asc" )
+    local page = fd:read( 65653 )
+    fd = nil
+    if page == nil then
+        return nil
+    end
+    local oldidxEnd = 0
+    local i = 0
+    local albums = {}
+    while true do
+        local idxEnd, id, name
+        _, idxEnd, id = string.find( page, "\"id\":([^\"]+),", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and id then
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, name = string.find( page, "\"name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and name then
+            oldidxEnd = idxEnd+1
+            name = vlc.strings.resolve_xml_special_chars( name )
+            albums[i] = {title=name,id=id}
+            i = i+1
+        else
+            break
+        end
+    end
+    return albums
+end
+
+function get_tracks_from_album( album )
+    local fd = vlc.stream( "http://api.jamendo.com/get2/id+name+duration+album_genre+album_dates/track/json/?album_id=" .. album )
+    local page = fd:read( 65653 )
+    fd = nil
+    if page == nil then
+        return nil
+    end
+    local oldidxEnd = 0
+    local i = 0
+    local tracks = {}
+    while true do
+        local idxEnd, id, name, album_genre, year, duration
+        _, idxEnd, id = string.find( page, "\"id\":([^\"]+),", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and id then
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, name = string.find( page, "\"name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and name then
+            name = vlc.strings.resolve_xml_special_chars( name )
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, duration = string.find( page, "\"duration\":([^\"]+),", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and duration then
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, album_genre = string.find( page, "\"album_genre\":\"([^\"]+)\"", oldidxEnd )
+        _, idxEnd, year = string.find( page, "\"year\":\"([^\"]+)\"", oldidxEnd )
+        tracks[i] = {title=name,id=id,genre=album_genre,date=year,duration=duration}
+        i = i+1
+    end
+    return tracks
+end
+
+function get_radio_from_id( id, max_results )
+    local fd = vlc.stream( "http://api.jamendo.com/get2/id+name+artist_name+album_name+duration+album_genre+album_dates/track/json/radio_track_inradioplaylist+track_album+album_artist/?order=numradio_asc&radio_id=" .. id .. "&n=" .. max_results )
+    local page = fd:read( 65653 )
+    fd = nil
+    if page == nil then
+        return nil
+    end
+    local radio_name
+    if id == "9" then radio_name="Rock"
+    elseif id == "8" then radio_name="Pop / Songwriting"
+    elseif id == "6" then radio_name="Jazz"
+    elseif id == "5" then radio_name="Hip-Hop"
+    elseif id == "7" then radio_name="Lounge"
+    elseif id == "4" then radio_name="Dance / Electro"
+    end
+    local radio_node = vlc.sd.add_node( {title="Radio " .. radio_name} )
+    local oldidxEnd = 0
+    local i = 0
+    while true do
+        local idxEnd, id, name, artist_name, album_name, album_genre, year, duration
+        _, idxEnd, id = string.find( page, "\"id\":([^\"]+),", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and id then
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, name = string.find( page, "\"name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and name then
+            name = vlc.strings.resolve_xml_special_chars( name )
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, artist_name = string.find( page, "\"artist_name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and artist_name then
+            artist_name = vlc.strings.resolve_xml_special_chars( artist_name )
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, album_name = string.find( page, "\"album_name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and album_name then
+            album_name = vlc.strings.resolve_xml_special_chars( album_name )
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, duration = string.find( page, "\"duration\":([^\"]+),", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and duration then
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, album_genre = string.find( page, "\"album_genre\":\"([^\"]+)\"", oldidxEnd )
+        _, idxEnd, year = string.find( page, "\"year\":\"([^\"]+)\"", oldidxEnd )
+        vlc.sd.add_item( {url="http://api.jamendo.com/get2/stream/track/redirect/?id=" .. id,title=artist_name .. " - " .. name,artist=artist_name,album=album_name,genre=album_genre,date=year,arturl="http://imgjam.com/albums/".. id .. "/covers/1.200.jpg",duration=duration,parent=radio_node} )
+    end
+    return tracks
+end
+
+function album_search( search, max_results )
+    local fd = vlc.stream( "http://api.jamendo.com/get2/id+name+artist_name/album/json/?searchquery=\"" .. search .. "\"&order=searchweight_desc&n=" .. max_results )
+    local page = fd:read( 65653 )
+    fd = nil
+    if page == nil then
+        return nil
+    end
+    local node = vlc.sd.add_node( {title="Album search: " .. search} )
+    local oldidxEnd = 0
+    while true do
+        local idxEnd, id, name, artist_name
+        _, idxEnd, id = string.find( page, "\"id\":([^\"]+),", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and id then
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, name = string.find( page, "\"name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and name then
+            name = vlc.strings.resolve_xml_special_chars( name )
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        _, idxEnd, artist_name = string.find( page, "\"artist_name\":\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and artist_name then
+            artist_name = vlc.strings.resolve_xml_special_chars( artist_name )
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        local album_node = vlc.sd.add_node( {title=artist_name .. " - " .. name,arturl="http://imgjam.com/albums/".. id .. "/covers/1.200.jpg",parent=node} )
+        local tracks = get_tracks_from_album( id )
+        local i = 0
+        while tracks[i] ~= nil do
+            vlc.sd.add_item( {url="http://api.jamendo.com/get2/stream/track/redirect/?id=" .. tracks[i].id,title=tracks[i].title,artist=artist_name,album=name,genre=tracks[i].genre,tracknum=i+1,date=tracks[i].date,arturl="http://imgjam.com/albums/".. id .. "/covers/1.200.jpg",duration=tracks[i].duration,parent=album_node} )
+            i = i+1
+        end
+    end
+end
+
+function artist_search( search, max_results )
+    local fd = vlc.stream( "http://api.jamendo.com/get2/idstr/artist/json/?searchquery=\"" .. search .. "\"&order=searchweight_desc&n=" .. max_results )
+    local page = fd:read( 65653 )
+    fd = nil
+    if page == nil then
+        return nil
+    end
+    local node = vlc.sd.add_node( {title="Artist search: " .. search} )
+    local oldidxEnd = 0
+    while true do
+        local idxEnd, idstr
+        _, idxEnd, idstr = string.find( page, "\"([^\"]+)\"", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd and idstr then
+            oldidxEnd = idxEnd+1
+        else
+            break
+        end
+        get_artist_from_idstr( idstr, node )
+    end
+end
diff --git a/share/lua/sd/youtube.lua b/share/lua/sd/youtube.lua
new file mode 100644
index 0000000..98c5999
--- /dev/null
+++ b/share/lua/sd/youtube.lua
@@ -0,0 +1,302 @@
+--SD_Description=Youtube
+--[[
+ $Id$
+
+ Copyright © 2007 the VideoLAN team
+ 
+ Authors: Fabio Ritrovato <exsephiroth87@gmail.com>
+
+ 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.
+--]]
+function main()
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Film & Animation",value="category=\"Film\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Autos & Vehicles",value="category=\"Autos\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Music",value="category=\"Music\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Pets & Animals",value="category=\"Animals\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Sports",value="category=\"Sports\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Travel & Events",value="category=\"Travel\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Short Movies",value="category=\"Shortmov\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Videoblogging",value="category=\"Videoblog\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Gaming",value="category=\"Games\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Comedy",value="category=\"Comedy\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="People & Blogs",value="category=\"People\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="News & Politics",value="category=\"News\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Entertainment",value="category=\"Entertainment\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Education",value="category=\"Education\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Howto & Style",value="category=\"Howto\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Nonprofits & Activism",value="category=\"Nonprofit\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Science & Technology",value="category=\"Tech\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies",value="category=\"Movies\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Anime/Animation",value="category=\"Movies_Anime_animation\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Comedy",value="category=\"Movies_Comedy\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Action/Adventure",value="category=\"Movies_Action_adventure\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Classics",value="category=\"Movies_Classics\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Foreign",value="category=\"Movies_Foreign\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Horror",value="category=\"Movies_Horror\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Drama",value="category=\"Movies_Drama\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Family",value="category=\"Movies_Family\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Shorts",value="category=\"Movies_Shorts\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Sci-Fi/Fantasy",value="category=\"Movies_Sci_fi_fantasy\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Movies - Thriller",value="category=\"Movies_Thriller\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Shows",value="category=\"Shows\""} )
+    vlc.sd.add_parameter_value( {parameter="Categories",name="Trailers",value="category=\"Trailers\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Top rated",value="category_order=\"top_rated\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Top favorites",value="category_order=\"top_favorites\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Most viewed",value="category_order=\"most_viewed\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Most popular",value="category_order=\"most_popular\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Most recent",value="category_order=\"most_recent\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Most discussed",value="category_order=\"most_discussed\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Most linked",value="category_order=\"most_linked\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Most responded",value="category_order=\"most_responded\""} )
+    vlc.sd.add_parameter_value( {parameter="Category order",name="Recently featured",value="category_order=\"recently_featured\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Australia",value="country=\"AU\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Brazil",value="country=\"BR\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Canada",value="country=\"CA\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Czech Republic",value="country=\"CZ\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="France",value="country=\"FR\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Germany",value="country=\"DE\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Great Britain",value="country=\"GB\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Holland",value="country=\"NL\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Hong Kong",value="country=\"HK\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="India",value="country=\"IN\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Ireland",value="country=\"IE\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Israel",value="country=\"IL\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Italy",value="country=\"IT\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Japan",value="country=\"JP\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Mexico",value="country=\"MX\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="New Zeland",value="country=\"NZ\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Poland",value="country=\"PL\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Russia",value="country=\"RU\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="South Korea",value="country=\"KR\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Spain",value="country=\"ES\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Sweden",value="country=\"SE\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="Taiwan",value="country=\"TW\""} )
+    vlc.sd.add_parameter_value( {parameter="Country",name="United States",value="country=\"US\""} )
+    vlc.sd.add_parameter_value( {parameter="Max results"} )
+    vlc.sd.add_parameter_value( {parameter="Search"} )
+    vlc.sd.add_parameter_value( {parameter="Search order",name="Relevance",value="search_order=\"relevance\""} )
+    vlc.sd.add_parameter_value( {parameter="Search order",name="Most recent",value="search_order=\"published\""} )
+    vlc.sd.add_parameter_value( {parameter="Search order",name="View count",value="search_order=\"viewCount\""} )
+    vlc.sd.add_parameter_value( {parameter="Search order",name="Rating",value="search_order=\"rating\""} )
+    vlc.sd.add_parameter_value( {parameter="Start index"} )
+    vlc.sd.add_parameter_value( {parameter="Time",name="Today",value="time=\"today\""} )
+    vlc.sd.add_parameter_value( {parameter="Time",name="This week",value="time=\"this_week\""} )
+    vlc.sd.add_parameter_value( {parameter="Time",name="This month",value="time=\"this_month\""} )
+    vlc.sd.add_parameter_value( {parameter="Time",name="All time",value="time=\"all_time\""} )
+end
+
+function item_put( string )
+    local _, _, category = string.find( string, "category=\"([^\"]+)\"" )
+    local _, _, search = string.find( string, "search=\"([^\"]+)\"" )
+    if category ~= nil or search ~= nil then
+        local _, _, category_order = string.find( string, "category_order=\"([^\"]+)\"" )
+        if category_order == nil then
+            category_order = "most_popular"
+        end
+        local time
+        if category_order ~= "most_recent" and category_order ~= "recently_featured" then
+            _, _, time = string.find( string, "time=\"([^\"]+)\"" )
+            if time == nil then
+                time = "today"
+            end
+        end
+        local search_order
+        if search ~= nil then
+            _, _, search_order = string.find( string, "search_order=\"([^\"]+)\"" )
+            if search_order == nil then
+                search_order = "relevance"
+            end
+        end
+        local _, _, country = string.find( string, "country=\"([^\"]+)\"" )
+        local _, _, max_results = string.find( string, "max_results=\"([^\"]+)\"" )
+        if max_results == nil then
+            max_results = "25"
+        end
+        local _, _, start_index = string.find( string, "start_index=\"([^\"]+)\"" )
+        if start_index == nil then
+            start_index = "1"
+        end
+        get_feed( search, category, category_order, search_order, time, country, max_results, start_index )
+        return
+    end
+end
+
+function get_feed( search, category, category_order, search_order, time, country, max_results, start_index )
+    local url
+    if search == nil then
+        url = "http://gdata.youtube.com/feeds/api/standardfeeds/"
+        if country ~= nil then
+            url = url .. country .. "/"
+        end
+    else
+        url = "http://gdata.youtube.com/feeds/api/videos?q=" .. search .. "&orderby=" .. search_order .. "&"
+    end
+    if search == nil then
+        url = url .. category_order .. "_" .. category .. "?"
+    end
+    url = url .. "v=2&max-results=" .. max_results .. "&start-index=" .. start_index
+    if search ~= nil and category ~= nil then
+        url = url .. "&category=" .. category
+    end
+    if time ~= nil then
+        url = url .. "&time=" .. time
+    end
+    local fd = vlc.stream( url )
+    local page = ""
+    local newpage = fd:read( 65653 )
+    while newpage ~= nil and newpage ~= "" do
+        page = page .. newpage
+        newpage = fd:read( 65653 )
+    end
+    fd = nil
+    if page == "" then
+        return nil
+    end
+    local oldidxEnd = 0, i, j
+    _, i = string.find ( page, "<title>", oldidxEnd )
+    j, oldidxEnd = string.find ( page, "</title>", oldidxEnd )
+    node = vlc.sd.add_node( {title=string.sub( page, i+1, j-1) } )
+    while true do
+        local idxEnd, published, title, url, author, category, description, keywords, arturl, duration
+        _, i = string.find ( page, "<published>", oldidxEnd )
+        j, idxEnd = string.find ( page, "</published>", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            published = string.sub( page, i+1, j-1) 
+            if published then
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        _, i = string.find ( page, "<title>", oldidxEnd )
+        j, idxEnd = string.find ( page, "</title>", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            title = string.sub( page, i+1, j-1) 
+            if title then
+                title = vlc.strings.resolve_xml_special_chars( title )
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        _, i = string.find ( page, "href='", oldidxEnd )
+        if i ~= nil then
+            j, idxEnd = string.find ( page, "'", i+1 )
+        else
+            break
+        end
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            url = string.sub( page, i+1, j-1) 
+            if url then
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        _, i = string.find ( page, "<name>", oldidxEnd )
+        j, idxEnd = string.find ( page, "</name>", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            author = string.sub( page, i+1, j-1) 
+            if author then
+                author = vlc.strings.resolve_xml_special_chars( author )
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        _, i = string.find ( page, "media:category label='", oldidxEnd )
+        if i ~= nil then
+            j, idxEnd = string.find ( page, "'", i+1 )
+        else
+            break
+        end
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            category = string.sub( page, i+1, j-1) 
+            if category then
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        _, i = string.find ( page, "duration='", oldidxEnd )
+        if i ~= nil then
+            j, idxEnd = string.find ( page, "'", i+1 )
+        else
+            break
+        end
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            duration = string.sub( page, i+1, j-1) 
+            if duration then
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        _, i = string.find ( page, "<media:description type='plain'>", oldidxEnd )
+        j, idxEnd = string.find ( page, "</media:description>", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            description = string.sub( page, i+1, j-1) 
+            if description then
+                description = vlc.strings.resolve_xml_special_chars( description )
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        _, i = string.find ( page, "<media:keywords>", oldidxEnd )
+        j, idxEnd = string.find ( page, "</media:keywords>", oldidxEnd )
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            keywords = string.sub( page, i+1, j-1) 
+            if keywords then
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        _, i = string.find ( page, "media:thumbnail url='", oldidxEnd )
+        if i ~= nil then
+            j, idxEnd = string.find ( page, "'", i+1 )
+        else
+            break
+        end
+        if idxEnd ~= nil and oldidxEnd ~= nil and idxEnd > oldidxEnd then
+            arturl = string.sub( page, i+1, j-1) 
+            if arturl then
+                oldidxEnd = idxEnd
+            else
+                break
+            end
+        else
+            break
+        end
+        vlc.sd.add_item( {title=title,url=url,artist=author,date=published,album=category,description=description,genre=keywords,arturl=arturl,duration=duration,parent=node} )
+    end
+end
-- 
1.6.0.4

