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
/*****************************************************************************
* 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 );
return pl_Yield( p_this );
......@@ -355,6 +355,15 @@ static int vlclua_playlist_next( lua_State * L )
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 )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
......@@ -363,6 +372,14 @@ static int vlclua_playlist_play( lua_State * L )
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 )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
......@@ -406,37 +423,14 @@ static int vlclua_playlist_random( 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
* implies knowledge of the playlist internals. */
playlist_t *p_playlist;
int i_size;
playlist_item_t *p_item, *p_parent;
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 );
int i_id = luaL_checkint( L, 1 );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int i_ret = playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
VLC_TRUE, NULL,
playlist_ItemGetById( p_playlist, i_id,
VLC_TRUE ) );
vlc_object_release( p_playlist );
lua_pushboolean( L, 1 );
return 1;
return vlclua_push_ret( L, i_ret );
}
static int vlclua_playlist_add( lua_State *L )
......@@ -463,23 +457,31 @@ static int vlclua_playlist_enqueue( lua_State *L )
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 */
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_item_t *p_root;
int i;
if( lua_isboolean( L, 1 ) && lua_toboolean( L, 1 ) )
p_root = p_playlist->p_ml_onelevel; /* media library */
else
p_root = p_playlist->p_local_onelevel; /* local/normal playlist */
lua_createtable( L, p_root->i_children, 0 );
for( i = 0; i < p_root->i_children; i++ )
input_item_t *p_input = p_item->p_input;
int i_flags = p_item->i_flags;
lua_newtable( L );
lua_pushinteger( L, p_item->i_id );
lua_setfield( L, -2, "id" );
lua_newtable( L );
#define CHECK_AND_SET_FLAG( name, label ) \
if( i_flags & PLAYLIST_ ## name ## _FLAG ) \
{ \
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_setfield( L, -2, "name" );
lua_pushstring( L, p_input->psz_uri );
......@@ -492,16 +494,166 @@ static int vlclua_playlist_get( lua_State *L )
lua_pushinteger( L, p_input->i_nb_played );
lua_setfield( L, -2, "nb_played" );
/* 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 );
}
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 );
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 )
{
/* 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? */
......@@ -655,7 +807,9 @@ static luaL_Reg p_reg_playlist[] =
{
{ "prev", vlclua_playlist_prev },
{ "next", vlclua_playlist_next },
{ "skip", vlclua_playlist_skip },
{ "play", vlclua_playlist_play },
{ "pause", vlclua_playlist_pause },
{ "stop", vlclua_playlist_stop },
{ "clear", vlclua_playlist_clear },
{ "repeat_", vlclua_playlist_repeat },
......@@ -666,11 +820,24 @@ static luaL_Reg p_reg_playlist[] =
{ "add", vlclua_playlist_add },
{ "enqueue", vlclua_playlist_enqueue },
{ "get", vlclua_playlist_get },
{ "search", vlclua_playlist_search },
{ "sort", vlclua_playlist_sort },
{ "stats", vlclua_input_stats },
{ 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[] =
{
{ "get", vlclua_volume_get },
......@@ -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, "msg", p_reg_msg );
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, "osd", p_reg_osd );
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 )
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 )
{
luaL_checktype( L, narg, LUA_TLIGHTUSERDATA ); /* can raise an error */
......@@ -119,6 +124,9 @@ int vlclua_gc_release( lua_State *L );
int vlclua_object_find( 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_del_callback( lua_State * );
......@@ -163,11 +171,15 @@ int vlclua_acl_add_host( lua_State * );
int vlclua_acl_add_net( 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
*****************************************************************************/
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__ )
int vlclua_push_ret( lua_State *, int i_error );
......
......@@ -61,14 +61,17 @@ This dialog needs the following dialogs to be fully functional: <none>
<span class="btn_text">Sort</span>
</button>
<div id="menu_sort" class="menu" >
<button class="menuout" onclick="pl_sort(1,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Name ascending" >Name</button><br/>
<button class="menuout" onclick="pl_sort(1,1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Name descending" >Name reverse</button><br/>
<button class="menuout" onclick="pl_sort(3,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Author ascending" >Author</button><br/>
<button class="menuout" onclick="pl_sort(3,1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Author ascending" >Author reverse</button><br/>
<button class="menuout" onclick="pl_sort(5,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Randomize" >Random</button><br/>
<button class="menuout" onclick="pl_sort(7,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Track number" >Track number</button><br/>
<button class="menuout" onclick="pl_sort(0,0);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Id ascending" >Id</button><br/>
<button class="menuout" onclick="pl_sort(0,1);hide_menu('menu_sort');" onmouseover="setclass(this,'menuover');" onmouseout="setclass(this,'menuout');" title="Sort by Id descending" >Id reverse</button><br/>
<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('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('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('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('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('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('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('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>
</td>
<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>
<span class="btn_text">Services Discovery</span>
</button>
<div id="menu_sd" class="menu" >
<?vlc --[[ FIXME
<vlc id="rpn" param1="services_discovery" />
<vlc id="foreach" param1="sd" param2="object" />
<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/>
<vlc id="end" />
]] ?>
<?vlc
local sd = vlc.sd.get_services_names()
for n,ln in pairs(sd) do
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/>]])
end
?>
</div>
</td>
</tr>
......
......@@ -25,17 +25,44 @@ vim:syntax=lua
< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
]] ?>
<node id="0" name="Undefined" ro="ro">
<?vlc
local playlist = vlc.playlist.get()
for i,item in ipairs(playlist) do
local name, path = vlc.convert_xml_special_chars(item.name,item.path)
print("<leaf id='"..tostring(i).."' uri='"..path.."' name='"..name.."' ro='ro' duration='"..tostring(item.duration).."'/>")
--[[<node id="0" name="Undefined" ro="ro">]]
function print_playlist(item)
if item.children then
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
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>
<?vlc --[[
</node>
<node id="9" name="Nevermind" ro="rw">
<leaf id="10" current="current" uri="file:///mnt/stuff/media/Nirvana/Nevermind/01 - Smells Like Teen Spirit.mp3" name="Smells Like Teen Spirit" ro="rw" duration="-1"/>
]]?>
......@@ -64,7 +64,7 @@ elseif command == "pl_delete" then
elseif command == "pl_empty" then
vlc.playlist.clear()
elseif command == "pl_sort" then
vlc.msg.err("FIXME: pl_sort unimplemented")
vlc.playlist.sort( val, id > 0 )
elseif command == "pl_random" then
vlc.playlist.random()
elseif command == "pl_loop" then
......@@ -72,14 +72,11 @@ elseif command == "pl_loop" then
elseif command == "pl_repeat" then
vlc.playlist.repeat_()
elseif command == "pl_sd" then
vlc.msg.err("FIXME: pl_sd unimplemented")
--[[
<vlc id="if" param1="val value services_discovery_is_loaded" />
<vlc id="rpn" param1="val value services_discovery_remove" />
<vlc id="else" />
<vlc id="rpn" param1="val value services_discovery_add" />
<vlc id="end" />
]]
if vlc.sd.is_loaded(val) then
vlc.sd.remove(val)
else
vlc.sd.add(val)
end
elseif command == "fullscreen" then
vlc.fullscreen()
elseif command == "snapshot" then
......
......@@ -164,29 +164,92 @@ function add(name,client,arg)
end
function playlist(name,client,arg)
-- TODO: add possibility to filter playlist items using a mask
function playlist0(item,prefix)
local prefix = prefix or ""
if not item.flags.disabled then
local str = "| "..prefix..tostring(item.id).." - "..item.name
if item.duration > 0 then
str = str.." ("..common.durationtostring(item.duration)..")"
end
if item.nb_played > 0 then
str = str.." [played "..tostring(item.nb_played).." time"
if item.nb_played > 1 then
str = str .. "s"
end
str = str .. "]"
end
client:append(str)
end
if item.children then
for _, c in ipairs(item.children) do
playlist0(c,prefix.." ")
end
end
end
local playlist
if arg == "ml" then
playlist = vlc.playlist.get(true)
client:append("+----[ Playlist - Media Library ]")
if name == "search" then
playlist = vlc.playlist.search(arg or "")
else
if tonumber(arg) then
print "number"
playlist = vlc.playlist.get(tonumber(arg))
elseif arg then
print "string"
playlist = vlc.playlist.get(arg)
else
playlist = vlc.playlist.get()
end
end
if name == "search" then
client:append("+----[ Search - "..(arg or "`reset'").." ]")
else
client:append("+----[ Playlist - "..playlist.name.." ]")
end
if playlist.children then
for _, item in ipairs(playlist.children) do
playlist0(item)
end
else
playlist0(playlist)
end
if name == "search" then
client:append("+----[ End of search - Use `search' to reset ]")
else
playlist = vlc.playlist.get()
client:append("+----[ Playlist ]")
client:append("+----[ End of playlist ]")
end
for i, item in pairs(playlist) do
local str = "| "..tostring(i).." - "..item.name
if item.duration > 0 then
str = str.." ("..common.durationtostring(item.duration)..")"
end
function playlist_sort(name,client,arg)
if not arg then
client:append("Valid sort keys are: id, title, artist, genre, random, duration, album.")
else
vlc.playlist.sort(arg)
end
end
function services_discovery(name,client,arg)
if arg then
if vlc.sd.is_loaded(arg) then
vlc.sd.remove(arg)
client:append(arg.." disabled.")
else
vlc.sd.add(arg)
client:append(arg.." enabled.")
end
if item.nb_played > 0 then
str = str.." played "..tostring(item.nb_played).." time"