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 )
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"
if item.nb_played > 1 then
str = str .. "s"
else
local sd = vlc.sd.get_services_names()
client:append("+----[ Services discovery ]")
for n,ln in pairs(sd) do
local status
if vlc.sd.is_loaded(n) then
status = "enabled"
else
status = "disabled"
end
client:append("| "..n..": " .. ln .. " (" .. status .. ")")
end
client:append(str)
client:append("+----[ End of services discovery ]")
end
client:append("+----[ End of playlist ]")
end
function print_text(label,text)
......@@ -338,6 +401,9 @@ commands_ordered = {
{ "add"; { func = add; args = "XYZ"; help = "add XYZ to playlist" } };
{ "enqueue"; { func = add; args = "XYZ"; help = "queue XYZ to 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" } };
{ "stop"; { func = skip2(vlc.playlist.stop); help = "stop stream" } };
{ "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