]> git.sesse.net Git - vlc/blobdiff - modules/misc/lua/intf.c
Don't include config.h from the headers - refs #297.
[vlc] / modules / misc / lua / intf.c
index 01d36a9e95624a7704f11138f4c3fd267c3703af..48dee622c94361cdf1f4e351034af3fb95b5f426 100644 (file)
 #   define  _GNU_SOURCE
 #endif
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include <vlc/vlc.h>
 #include <vlc_meta.h>
 #include <vlc_charset.h>
@@ -53,7 +57,7 @@ struct intf_sys_t
 /*****************************************************************************
  * Internal lua<->vlc utils
  *****************************************************************************/
-static inline playlist_t *vlclua_get_playlist_internal( lua_State *L )
+playlist_t *vlclua_get_playlist_internal( lua_State *L )
 {
     vlc_object_t *p_this = vlclua_get_this( L );
     return pl_Yield( p_this );
@@ -122,7 +126,7 @@ static int vlclua_input_info( lua_State *L )
     int i_cat;
     int i;
     if( !p_input ) return vlclua_error( L );
-    vlc_mutex_lock( &input_GetItem(p_input)->lock );
+    //vlc_mutex_lock( &input_GetItem(p_input)->lock );
     i_cat = input_GetItem(p_input)->i_categories;
     lua_createtable( L, 0, i_cat );
     for( i = 0; i < i_cat; i++ )
@@ -141,7 +145,7 @@ static int vlclua_input_info( lua_State *L )
         }
         lua_settable( L, -3 );
     }
-    vlc_object_release( p_input );
+    //vlc_object_release( p_input );
     return 1;
 }
 
@@ -165,6 +169,36 @@ static int vlclua_get_title( lua_State *L )
     return 1;
 }
 
+static int vlclua_input_stats( lua_State *L )
+{
+    input_thread_t *p_input = vlclua_get_input_internal( L );
+    input_item_t *p_item = p_input && p_input->p ? input_GetItem( p_input ) : NULL;
+    lua_newtable( L );
+    if( p_item )
+    {
+#define STATS_INT( n ) lua_pushinteger( L, p_item->p_stats->i_ ## n ); \
+                       lua_setfield( L, -2, #n );
+#define STATS_FLOAT( n ) lua_pushnumber( L, p_item->p_stats->f_ ## n ); \
+                         lua_setfield( L, -2, #n );
+        STATS_INT( read_bytes )
+        STATS_FLOAT( input_bitrate )
+        STATS_INT( demux_read_bytes )
+        STATS_FLOAT( demux_bitrate )
+        STATS_INT( decoded_video )
+        STATS_INT( displayed_pictures )
+        STATS_INT( lost_pictures )
+        STATS_INT( decoded_audio )
+        STATS_INT( played_abuffers )
+        STATS_INT( lost_abuffers )
+        STATS_INT( sent_packets )
+        STATS_INT( sent_bytes )
+        STATS_FLOAT( send_bitrate )
+#undef STATS_INT
+#undef STATS_FLOAT
+    }
+    return 1;
+}
+
 /*****************************************************************************
  * Vout control
  *****************************************************************************/
@@ -325,6 +359,15 @@ static int vlclua_playlist_next( lua_State * L )
     return 0;
 }
 
+static int vlclua_playlist_skip( lua_State * L )
+{
+    int i_skip = luaL_checkint( L, 1 );
+    playlist_t *p_playlist = vlclua_get_playlist_internal( L );
+    playlist_Skip( p_playlist, i_skip );
+    vlc_object_release( p_playlist );
+    return 0;
+}
+
 static int vlclua_playlist_play( lua_State * L )
 {
     playlist_t *p_playlist = vlclua_get_playlist_internal( L );
@@ -333,6 +376,14 @@ static int vlclua_playlist_play( lua_State * L )
     return 0;
 }
 
+static int vlclua_playlist_pause( lua_State * L )
+{
+    playlist_t *p_playlist = vlclua_get_playlist_internal( L );
+    playlist_Pause( p_playlist );
+    vlc_object_release( p_playlist );
+    return 0;
+}
+
 static int vlclua_playlist_stop( lua_State * L )
 {
     playlist_t *p_playlist = vlclua_get_playlist_internal( L );
@@ -376,37 +427,14 @@ static int vlclua_playlist_random( lua_State * L )
 
 static int vlclua_playlist_goto( lua_State * L )
 {
-    /* XXX: logic copied from rc.c ... i'm not sure that it's ok as it
-     *      implies knowledge of the playlist internals. */
-    playlist_t *p_playlist;
-    int i_size;
-    playlist_item_t *p_item, *p_parent;
-
-    int i_pos;
-    if( lua_gettop( L ) != 1 ) return vlclua_error( L );
-    i_pos = luaL_checkint( L, -1 );
-    lua_pop( L, 1 );
-    if( i_pos <= 0 ) return 0;
-
-    p_playlist = vlclua_get_playlist_internal( L );
-    /* The playlist stores 2 times the same item: onelevel & category */
-    i_size = p_playlist->items.i_size / 2;
-
-    if( i_pos > i_size )
-    {
-        vlc_object_release( p_playlist );
-        return 0;
-    }
-
-    p_item = p_parent = p_playlist->items.p_elems[i_pos*2-1];
-    while( p_parent->p_parent )
-        p_parent = p_parent->p_parent;
-    playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, VLC_TRUE,
-                      p_parent, p_item );
-
+    int i_id = luaL_checkint( L, 1 );
+    playlist_t *p_playlist = vlclua_get_playlist_internal( L );
+    int i_ret = playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
+                                  VLC_TRUE, NULL,
+                                  playlist_ItemGetById( p_playlist, i_id,
+                                                        VLC_TRUE ) );
     vlc_object_release( p_playlist );
-    lua_pushboolean( L, 1 );
-    return 1;
+    return vlclua_push_ret( L, i_ret );
 }
 
 static int vlclua_playlist_add( lua_State *L )
@@ -433,42 +461,171 @@ static int vlclua_playlist_enqueue( lua_State *L )
     return 1;
 }
 
-static int vlclua_playlist_get( lua_State *L )
+static void push_playlist_item( lua_State *L, playlist_item_t *p_item );
+static void push_playlist_item( lua_State *L, playlist_item_t *p_item )
 {
-    /* TODO: make it possible to get the tree playlist */
-    playlist_t *p_playlist = vlclua_get_playlist_internal( L );
-    playlist_item_t *p_root;
-    int i;
-    if( lua_isboolean( L, 1 ) && lua_toboolean( L, 1 ) )
-        p_root = p_playlist->p_ml_onelevel; /* media library */
-    else
-        p_root = p_playlist->p_local_onelevel; /* local/normal playlist */
-    lua_createtable( L, p_root->i_children, 0 );
-    for( i = 0; i < p_root->i_children; i++ )
+    input_item_t *p_input = p_item->p_input;
+    int i_flags = p_item->i_flags;
+    lua_newtable( L );
+    lua_pushinteger( L, p_item->i_id );
+    lua_setfield( L, -2, "id" );
+    lua_newtable( L );
+#define CHECK_AND_SET_FLAG( name, label ) \
+    if( i_flags & PLAYLIST_ ## name ## _FLAG ) \
+    { \
+        lua_pushboolean( L, 1 ); \
+        lua_setfield( L, -2, #label ); \
+    }
+    CHECK_AND_SET_FLAG( SAVE, save )
+    CHECK_AND_SET_FLAG( SKIP, skip )
+    CHECK_AND_SET_FLAG( DBL, disabled )
+    CHECK_AND_SET_FLAG( RO, ro )
+    CHECK_AND_SET_FLAG( REMOVE, remove )
+    CHECK_AND_SET_FLAG( EXPANDED, expanded )
+#undef CHECK_AND_SET_FLAG
+    lua_setfield( L, -2, "flags" );
+    if( p_input )
     {
-        playlist_item_t *p_item = p_root->pp_children[i];
-        input_item_t *p_input = p_item->p_input;
-        lua_pushinteger( L, i+1 );
-        lua_newtable( L );
         lua_pushstring( L, p_input->psz_name );
         lua_setfield( L, -2, "name" );
         lua_pushstring( L, p_input->psz_uri );
         lua_setfield( L, -2, "path" );
-        lua_pushnumber( L, ((double)p_input->i_duration)*1e-6 );
+        if( p_input->i_duration < 0 )
+            lua_pushnumber( L, -1 );
+        else
+            lua_pushnumber( L, ((double)p_input->i_duration)*1e-6 );
         lua_setfield( L, -2, "duration" );
         lua_pushinteger( L, p_input->i_nb_played );
         lua_setfield( L, -2, "nb_played" );
         /* TODO: add (optional) info categories, meta, options, es */
-        lua_settable( L, -3 );
     }
+    if( p_item->i_children >= 0 )
+    {
+        int i;
+        lua_createtable( L, p_item->i_children, 0 );
+        for( i = 0; i < p_item->i_children; i++ )
+        {
+            push_playlist_item( L, p_item->pp_children[i] );
+            lua_rawseti( L, -2, i+1 );
+        }
+        lua_setfield( L, -2, "children" );
+    }
+}
+
+static int vlclua_playlist_get( lua_State *L )
+{
+    playlist_t *p_playlist = vlclua_get_playlist_internal( L );
+    int b_category = luaL_optboolean( L, 2, 1 ); /* Default to tree playlist (discared when 1st argument is a playlist_item's id) */
+    playlist_item_t *p_item = NULL;
+
+    if( lua_isnumber( L, 1 ) )
+    {
+        int i_id = lua_tointeger( L, 1 );
+        p_item = playlist_ItemGetById( p_playlist, i_id, VLC_TRUE );
+        if( !p_item )
+        {
+            vlc_object_release( p_playlist );
+            return 0; /* Should we return an error instead? */
+        }
+    }
+    else if( lua_isstring( L, 1 ) )
+    {
+        const char *psz_what = lua_tostring( L, 1 );
+        if( !strcasecmp( psz_what, "normal" )
+         || !strcasecmp( psz_what, "playlist" ) )
+            p_item = b_category ? p_playlist->p_local_category
+                                : p_playlist->p_local_onelevel;
+        else if( !strcasecmp( psz_what, "ml" )
+              || !strcasecmp( psz_what, "media library" ) )
+            p_item = b_category ? p_playlist->p_ml_category
+                                : p_playlist->p_ml_onelevel;
+        else if( !strcasecmp( psz_what, "root" ) )
+            p_item = b_category ? p_playlist->p_root_category
+                                : p_playlist->p_root_onelevel;
+        else
+        {
+            int i;
+            for( i = 0; i < p_playlist->i_sds; i++ )
+            {
+                if( !strcasecmp( psz_what,
+                                 p_playlist->pp_sds[i]->p_sd->psz_module ) )
+                {
+                    p_item = b_category ? p_playlist->pp_sds[i]->p_cat
+                                        : p_playlist->pp_sds[i]->p_one;
+                    break;
+                }
+            }
+            if( !p_item )
+            {
+                vlc_object_release( p_playlist );
+                return 0; /* Should we return an error instead? */
+            }
+        }
+    }
+    else
+    {
+        p_item = b_category ? p_playlist->p_root_category
+                            : p_playlist->p_root_onelevel;
+    }
+    push_playlist_item( L, p_item );
+    vlc_object_release( p_playlist );
+    return 1;
+}
+
+static int vlclua_playlist_search( lua_State *L )
+{
+    playlist_t *p_playlist = vlclua_get_playlist_internal( L );
+    const char *psz_string = luaL_optstring( L, 1, "" );
+    int b_category = luaL_optboolean( L, 2, 1 ); /* default to category */
+    playlist_item_t *p_item = b_category ? p_playlist->p_root_category
+                                         : p_playlist->p_root_onelevel;
+    playlist_LiveSearchUpdate( p_playlist, p_item, psz_string );
+    push_playlist_item( L, p_item );
     vlc_object_release( p_playlist );
     return 1;
 }
 
+static int vlc_sort_key_from_string( const char *psz_name )
+{
+    static const struct
+    {
+        const char *psz_name;
+        int i_key;
+    } pp_keys[] =
+        { { "id", SORT_ID },
+          { "title", SORT_TITLE },
+          { "title nodes first", SORT_TITLE_NODES_FIRST },
+          { "artist", SORT_ARTIST },
+          { "genre", SORT_GENRE },
+          { "random", SORT_RANDOM },
+          { "duration", SORT_DURATION },
+          { "title numeric", SORT_TITLE_NUMERIC },
+          { "album", SORT_ALBUM },
+          { NULL, -1 } };
+    int i;
+    for( i = 0; pp_keys[i].psz_name; i++ )
+    {
+        if( !strcmp( psz_name, pp_keys[i].psz_name ) )
+            return pp_keys[i].i_key;
+    }
+    return -1;
+}
+
 static int vlclua_playlist_sort( lua_State *L )
 {
     /* allow setting the different sort keys */
-    return 0;
+    int i_mode = vlc_sort_key_from_string( luaL_checkstring( L, 1 ) );
+    if( i_mode == -1 )
+        return luaL_error( L, "Invalid search key." );
+    int i_type = luaL_optboolean( L, 2, 0 ) ? ORDER_REVERSE : ORDER_NORMAL;
+    int b_category = luaL_optboolean( L, 3, 1 ); /* default to category */
+    playlist_t *p_playlist = vlclua_get_playlist_internal( L );
+    playlist_item_t *p_root = b_category ? p_playlist->p_local_category
+                                         : p_playlist->p_local_onelevel;
+    int i_ret = playlist_RecursiveNodeSort( p_playlist, p_root, i_mode,
+                                            i_type );
+    vlc_object_release( p_playlist );
+    return vlclua_push_ret( L, i_ret );
 }
 
 /* FIXME: split this in 3 different functions? */
@@ -476,15 +633,16 @@ static int vlclua_playlist_status( lua_State *L )
 {
     intf_thread_t *p_intf = (intf_thread_t *)vlclua_get_this( L );
     playlist_t *p_playlist = pl_Yield( p_intf );
+    /*
     int i_count = 0;
-    lua_settop( L, 0 );
+    lua_settop( L, 0 );*/
     if( p_playlist->p_input )
     {
-        char *psz_uri =
+        /*char *psz_uri =
             input_item_GetURI( input_GetItem( p_playlist->p_input ) );
         lua_pushstring( L, psz_uri );
         free( psz_uri );
-        lua_pushnumber( L, config_GetInt( p_intf, "volume" ) );
+        lua_pushnumber( L, config_GetInt( p_intf, "volume" ) );*/
         vlc_mutex_lock( &p_playlist->object_lock );
         switch( p_playlist->status.i_status )
         {
@@ -492,7 +650,7 @@ static int vlclua_playlist_status( lua_State *L )
                 lua_pushstring( L, "stopped" );
                 break;
             case PLAYLIST_RUNNING:
-                lua_pushstring( L, "running" );
+                lua_pushstring( L, "playing" );
                 break;
             case PLAYLIST_PAUSED:
                 lua_pushstring( L, "paused" );
@@ -502,10 +660,14 @@ static int vlclua_playlist_status( lua_State *L )
                 break;
         }
         vlc_mutex_unlock( &p_playlist->object_lock );
-        i_count += 3;
+        /*i_count += 3;*/
+    }
+    else
+    {
+        lua_pushstring( L, "stopped" );
     }
     vlc_object_release( p_playlist );
-    return i_count;
+    return 1;
 }
 
 
@@ -552,14 +714,23 @@ static luaL_Reg p_reg[] =
 
     { "decode_uri", vlclua_decode_uri },
     { "resolve_xml_special_chars", vlclua_resolve_xml_special_chars },
+    { "convert_xml_special_chars", vlclua_convert_xml_special_chars },
 
     { "lock_and_wait", vlclua_lock_and_wait },
     { "signal", vlclua_signal },
 
     { "version", vlclua_version },
+    { "license", vlclua_license },
+    { "copyright", vlclua_copyright },
     { "should_die", vlclua_intf_should_die },
     { "quit", vlclua_quit },
 
+    { "homedir", vlclua_homedir },
+    { "datadir", vlclua_datadir },
+    { "configdir", vlclua_configdir },
+    { "cachedir", vlclua_cachedir },
+    { "datadir_list", vlclua_datadir_list },
+
     { NULL, NULL }
 };
 
@@ -608,7 +779,9 @@ static luaL_Reg p_reg_playlist[] =
 {
     { "prev", vlclua_playlist_prev },
     { "next", vlclua_playlist_next },
+    { "skip", vlclua_playlist_skip },
     { "play", vlclua_playlist_play },
+    { "pause", vlclua_playlist_pause },
     { "stop", vlclua_playlist_stop },
     { "clear", vlclua_playlist_clear },
     { "repeat_", vlclua_playlist_repeat },
@@ -619,6 +792,20 @@ static luaL_Reg p_reg_playlist[] =
     { "add", vlclua_playlist_add },
     { "enqueue", vlclua_playlist_enqueue },
     { "get", vlclua_playlist_get },
+    { "search", vlclua_playlist_search },
+    { "sort", vlclua_playlist_sort },
+
+    { "stats", vlclua_input_stats },
+
+    { NULL, NULL }
+};
+
+static luaL_Reg p_reg_sd[] =
+{
+    { "get_services_names", vlclua_sd_get_services_names },
+    { "add", vlclua_sd_add },
+    { "remove", vlclua_sd_remove },
+    { "is_loaded", vlclua_sd_is_loaded },
 
     { NULL, NULL }
 };
@@ -663,6 +850,9 @@ static luaL_Reg p_reg_fd[] =
 /*    { "open", vlclua_fd_open },*/
     { "read", vlclua_fd_read },
     { "write", vlclua_fd_write },
+    { "stat", vlclua_stat },
+
+    { "opendir", vlclua_opendir },
 
     { "new_fd_set", vlclua_fd_set_new },
     { "fd_clr", vlclua_fd_clr },
@@ -682,6 +872,32 @@ static luaL_Reg p_reg_vlm[] =
     { NULL, NULL }
 };
 
+static luaL_Reg p_reg_httpd[] =
+{
+    { "host_new", vlclua_httpd_tls_host_new },
+    { "host_delete", vlclua_httpd_host_delete },
+    { "handler_new", vlclua_httpd_handler_new },
+    { "handler_delete", vlclua_httpd_handler_delete },
+    { "file_new", vlclua_httpd_file_new },
+    { "file_delete", vlclua_httpd_file_delete },
+    { "redirect_new", vlclua_httpd_redirect_new },
+    { "redirect_delete", vlclua_httpd_redirect_delete },
+
+    { NULL, NULL }
+};
+
+static luaL_Reg p_reg_acl[] =
+{
+    { "create", vlclua_acl_create },
+    { "delete", vlclua_acl_delete },
+    { "check", vlclua_acl_check },
+    { "duplicate", vlclua_acl_duplicate },
+    { "add_host", vlclua_acl_add_host },
+    { "add_net", vlclua_acl_add_net },
+    { "load_file", vlclua_acl_load_file },
+
+    { NULL, NULL }
+};
 
 static void Run( intf_thread_t *p_intf );
 
@@ -729,6 +945,8 @@ static struct
     /* { "hotkeys", "hotkeys" }, */
     { "luatelnet", "telnet" },
     /* { "telnet", "telnet" }, */
+    { "luahttp", "http" },
+    /* { "http", "http" }, */
     { NULL, NULL } };
 
 static vlc_bool_t WordInList( const char *psz_list, const char *psz_word )
@@ -811,11 +1029,14 @@ int E_(Open_LuaIntf)( vlc_object_t *p_this )
     luaL_register_submodule( L, "config", p_reg_config );
     luaL_register_submodule( L, "msg", p_reg_msg );
     luaL_register_submodule( L, "playlist", p_reg_playlist );
+    luaL_register_submodule( L, "sd", p_reg_sd );
     luaL_register_submodule( L, "volume", p_reg_volume );
     luaL_register_submodule( L, "osd", p_reg_osd );
     luaL_register_submodule( L, "net", p_reg_net );
     luaL_register_submodule( L, "fd", p_reg_fd );
     luaL_register_submodule( L, "vlm", p_reg_vlm );
+    luaL_register_submodule( L, "httpd", p_reg_httpd );
+    luaL_register_submodule( L, "acl", p_reg_acl );
     /* clean up */
     lua_pop( L, 1 );