You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
617 lines
17 KiB
617 lines
17 KiB
/*****************************************************************************
|
|
* playlist.c
|
|
*****************************************************************************
|
|
* Copyright (C) 2007-2011 the VideoLAN team
|
|
*
|
|
* Authors: Antoine Cellerier <dionoea at videolan tod org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Preamble
|
|
*****************************************************************************/
|
|
#ifndef _GNU_SOURCE
|
|
# define _GNU_SOURCE
|
|
#endif
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <vlc_common.h>
|
|
|
|
#include <vlc_interface.h>
|
|
#include <vlc_playlist.h>
|
|
#include <vlc_player.h>
|
|
|
|
#include "../vlc.h"
|
|
#include "../libs.h"
|
|
#include "input.h"
|
|
#include "variables.h"
|
|
#include "misc.h"
|
|
|
|
void vlclua_set_playlist_internal(lua_State *L, vlc_playlist_t *playlist)
|
|
{
|
|
vlclua_set_object(L, vlclua_set_playlist_internal, playlist);
|
|
}
|
|
|
|
vlc_playlist_t *vlclua_get_playlist_internal(lua_State *L)
|
|
{
|
|
return vlclua_get_object(L, vlclua_set_playlist_internal);
|
|
}
|
|
|
|
static int vlclua_playlist_prev(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
vlc_playlist_Lock(playlist);
|
|
vlc_playlist_Prev(playlist);
|
|
vlc_playlist_Unlock(playlist);
|
|
return 0;
|
|
}
|
|
|
|
static int vlclua_playlist_next(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
vlc_playlist_Lock(playlist);
|
|
vlc_playlist_Next(playlist);
|
|
vlc_playlist_Unlock(playlist);
|
|
return 0;
|
|
}
|
|
|
|
static int vlclua_playlist_skip(lua_State *L)
|
|
{
|
|
int n = luaL_checkinteger( L, 1 );
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
if (n < 0) {
|
|
for (int i = 0; i < -n; i++)
|
|
vlc_playlist_Prev(playlist);
|
|
} else {
|
|
for (int i = 0; i < n; ++i)
|
|
vlc_playlist_Next(playlist);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int vlclua_playlist_play(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
vlc_playlist_Lock(playlist);
|
|
if (vlc_playlist_GetCurrentIndex(playlist) == -1 &&
|
|
vlc_playlist_Count(playlist) > 0)
|
|
vlc_playlist_GoTo(playlist, 0);
|
|
vlc_playlist_Start(playlist);
|
|
vlc_playlist_Unlock(playlist);
|
|
return 0;
|
|
}
|
|
|
|
static int vlclua_playlist_pause(lua_State *L)
|
|
{
|
|
/* this is in fact a toggle pause */
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
vlc_player_t *player = vlc_playlist_GetPlayer(playlist);
|
|
|
|
vlc_player_Lock(player);
|
|
if (vlc_player_GetState(player) != VLC_PLAYER_STATE_PAUSED)
|
|
vlc_player_Pause(player);
|
|
else
|
|
vlc_player_Resume(player);
|
|
vlc_player_Unlock(player);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vlclua_playlist_stop(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
vlc_playlist_Lock(playlist);
|
|
vlc_playlist_Stop(playlist);
|
|
vlc_playlist_Unlock(playlist);
|
|
return 0;
|
|
}
|
|
|
|
static int vlclua_playlist_clear( lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
vlc_playlist_Lock(playlist);
|
|
vlc_playlist_Clear(playlist);
|
|
vlc_playlist_Unlock(playlist);
|
|
return 0;
|
|
}
|
|
|
|
static bool take_bool(lua_State *L)
|
|
{
|
|
const char *s = luaL_checkstring(L, -1);
|
|
lua_pop( L, 1 );
|
|
return s && !strcmp(s, "on");
|
|
}
|
|
|
|
static int vlclua_playlist_repeat_(lua_State *L,
|
|
enum vlc_playlist_playback_repeat enabled_mode)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
int top = lua_gettop(L);
|
|
if (top > 1)
|
|
return vlclua_error(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
|
|
bool enable;
|
|
if (top == 0)
|
|
{
|
|
/* no value provided, toggle the current */
|
|
enum vlc_playlist_playback_repeat repeat =
|
|
vlc_playlist_GetPlaybackRepeat(playlist);
|
|
enable = repeat != enabled_mode;
|
|
}
|
|
else
|
|
{
|
|
/* use the provided value */
|
|
enable = take_bool(L);
|
|
}
|
|
|
|
enum vlc_playlist_playback_repeat new_repeat = enable
|
|
? enabled_mode
|
|
: VLC_PLAYLIST_PLAYBACK_REPEAT_NONE;
|
|
|
|
vlc_playlist_SetPlaybackRepeat(playlist, new_repeat);
|
|
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
lua_pushboolean(L, enable);
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_repeat(lua_State *L)
|
|
{
|
|
return vlclua_playlist_repeat_(L, VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT);
|
|
}
|
|
|
|
static int vlclua_playlist_loop(lua_State *L)
|
|
{
|
|
return vlclua_playlist_repeat_(L, VLC_PLAYLIST_PLAYBACK_REPEAT_ALL);
|
|
}
|
|
|
|
static int vlclua_playlist_get_repeat(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
enum vlc_playlist_playback_repeat repeat =
|
|
vlc_playlist_GetPlaybackRepeat(playlist);
|
|
bool result = repeat != VLC_PLAYLIST_PLAYBACK_REPEAT_NONE;
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
lua_pushboolean(L, result);
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_get_loop(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
enum vlc_playlist_playback_repeat repeat =
|
|
vlc_playlist_GetPlaybackRepeat(playlist);
|
|
bool result = repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL;
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
lua_pushboolean(L, result);
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_random(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
int top = lua_gettop(L);
|
|
if (top > 1)
|
|
return vlclua_error(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
|
|
bool enable;
|
|
if (top == 0)
|
|
{
|
|
enum vlc_playlist_playback_order order =
|
|
vlc_playlist_GetPlaybackOrder(playlist);
|
|
enable = order != VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM;
|
|
}
|
|
else
|
|
{
|
|
/* use the provided value */
|
|
enable = take_bool(L);
|
|
}
|
|
|
|
enum vlc_playlist_playback_order new_order = enable
|
|
? VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
|
|
: VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL;
|
|
|
|
vlc_playlist_SetPlaybackOrder(playlist, new_order);
|
|
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
lua_pushboolean(L, enable);
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_get_random(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
enum vlc_playlist_playback_order order =
|
|
vlc_playlist_GetPlaybackOrder(playlist);
|
|
bool result = order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM;
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
lua_pushboolean(L, result);
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_gotoitem(lua_State *L)
|
|
{
|
|
uint64_t id = luaL_checkinteger(L, 1);
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
int ret;
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
ssize_t index = vlc_playlist_IndexOfId(playlist, id);
|
|
if (index == -1)
|
|
ret = VLC_ENOENT;
|
|
else
|
|
{
|
|
vlc_playlist_GoTo(playlist, index);
|
|
ret = VLC_SUCCESS;
|
|
}
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
return vlclua_push_ret(L, ret);
|
|
}
|
|
|
|
static int vlclua_playlist_delete(lua_State *L)
|
|
{
|
|
uint64_t id = luaL_checkinteger(L, 1);
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
int ret;
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
ssize_t index = vlc_playlist_IndexOfId(playlist, id);
|
|
if (index == -1)
|
|
ret = -1;
|
|
else
|
|
{
|
|
vlc_playlist_RemoveOne(playlist, index);
|
|
ret = VLC_SUCCESS;
|
|
}
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
return vlclua_push_ret(L, ret);
|
|
}
|
|
|
|
static int vlclua_playlist_move(lua_State *L)
|
|
{
|
|
uint64_t item_id = luaL_checkinteger(L, 1);
|
|
uint64_t target_id = luaL_checkinteger(L, 2);
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
int ret;
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
ssize_t item_index = vlc_playlist_IndexOfId(playlist, item_id);
|
|
ssize_t target_index = vlc_playlist_IndexOfId(playlist, target_id);
|
|
if (item_index == -1 || target_index == -1)
|
|
ret = -1;
|
|
else
|
|
{
|
|
/* if the current item was before the target, moving it shifts the
|
|
* target item by one */
|
|
size_t new_index = item_index <= target_index ? target_index
|
|
: target_index + 1;
|
|
vlc_playlist_MoveOne(playlist, item_index, new_index);
|
|
ret = VLC_SUCCESS;
|
|
}
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
return vlclua_push_ret(L, ret);
|
|
}
|
|
|
|
static int vlclua_playlist_add_common(lua_State *L, bool play)
|
|
{
|
|
vlc_object_t *obj = vlclua_get_this(L);
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
int count = 0;
|
|
|
|
/* playlist */
|
|
if (!lua_istable(L, -1))
|
|
{
|
|
msg_Warn(obj, "Playlist should be a table.");
|
|
return 0;
|
|
}
|
|
|
|
lua_pushnil(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
|
|
/* playlist nil */
|
|
while (lua_next(L, -2))
|
|
{
|
|
input_item_t *item = vlclua_read_input_item(obj, L);
|
|
if (item != NULL)
|
|
{
|
|
int ret = vlc_playlist_AppendOne(playlist, item);
|
|
if (ret == VLC_SUCCESS)
|
|
{
|
|
count++;
|
|
if (play)
|
|
{
|
|
size_t last = vlc_playlist_Count(playlist) - 1;
|
|
vlc_playlist_PlayAt(playlist, last);
|
|
}
|
|
}
|
|
input_item_Release(item);
|
|
}
|
|
/* pop the value, keep the key for the next lua_next() call */
|
|
lua_pop(L, 1);
|
|
}
|
|
/* playlist */
|
|
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
lua_pushinteger(L, count);
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_add(lua_State *L)
|
|
{
|
|
return vlclua_playlist_add_common(L, true);
|
|
}
|
|
|
|
static int vlclua_playlist_enqueue(lua_State *L)
|
|
{
|
|
return vlclua_playlist_add_common(L, false);
|
|
}
|
|
|
|
static void push_playlist_item(lua_State *L, vlc_playlist_item_t *item)
|
|
{
|
|
lua_newtable(L);
|
|
|
|
lua_pushinteger(L, vlc_playlist_item_GetId(item));
|
|
lua_setfield(L, -2, "id");
|
|
|
|
input_item_t *media = vlc_playlist_item_GetMedia(item);
|
|
|
|
/* Apart from nb_played, these fields unfortunately duplicate
|
|
fields already available from the input item */
|
|
char *name = input_item_GetTitleFbName(media);
|
|
lua_pushstring(L, name);
|
|
free(name);
|
|
lua_setfield(L, -2, "name");
|
|
|
|
lua_pushstring(L, media->psz_uri);
|
|
lua_setfield(L, -2, "path");
|
|
|
|
if( media->i_duration < 0 )
|
|
lua_pushnumber(L, -1);
|
|
else
|
|
lua_pushnumber(L, secf_from_vlc_tick(media->i_duration));
|
|
lua_setfield(L, -2, "duration");
|
|
|
|
luaopen_input_item(L, media);
|
|
}
|
|
|
|
static int vlclua_playlist_get(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
uint64_t item_id = luaL_checkinteger(L, 1);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
ssize_t index = vlc_playlist_IndexOfId(playlist, item_id);
|
|
vlc_playlist_item_t *item = index != -1 ? vlc_playlist_Get(playlist, index)
|
|
: NULL;
|
|
if (item)
|
|
push_playlist_item(L, item);
|
|
else
|
|
lua_pushnil(L);
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_list(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
|
|
size_t count = vlc_playlist_Count(playlist);
|
|
lua_createtable(L, count, 0);
|
|
|
|
for (size_t i = 0; i < count; ++i)
|
|
{
|
|
push_playlist_item(L, vlc_playlist_Get(playlist, i));
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_current(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
ssize_t current = vlc_playlist_GetCurrentIndex(playlist);
|
|
int id;
|
|
if (current != -1) {
|
|
vlc_playlist_item_t *item = vlc_playlist_Get(playlist, current);
|
|
id = vlc_playlist_item_GetId(item);
|
|
} else
|
|
id = -1;
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
lua_pushinteger(L, id);
|
|
return 1;
|
|
}
|
|
|
|
static int vlclua_playlist_current_item(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
ssize_t index = vlc_playlist_GetCurrentIndex(playlist);
|
|
vlc_playlist_item_t *item = index != -1 ? vlc_playlist_Get(playlist, index)
|
|
: NULL;
|
|
if (item)
|
|
push_playlist_item(L, item);
|
|
else
|
|
lua_pushnil(L);
|
|
vlc_playlist_Unlock(playlist);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool vlc_sort_key_from_string(const char *keyname,
|
|
enum vlc_playlist_sort_key *key)
|
|
{
|
|
static const struct
|
|
{
|
|
const char *keyname;
|
|
enum vlc_playlist_sort_key key;
|
|
} map[] = {
|
|
{ "title", VLC_PLAYLIST_SORT_KEY_TITLE },
|
|
{ "artist", VLC_PLAYLIST_SORT_KEY_ARTIST },
|
|
{ "genre", VLC_PLAYLIST_SORT_KEY_GENRE },
|
|
{ "duration", VLC_PLAYLIST_SORT_KEY_DURATION },
|
|
{ "album", VLC_PLAYLIST_SORT_KEY_ALBUM },
|
|
};
|
|
for (size_t i = 0; i < ARRAY_SIZE(map); ++i)
|
|
{
|
|
if (!strcmp(keyname, map[i].keyname))
|
|
{
|
|
*key = map[i].key;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int vlclua_playlist_sort( lua_State *L )
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
const char *keyname = luaL_checkstring(L, 1);
|
|
|
|
int ret;
|
|
if (!strcmp(keyname, "random"))
|
|
{
|
|
/* sort randomly -> shuffle */
|
|
vlc_playlist_Lock(playlist);
|
|
vlc_playlist_Shuffle(playlist);
|
|
vlc_playlist_Unlock(playlist);
|
|
ret = VLC_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
struct vlc_playlist_sort_criterion criterion;
|
|
if (!vlc_sort_key_from_string(keyname, &criterion.key))
|
|
return luaL_error(L, "Invalid search key.");
|
|
criterion.order = luaL_optboolean(L, 2, 0)
|
|
? VLC_PLAYLIST_SORT_ORDER_DESCENDING
|
|
: VLC_PLAYLIST_SORT_ORDER_ASCENDING;
|
|
|
|
vlc_playlist_Lock(playlist);
|
|
ret = vlc_playlist_Sort(playlist, &criterion, 1);
|
|
vlc_playlist_Unlock(playlist);
|
|
}
|
|
return vlclua_push_ret(L, ret);
|
|
}
|
|
|
|
static int vlclua_playlist_status(lua_State *L)
|
|
{
|
|
vlc_playlist_t *playlist = vlclua_get_playlist_internal(L);
|
|
|
|
vlc_player_t *player = vlc_playlist_GetPlayer(playlist);
|
|
vlc_player_Lock(player);
|
|
enum vlc_player_state state = vlc_player_GetState(player);
|
|
vlc_player_Unlock(player);
|
|
|
|
switch (state)
|
|
{
|
|
case VLC_PLAYER_STATE_STOPPED:
|
|
lua_pushliteral(L, "stopped");
|
|
break;
|
|
case VLC_PLAYER_STATE_STARTED:
|
|
lua_pushliteral(L, "started");
|
|
break;
|
|
case VLC_PLAYER_STATE_PLAYING:
|
|
lua_pushliteral(L, "playing");
|
|
break;
|
|
case VLC_PLAYER_STATE_PAUSED:
|
|
lua_pushliteral(L, "paused");
|
|
break;
|
|
case VLC_PLAYER_STATE_STOPPING:
|
|
lua_pushliteral(L, "stopping");
|
|
break;
|
|
default:
|
|
lua_pushliteral(L, "unknown");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
*****************************************************************************/
|
|
static const luaL_Reg vlclua_playlist_reg[] = {
|
|
{ "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 }, // repeat is a reserved lua keyword...
|
|
{ "repeat_", vlclua_playlist_repeat }, // ... provide repeat_ too.
|
|
{ "loop", vlclua_playlist_loop },
|
|
{ "random", vlclua_playlist_random },
|
|
{ "get_repeat", vlclua_playlist_get_repeat },
|
|
{ "get_loop", vlclua_playlist_get_loop },
|
|
{ "get_random", vlclua_playlist_get_random },
|
|
#if LUA_VERSION_NUM < 502
|
|
{ "goto", vlclua_playlist_gotoitem },
|
|
#endif
|
|
{ "gotoitem", vlclua_playlist_gotoitem },
|
|
{ "add", vlclua_playlist_add },
|
|
{ "enqueue", vlclua_playlist_enqueue },
|
|
{ "get", vlclua_playlist_get },
|
|
{ "list", vlclua_playlist_list },
|
|
{ "current", vlclua_playlist_current },
|
|
{ "current_item", vlclua_playlist_current_item },
|
|
{ "sort", vlclua_playlist_sort },
|
|
{ "status", vlclua_playlist_status },
|
|
{ "delete", vlclua_playlist_delete },
|
|
{ "move", vlclua_playlist_move },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
void luaopen_playlist( lua_State *L )
|
|
{
|
|
lua_newtable( L );
|
|
luaL_register( L, NULL, vlclua_playlist_reg );
|
|
lua_setfield( L, -2, "playlist" );
|
|
}
|
|
|