1 /*****************************************************************************
2 * sd.c: Services discovery related functions
3 *****************************************************************************
4 * Copyright (C) 2007-2008 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea at videolan tod org>
8 * Fabio Ritrovato <sephiroth87 at videolan dot org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_services_discovery.h>
38 #include <vlc_playlist.h>
39 #include <vlc_charset.h>
45 /*****************************************************************************
47 *****************************************************************************/
48 static int vlclua_node_add_subitem( lua_State * );
49 static int vlclua_node_add_subnode( lua_State * );
51 static const luaL_Reg vlclua_node_reg[] = {
52 { "add_subitem", vlclua_node_add_subitem },
53 { "add_subnode", vlclua_node_add_subnode },
57 #define vlclua_item_luareg( a ) \
58 { "set_" # a, vlclua_item_set_ ## a },
60 #define vlclua_item_meta( lowercase, normal ) \
61 static int vlclua_item_set_ ## lowercase ( lua_State *L )\
63 services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );\
64 input_item_t **pp_node = (input_item_t **)luaL_checkudata( L, 1, "input_item_t" );\
67 if( lua_isstring( L, -1 ) )\
69 input_item_Set ## normal ( *pp_node, lua_tostring( L, -1 ) );\
71 msg_Err( p_sd, "Error parsing set_ " # lowercase " arguments" );\
76 vlclua_item_meta(title, Title)
77 vlclua_item_meta(artist, Artist)
78 vlclua_item_meta(genre, Genre)
79 vlclua_item_meta(copyright, Copyright)
80 vlclua_item_meta(album, Album)
81 vlclua_item_meta(tracknum, TrackNum)
82 vlclua_item_meta(description, Description)
83 vlclua_item_meta(rating, Rating)
84 vlclua_item_meta(date, Date)
85 vlclua_item_meta(setting, Setting)
86 vlclua_item_meta(url, URL)
87 vlclua_item_meta(language, Language)
88 vlclua_item_meta(nowplaying, NowPlaying)
89 vlclua_item_meta(publisher, Publisher)
90 vlclua_item_meta(encodedby, EncodedBy)
91 vlclua_item_meta(arturl, ArtworkURL)
92 vlclua_item_meta(trackid, TrackID)
94 static const luaL_Reg vlclua_item_reg[] = {
95 vlclua_item_luareg(title)
96 vlclua_item_luareg(artist)
97 vlclua_item_luareg(genre)
98 vlclua_item_luareg(copyright)
99 vlclua_item_luareg(album)
100 vlclua_item_luareg(tracknum)
101 vlclua_item_luareg(description)
102 vlclua_item_luareg(rating)
103 vlclua_item_luareg(date)
104 vlclua_item_luareg(setting)
105 vlclua_item_luareg(url)
106 vlclua_item_luareg(language)
107 vlclua_item_luareg(nowplaying)
108 vlclua_item_luareg(publisher)
109 vlclua_item_luareg(encodedby)
110 vlclua_item_luareg(arturl)
111 vlclua_item_luareg(trackid)
115 static int vlclua_sd_get_services_names( lua_State *L )
117 playlist_t *p_playlist = vlclua_get_playlist_internal( L );
118 char **ppsz_longnames;
119 char **ppsz_names = vlc_sd_GetNames( p_playlist, &ppsz_longnames, NULL );
123 char **ppsz_longname = ppsz_longnames;
124 char **ppsz_name = ppsz_names;
127 for( ; *ppsz_name; ppsz_name++,ppsz_longname++ )
129 lua_pushstring( L, *ppsz_longname );
130 lua_setfield( L, -2, *ppsz_name );
132 free( *ppsz_longname );
135 free( ppsz_longnames );
139 static int vlclua_sd_add( lua_State *L )
141 const char *psz_sd = luaL_checkstring( L, 1 );
142 playlist_t *p_playlist = vlclua_get_playlist_internal( L );
143 int i_ret = playlist_ServicesDiscoveryAdd( p_playlist, psz_sd );
144 return vlclua_push_ret( L, i_ret );
147 static int vlclua_sd_remove( lua_State *L )
149 const char *psz_sd = luaL_checkstring( L, 1 );
150 playlist_t *p_playlist = vlclua_get_playlist_internal( L );
151 int i_ret = playlist_ServicesDiscoveryRemove( p_playlist, psz_sd );
152 return vlclua_push_ret( L, i_ret );
155 static int vlclua_sd_is_loaded( lua_State *L )
157 const char *psz_sd = luaL_checkstring( L, 1 );
158 playlist_t *p_playlist = vlclua_get_playlist_internal( L );
159 lua_pushboolean( L, playlist_IsServicesDiscoveryLoaded( p_playlist, psz_sd ));
163 static int vlclua_sd_add_node( lua_State *L )
165 services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
166 if( lua_istable( L, -1 ) )
168 lua_getfield( L, -1, "title" );
169 if( lua_isstring( L, -1 ) )
171 const char *psz_name = lua_tostring( L, -1 );
172 input_item_t *p_input = input_item_NewWithType( "vlc://nop",
173 psz_name, 0, NULL, 0,
174 -1, ITEM_TYPE_NODE );
179 lua_getfield( L, -1, "arturl" );
180 if( lua_isstring( L, -1 ) && strcmp( lua_tostring( L, -1 ), "" ) )
182 char *psz_value = strdup( lua_tostring( L, -1 ) );
183 EnsureUTF8( psz_value );
184 msg_Dbg( p_sd, "ArtURL: %s", psz_value );
185 /** @todo Ask for art download if not local file */
186 input_item_SetArtURL( p_input, psz_value );
190 lua_getfield( L, -1, "category" );
191 if( lua_isstring( L, -1 ) )
192 services_discovery_AddItem( p_sd, p_input, luaL_checkstring( L, -1 ) );
194 services_discovery_AddItem( p_sd, p_input, NULL );
195 input_item_t **udata = (input_item_t **)
196 lua_newuserdata( L, sizeof( input_item_t * ) );
198 if( luaL_newmetatable( L, "node" ) )
201 luaL_register( L, NULL, vlclua_node_reg );
202 lua_setfield( L, -2, "__index" );
204 lua_setmetatable( L, -2 );
208 msg_Err( p_sd, "vlc.sd.add_node: the \"title\" parameter can't be empty" );
211 msg_Err( p_sd, "Error parsing add_node arguments" );
215 static int vlclua_sd_add_item( lua_State *L )
217 services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
218 if( lua_istable( L, -1 ) )
220 lua_getfield( L, -1, "path" );
221 if( lua_isstring( L, -1 ) )
223 char **ppsz_options = NULL;
225 const char *psz_path = lua_tostring( L, -1 );
228 vlclua_read_options( p_sd, L, &i_options, &ppsz_options );
229 lua_getfield( L, -1, "title" );
230 const char *psz_title = luaL_checkstring( L, -1 ) ? luaL_checkstring( L, -1 ) : psz_path;
231 input_item_t *p_input = input_item_NewExt( psz_path, psz_title,
233 (const char **)ppsz_options,
234 VLC_INPUT_OPTION_TRUSTED, -1 );
239 vlclua_read_meta_data( p_sd, L, p_input );
240 /* This one is to be tested... */
241 vlclua_read_custom_meta_data( p_sd, L, p_input );
242 /* The duration is given in seconds, convert to microseconds */
243 lua_getfield( L, -1, "duration" );
244 if( lua_isnumber( L, -1 ) )
245 input_item_SetDuration( p_input, (lua_tonumber( L, -1 )*1e6) );
246 else if( !lua_isnil( L, -1 ) )
247 msg_Warn( p_sd, "Item duration should be a number (in seconds)." );
249 lua_getfield( L, -1, "category" );
250 if( lua_isstring( L, -1 ) )
251 services_discovery_AddItem( p_sd, p_input, luaL_checkstring( L, -1 ) );
253 services_discovery_AddItem( p_sd, p_input, NULL );
255 input_item_t **udata = (input_item_t **)
256 lua_newuserdata( L, sizeof( input_item_t * ) );
258 if( luaL_newmetatable( L, "input_item_t" ) )
261 luaL_register( L, NULL, vlclua_item_reg );
262 lua_setfield( L, -2, "__index" );
263 lua_pushliteral( L, "none of your business" );
264 lua_setfield( L, -2, "__metatable" );
266 lua_setmetatable( L, -2 );
267 vlc_gc_decref( p_input );
269 while( i_options > 0 )
270 free( ppsz_options[--i_options] );
271 free( ppsz_options );
274 msg_Err( p_sd, "vlc.sd.add_item: the \"path\" parameter can't be empty" );
277 msg_Err( p_sd, "Error parsing add_item arguments" );
281 static int vlclua_sd_remove_item( lua_State *L )
283 services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
284 if( !lua_isnil( L, 1 ) )
286 input_item_t **pp_input = luaL_checkudata( L, 1, "input_item_t" );
288 services_discovery_RemoveItem( p_sd, *pp_input );
289 /* Make sure we won't try to remove it again */
295 static int vlclua_sd_remove_all_items_nodes( lua_State *L )
297 services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
298 services_discovery_RemoveAll( p_sd );
302 static int vlclua_node_add_subitem( lua_State *L )
304 services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
305 input_item_t **pp_node = (input_item_t **)luaL_checkudata( L, 1, "node" );
308 if( lua_istable( L, -1 ) )
310 lua_getfield( L, -1, "path" );
311 if( lua_isstring( L, -1 ) )
313 char **ppsz_options = NULL;
315 const char *psz_path = lua_tostring( L, -1 );
316 vlclua_read_options( p_sd, L, &i_options, &ppsz_options );
317 input_item_node_t *p_input_node = input_item_node_Create( *pp_node );
318 input_item_t *p_input = input_item_NewExt( psz_path,
320 (const char **)ppsz_options,
321 VLC_INPUT_OPTION_TRUSTED, -1 );
326 vlclua_read_meta_data( p_sd, L, p_input );
327 /* This one is to be tested... */
328 vlclua_read_custom_meta_data( p_sd, L, p_input );
329 lua_getfield( L, -1, "duration" );
330 if( lua_isnumber( L, -1 ) )
331 input_item_SetDuration( p_input, (lua_tonumber( L, -1 )*1e6) );
332 else if( !lua_isnil( L, -1 ) )
333 msg_Warn( p_sd, "Item duration should be a number (in seconds)." );
335 input_item_node_AppendItem( p_input_node, p_input );
336 input_item_node_PostAndDelete( p_input_node );
337 input_item_t **udata = (input_item_t **)
338 lua_newuserdata( L, sizeof( input_item_t * ) );
340 if( luaL_newmetatable( L, "input_item_t" ) )
343 luaL_register( L, NULL, vlclua_item_reg );
344 lua_setfield( L, -2, "__index" );
345 lua_pushliteral( L, "none of your business" );
346 lua_setfield( L, -2, "__metatable" );
348 lua_setmetatable( L, -2 );
349 vlc_gc_decref( p_input );
351 while( i_options > 0 )
352 free( ppsz_options[--i_options] );
353 free( ppsz_options );
356 msg_Err( p_sd, "node:add_subitem: the \"path\" parameter can't be empty" );
359 msg_Err( p_sd, "Error parsing add_subitem arguments" );
364 static int vlclua_node_add_subnode( lua_State *L )
366 services_discovery_t *p_sd = (services_discovery_t *)vlclua_get_this( L );
367 input_item_t **pp_node = (input_item_t **)luaL_checkudata( L, 1, "node" );
370 if( lua_istable( L, -1 ) )
372 lua_getfield( L, -1, "title" );
373 if( lua_isstring( L, -1 ) )
375 const char *psz_name = lua_tostring( L, -1 );
376 input_item_node_t *p_input_node = input_item_node_Create( *pp_node );
377 input_item_t *p_input = input_item_NewWithType( "vlc://nop",
378 psz_name, 0, NULL, 0,
379 -1, ITEM_TYPE_NODE );
384 lua_getfield( L, -1, "arturl" );
385 if( lua_isstring( L, -1 ) && strcmp( lua_tostring( L, -1 ), "" ) )
387 char *psz_value = strdup( lua_tostring( L, -1 ) );
388 EnsureUTF8( psz_value );
389 msg_Dbg( p_sd, "ArtURL: %s", psz_value );
390 input_item_SetArtURL( p_input, psz_value );
393 input_item_node_AppendItem( p_input_node, p_input );
394 input_item_node_PostAndDelete( p_input_node );
395 input_item_t **udata = (input_item_t **)
396 lua_newuserdata( L, sizeof( input_item_t * ) );
398 if( luaL_newmetatable( L, "node" ) )
401 luaL_register( L, NULL, vlclua_node_reg );
402 lua_setfield( L, -2, "__index" );
404 lua_setmetatable( L, -2 );
408 msg_Err( p_sd, "node:add_node: the \"title\" parameter can't be empty" );
411 msg_Err( p_sd, "Error parsing add_node arguments" );
416 /*****************************************************************************
418 *****************************************************************************/
419 static const luaL_Reg vlclua_sd_reg[] = {
420 { "get_services_names", vlclua_sd_get_services_names },
421 { "add", vlclua_sd_add },
422 { "remove", vlclua_sd_remove },
423 { "is_loaded", vlclua_sd_is_loaded },
424 { "add_node", vlclua_sd_add_node },
425 { "add_item", vlclua_sd_add_item },
426 { "remove_item", vlclua_sd_remove_item },
427 { "remove_all_items_nodes", vlclua_sd_remove_all_items_nodes },
431 void luaopen_sd( lua_State *L )
434 luaL_register( L, NULL, vlclua_sd_reg );
435 lua_setfield( L, -2, "sd" );