]> git.sesse.net Git - vlc/blob - modules/misc/lua/vlc.c
Remove E_()
[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/vlc.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( _("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( _("Lua Playlist") );
69         set_description( _("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( _("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, vlclua_get_this( L )->p_libvlc->psz_homedir );
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 #       ifdef WIN32
429         if( asprintf( &ppsz_dir_list[i], "%s" DIR_SEP "scripts" DIR_SEP "%s",
430                       psz_vlcpath, luadirname )  < 0 )
431             return VLC_ENOMEM;
432         i++;
433 #       else
434          if( asprintf( &ppsz_dir_list[i], "%s" DIR_SEP "share" DIR_SEP "lua" DIR_SEP "%s",
435                       psz_vlcpath, luadirname )  < 0 )
436             return VLC_ENOMEM;
437         i++;
438 #       endif
439
440     }
441 #   else
442     if( asprintf( &ppsz_dir_list[i],
443                   "share" DIR_SEP "lua" DIR_SEP "%s", luadirname ) < 0 )
444         return VLC_ENOMEM;
445
446 #   ifdef HAVE_SYS_STAT_H
447     {
448         struct stat stat_info;
449         if( ( utf8_stat( ppsz_dir_list[i], &stat_info ) == -1 )
450             || !S_ISDIR( stat_info.st_mode ) )
451         {
452             free(ppsz_dir_list[i]);
453             if( asprintf( &ppsz_dir_list[i], "%s" DIR_SEP "lua" DIR_SEP "%s",
454                           config_GetDataDir (), luadirname ) < 0 )
455                 return VLC_ENOMEM;
456         }
457     }
458 #   endif
459     i++;
460 #   endif
461     return VLC_SUCCESS;
462 }
463
464 /*****************************************************************************
465  * Will execute func on all scripts in luadirname, and stop if func returns
466  * success.
467  *****************************************************************************/
468 int vlclua_scripts_batch_execute( vlc_object_t *p_this,
469                                   const char * luadirname,
470                                   int (*func)(vlc_object_t *, const char *, lua_State *, void *),
471                                   lua_State * L,
472                                   void * user_data)
473 {
474     int i_ret = VLC_EGENERIC;
475
476     char **ppsz_filelist = NULL;
477     char **ppsz_fileend  = NULL;
478     char **ppsz_file;
479
480     char  *ppsz_dir_list[] = { NULL, NULL, NULL, NULL };
481     char **ppsz_dir;
482
483     i_ret = vlclua_dir_list( p_this, luadirname, ppsz_dir_list );
484     if( i_ret != VLC_SUCCESS )
485         return i_ret;
486     i_ret = VLC_EGENERIC;
487
488
489     for( ppsz_dir = ppsz_dir_list; *ppsz_dir; ppsz_dir++ )
490     {
491         int i_files;
492
493         if( ppsz_filelist )
494         {
495             for( ppsz_file = ppsz_filelist; ppsz_file < ppsz_fileend;
496                  ppsz_file++ )
497                 free( *ppsz_file );
498             free( ppsz_filelist );
499             ppsz_filelist = NULL;
500         }
501
502         msg_Dbg( p_this, "Trying Lua scripts in %s", *ppsz_dir );
503         i_files = utf8_scandir( *ppsz_dir, &ppsz_filelist, file_select,
504                                 file_compare );
505         if( i_files < 1 ) continue;
506         ppsz_fileend = ppsz_filelist + i_files;
507
508         for( ppsz_file = ppsz_filelist; ppsz_file < ppsz_fileend; ppsz_file++ )
509         {
510             char  *psz_filename;
511             if( asprintf( &psz_filename,
512                           "%s" DIR_SEP "%s", *ppsz_dir, *ppsz_file ) < 0)
513                 return VLC_ENOMEM;
514             msg_Dbg( p_this, "Trying Lua playlist script %s", psz_filename );
515
516             i_ret = func( p_this, psz_filename, L, user_data );
517
518             free( psz_filename );
519
520             if( i_ret == VLC_SUCCESS ) break;
521         }
522         if( i_ret == VLC_SUCCESS ) break;
523     }
524
525     if( ppsz_filelist )
526     {
527         for( ppsz_file = ppsz_filelist; ppsz_file < ppsz_fileend;
528              ppsz_file++ )
529             free( *ppsz_file );
530         free( ppsz_filelist );
531     }
532     for( ppsz_dir = ppsz_dir_list; *ppsz_dir; ppsz_dir++ )
533         free( *ppsz_dir );
534
535     return i_ret;
536 }
537
538
539 /*****************************************************************************
540  * Meta data setters utility.
541  * Playlist item table should be on top of the stack when these are called
542  *****************************************************************************/
543 void __vlclua_read_meta_data( vlc_object_t *p_this, lua_State *L,
544                               input_item_t *p_input )
545 {
546 #define TRY_META( a, b )                                        \
547     lua_getfield( L, -1, a );                                   \
548     if( lua_isstring( L, -1 ) )                                 \
549     {                                                           \
550         char *psz_value = strdup( lua_tostring( L, -1 ) );      \
551         EnsureUTF8( psz_value );                                \
552         msg_Dbg( p_this, #b ": %s", psz_value );                \
553         input_item_Set ## b ( p_input, psz_value );             \
554         free( psz_value );                                      \
555     }                                                           \
556     lua_pop( L, 1 ); /* pop a */
557     TRY_META( "title", Title );
558     TRY_META( "artist", Artist );
559     TRY_META( "genre", Genre );
560     TRY_META( "copyright", Copyright );
561     TRY_META( "album", Album );
562     TRY_META( "tracknum", TrackNum );
563     TRY_META( "description", Description );
564     TRY_META( "rating", Rating );
565     TRY_META( "date", Date );
566     TRY_META( "setting", Setting );
567     TRY_META( "url", URL );
568     TRY_META( "language", Language );
569     TRY_META( "nowplaying", NowPlaying );
570     TRY_META( "publisher", Publisher );
571     TRY_META( "encodedby", EncodedBy );
572     TRY_META( "arturl", ArtURL );
573     TRY_META( "trackid", TrackID );
574 }
575
576 void __vlclua_read_custom_meta_data( vlc_object_t *p_this, lua_State *L,
577                                      input_item_t *p_input )
578 {
579     /* ... item */
580     lua_getfield( L, -1, "meta" );
581     /* ... item meta */
582     if( lua_istable( L, -1 ) )
583     {
584         lua_pushnil( L );
585         /* ... item meta nil */
586         while( lua_next( L, -2 ) )
587         {
588             /* ... item meta key value */
589             if( !lua_isstring( L, -2 ) )
590             {
591                 msg_Warn( p_this, "Custom meta data category name must be "
592                                    "a string" );
593             }
594             else if( !lua_istable( L, -1 ) )
595             {
596                 msg_Warn( p_this, "Custom meta data category contents "
597                                    "must be a table" );
598             }
599             else
600             {
601                 const char *psz_meta_category = lua_tostring( L, -2 );
602                 msg_Dbg( p_this, "Found custom meta data category: %s",
603                          psz_meta_category );
604                 lua_pushnil( L );
605                 /* ... item meta key value nil */
606                 while( lua_next( L, -2 ) )
607                 {
608                     /* ... item meta key value key2 value2 */
609                     if( !lua_isstring( L, -2 ) )
610                     {
611                         msg_Warn( p_this, "Custom meta category item name "
612                                            "must be a string." );
613                     }
614                     else if( !lua_isstring( L, -1 ) )
615                     {
616                         msg_Warn( p_this, "Custom meta category item value "
617                                            "must be a string." );
618                     }
619                     else
620                     {
621                         const char *psz_meta_name =
622                             lua_tostring( L, -2 );
623                         const char *psz_meta_value =
624                             lua_tostring( L, -1 );
625                         msg_Dbg( p_this, "Custom meta %s, %s: %s",
626                                  psz_meta_category, psz_meta_name,
627                                  psz_meta_value );
628                         input_ItemAddInfo( p_input, psz_meta_category,
629                                            psz_meta_name, psz_meta_value );
630                     }
631                     lua_pop( L, 1 ); /* pop item */
632                     /* ... item meta key value key2 */
633                 }
634                 /* ... item meta key value */
635             }
636             lua_pop( L, 1 ); /* pop category */
637             /* ... item meta key */
638         }
639         /* ... item meta */
640     }
641     lua_pop( L, 1 ); /* pop "meta" */
642     /* ... item -> back to original stack */
643 }
644
645 /*****************************************************************************
646  * Playlist utilities
647  ****************************************************************************/
648 /**
649  * Playlist item table should be on top of the stack when this is called
650  */
651 void __vlclua_read_options( vlc_object_t *p_this, lua_State *L,
652                             int *pi_options, char ***pppsz_options )
653 {
654     lua_getfield( L, -1, "options" );
655     if( lua_istable( L, -1 ) )
656     {
657         lua_pushnil( L );
658         while( lua_next( L, -2 ) )
659         {
660             if( lua_isstring( L, -1 ) )
661             {
662                 char *psz_option = strdup( lua_tostring( L, -1 ) );
663                 msg_Dbg( p_this, "Option: %s", psz_option );
664                 INSERT_ELEM( *pppsz_options, *pi_options, *pi_options,
665                              psz_option );
666             }
667             else
668             {
669                 msg_Warn( p_this, "Option should be a string" );
670             }
671             lua_pop( L, 1 ); /* pop option */
672         }
673     }
674     lua_pop( L, 1 ); /* pop "options" */
675 }
676
677 int __vlclua_playlist_add_internal( vlc_object_t *p_this, lua_State *L,
678                                     playlist_t *p_playlist,
679                                     input_item_t *p_parent, bool b_play )
680 {
681     int i_count = 0;
682
683     /* playlist */
684     if( lua_istable( L, -1 ) )
685     {
686         lua_pushnil( L );
687         /* playlist nil */
688         while( lua_next( L, -2 ) )
689         {
690             /* playlist key item */
691             /* <Parse playlist item> */
692             if( lua_istable( L, -1 ) )
693             {
694                 lua_getfield( L, -1, "path" );
695                 /* playlist key item path */
696                 if( lua_isstring( L, -1 ) )
697                 {
698                     const char   *psz_path     = NULL;
699                     const char   *psz_name     = NULL;
700                     char        **ppsz_options = NULL;
701                     int           i_options    = 0;
702                     mtime_t       i_duration   = -1;
703                     input_item_t *p_input;
704
705                     /* Read path and name */
706                     psz_path = lua_tostring( L, -1 );
707                     msg_Dbg( p_this, "Path: %s", psz_path );
708                     lua_getfield( L, -2, "name" );
709                     /* playlist key item path name */
710                     if( lua_isstring( L, -1 ) )
711                     {
712                         psz_name = lua_tostring( L, -1 );
713                         msg_Dbg( p_this, "Name: %s", psz_name );
714                     }
715                     else
716                     {
717                         if( !lua_isnil( L, -1 ) )
718                             msg_Warn( p_this, "Playlist item name should be a string." );
719                         psz_name = psz_path;
720                     }
721
722                     /* Read duration */
723                     lua_getfield( L, -3, "duration" );
724                     /* playlist key item path name duration */
725                     if( lua_isnumber( L, -1 ) )
726                     {
727                         i_duration = (mtime_t)(lua_tonumber( L, -1 )*1e6);
728                     }
729                     else if( !lua_isnil( L, -1 ) )
730                     {
731                         msg_Warn( p_this, "Playlist item duration should be a number (in seconds)." );
732                     }
733                     lua_pop( L, 1 ); /* pop "duration" */
734
735                     /* playlist key item path name */
736
737                     /* Read options: item must be on top of stack */
738                     lua_pushvalue( L, -3 );
739                     /* playlist key item path name item */
740                     vlclua_read_options( p_this, L, &i_options, &ppsz_options );
741
742                     /* Create input item */
743                     p_input = input_ItemNewExt( p_playlist, psz_path,
744                                                 psz_name, i_options,
745                                                 (const char **)ppsz_options,
746                                                 i_duration );
747                     lua_pop( L, 3 ); /* pop "path name item" */
748                     /* playlist key item */
749
750                     /* Read meta data: item must be on top of stack */
751                     vlclua_read_meta_data( p_this, L, p_input );
752
753                     /* Read custom meta data: item must be on top of stack*/
754                     vlclua_read_custom_meta_data( p_this, L, p_input );
755
756                     /* Append item to playlist */
757                     if( p_parent ) /* Add to node */
758                         input_ItemAddSubItem( p_parent, p_input );
759                     else /* Play or Enqueue (preparse) */
760                         /* FIXME: playlist_AddInput() can fail */
761                         playlist_AddInput( p_playlist, p_input,
762                                PLAYLIST_APPEND | 
763                                ( b_play ? PLAYLIST_GO : PLAYLIST_PREPARSE ),
764                                PLAYLIST_END, true, false );
765                     i_count ++; /* increment counter */
766                     vlc_gc_decref( p_input );
767                     while( i_options > 0 )
768                         free( ppsz_options[--i_options] );
769                     free( ppsz_options );
770                 }
771                 else
772                 {
773                     lua_pop( L, 1 ); /* pop "path" */
774                     msg_Warn( p_this,
775                              "Playlist item's path should be a string" );
776                 }
777                 /* playlist key item */
778             }
779             else
780             {
781                 msg_Warn( p_this, "Playlist item should be a table" );
782             }
783             /* <Parse playlist item> */
784             lua_pop( L, 1 ); /* pop the value, keep the key for
785                               * the next lua_next() call */
786             /* playlist key */
787         }
788         /* playlist */
789     }
790     else
791     {
792         msg_Warn( p_this, "Playlist should be a table." );
793     }
794     return i_count;
795 }