Commit 87c76c20 authored by Antoine Cellerier's avatar Antoine Cellerier

Add services discovery support and enhance playlist support for lua interface...

Add services discovery support and enhance playlist support for lua interface modules. Added "search", "sort" and "sd" commands to rc.lua. Restored true playlist functionality and sd selection in the lua http intf.
parent 8ca1085a
SOURCES_lua = playlist.c meta.c intf.c vlc.c vlc.h callbacks.c objects.c variables.c configuration.c net.c vlm.c httpd.c acl.c SOURCES_lua = playlist.c meta.c intf.c vlc.c vlc.h callbacks.c objects.c variables.c configuration.c net.c vlm.c httpd.c acl.c sd.c
...@@ -53,7 +53,7 @@ struct intf_sys_t ...@@ -53,7 +53,7 @@ struct intf_sys_t
/***************************************************************************** /*****************************************************************************
* Internal lua<->vlc utils * Internal lua<->vlc utils
*****************************************************************************/ *****************************************************************************/
static inline playlist_t *vlclua_get_playlist_internal( lua_State *L ) playlist_t *vlclua_get_playlist_internal( lua_State *L )
{ {
vlc_object_t *p_this = vlclua_get_this( L ); vlc_object_t *p_this = vlclua_get_this( L );
return pl_Yield( p_this ); return pl_Yield( p_this );
...@@ -355,6 +355,15 @@ static int vlclua_playlist_next( lua_State * L ) ...@@ -355,6 +355,15 @@ static int vlclua_playlist_next( lua_State * L )
return 0; return 0;
} }
static int vlclua_playlist_skip( lua_State * L )
{
int i_skip = luaL_checkint( L, 1 );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Skip( p_playlist, i_skip );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_play( lua_State * L ) static int vlclua_playlist_play( lua_State * L )
{ {
playlist_t *p_playlist = vlclua_get_playlist_internal( L ); playlist_t *p_playlist = vlclua_get_playlist_internal( L );
...@@ -363,6 +372,14 @@ static int vlclua_playlist_play( lua_State * L ) ...@@ -363,6 +372,14 @@ static int vlclua_playlist_play( lua_State * L )
return 0; return 0;
} }
static int vlclua_playlist_pause( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Pause( p_playlist );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_stop( lua_State * L ) static int vlclua_playlist_stop( lua_State * L )
{ {
playlist_t *p_playlist = vlclua_get_playlist_internal( L ); playlist_t *p_playlist = vlclua_get_playlist_internal( L );
...@@ -406,37 +423,14 @@ static int vlclua_playlist_random( lua_State * L ) ...@@ -406,37 +423,14 @@ static int vlclua_playlist_random( lua_State * L )
static int vlclua_playlist_goto( lua_State * L ) static int vlclua_playlist_goto( lua_State * L )
{ {
/* XXX: logic copied from rc.c ... i'm not sure that it's ok as it int i_id = luaL_checkint( L, 1 );
* implies knowledge of the playlist internals. */ playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_t *p_playlist; int i_ret = playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
int i_size; VLC_TRUE, NULL,
playlist_item_t *p_item, *p_parent; playlist_ItemGetById( p_playlist, i_id,
VLC_TRUE ) );
int i_pos;
if( lua_gettop( L ) != 1 ) return vlclua_error( L );
i_pos = luaL_checkint( L, -1 );
lua_pop( L, 1 );
if( i_pos <= 0 ) return 0;
p_playlist = vlclua_get_playlist_internal( L );
/* The playlist stores 2 times the same item: onelevel & category */
i_size = p_playlist->items.i_size / 2;
if( i_pos > i_size )
{
vlc_object_release( p_playlist );
return 0;
}
p_item = p_parent = p_playlist->items.p_elems[i_pos*2-1];
while( p_parent->p_parent )
p_parent = p_parent->p_parent;
playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, VLC_TRUE,
p_parent, p_item );
vlc_object_release( p_playlist ); vlc_object_release( p_playlist );
lua_pushboolean( L, 1 ); return vlclua_push_ret( L, i_ret );
return 1;
} }
static int vlclua_playlist_add( lua_State *L ) static int vlclua_playlist_add( lua_State *L )
...@@ -463,23 +457,31 @@ static int vlclua_playlist_enqueue( lua_State *L ) ...@@ -463,23 +457,31 @@ static int vlclua_playlist_enqueue( lua_State *L )
return 1; return 1;
} }
static int vlclua_playlist_get( lua_State *L ) static void push_playlist_item( lua_State *L, playlist_item_t *p_item );
static void push_playlist_item( lua_State *L, playlist_item_t *p_item )
{ {
/* TODO: make it possible to get the tree playlist */ input_item_t *p_input = p_item->p_input;
playlist_t *p_playlist = vlclua_get_playlist_internal( L ); int i_flags = p_item->i_flags;
playlist_item_t *p_root; lua_newtable( L );
int i; lua_pushinteger( L, p_item->i_id );
if( lua_isboolean( L, 1 ) && lua_toboolean( L, 1 ) ) lua_setfield( L, -2, "id" );
p_root = p_playlist->p_ml_onelevel; /* media library */ lua_newtable( L );
else #define CHECK_AND_SET_FLAG( name, label ) \
p_root = p_playlist->p_local_onelevel; /* local/normal playlist */ if( i_flags & PLAYLIST_ ## name ## _FLAG ) \
lua_createtable( L, p_root->i_children, 0 ); { \
for( i = 0; i < p_root->i_children; i++ ) lua_pushboolean( L, 1 ); \
lua_setfield( L, -2, #label ); \
}
CHECK_AND_SET_FLAG( SAVE, save )
CHECK_AND_SET_FLAG( SKIP, skip )
CHECK_AND_SET_FLAG( DBL, disabled )
CHECK_AND_SET_FLAG( RO, ro )
CHECK_AND_SET_FLAG( REMOVE, remove )
CHECK_AND_SET_FLAG( EXPANDED, expanded )
#undef CHECK_AND_SET_FLAG
lua_setfield( L, -2, "flags" );
if( p_input )
{ {
playlist_item_t *p_item = p_root->pp_children[i];
input_item_t *p_input = p_item->p_input;
lua_pushinteger( L, i+1 );
lua_newtable( L );
lua_pushstring( L, p_input->psz_name ); lua_pushstring( L, p_input->psz_name );
lua_setfield( L, -2, "name" ); lua_setfield( L, -2, "name" );
lua_pushstring( L, p_input->psz_uri ); lua_pushstring( L, p_input->psz_uri );
...@@ -492,16 +494,166 @@ static int vlclua_playlist_get( lua_State *L ) ...@@ -492,16 +494,166 @@ static int vlclua_playlist_get( lua_State *L )
lua_pushinteger( L, p_input->i_nb_played ); lua_pushinteger( L, p_input->i_nb_played );
lua_setfield( L, -2, "nb_played" ); lua_setfield( L, -2, "nb_played" );
/* TODO: add (optional) info categories, meta, options, es */ /* TODO: add (optional) info categories, meta, options, es */
}
if( p_item->i_children >= 0 )
{
int i;
lua_createtable( L, p_item->i_children, 0 );
for( i = 0; i < p_item->i_children; i++ )
{
push_playlist_item( L, p_item->pp_children[i] );
lua_rawseti( L, -2, i+1 );
}
lua_setfield( L, -2, "children" );
}
}
static int vlclua_playlist_get( lua_State *L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int b_category = luaL_optboolean( L, 2, 1 ); /* Default to tree playlist (discared when 1st argument is a playlist_item's id) */
playlist_item_t *p_item = NULL;
if( lua_isnumber( L, 1 ) )
{
int i_id = lua_tointeger( L, 1 );
p_item = playlist_ItemGetById( p_playlist, i_id, VLC_TRUE );
if( !p_item )
{
vlc_object_release( p_playlist );
return 0; /* Should we return an error instead? */
}
}
else if( lua_isstring( L, 1 ) )
{
const char *psz_what = lua_tostring( L, 1 );
if( !strcasecmp( psz_what, "normal" )
|| !strcasecmp( psz_what, "playlist" ) )
p_item = b_category ? p_playlist->p_local_category
: p_playlist->p_local_onelevel;
else if( !strcasecmp( psz_what, "ml" )
|| !strcasecmp( psz_what, "media library" ) )
p_item = b_category ? p_playlist->p_ml_category
: p_playlist->p_ml_onelevel;
else if( !strcasecmp( psz_what, "root" ) )
p_item = b_category ? p_playlist->p_root_category
: p_playlist->p_root_onelevel;
else
{
int i;
for( i = 0; i < p_playlist->i_sds; i++ )
{
if( !strcasecmp( psz_what,
p_playlist->pp_sds[i]->p_sd->psz_module ) )
{
p_item = b_category ? p_playlist->pp_sds[i]->p_cat
: p_playlist->pp_sds[i]->p_one;
break;
}
}
if( !p_item )
{
vlc_object_release( p_playlist );
return 0; /* Should we return an error instead? */
}
}
}
else
{
p_item = b_category ? p_playlist->p_root_category
: p_playlist->p_root_onelevel;
}
push_playlist_item( L, p_item );
vlc_object_release( p_playlist );
return 1;
}
#if 0
int s;
lua_createtable( L, 0, 2 + p_playlist->i_sds );
for( s = -2; s < p_playlist->i_sds; s++ )
{
playlist_item_t *p_root;
switch( s )
{
case -2:
/* local/normal playlist */
lua_pushstring( L, "local" );
p_root = p_playlist->p_local_onelevel;
break;
case -1:
/* media library */
lua_pushstring( L, "ml" );
p_root = p_playlist->p_ml_onelevel;
break;
default:
lua_pushstring( L, p_playlist->pp_sds[s]->p_sd->psz_module );
printf("%s\n", p_playlist->pp_sds[s]->p_sd->psz_module );
p_root = p_playlist->pp_sds[s]->p_one;
break;
}
printf("s = %d\n", s);
printf("children = %d\n", p_root->i_children );
push_playlist_item( L, p_root );
lua_settable( L, -3 ); lua_settable( L, -3 );
} }
printf("done\n");
#endif
static int vlclua_playlist_search( lua_State *L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
const char *psz_string = luaL_optstring( L, 1, "" );
int b_category = luaL_optboolean( L, 2, 1 ); /* default to category */
playlist_LiveSearchUpdate( p_playlist,
b_category ? p_playlist->p_root_category
: p_playlist->p_root_onelevel,
psz_string );
push_playlist_item( L, p_playlist->p_root_category );
vlc_object_release( p_playlist ); vlc_object_release( p_playlist );
return 1; return 1;
} }
static int vlc_sort_key_from_string( const char *psz_name )
{
static const struct
{
const char *psz_name;
int i_key;
} pp_keys[] =
{ { "id", SORT_ID },
{ "title", SORT_TITLE },
{ "title nodes first", SORT_TITLE_NODES_FIRST },
{ "artist", SORT_ARTIST },
{ "genre", SORT_GENRE },
{ "random", SORT_RANDOM },
{ "duration", SORT_DURATION },
{ "title numeric", SORT_TITLE_NUMERIC },
{ "album", SORT_ALBUM },
{ NULL, -1 } };
int i;
for( i = 0; pp_keys[i].psz_name; i++ )
{
if( !strcmp( psz_name, pp_keys[i].psz_name ) )
return pp_keys[i].i_key;
}
return -1;
}
static int vlclua_playlist_sort( lua_State *L ) static int vlclua_playlist_sort( lua_State *L )
{ {
/* allow setting the different sort keys */ /* allow setting the different sort keys */
return 0; int i_mode = vlc_sort_key_from_string( luaL_checkstring( L, 1 ) );
if( i_mode == -1 )
return luaL_error( L, "Invalid search key." );
int i_type = luaL_optboolean( L, 2, 0 ) ? ORDER_REVERSE : ORDER_NORMAL;
int b_category = luaL_optboolean( L, 3, 1 ); /* default to category */
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_item_t *p_root = b_category ? p_playlist->p_local_category
: p_playlist->p_local_onelevel;
int i_ret = playlist_RecursiveNodeSort( p_playlist, p_root, i_mode,
i_type );
vlc_object_release( p_playlist );
return vlclua_push_ret( L, i_ret );
} }
/* FIXME: split this in 3 different functions? */ /* FIXME: split this in 3 different functions? */
...@@ -655,7 +807,9 @@ static luaL_Reg p_reg_playlist[] = ...@@ -655,7 +807,9 @@ static luaL_Reg p_reg_playlist[] =
{ {
{ "prev", vlclua_playlist_prev }, { "prev", vlclua_playlist_prev },
{ "next", vlclua_playlist_next }, { "next", vlclua_playlist_next },
{ "skip", vlclua_playlist_skip },
{ "play", vlclua_playlist_play }, { "play", vlclua_playlist_play },
{ "pause", vlclua_playlist_pause },
{ "stop", vlclua_playlist_stop }, { "stop", vlclua_playlist_stop },
{ "clear", vlclua_playlist_clear }, { "clear", vlclua_playlist_clear },
{ "repeat_", vlclua_playlist_repeat }, { "repeat_", vlclua_playlist_repeat },
...@@ -666,11 +820,24 @@ static luaL_Reg p_reg_playlist[] = ...@@ -666,11 +820,24 @@ static luaL_Reg p_reg_playlist[] =
{ "add", vlclua_playlist_add }, { "add", vlclua_playlist_add },
{ "enqueue", vlclua_playlist_enqueue }, { "enqueue", vlclua_playlist_enqueue },
{ "get", vlclua_playlist_get }, { "get", vlclua_playlist_get },
{ "search", vlclua_playlist_search },
{ "sort", vlclua_playlist_sort },
{ "stats", vlclua_input_stats }, { "stats", vlclua_input_stats },
{ NULL, NULL } { NULL, NULL }
}; };
static luaL_Reg p_reg_sd[] =
{
{ "get_services_names", vlclua_sd_get_services_names },
{ "add", vlclua_sd_add },
{ "remove", vlclua_sd_remove },
{ "is_loaded", vlclua_sd_is_loaded },
{ NULL, NULL }
};
static luaL_Reg p_reg_volume[] = static luaL_Reg p_reg_volume[] =
{ {
{ "get", vlclua_volume_get }, { "get", vlclua_volume_get },
...@@ -888,6 +1055,7 @@ int E_(Open_LuaIntf)( vlc_object_t *p_this ) ...@@ -888,6 +1055,7 @@ int E_(Open_LuaIntf)( vlc_object_t *p_this )
luaL_register_submodule( L, "config", p_reg_config ); luaL_register_submodule( L, "config", p_reg_config );
luaL_register_submodule( L, "msg", p_reg_msg ); luaL_register_submodule( L, "msg", p_reg_msg );
luaL_register_submodule( L, "playlist", p_reg_playlist ); luaL_register_submodule( L, "playlist", p_reg_playlist );
luaL_register_submodule( L, "sd", p_reg_sd );
luaL_register_submodule( L, "volume", p_reg_volume ); luaL_register_submodule( L, "volume", p_reg_volume );
luaL_register_submodule( L, "osd", p_reg_osd ); luaL_register_submodule( L, "osd", p_reg_osd );
luaL_register_submodule( L, "net", p_reg_net ); luaL_register_submodule( L, "net", p_reg_net );
......
/*****************************************************************************
* sd.c: Services discovery related functions
*****************************************************************************
* Copyright (C) 2007 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <vlc/vlc.h>
#include <vlc_services_discovery.h>
#include <vlc_playlist.h>
#include <lua.h> /* Low level lua C API */
#include <lauxlib.h> /* Higher level C API */
#include <lualib.h> /* Lua libs */
#include "vlc.h"
/*****************************************************************************
*
*****************************************************************************/
int vlclua_sd_get_services_names( lua_State *L )
{
vlc_object_t *p_this = vlclua_get_this( L );
char **ppsz_longnames;
char **ppsz_names = services_discovery_GetServicesNames( p_this, &ppsz_longnames );
char **ppsz_longname = ppsz_longnames;
char **ppsz_name = ppsz_names;
lua_settop( L, 0 );
lua_newtable( L );
for( ; *ppsz_name; ppsz_name++,ppsz_longname++ )
{
lua_pushstring( L, *ppsz_longname );
lua_setfield( L, -2, *ppsz_name );
free( *ppsz_name );
free( *ppsz_longname );
}
free( ppsz_names );
free( ppsz_longnames );
return 1;
}
int vlclua_sd_add( lua_State *L )
{
const char *psz_sd = luaL_checkstring( L, 1 );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int i_ret = playlist_ServicesDiscoveryAdd( p_playlist, psz_sd );
vlc_object_release( p_playlist );
return vlclua_push_ret( L, i_ret );
}
int vlclua_sd_remove( lua_State *L )
{
const char *psz_sd = luaL_checkstring( L, 1 );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int i_ret = playlist_ServicesDiscoveryRemove( p_playlist, psz_sd );
vlc_object_release( p_playlist );
return vlclua_push_ret( L, i_ret );
}
int vlclua_sd_is_loaded( lua_State *L )
{
const char *psz_sd = luaL_checkstring( L, 1 );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
lua_pushboolean( L, playlist_IsServicesDiscoveryLoaded( p_playlist, psz_sd ));
vlc_object_release( p_playlist );
return 1;
}
...@@ -86,6 +86,11 @@ static inline int luaL_checkboolean( lua_State *L, int narg ) ...@@ -86,6 +86,11 @@ static inline int luaL_checkboolean( lua_State *L, int narg )
return lua_toboolean( L, narg ); return lua_toboolean( L, narg );
} }
static inline int luaL_optboolean( lua_State *L, int narg, int def )
{
return luaL_opt( L, luaL_checkboolean, narg, def );
}
static inline const void *luaL_checklightuserdata( lua_State *L, int narg ) static inline const void *luaL_checklightuserdata( lua_State *L, int narg )
{ {
luaL_checktype( L, narg, LUA_TLIGHTUSERDATA ); /* can raise an error */ luaL_checktype( L, narg, LUA_TLIGHTUSERDATA ); /* can raise an error */
...@@ -119,6 +124,9 @@ int vlclua_gc_release( lua_State *L ); ...@@ -119,6 +124,9 @@ int vlclua_gc_release( lua_State *L );
int vlclua_object_find( lua_State *L ); int vlclua_object_find( lua_State *L );
int vlclua_object_find_name( lua_State *L ); int vlclua_object_find_name( lua_State *L );
vlc_object_t * vlclua_get_this( lua_State * );
playlist_t *vlclua_get_playlist_internal( lua_State * );
int vlclua_add_callback( lua_State * ); int vlclua_add_callback( lua_State * );
int vlclua_del_callback( lua_State * ); int vlclua_del_callback( lua_State * );
...@@ -163,11 +171,15 @@ int vlclua_acl_add_host( lua_State * ); ...@@ -163,11 +171,15 @@ int vlclua_acl_add_host( lua_State * );
int vlclua_acl_add_net( lua_State * ); int vlclua_acl_add_net( lua_State * );
int vlclua_acl_load_file( lua_State * ); int vlclua_acl_load_file( lua_State * );
int vlclua_sd_get_services_names( lua_State * );
int vlclua_sd_add( lua_State * );
int vlclua_sd_remove( lua_State * );
int vlclua_sd_is_loaded( lua_State * );
/***************************************************************************** /*****************************************************************************
* Lua function bridge * Lua function bridge
*****************************************************************************/ *****************************************************************************/
vlc_object_t * vlclua_get_this( lua_State * );
#define vlclua_error( L ) luaL_error( L, "VLC lua error in file %s line %d (function %s)", __FILE__, __LINE__, __func__ ) #define vlclua_error( L ) luaL_error( L, "VLC lua error in file %s line %d (function %s)", __FILE__, __LINE__, __func__ )
int vlclua_push_ret( lua_State *, int i_error ); int vlclua_push_ret( lua_State *, int i_error );
......
...@@ -61,14 +61,17 @@ This dialog needs the following dialogs to be fully functional: <none> ...@@ -61,14 +61,17 @@ This dialog needs the following dialogs to be fully functional: <none>
<span class="btn_text">Sort</span> <span class="btn_text">Sort</span>
</button> </button>
<div id="menu_sort" class="menu" > <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('title',0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Title ascending" >Title</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('title',1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Title descending" >Title 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('artist',0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Artist ascending" >Artist</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('artist',1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Artist ascending" >Artist 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('album',0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Album ascending" >Album</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('album',1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Album ascending" >Album reverse</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('genre',0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Genre ascending" >Genre</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/> <button class="menuout" onclick="pl_sort('genre',1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Genre ascending" >Genre reverse</button><br/>
<button class="menuout" onclick="pl_sort('random',0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Randomize" >Random</button><br/>
<button class="menuout" onclick="pl_sort('id',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('id',1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Id descending" >Id reverse</button><br/>
</div> </div>
</td> </td>
<td onmouseover="show_menu('menu_sd');" onmouseout="hide_menu('menu_sd');"> <td onmouseover="show_menu('menu_sd');" onmouseout="hide_menu('menu_sd');">
...@@ -77,12 +80,12 @@ This dialog needs the following dialogs to be fully functional: <none> ...@@ -77,12 +80,12 @@ This dialog needs the following dialogs to be fully functional: <none>
<span class="btn_text">Services Discovery</span> <span class="btn_text">Services Discovery</span>
</button> </button>
<div id="menu_sd" class="menu" > <div id="menu_sd" class="menu" >
<?vlc --[[ FIXME <?vlc
<vlc id="rpn" param1="services_discovery" /> local sd = vlc.sd.get_services_names()
<vlc id="foreach" param1="sd" param2="object" /> for n,ln in pairs(sd) do
<button onclick="pl_sd('<vlc id="value" param1="sd" />');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/> print([[<button onclick="pl_sd(']]..n..[[');hide_menu('menu_sd');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" class="menuout" title="Toggle ]]..ln..[[" >]]..ln..[[</button><br/>]])
<vlc id="end" /> end
]] ?> ?>
</div> </div>
</td> </td>
</tr> </tr>
......
...@@ -25,17 +25,44 @@ vim:syntax=lua ...@@ -25,17 +25,44 @@ vim:syntax=lua
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
]] ?> ]] ?>
<node id="0" name="Undefined" ro="ro">
<?vlc <?vlc
local playlist = vlc.playlist.get() --[[<node id="0" name="Undefined" ro="ro">]]
for i,item in ipairs(playlist) do function print_playlist(item)
local name, path = vlc.convert_xml_special_chars(item.name,item.path) if item.children then
print("<leaf id='"..tostring(i).."' uri='"..path.."' name='"..name.."' ro='ro' duration='"..tostring(item.duration).."'/>") local name = vlc.convert_xml_special_chars(item.name)
print("<node id=\""..tostring(item.id).."\" name=\""..name.."\" ro=\""..(item.flags.ro and "ro" or "rw").."\">")
for _, c in ipairs(item.children) do
print_playlist(c)
end
print("</node>")
else
local name, path = vlc.convert_xml_special_chars(item.name,item.path or "")
print("<leaf id='"..tostring(item.id).."' uri='"..path.."' name='"..name.."' ro='"..(item.flags.ro and "ro" or "rw").."' duration='"..tostring(item.duration).."'/>")
end
end end
function a(t,pre)
local pre = pre or ""
for k,v in pairs(t) do
vlc.msg.err(pre..tostring(k).." : "..tostring(v))
if type(v) == "table" then
a(v,pre.." ")
end
end
end
--[[
for cat,pl in pairs(p) do
print("<node id=\"-1\" name=\""..cat.."\" ro=\"ro\">")
print_playlist(pl)
print("</node>")
end
--]]
local p = vlc.playlist.get()
-- a(p) Uncomment to debug
print_playlist(p)
?> ?>
</node>