From cb9d1b3d275fac683a4128b93a76ab72c99a0209 Mon Sep 17 00:00:00 2001 From: Qball Cow Date: Wed, 26 Sep 2007 08:25:35 +0000 Subject: Playlist queue patch (http://musicpd.org/mantis/view.php?id=1478) version 11. This adds the following commands: * queueid Add song to the queue. * dequeue Remove song from from the queue * queueinfo List the queue To the statusfield it adds the following entry: playlistqueue: 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 --- src/command.c | 50 +++++++++++++++++ src/list.c | 15 +++++ src/list.h | 6 ++ src/playlist.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/playlist.h | 15 +++++ 5 files changed, 258 insertions(+), 1 deletion(-) diff --git a/src/command.c b/src/command.c index 84a30db2b..83a8d3a2d 100644 --- a/src/command.c +++ b/src/command.c @@ -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); diff --git a/src/list.c b/src/list.c index 71c30f7b6..14832adb7 100644 --- a/src/list.c +++ b/src/list.c @@ -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; diff --git a/src/list.h b/src/list.h index 5938934ff..35451ec24 100644 --- a/src/list.h +++ b/src/list.h @@ -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 */ diff --git a/src/playlist.c b/src/playlist.c index f4fd02ce1..5c14ff406 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -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; +} diff --git a/src/playlist.h b/src/playlist.h index 0ae3a677f..6576ff27b 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -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 -- cgit v1.2.3