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