This adds the following commands:
* queueid <id>		Add song <id> to the queue.
* dequeue <pos>		Remove song from <pos> from the queue
* queueinfo			List the queue

To the statusfield it adds the following entry:
playlistqueue:	<uid>		UID can be used by clients to track changes in the playlist queue.



git-svn-id: https://svn.musicpd.org/mpd/trunk@6927 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
Qball Cow 2007-09-26 08:25:35 +00:00
parent 3a03b89b48
commit cb9d1b3d27
5 changed files with 258 additions and 1 deletions

View File

@ -98,6 +98,9 @@
#define COMMAND_PLAYLISTSEARCH "playlistsearch"
#define COMMAND_PLAYLISTMOVE "playlistmove"
#define COMMAND_PLAYLISTDELETE "playlistdelete"
#define COMMAND_QUEUEID "queueid"
#define COMMAND_DEQUEUE "dequeue"
#define COMMAND_QUEUEINFO "queueinfo"
#define COMMAND_TAGTYPES "tagtypes"
#define COMMAND_COUNT "count"
#define COMMAND_RENAME "rename"
@ -107,6 +110,7 @@
#define COMMAND_STATUS_REPEAT "repeat"
#define COMMAND_STATUS_RANDOM "random"
#define COMMAND_STATUS_PLAYLIST "playlist"
#define COMMAND_STATUS_PLAYLIST_QUEUE "playlistqueue"
#define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength"
#define COMMAND_STATUS_SONG "song"
#define COMMAND_STATUS_SONGID "songid"
@ -278,6 +282,8 @@ static int commandStatus(int fd, int *permission, int argc, char *argv[])
getPlaylistRandomStatus());
fdprintf(fd, "%s: %li\n", COMMAND_STATUS_PLAYLIST,
getPlaylistVersion());
fdprintf(fd, "%s: %li\n", COMMAND_STATUS_PLAYLIST_QUEUE,
getPlaylistQueueVersion());
fdprintf(fd, "%s: %i\n", COMMAND_STATUS_PLAYLIST_LENGTH,
getPlaylistLength());
fdprintf(fd, "%s: %i\n", COMMAND_STATUS_CROSSFADE,
@ -625,6 +631,47 @@ static int handlePlaylistMove(int fd, int *permission, int argc, char *argv[])
return moveSongInStoredPlaylistByPath(fd, playlist, from, to);
}
static int handleQueueInfo(int fd, int *permission, int argc, char *argv[])
{
return playlistQueueInfo(fd);
}
static int handleQueueId(int fd, int *permission, int argc, char *argv[])
{
int id, position = -1;
char *test;
id = strtol(argv[1], &test, 10);
if (*test != '\0') {
commandError(fd, ACK_ERROR_ARG,
"\"%s\" is not a integer", argv[1]);
return -1;
}
if (argc == 3) {
position = strtol(argv[2], &test, 10);
if (*test != '\0') {
commandError(fd, ACK_ERROR_ARG,
"\"%s\" is not a integer", argv[2]);
return -1;
}
}
return addToPlaylistQueueById(fd, id, position);
}
static int handleDequeue(int fd, int *permission, int argc, char *argv[])
{
int pos;
char *test;
pos = strtol(argv[1], &test, 10);
if (*test != '\0') {
commandError(fd, ACK_ERROR_ARG,
"\"%s\" is not a integer", argv[1]);
return -1;
}
return deleteFromPlaylistQueue(fd, pos);
}
static int listHandleUpdate(int fd,
int *permission,
int argc,
@ -1121,6 +1168,9 @@ void initCommands(void)
addCommand(COMMAND_PLAYLISTSEARCH, PERMISSION_READ, 2, -1, handlePlaylistSearch, NULL);
addCommand(COMMAND_PLAYLISTMOVE, PERMISSION_CONTROL, 3, 3, handlePlaylistMove, NULL);
addCommand(COMMAND_PLAYLISTDELETE, PERMISSION_CONTROL, 2, 2, handlePlaylistDelete, NULL);
addCommand(COMMAND_QUEUEINFO, PERMISSION_CONTROL, 0, 0, handleQueueInfo, NULL);
addCommand(COMMAND_QUEUEID, PERMISSION_CONTROL, 1, 2, handleQueueId, NULL);
addCommand(COMMAND_DEQUEUE, PERMISSION_CONTROL, 1, 1, handleDequeue, NULL);
addCommand(COMMAND_TAGTYPES, PERMISSION_READ, 0, 0, handleTagTypes, NULL);
addCommand(COMMAND_COUNT, PERMISSION_READ, 2, -1, handleCount, NULL);
addCommand(COMMAND_RENAME, PERMISSION_CONTROL, 2, 2, handleRename, NULL);

View File

@ -287,6 +287,21 @@ int findInList(List * list, char *key, void **data)
return 0;
}
ListNode *getNodeByPosition(List *list, int pos)
{
ListNode *tmpNode;
assert(list != NULL);
if (pos < 0 || pos >= list->numberOfNodes)
return NULL;
tmpNode = list->firstNode;
while (pos-- > 0)
tmpNode = tmpNode->nextNode;
return tmpNode;
}
int deleteFromList(List * list, char *key)
{
ListNode *tmpNode;

View File

@ -100,6 +100,12 @@ int findInList(List * list, char *key, void **data);
the info would be found */
int findNodeInList(List * list, char *key, ListNode ** node, int *pos);
/*
* returns ListNode at position _pos_ from first node. If no ListNode exists
* at position _pos_ returns NULL
*/
ListNode *getNodeByPosition(List *list, int pos);
/* frees memory malloc'd for list and its nodes
* _list_ -> List to be free'd
*/

View File

@ -73,9 +73,12 @@ static int playlist_noGoToNext;
int playlist_saveAbsolutePaths = DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS;
static List *playlistQueue;
static void swapOrder(int a, int b);
static int playPlaylistOrderNumber(int fd, int orderNum);
static void randomizeOrder(int start, int end);
static void clearPlayerQueue(void);
static void incrPlaylistVersion(void)
{
@ -103,6 +106,14 @@ void playlistVersionChange(void)
incrPlaylistVersion();
}
static void incrPlaylistQueueVersion(void)
{
static unsigned long max = ((mpd_uint32) 1 << 31) - 1;
playlist.queueversion++;
if (playlist.queueversion >= max)
playlist.queueversion = 1;
}
static void incrPlaylistCurrent(void)
{
if (playlist.current < 0)
@ -126,6 +137,7 @@ void initPlaylist(void)
playlist.length = 0;
playlist.repeat = 0;
playlist.version = 1;
playlist.queueversion = 1;
playlist.random = 0;
playlist.queued = -1;
playlist.current = -1;
@ -160,6 +172,8 @@ void initPlaylist(void)
for (i = 0; i < playlist_max_length * PLAYLIST_HASH_MULT; i++) {
playlist.idToPosition[i] = -1;
}
playlistQueue = makeList(DEFAULT_FREE_DATA_FUNC, 0);
}
static int getNextId(void)
@ -205,6 +219,7 @@ int clearPlaylist(int fd)
if (stopPlaylist(fd) < 0)
return -1;
clearPlaylistQueue();
for (i = 0; i < playlist.length; i++) {
if (playlist.songs[i]->type == SONG_TYPE_URL) {
@ -485,7 +500,28 @@ static void swapSongs(int song1, int song2)
static void queueNextSongInPlaylist(void)
{
if (playlist.current < playlist.length - 1) {
if (playlistQueue->numberOfNodes != 0) {
int i;
/* we need to find where in order[] is first song from queue */
for (i=0;i < playlist.length; i++)
if (playlist.order[i] == playlist.
idToPosition[*(int *)playlistQueue->
firstNode->data])
break;
clearPlayerQueue();
playlist.queued = i;
DEBUG("playlist: queue song %i:\"%s\"\n",
playlist.queued,
getSongUrl(playlist.
songs[playlist.order[playlist.queued]]));
if (queueSong(playlist.songs[playlist.order[playlist.queued]]) <
0) {
playlist.queued = -1;
playlist_queueError = 1;
}
} else if (playlist.current < playlist.length - 1) {
clearPlayerQueue();
playlist.queued = playlist.current + 1;
DEBUG("playlist: queue song %i:\"%s\"\n",
playlist.queued,
@ -500,6 +536,7 @@ static void queueNextSongInPlaylist(void)
if (playlist.length > 1 && playlist.random) {
randomizeOrder(0, playlist.length - 1);
}
clearPlayerQueue();
playlist.queued = 0;
DEBUG("playlist: queue song %i:\"%s\"\n",
playlist.queued,
@ -527,6 +564,9 @@ static void syncPlaylistWithQueue(int queue)
if (playlist.queued >= 0) {
DEBUG("playlist: now playing queued song\n");
playlist.current = playlist.queued;
if (playlistQueue->numberOfNodes > 0) {
deleteFromPlaylistQueueInternal(0);
}
}
playlist.queued = -1;
if (queue)
@ -737,12 +777,29 @@ int deleteFromPlaylist(int fd, int song)
{
int i;
int songOrder;
ListNode *qItem;
if (song < 0 || song >= playlist.length) {
commandError(fd, ACK_ERROR_NO_EXIST,
"song doesn't exist: \"%i\"", song);
return -1;
}
/* we need to clear song from queue */
i = 0;
qItem = playlistQueue->firstNode;
while (qItem) {
if (playlist.idToPosition[*(int *)qItem->data] ==
song) {
qItem = qItem->nextNode;
deleteFromPlaylistQueueInternal(i);
/* can be queued multiple times */
continue;
}
i++;
qItem = qItem->nextNode;
}
if (playlist_state == PLAYLIST_STATE_PLAY) {
if (playlist.queued >= 0
@ -859,9 +916,28 @@ static int playPlaylistOrderNumber(int fd, int orderNum)
playlist.current = orderNum;
/* are we playing from queue ? */
if (playlistQueue->numberOfNodes > 0 &&
playlist.idToPosition[*(int *)playlistQueue->
firstNode->data] == playlist.order[orderNum]) {
deleteFromPlaylistQueueInternal(0);
queueNextSongInPlaylist();
}
return 0;
}
int playNextPlaylistQueue(int fd, int stopOnError)
{
int ret;
if (playlistQueue->numberOfNodes == 0)
return -1;
ret = playPlaylistById(fd, *(int *)playlistQueue->firstNode->data,
stopOnError);
return ret;
}
int playPlaylist(int fd, int song, int stopOnError)
{
int i = song;
@ -875,6 +951,12 @@ int playPlaylist(int fd, int song, int stopOnError)
if (playlist_state == PLAYLIST_STATE_PLAY) {
return playerSetPause(fd, 0);
}
if (playlist_state != PLAYLIST_STATE_STOP &&
playNextPlaylistQueue(fd, stopOnError) == 0) {
return 0;
}
if (playlist.current >= 0 && playlist.current < playlist.length) {
i = playlist.current;
} else {
@ -982,6 +1064,9 @@ int nextSongInPlaylist(int fd)
playlist_stopOnError = 0;
if (playNextPlaylistQueue(fd, 0) == 0)
return 0;
if (playlist.current < playlist.length - 1) {
return playPlaylistOrderNumber(fd, playlist.current + 1);
} else if (playlist.length && playlist.repeat) {
@ -1349,6 +1434,11 @@ unsigned long getPlaylistVersion(void)
return playlist.version;
}
unsigned long getPlaylistQueueVersion(void)
{
return playlist.queueversion;
}
int getPlaylistLength(void)
{
return playlist.length;
@ -1496,3 +1586,84 @@ void findSongsInPlaylist(int fd, int numItems, LocateTagItem * items)
printPlaylistSongInfo(fd, i);
}
}
void clearPlaylistQueue(void)
{
freeList(playlistQueue);
playlistQueue = makeList(DEFAULT_FREE_DATA_FUNC, 0);
incrPlaylistQueueVersion();
}
int addToPlaylistQueueById(int fd, int song, int toPosition)
{
int pos, *data;
ListNode *prevItem;
pos = playlist.idToPosition[song];
if (pos < 0 || pos >= playlist.length) {
commandError(fd, ACK_ERROR_NO_EXIST,
"song doesn't exist: \"%i\"", song);
return -1;
}
if (toPosition < -1 || toPosition > playlistQueue->numberOfNodes) {
commandError(fd, ACK_ERROR_ARG,
"queue position out of range: \"%i\"", toPosition);
return -1;
}
data = xmalloc(sizeof(int));
*data = song;
if (toPosition == -1) {
insertInList(playlistQueue, (char *)1, data);
} else {
prevItem = getNodeByPosition(playlistQueue, toPosition);
if (prevItem == NULL) {
insertInList(playlistQueue, (char *)1, data);
} else
insertInListBeforeNode(playlistQueue, prevItem, -1,
(char*) 1, data);
}
if (playlistQueue->numberOfNodes == 1 || toPosition == 0)
queueNextSongInPlaylist();
incrPlaylistQueueVersion();
return 0;
}
int deleteFromPlaylistQueue(int fd, int song)
{
if (song < 0 || song >= playlistQueue->numberOfNodes) {
commandError(fd, ACK_ERROR_NO_EXIST,
"song doesn't exist: \"%i\"", song);
return -1;
}
return deleteFromPlaylistQueueInternal(song);
}
int deleteFromPlaylistQueueInternal(int song)
{
ListNode *delItem;
delItem = getNodeByPosition(playlistQueue, song);
if (delItem == NULL)
return -1;
deleteNodeFromList(playlistQueue, delItem);
if (song == 0)
queueNextSongInPlaylist();
incrPlaylistQueueVersion();
return 0;
}
int playlistQueueInfo(int fd)
{
ListNode *cur = playlistQueue->firstNode;
int no = 0;
while (cur) {
printSongInfo(fd, playlist.songs[playlist.idToPosition[*(int *)cur->data]]);
fdprintf(fd, "Pos: %i\nId: %i\n", no++, *(int *)cur->data);
cur = cur->nextNode;
}
return 0;
}

View File

@ -43,6 +43,7 @@ typedef struct _Playlist {
int repeat;
int random;
mpd_uint32 version;
mpd_uint32 queueversion;
} Playlist;
extern int playlist_saveAbsolutePaths;
@ -79,6 +80,8 @@ int stopPlaylist(int fd);
int playPlaylist(int fd, int song, int stopOnError);
int playNextPlaylistQueue(int fd, int stopOnError);
int playPlaylistById(int fd, int song, int stopOnError);
int nextSongInPlaylist(int fd);
@ -123,6 +126,8 @@ int getPlaylistLength(void);
unsigned long getPlaylistVersion(void);
unsigned long getPlaylistQueueVersion(void);
void playPlaylistIfPlayerStopped(void);
int seekSongInPlaylist(int fd, int song, float time);
@ -141,4 +146,14 @@ void searchForSongsInPlaylist(int fd, int numItems, LocateTagItem * items);
void findSongsInPlaylist(int fd, int numItems, LocateTagItem * items);
void clearPlaylistQueue(void);
int addToPlaylistQueueById(int fd, int song, int toPosition);
int deleteFromPlaylistQueue(int fd, int song);
int deleteFromPlaylistQueueInternal(int song);
int playlistQueueInfo(int fd);
#endif