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
This diff is collapsed.
/*****************************************************************************
* 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>
<?vlc --[[ <?vlc --[[
</node>
<node id="9" name="Nevermind" ro="rw"> <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"/> <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 ...@@ -64,7 +64,7 @@ elseif command == "pl_delete" then
elseif command == "pl_empty" then elseif command == "pl_empty" then
vlc.playlist.clear() vlc.playlist.clear()
elseif command == "pl_sort" then elseif command == "pl_sort" then
vlc.msg.err("FIXME: pl_sort unimplemented") vlc.playlist.sort( val, id > 0 )
elseif command == "pl_random" then elseif command == "pl_random" then
vlc.playlist.random() vlc.playlist.random()
elseif command == "pl_loop" then elseif command == "pl_loop" then
...@@ -72,14 +72,11 @@ elseif command == "pl_loop" then ...@@ -72,14 +72,11 @@ elseif command == "pl_loop" then
elseif command == "pl_repeat" then elseif command == "pl_repeat" then
vlc.playlist.repeat_() vlc.playlist.repeat_()
elseif command == "pl_sd" then elseif command == "pl_sd" then
vlc.msg.err("FIXME: pl_sd unimplemented") if vlc.sd.is_loaded(val) then
--[[ vlc.sd.remove(val)
<vlc id="if" param1="val value services_discovery_is_loaded" /> else
<vlc id="rpn" param1="val value services_discovery_remove" /> vlc.sd.add(val)
<vlc id="else" /> end
<vlc id="rpn" param1="val value services_discovery_add" />
<vlc id="end" />
]]
elseif command == "fullscreen" then elseif command == "fullscreen" then
vlc.fullscreen() vlc.fullscreen()
elseif command == "snapshot" then elseif command == "snapshot" then
......
...@@ -164,29 +164,92 @@ function add(name,client,arg) ...@@ -164,29 +164,92 @@ function add(name,client,arg)
end end
function playlist(name,client,arg) 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 local playlist
if arg == "ml" then if name == "search" then
playlist = vlc.playlist.get(true) playlist = vlc.playlist.search(arg or "")
client:append("+----[ Playlist - Media Library ]") 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 else
playlist = vlc.playlist.get() client:append("+----[ End of playlist ]")
client:append("+----[ Playlist ]")
end end
for i, item in pairs(playlist) do end
local str = "| "..tostring(i).." - "..item.name
if item.duration > 0 then function playlist_sort(name,client,arg)
str = str.." ("..common.durationtostring(item.duration)..")" 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 end
if item.nb_played > 0 then else
str = str.." played "..tostring(item.nb_played).." time" local sd = vlc.sd.get_services_names()
if item.nb_played > 1 then client:append("+----[ Services discovery ]")
str = str .. "s" for n,ln in pairs(sd) do
local status
if vlc.sd.is_loaded(n) then
status = "enabled"
else
status = "disabled"
end end
client:append("| "..n..": " .. ln .. " (" .. status .. ")")
end end
client:append(str) client:append("+----[ End of services discovery ]")
end end
client:append("+----[ End of playlist ]")
end end
function print_text(label,text) function print_text(label,text)
...@@ -338,6 +401,9 @@ commands_ordered = { ...@@ -338,6 +401,9 @@ commands_ordered = {
{ "add"; { func = add; args = "XYZ"; help = "add XYZ to playlist" } }; { "add"; { func = add; args = "XYZ"; help = "add XYZ to playlist" } };
{ "enqueue"; { func = add; args = "XYZ"; help = "queue XYZ to playlist" } }; { "enqueue"; { func = add; args = "XYZ"; help = "queue XYZ to playlist" } };
{ "playlist"; { func = playlist; help = "show items currently in playlist" } }; { "playlist"; { func = playlist; help = "show items currently in playlist" } };
{ "search"; { func = playlist; args = "[string]"; help = "search for items in playlist (or reset search)" } };
{ "sort"; { func = playlist_sort; args = "key"; help = "sort the playlist" } };
{ "sd"; { func = services_discovery; args = "[sd]"; help = "show services discovery or toggle" } };
{ "play"; { func = skip2(vlc.playlist.play); help = "play stream" } }; { "play"; { func = skip2(vlc.playlist.play); help = "play stream" } };
{ "stop"; { func = skip2(vlc.playlist.stop); help = "stop stream" } }; { "stop"; { func = skip2(vlc.playlist.stop); help = "stop stream" } };
{ "next"; { func = skip2(vlc.playlist.next); help = "next playlist item" } }; { "next"; { func = skip2(vlc.playlist.next); help = "next playlist item" } };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment