1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2007-2011 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea at videolan tod org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
35 #include <vlc_common.h>
37 #include <vlc_interface.h>
38 #include <vlc_playlist_legacy.h>
43 #include "variables.h"
46 void vlclua_set_playlist_internal( lua_State
*L
, playlist_t
*pl
)
48 vlclua_set_object( L
, vlclua_set_playlist_internal
, pl
);
51 playlist_t
*vlclua_get_playlist_internal( lua_State
*L
)
53 return vlclua_get_object( L
, vlclua_set_playlist_internal
);
56 static int vlclua_playlist_prev( lua_State
* L
)
58 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
59 playlist_Prev( p_playlist
);
63 static int vlclua_playlist_next( lua_State
* L
)
65 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
66 playlist_Next( p_playlist
);
70 static int vlclua_playlist_skip( lua_State
* L
)
72 int i_skip
= luaL_checkinteger( L
, 1 );
73 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
74 playlist_Skip( p_playlist
, i_skip
);
78 static int vlclua_playlist_play( lua_State
* L
)
80 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
81 playlist_Play( p_playlist
);
85 static int vlclua_playlist_pause( lua_State
* L
)
87 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
88 playlist_TogglePause( p_playlist
);
92 static int vlclua_playlist_stop( lua_State
* L
)
94 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
95 playlist_Stop( p_playlist
);
99 static int vlclua_playlist_clear( lua_State
* L
)
101 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
102 playlist_Stop( p_playlist
); /* Isn't this already implied by Clear? */
103 playlist_Clear( p_playlist
, pl_Unlocked
);
107 static int vlclua_playlist_repeat( lua_State
* L
)
109 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
110 int i_ret
= vlclua_var_toggle_or_set( L
, p_playlist
, "repeat" );
114 static int vlclua_playlist_loop( lua_State
* L
)
116 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
117 int i_ret
= vlclua_var_toggle_or_set( L
, p_playlist
, "loop" );
121 static int vlclua_playlist_random( lua_State
* L
)
123 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
124 int i_ret
= vlclua_var_toggle_or_set( L
, p_playlist
, "random" );
128 static int vlclua_playlist_gotoitem( lua_State
* L
)
130 int i_id
= luaL_checkinteger( L
, 1 );
131 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
133 playlist_ViewPlay( p_playlist
, NULL
,
134 playlist_ItemGetById( p_playlist
, i_id
) );
136 return vlclua_push_ret( L
, VLC_SUCCESS
);
139 static int vlclua_playlist_delete( lua_State
* L
)
141 int i_id
= luaL_checkinteger( L
, 1 );
142 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
145 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
, i_id
);
147 playlist_NodeDelete( p_playlist
, p_item
);
150 return vlclua_push_ret( L
, (p_item
!= NULL
) ? 0 : -1 );
153 static int vlclua_playlist_move( lua_State
* L
)
155 int i_item
= luaL_checkinteger( L
, 1 );
156 int i_target
= luaL_checkinteger( L
, 2 );
157 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
159 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
, i_item
);
160 playlist_item_t
*p_target
= playlist_ItemGetById( p_playlist
, i_target
);
161 if( !p_item
|| !p_target
)
164 return vlclua_push_ret( L
, -1 );
167 if( p_target
->i_children
!= -1 )
168 i_ret
= playlist_TreeMove( p_playlist
, p_item
, p_target
, 0 );
170 i_ret
= playlist_TreeMove( p_playlist
, p_item
, p_target
->p_parent
, p_target
->i_id
- p_target
->p_parent
->pp_children
[0]->i_id
+ 1 );
172 return vlclua_push_ret( L
, i_ret
);
175 static int vlclua_playlist_add_common(lua_State
*L
, bool play
)
177 vlc_object_t
*obj
= vlclua_get_this(L
);
178 playlist_t
*playlist
= vlclua_get_playlist_internal(L
);
182 if (!lua_istable(L
, -1))
184 msg_Warn(obj
, "Playlist should be a table.");
191 while (lua_next(L
, -2))
193 input_item_t
*item
= vlclua_read_input_item(obj
, L
);
196 /* Play or Enqueue (preparse) */
197 /* FIXME: playlist_AddInput() can fail */
198 playlist_AddInput(playlist
, item
, play
);
199 input_item_Release(item
);
202 /* pop the value, keep the key for the next lua_next() call */
207 lua_pushinteger(L
, count
);
211 static int vlclua_playlist_add( lua_State
*L
)
213 return vlclua_playlist_add_common(L
, true);
216 static int vlclua_playlist_enqueue( lua_State
*L
)
218 return vlclua_playlist_add_common(L
, false);
221 static void push_playlist_item( lua_State
*L
, playlist_item_t
*p_item
)
223 input_item_t
*p_input
= p_item
->p_input
;
225 i_flags
= p_item
->i_flags
;
227 lua_pushinteger( L
, p_item
->i_id
);
228 lua_setfield( L
, -2, "id" );
230 #define CHECK_AND_SET_FLAG( name, label ) \
231 if( i_flags & PLAYLIST_ ## name ## _FLAG ) \
233 lua_pushboolean( L, 1 ); \
234 lua_setfield( L, -2, #label ); \
236 CHECK_AND_SET_FLAG( DBL
, disabled
)
237 CHECK_AND_SET_FLAG( RO
, ro
)
238 #undef CHECK_AND_SET_FLAG
239 lua_setfield( L
, -2, "flags" );
242 /* Apart from nb_played, these fields unfortunately duplicate
243 fields already available from the input item */
244 char *psz_name
= input_item_GetTitleFbName( p_input
);
245 lua_pushstring( L
, psz_name
);
247 lua_setfield( L
, -2, "name" );
248 lua_pushstring( L
, p_input
->psz_uri
);
249 lua_setfield( L
, -2, "path" );
250 if( p_input
->i_duration
< 0 )
251 lua_pushnumber( L
, -1 );
253 lua_pushnumber( L
, secf_from_vlc_tick(p_input
->i_duration
) );
254 lua_setfield( L
, -2, "duration" );
255 lua_pushinteger( L
, p_item
->i_nb_played
);
256 lua_setfield( L
, -2, "nb_played" );
257 luaopen_input_item( L
, p_input
);
259 if( p_item
->i_children
>= 0 )
262 lua_createtable( L
, p_item
->i_children
, 0 );
263 for( i
= 0; i
< p_item
->i_children
; i
++ )
265 push_playlist_item( L
, p_item
->pp_children
[i
] );
266 lua_rawseti( L
, -2, i
+1 );
268 lua_setfield( L
, -2, "children" );
272 static int vlclua_playlist_get( lua_State
*L
)
274 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
276 playlist_item_t
*p_item
= NULL
;
278 if( lua_isnumber( L
, 1 ) )
280 int i_id
= lua_tointeger( L
, 1 );
281 p_item
= playlist_ItemGetById( p_playlist
, i_id
);
285 return 0; /* Should we return an error instead? */
288 else if( lua_isstring( L
, 1 ) )
290 const char *psz_what
= lua_tostring( L
, 1 );
291 if( !strcasecmp( psz_what
, "normal" )
292 || !strcasecmp( psz_what
, "playlist" ) )
293 p_item
= p_playlist
->p_playing
;
294 else if( !strcasecmp( psz_what
, "root" ) )
295 p_item
= &p_playlist
->root
;
298 /* currently, psz_what must be SD module's longname! */
299 p_item
= playlist_ChildSearchName( &p_playlist
->root
, psz_what
);
304 return 0; /* Should we return an error instead? */
310 p_item
= &p_playlist
->root
;
312 push_playlist_item( L
, p_item
);
317 static int vlclua_playlist_search( lua_State
*L
)
319 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
320 const char *psz_string
= luaL_optstring( L
, 1, "" );
322 playlist_LiveSearchUpdate( p_playlist
, &p_playlist
->root
, psz_string
, true );
323 push_playlist_item( L
, &p_playlist
->root
);
328 static int vlclua_playlist_current( lua_State
*L
)
330 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
331 playlist_item_t
*item
;
335 item
= playlist_CurrentPlayingItem( p_playlist
);
339 lua_pushinteger( L
, id
);
343 static int vlc_sort_key_from_string( const char *psz_name
)
347 const char *psz_name
;
351 { "title", SORT_TITLE
},
352 { "title nodes first", SORT_TITLE_NODES_FIRST
},
353 { "artist", SORT_ARTIST
},
354 { "genre", SORT_GENRE
},
355 { "random", SORT_RANDOM
},
356 { "duration", SORT_DURATION
},
357 { "title numeric", SORT_TITLE_NUMERIC
},
358 { "album", SORT_ALBUM
},
361 for( i
= 0; pp_keys
[i
].psz_name
; i
++ )
363 if( !strcmp( psz_name
, pp_keys
[i
].psz_name
) )
364 return pp_keys
[i
].i_key
;
369 static int vlclua_playlist_sort( lua_State
*L
)
371 /* allow setting the different sort keys */
372 int i_mode
= vlc_sort_key_from_string( luaL_checkstring( L
, 1 ) );
374 return luaL_error( L
, "Invalid search key." );
375 int i_type
= luaL_optboolean( L
, 2, 0 ) ? ORDER_REVERSE
: ORDER_NORMAL
;
376 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
378 int i_ret
= playlist_RecursiveNodeSort( p_playlist
, p_playlist
->p_playing
,
381 return vlclua_push_ret( L
, i_ret
);
384 static int vlclua_playlist_status( lua_State
*L
)
386 playlist_t
*p_playlist
= vlclua_get_playlist_internal( L
);
388 int status
= playlist_Status( p_playlist
);
392 case PLAYLIST_STOPPED
:
393 lua_pushliteral( L
, "stopped" );
395 case PLAYLIST_RUNNING
:
396 lua_pushliteral( L
, "playing" );
398 case PLAYLIST_PAUSED
:
399 lua_pushliteral( L
, "paused" );
402 lua_pushliteral( L
, "unknown" );
408 /*****************************************************************************
410 *****************************************************************************/
411 static const luaL_Reg vlclua_playlist_reg
[] = {
412 { "prev", vlclua_playlist_prev
},
413 { "next", vlclua_playlist_next
},
414 { "skip", vlclua_playlist_skip
},
415 { "play", vlclua_playlist_play
},
416 { "pause", vlclua_playlist_pause
},
417 { "stop", vlclua_playlist_stop
},
418 { "clear", vlclua_playlist_clear
},
419 { "repeat", vlclua_playlist_repeat
}, // repeat is a reserved lua keyword...
420 { "repeat_", vlclua_playlist_repeat
}, // ... provide repeat_ too.
421 { "loop", vlclua_playlist_loop
},
422 { "random", vlclua_playlist_random
},
423 #if LUA_VERSION_NUM < 502
424 { "goto", vlclua_playlist_gotoitem
},
426 { "gotoitem", vlclua_playlist_gotoitem
},
427 { "add", vlclua_playlist_add
},
428 { "enqueue", vlclua_playlist_enqueue
},
429 { "get", vlclua_playlist_get
},
430 { "search", vlclua_playlist_search
},
431 { "current", vlclua_playlist_current
},
432 { "sort", vlclua_playlist_sort
},
433 { "status", vlclua_playlist_status
},
434 { "delete", vlclua_playlist_delete
},
435 { "move", vlclua_playlist_move
},
439 void luaopen_playlist( lua_State
*L
)
442 luaL_register( L
, NULL
, vlclua_playlist_reg
);
443 lua_setfield( L
, -2, "playlist" );