aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQball Cow <qball@qballcow.nl>2007-09-26 08:25:35 +0000
committerQball Cow <qball@qballcow.nl>2007-09-26 08:25:35 +0000
commitcb9d1b3d275fac683a4128b93a76ab72c99a0209 (patch)
tree15e8cccedd2db17faa35a040f9432d61dabb86aa
parent3a03b89b48eb206c82878dc7743ffc412c30039b (diff)
downloadmpd-cb9d1b3d275fac683a4128b93a76ab72c99a0209.tar.gz
mpd-cb9d1b3d275fac683a4128b93a76ab72c99a0209.tar.xz
mpd-cb9d1b3d275fac683a4128b93a76ab72c99a0209.zip
Playlist queue patch (http://musicpd.org/mantis/view.php?id=1478) version 11.
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
Diffstat (limited to '')
-rw-r--r--src/command.c50
-rw-r--r--src/list.c15
-rw-r--r--src/list.h6
-rw-r--r--src/playlist.c173
-rw-r--r--src/playlist.h15
5 files changed, 258 insertions, 1 deletions
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