]> git.sesse.net Git - vlc/blob - modules/misc/lua/vlc.c
lua: Don't use the playlist in the lua demux.
[vlc] / modules / misc / lua / vlc.c
1 /*****************************************************************************
2  * vlc.c: Generic lua interface functions
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea at videolan tod org>
8  *          Pierre d'Herbemont <pdherbemont # videolan.org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifndef  _GNU_SOURCE
29 #   define  _GNU_SOURCE
30 #endif
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <assert.h>
37
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_meta.h>
41 #include <vlc_charset.h>
42 #include <vlc_aout.h>
43
44 #include <lua.h>        /* Low level lua C API */
45 #include <lauxlib.h>    /* Higher level C API */
46 #include <lualib.h>     /* Lua libs */
47
48 #include "vlc.h"
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53
54 #define INTF_TEXT N_("Lua interface")
55 #define INTF_LONGTEXT N_("Lua interface module to load")
56
57 #define CONFIG_TEXT N_("Lua interface configuration")
58 #define CONFIG_LONGTEXT N_("Lua interface configuration string. Format is: '[\"<interface module name>\"] = { <option> = <value>, ...}, ...'.")
59
60 vlc_module_begin();
61     add_submodule();
62         set_shortname( N_( "Lua Art" ) );
63         set_description( N_("Fetch artwork using lua scripts") );
64         set_capability( "art finder", 10 );
65         set_callbacks( FindArt, NULL );
66     add_submodule();
67         add_shortcut( "luaplaylist" );
68         set_category( CAT_INPUT );
69         set_subcategory( SUBCAT_INPUT_DEMUX );
70         set_shortname( N_("Lua Playlist") );
71         set_description( N_("Lua Playlist Parser Interface") );
72         set_capability( "demux", 2 );
73         set_callbacks( Import_LuaPlaylist, Close_LuaPlaylist );
74     add_submodule();
75         add_shortcut( "luaintf" );
76         add_shortcut( "luarc" );
77         /* add_shortcut( "rc" ); */
78         add_shortcut( "luahotkeys" );
79         /* add_shortcut( "hotkeys" ); */
80         add_shortcut( "luatelnet" );
81         /* add_shortcut( "telnet" ); */
82         add_shortcut( "luahttp" );
83         /* add_shortcut( "http" ); */
84         set_description( N_("Lua Interface Module") );
85         set_capability( "interface", 0 );
86         add_string( "lua-intf", "dummy", NULL,
87                     INTF_TEXT, INTF_LONGTEXT, false );
88         add_string( "lua-config", "", NULL,
89                     CONFIG_TEXT, CONFIG_LONGTEXT, false );
90         set_callbacks( Open_LuaIntf, Close_LuaIntf );
91 vlc_module_end();
92
93 /*****************************************************************************
94  * Internal lua<->vlc utils
95  *****************************************************************************/
96 vlc_object_t * vlclua_get_this( lua_State *L )
97 {
98     vlc_object_t * p_this;
99     lua_getglobal( L, "vlc" );
100     lua_getfield( L, -1, "private" );
101     p_this = (vlc_object_t*)lua_topointer( L, lua_gettop( L ) );
102     lua_pop( L, 2 );
103     return p_this;
104 }
105
106 /*****************************************************************************
107  * VLC error code translation
108  *****************************************************************************/
109 int vlclua_push_ret( lua_State *L, int i_error )
110 {
111     lua_pushnumber( L, i_error );
112     lua_pushstring( L, vlc_error( i_error ) );
113     return 2;
114 }
115
116 /*****************************************************************************
117  * Get the VLC version string
118  *****************************************************************************/
119 int vlclua_version( lua_State *L )
120 {
121     lua_pushstring( L, VLC_Version() );
122     return 1;
123 }
124
125 /*****************************************************************************
126  * Get the VLC copyright
127  *****************************************************************************/
128 int vlclua_copyright( lua_State *L )
129 {
130     lua_pushstring( L, COPYRIGHT_MESSAGE );
131     return 1;
132 }
133
134 /*****************************************************************************
135  * Get the VLC license msg/disclaimer
136  *****************************************************************************/
137 int vlclua_license( lua_State *L )
138 {
139     lua_pushstring( L, LICENSE_MSG );
140     return 1;
141 }
142
143 /*****************************************************************************
144  * Quit VLC
145  *****************************************************************************/
146 int vlclua_quit( lua_State *L )
147 {
148     vlc_object_t *p_this = vlclua_get_this( L );
149     /* The rc.c code also stops the playlist ... not sure if this is needed
150      * though. */
151     vlc_object_kill( p_this->p_libvlc );
152     return 0;
153 }
154
155 /*****************************************************************************
156  * Global properties getters
157  *****************************************************************************/
158 int vlclua_datadir( lua_State *L )
159 {
160     lua_pushstring( L, config_GetDataDir() );
161     return 1;
162 }
163 int vlclua_homedir( lua_State *L )
164 {
165     lua_pushstring( L, config_GetHomeDir() );
166     return 1;
167 }
168 int vlclua_configdir( lua_State *L )
169 {
170     char *dir = config_GetUserConfDir();
171     lua_pushstring( L, dir );
172     free( dir );
173     return 1;
174 }
175 int vlclua_cachedir( lua_State *L )
176 {
177     char *dir = config_GetCacheDir();
178     lua_pushstring( L, dir );
179     free( dir );
180     return 1;
181 }
182 int vlclua_datadir_list( lua_State *L )
183 {
184     const char *psz_dirname = luaL_checkstring( L, 1 );
185     vlc_object_t *p_this = vlclua_get_this( L );
186     char  *ppsz_dir_list[] = { NULL, NULL, NULL, NULL };
187     char **ppsz_dir = ppsz_dir_list;
188     int i = 1;
189
190     if( vlclua_dir_list( p_this, psz_dirname, ppsz_dir_list ) != VLC_SUCCESS )
191         return 0;
192     lua_newtable( L );
193     for( ; *ppsz_dir; ppsz_dir++ )
194     {
195         lua_pushstring( L, *ppsz_dir );
196         lua_rawseti( L, -2, i );
197         i ++;
198     }
199     return 1;
200 }
201
202 /*****************************************************************************
203  * Volume related
204  *****************************************************************************/
205 int vlclua_volume_set( lua_State *L )
206 {
207     vlc_object_t *p_this = vlclua_get_this( L );
208     int i_volume = luaL_checkint( L, 1 );
209     /* Do we need to check that i_volume is in the AOUT_VOLUME_MIN->MAX range?*/
210     return vlclua_push_ret( L, aout_VolumeSet( p_this, i_volume ) );
211 }
212
213 int vlclua_volume_get( lua_State *L )
214 {
215     vlc_object_t *p_this = vlclua_get_this( L );
216     audio_volume_t i_volume;
217     if( aout_VolumeGet( p_this, &i_volume ) == VLC_SUCCESS )
218         lua_pushnumber( L, i_volume );
219     else
220         lua_pushnil( L );
221     return 1;
222 }
223
224 int vlclua_volume_up( lua_State *L )
225 {
226     audio_volume_t i_volume;
227     aout_VolumeUp( vlclua_get_this( L ),
228                    luaL_optint( L, 1, 1 ),
229                    &i_volume );
230     lua_pushnumber( L, i_volume );
231     return 1;
232 }
233
234 int vlclua_volume_down( lua_State *L )
235 {
236     audio_volume_t i_volume;
237     aout_VolumeDown( vlclua_get_this( L ),
238                      luaL_optint( L, 1, 1 ),
239                      &i_volume );
240     lua_pushnumber( L, i_volume );
241     return 1;
242 }
243
244 /*****************************************************************************
245  * Stream handling
246  *****************************************************************************/
247 int vlclua_stream_new( lua_State *L )
248 {
249     vlc_object_t * p_this = vlclua_get_this( L );
250     stream_t * p_stream;
251     const char * psz_url;
252     psz_url = luaL_checkstring( L, -1 );
253     p_stream = stream_UrlNew( p_this, psz_url );
254     if( !p_stream )
255         return luaL_error( L, "Error when opening url: `%s'", psz_url );
256     lua_pushlightuserdata( L, p_stream );
257     return 1;
258 }
259
260 int vlclua_stream_read( lua_State *L )
261 {
262     stream_t * p_stream;
263     int n;
264     uint8_t *p_read;
265     int i_read;
266     p_stream = (stream_t *)luaL_checklightuserdata( L, 1 );
267     n = luaL_checkint( L, 2 );
268     p_read = malloc( n );
269     if( !p_read ) return vlclua_error( L );
270     i_read = stream_Read( p_stream, p_read, n );
271     lua_pushlstring( L, (const char *)p_read, i_read );
272     free( p_read );
273     return 1;
274 }
275
276 int vlclua_stream_readline( lua_State *L )
277 {
278     stream_t * p_stream;
279     p_stream = (stream_t *)luaL_checklightuserdata( L, 1 );
280     char *psz_line = stream_ReadLine( p_stream );
281     if( psz_line )
282     {
283         lua_pushstring( L, psz_line );
284         free( psz_line );
285     }
286     else
287         lua_pushnil( L );
288     return 1;
289 }
290
291 int vlclua_stream_delete( lua_State *L )
292 {
293     stream_t * p_stream;
294     p_stream = (stream_t *)luaL_checklightuserdata( L, 1 );
295     stream_Delete( p_stream );
296     return 0;
297 }
298
299 /*****************************************************************************
300  * String transformations
301  *****************************************************************************/
302 int vlclua_decode_uri( lua_State *L )
303 {
304     int i_top = lua_gettop( L );
305     int i;
306     for( i = 1; i <= i_top; i++ )
307     {
308         const char *psz_cstring = luaL_checkstring( L, 1 );
309         char *psz_string = strdup( psz_cstring );
310         lua_remove( L, 1 ); /* remove elements to prevent being limited by
311                              * the stack's size (this function will work with
312                              * up to (stack size - 1) arguments */
313         decode_URI( psz_string );
314         lua_pushstring( L, psz_string );
315         free( psz_string );
316     }
317     return i_top;
318 }
319
320 int vlclua_resolve_xml_special_chars( lua_State *L )
321 {
322     int i_top = lua_gettop( L );
323     int i;
324     for( i = 1; i <= i_top; i++ )
325     {
326         const char *psz_cstring = luaL_checkstring( L, 1 );
327         char *psz_string = strdup( psz_cstring );
328         lua_remove( L, 1 ); /* remove elements to prevent being limited by
329                              * the stack's size (this function will work with
330                              * up to (stack size - 1) arguments */
331         resolve_xml_special_chars( psz_string );
332         lua_pushstring( L, psz_string );
333         free( psz_string );
334     }
335     return i_top;
336 }
337
338 int vlclua_convert_xml_special_chars( lua_State *L )
339 {
340     int i_top = lua_gettop( L );
341     int i;
342     for( i = 1; i <= i_top; i++ )
343     {
344         char *psz_string = convert_xml_special_chars( luaL_checkstring(L,1) );
345         lua_remove( L, 1 );
346         lua_pushstring( L, psz_string );
347         free( psz_string );
348     }
349     return i_top;
350 }
351
352 /*****************************************************************************
353  * Messaging facilities
354  *****************************************************************************/
355 int vlclua_msg_dbg( lua_State *L )
356 {
357     int i_top = lua_gettop( L );
358     vlc_object_t *p_this = vlclua_get_this( L );
359     int i;
360     for( i = 1; i <= i_top; i++ )
361         msg_Dbg( p_this, "%s", luaL_checkstring( L, 1 ) );
362     return 0;
363 }
364 int vlclua_msg_warn( lua_State *L )
365 {
366     int i_top = lua_gettop( L );
367     vlc_object_t *p_this = vlclua_get_this( L );
368     int i;
369     for( i = 1; i <= i_top; i++ )
370         msg_Warn( p_this, "%s", luaL_checkstring( L, i ) );
371     return 0;
372 }
373 int vlclua_msg_err( lua_State *L )
374 {
375     int i_top = lua_gettop( L );
376     vlc_object_t *p_this = vlclua_get_this( L );
377     int i;
378     for( i = 1; i <= i_top; i++ )
379         msg_Err( p_this, "%s", luaL_checkstring( L, i ) );
380     return 0;
381 }
382 int vlclua_msg_info( lua_State *L )
383 {
384     int i_top = lua_gettop( L );
385     vlc_object_t *p_this = vlclua_get_this( L );
386     int i;
387     for( i = 1; i <= i_top; i++ )
388         msg_Info( p_this, "%s", luaL_checkstring( L, i ) );
389     return 0;
390 }
391
392 /*****************************************************************************
393  *
394  *****************************************************************************/
395 static int file_select( const char *file )
396 {
397     int i = strlen( file );
398     return i > 4 && !strcmp( file+i-4, ".lua" );
399 }
400
401 static int file_compare( const char **a, const char **b )
402 {
403     return strcmp( *a, *b );
404 }
405
406 int vlclua_dir_list( vlc_object_t *p_this, const char *luadirname,
407                      char **ppsz_dir_list )
408 {
409     int i = 0;
410     char *datadir = config_GetUserDataDir();
411     if( datadir == NULL )
412         return VLC_ENOMEM;
413
414     if( asprintf( &ppsz_dir_list[i], "%s" DIR_SEP "lua" DIR_SEP "%s",
415                    datadir, luadirname ) < 0 )
416     {
417         free( datadir );
418         return VLC_ENOMEM;
419     }
420     free( datadir );
421     i++;
422
423 #   if defined(__APPLE__) || defined(SYS_BEOS) || defined(WIN32)
424     {
425         const char *psz_vlcpath = config_GetDataDir();
426         if( asprintf( &ppsz_dir_list[i], "%s" DIR_SEP "lua" DIR_SEP "%s",
427                       psz_vlcpath, luadirname )  < 0 )
428             return VLC_ENOMEM;
429         i++;
430         if( asprintf( &ppsz_dir_list[i], "%s" DIR_SEP "share" DIR_SEP "lua" DIR_SEP "%s",
431                       psz_vlcpath, luadirname )  < 0 )
432             return VLC_ENOMEM;
433         i++;
434
435     }
436 #   else
437     if( asprintf( &ppsz_dir_list[i],
438                   "share" DIR_SEP "lua" DIR_SEP "%s", luadirname ) < 0 )
439         return VLC_ENOMEM;
440
441 #   ifdef HAVE_SYS_STAT_H
442     {
443         struct stat stat_info;
444         if( ( utf8_stat( ppsz_dir_list[i], &stat_info ) == -1 )
445             || !S_ISDIR( stat_info.st_mode ) )
446         {
447             free(ppsz_dir_list[i]);
448             if( asprintf( &ppsz_dir_list[i], "%s" DIR_SEP "lua" DIR_SEP "%s",
449                           config_GetDataDir (), luadirname ) < 0 )
450                 return VLC_ENOMEM;
451         }
452     }
453 #   endif
454     i++;
455 #   endif
456     return VLC_SUCCESS;
457 }
458
459 /*****************************************************************************
460  * Will execute func on all scripts in luadirname, and stop if func returns
461  * success.
462  *****************************************************************************/
463 int vlclua_scripts_batch_execute( vlc_object_t *p_this,
464                                   const char * luadirname,
465                                   int (*func)(vlc_object_t *, const char *, lua_State *, void *),
466                                   lua_State * L,
467                                   void * user_data)
468 {
469     int i_ret = VLC_EGENERIC;
470
471     char **ppsz_filelist = NULL;
472     char **ppsz_fileend  = NULL;
473     char **ppsz_file;
474
475     char  *ppsz_dir_list[] = { NULL, NULL, NULL, NULL };
476     char **ppsz_dir;
477
478     i_ret = vlclua_dir_list( p_this, luadirname, ppsz_dir_list );
479     if( i_ret != VLC_SUCCESS )
480         return i_ret;
481     i_ret = VLC_EGENERIC;
482
483
484     for( ppsz_dir = ppsz_dir_list; *ppsz_dir; ppsz_dir++ )
485     {
486         int i_files;
487
488         if( ppsz_filelist )
489         {
490             for( ppsz_file = ppsz_filelist; ppsz_file < ppsz_fileend;
491                  ppsz_file++ )
492                 free( *ppsz_file );
493             free( ppsz_filelist );
494             ppsz_filelist = NULL;
495         }
496
497         msg_Dbg( p_this, "Trying Lua scripts in %s", *ppsz_dir );
498         i_files = utf8_scandir( *ppsz_dir, &ppsz_filelist, file_select,
499                                 file_compare );
500         if( i_files < 1 ) continue;
501         ppsz_fileend = ppsz_filelist + i_files;
502
503         for( ppsz_file = ppsz_filelist; ppsz_file < ppsz_fileend; ppsz_file++ )
504         {
505             char  *psz_filename;
506             if( asprintf( &psz_filename,
507                           "%s" DIR_SEP "%s", *ppsz_dir, *ppsz_file ) < 0)
508                 return VLC_ENOMEM;
509             msg_Dbg( p_this, "Trying Lua playlist script %s", psz_filename );
510
511             i_ret = func( p_this, psz_filename, L, user_data );
512
513             free( psz_filename );
514
515             if( i_ret == VLC_SUCCESS ) break;
516         }
517         if( i_ret == VLC_SUCCESS ) break;
518     }
519
520     if( ppsz_filelist )
521     {
522         for( ppsz_file = ppsz_filelist; ppsz_file < ppsz_fileend;
523              ppsz_file++ )
524             free( *ppsz_file );
525         free( ppsz_filelist );
526     }
527     for( ppsz_dir = ppsz_dir_list; *ppsz_dir; ppsz_dir++ )
528         free( *ppsz_dir );
529
530     return i_ret;
531 }
532
533
534 /*****************************************************************************
535  * Meta data setters utility.
536  * Playlist item table should be on top of the stack when these are called
537  *****************************************************************************/
538 void __vlclua_read_meta_data( vlc_object_t *p_this, lua_State *L,
539                               input_item_t *p_input )
540 {
541 #define TRY_META( a, b )                                        \
542     lua_getfield( L, -1, a );                                   \
543     if( lua_isstring( L, -1 ) )                                 \
544     {                                                           \
545         char *psz_value = strdup( lua_tostring( L, -1 ) );      \
546         EnsureUTF8( psz_value );                                \
547         msg_Dbg( p_this, #b ": %s", psz_value );                \
548         input_item_Set ## b ( p_input, psz_value );             \
549         free( psz_value );                                      \
550     }                                                           \
551     lua_pop( L, 1 ); /* pop a */
552     TRY_META( "title", Title );
553     TRY_META( "artist", Artist );
554     TRY_META( "genre", Genre );
555     TRY_META( "copyright", Copyright );
556     TRY_META( "album", Album );
557     TRY_META( "tracknum", TrackNum );
558     TRY_META( "description", Description );
559     TRY_META( "rating", Rating );
560     TRY_META( "date", Date );
561     TRY_META( "setting", Setting );
562     TRY_META( "url", URL );
563     TRY_META( "language", Language );
564     TRY_META( "nowplaying", NowPlaying );
565     TRY_META( "publisher", Publisher );
566     TRY_META( "encodedby", EncodedBy );
567     TRY_META( "arturl", ArtURL );
568     TRY_META( "trackid", TrackID );
569 }
570
571 void __vlclua_read_custom_meta_data( vlc_object_t *p_this, lua_State *L,
572                                      input_item_t *p_input )
573 {
574     /* ... item */
575     lua_getfield( L, -1, "meta" );
576     /* ... item meta */
577     if( lua_istable( L, -1 ) )
578     {
579         lua_pushnil( L );
580         /* ... item meta nil */
581         while( lua_next( L, -2 ) )
582         {
583             /* ... item meta key value */
584             if( !lua_isstring( L, -2 ) )
585             {
586                 msg_Warn( p_this, "Custom meta data category name must be "
587                                    "a string" );
588             }
589             else if( !lua_istable( L, -1 ) )
590             {
591                 msg_Warn( p_this, "Custom meta data category contents "
592                                    "must be a table" );
593             }
594             else
595             {
596                 const char *psz_meta_category = lua_tostring( L, -2 );
597                 msg_Dbg( p_this, "Found custom meta data category: %s",
598                          psz_meta_category );
599                 lua_pushnil( L );
600                 /* ... item meta key value nil */
601                 while( lua_next( L, -2 ) )
602                 {
603                     /* ... item meta key value key2 value2 */
604                     if( !lua_isstring( L, -2 ) )
605                     {
606                         msg_Warn( p_this, "Custom meta category item name "
607                                            "must be a string." );
608                     }
609                     else if( !lua_isstring( L, -1 ) )
610                     {
611                         msg_Warn( p_this, "Custom meta category item value "
612                                            "must be a string." );
613                     }
614                     else
615                     {
616                         const char *psz_meta_name =
617                             lua_tostring( L, -2 );
618                         const char *psz_meta_value =
619                             lua_tostring( L, -1 );
620                         msg_Dbg( p_this, "Custom meta %s, %s: %s",
621                                  psz_meta_category, psz_meta_name,
622                                  psz_meta_value );
623                         input_ItemAddInfo( p_input, psz_meta_category,
624                                            psz_meta_name, psz_meta_value );
625                     }
626                     lua_pop( L, 1 ); /* pop item */
627                     /* ... item meta key value key2 */
628                 }
629                 /* ... item meta key value */
630             }
631             lua_pop( L, 1 ); /* pop category */
632             /* ... item meta key */
633         }
634         /* ... item meta */
635     }
636     lua_pop( L, 1 ); /* pop "meta" */
637     /* ... item -> back to original stack */
638 }
639
640 /*****************************************************************************
641  * Playlist utilities
642  ****************************************************************************/
643 /**
644  * Playlist item table should be on top of the stack when this is called
645  */
646 void __vlclua_read_options( vlc_object_t *p_this, lua_State *L,
647                             int *pi_options, char ***pppsz_options )
648 {
649     lua_getfield( L, -1, "options" );
650     if( lua_istable( L, -1 ) )
651     {
652         lua_pushnil( L );
653         while( lua_next( L, -2 ) )
654         {
655             if( lua_isstring( L, -1 ) )
656             {
657                 char *psz_option = strdup( lua_tostring( L, -1 ) );
658                 msg_Dbg( p_this, "Option: %s", psz_option );
659                 INSERT_ELEM( *pppsz_options, *pi_options, *pi_options,
660                              psz_option );
661             }
662             else
663             {
664                 msg_Warn( p_this, "Option should be a string" );
665             }
666             lua_pop( L, 1 ); /* pop option */
667         }
668     }
669     lua_pop( L, 1 ); /* pop "options" */
670 }
671
672 int __vlclua_playlist_add_internal( vlc_object_t *p_this, lua_State *L,
673                                     playlist_t *p_playlist,
674                                     input_item_t *p_parent, bool b_play )
675 {
676     int i_count = 0;
677
678     assert( p_parent || p_playlist );
679
680     /* playlist */
681     if( lua_istable( L, -1 ) )
682     {
683         lua_pushnil( L );
684         /* playlist nil */
685         while( lua_next( L, -2 ) )
686         {
687             /* playlist key item */
688             /* <Parse playlist item> */
689             if( lua_istable( L, -1 ) )
690             {
691                 lua_getfield( L, -1, "path" );
692                 /* playlist key item path */
693                 if( lua_isstring( L, -1 ) )
694                 {
695                     const char   *psz_path     = NULL;
696                     const char   *psz_name     = NULL;
697                     char        **ppsz_options = NULL;
698                     int           i_options    = 0;
699                     mtime_t       i_duration   = -1;
700                     input_item_t *p_input;
701
702                     /* Read path and name */
703                     psz_path = lua_tostring( L, -1 );
704                     msg_Dbg( p_this, "Path: %s", psz_path );
705                     lua_getfield( L, -2, "name" );
706                     /* playlist key item path name */
707                     if( lua_isstring( L, -1 ) )
708                     {
709                         psz_name = lua_tostring( L, -1 );
710                         msg_Dbg( p_this, "Name: %s", psz_name );
711                     }
712                     else
713                     {
714                         if( !lua_isnil( L, -1 ) )
715                             msg_Warn( p_this, "Playlist item name should be a string." );
716                         psz_name = psz_path;
717                     }
718
719                     /* Read duration */
720                     lua_getfield( L, -3, "duration" );
721                     /* playlist key item path name duration */
722                     if( lua_isnumber( L, -1 ) )
723                     {
724                         i_duration = (mtime_t)(lua_tonumber( L, -1 )*1e6);
725                     }
726                     else if( !lua_isnil( L, -1 ) )
727                     {
728                         msg_Warn( p_this, "Playlist item duration should be a number (in seconds)." );
729                     }
730                     lua_pop( L, 1 ); /* pop "duration" */
731
732                     /* playlist key item path name */
733
734                     /* Read options: item must be on top of stack */
735                     lua_pushvalue( L, -3 );
736                     /* playlist key item path name item */
737                     vlclua_read_options( p_this, L, &i_options, &ppsz_options );
738
739                     /* Create input item */
740                     p_input = input_ItemNewExt( p_playlist, psz_path,
741                                                 psz_name, i_options,
742                                                 (const char **)ppsz_options,
743                                                 i_duration );
744                     lua_pop( L, 3 ); /* pop "path name item" */
745                     /* playlist key item */
746
747                     /* Read meta data: item must be on top of stack */
748                     vlclua_read_meta_data( p_this, L, p_input );
749
750                     /* Read custom meta data: item must be on top of stack*/
751                     vlclua_read_custom_meta_data( p_this, L, p_input );
752
753                     /* Append item to playlist */
754                     if( p_parent ) /* Add to node */
755                         input_ItemAddSubItem( p_parent, p_input );
756                     else /* Play or Enqueue (preparse) */
757                         /* FIXME: playlist_AddInput() can fail */
758                         playlist_AddInput( p_playlist, p_input,
759                                PLAYLIST_APPEND | 
760                                ( b_play ? PLAYLIST_GO : PLAYLIST_PREPARSE ),
761                                PLAYLIST_END, true, false );
762                     i_count ++; /* increment counter */
763                     vlc_gc_decref( p_input );
764                     while( i_options > 0 )
765                         free( ppsz_options[--i_options] );
766                     free( ppsz_options );
767                 }
768                 else
769                 {
770                     lua_pop( L, 1 ); /* pop "path" */
771                     msg_Warn( p_this,
772                              "Playlist item's path should be a string" );
773                 }
774                 /* playlist key item */
775             }
776             else
777             {
778                 msg_Warn( p_this, "Playlist item should be a table" );
779             }
780             /* <Parse playlist item> */
781             lua_pop( L, 1 ); /* pop the value, keep the key for
782                               * the next lua_next() call */
783             /* playlist key */
784         }
785         /* playlist */
786     }
787     else
788     {
789         msg_Warn( p_this, "Playlist should be a table." );
790     }
791     return i_count;
792 }