aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-07-12 03:00:01 +0200
committerMax Kellermann <max@duempel.org>2014-07-12 18:55:41 +0200
commit751995ab95298bbc0afad6958bfccce535edf53c (patch)
tree29e8b8d35536e98fc503963d86260d74a872db91 /src
parent5ca6e2910ae0a8a2d1fa7b16f56130d533251ff9 (diff)
downloadmpd-751995ab95298bbc0afad6958bfccce535edf53c.tar.gz
mpd-751995ab95298bbc0afad6958bfccce535edf53c.tar.xz
mpd-751995ab95298bbc0afad6958bfccce535edf53c.zip
QueueCommands: new command "rangeid"
Manipulates the playback range of a queued song.
Diffstat (limited to 'src')
-rw-r--r--src/command/AllCommands.cxx1
-rw-r--r--src/command/QueueCommands.cxx54
-rw-r--r--src/command/QueueCommands.hxx3
-rw-r--r--src/queue/Playlist.hxx8
-rw-r--r--src/queue/PlaylistEdit.cxx57
5 files changed, 123 insertions, 0 deletions
diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx
index 6143dacdf..d29950eeb 100644
--- a/src/command/AllCommands.cxx
+++ b/src/command/AllCommands.cxx
@@ -150,6 +150,7 @@ static const struct command commands[] = {
{ "prio", PERMISSION_CONTROL, 2, -1, handle_prio },
{ "prioid", PERMISSION_CONTROL, 2, -1, handle_prioid },
{ "random", PERMISSION_CONTROL, 1, 1, handle_random },
+ { "rangeid", PERMISSION_ADD, 2, 2, handle_rangeid },
{ "readcomments", PERMISSION_READ, 1, 1, handle_read_comments },
{ "readmessages", PERMISSION_READ, 0, 0, handle_read_messages },
{ "rename", PERMISSION_CONTROL, 2, 2, handle_rename },
diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx
index 1ff7a732b..c99a6687a 100644
--- a/src/command/QueueCommands.cxx
+++ b/src/command/QueueCommands.cxx
@@ -34,6 +34,7 @@
#include "ls.hxx"
#include "util/ConstBuffer.hxx"
#include "util/UriUtil.hxx"
+#include "util/NumberParser.hxx"
#include "util/Error.hxx"
#include "fs/AllocatedPath.hxx"
@@ -118,6 +119,59 @@ handle_addid(Client &client, unsigned argc, char *argv[])
return CommandResult::OK;
}
+/**
+ * Parse a string in the form "START:END", both being (optional)
+ * fractional non-negative time offsets in seconds. Returns both in
+ * integer milliseconds. Omitted values are zero.
+ */
+static bool
+parse_time_range(const char *p, unsigned &start_ms, unsigned &end_ms)
+{
+ char *endptr;
+
+ const float start = ParseFloat(p, &endptr);
+ if (*endptr != ':' || start < 0)
+ return false;
+
+ start_ms = endptr > p
+ ? unsigned(start * 1000u)
+ : 0u;
+
+ p = endptr + 1;
+
+ const float end = ParseFloat(p, &endptr);
+ if (*endptr != 0 || end < 0)
+ return false;
+
+ end_ms = endptr > p
+ ? unsigned(end * 1000u)
+ : 0u;
+
+ return end_ms == 0 || end_ms > start_ms;
+}
+
+CommandResult
+handle_rangeid(Client &client, gcc_unused unsigned argc, char *argv[])
+{
+ unsigned id;
+ if (!check_unsigned(client, &id, argv[1]))
+ return CommandResult::ERROR;
+
+ unsigned start_ms, end_ms;
+ if (!parse_time_range(argv[2], start_ms, end_ms)) {
+ command_error(client, ACK_ERROR_ARG, "Bad range");
+ return CommandResult::ERROR;
+ }
+
+ Error error;
+ if (!client.partition.playlist.SetSongIdRange(client.partition.pc,
+ id, start_ms, end_ms,
+ error))
+ return print_error(client, error);
+
+ return CommandResult::OK;
+}
+
CommandResult
handle_delete(Client &client, gcc_unused unsigned argc, char *argv[])
{
diff --git a/src/command/QueueCommands.hxx b/src/command/QueueCommands.hxx
index ece543cfd..f98f7bad2 100644
--- a/src/command/QueueCommands.hxx
+++ b/src/command/QueueCommands.hxx
@@ -31,6 +31,9 @@ CommandResult
handle_addid(Client &client, unsigned argc, char *argv[]);
CommandResult
+handle_rangeid(Client &client, unsigned argc, char *argv[]);
+
+CommandResult
handle_delete(Client &client, unsigned argc, char *argv[]);
CommandResult
diff --git a/src/queue/Playlist.hxx b/src/queue/Playlist.hxx
index f2d778382..0f73a0513 100644
--- a/src/queue/Playlist.hxx
+++ b/src/queue/Playlist.hxx
@@ -225,6 +225,14 @@ public:
PlaylistResult SetPriorityId(PlayerControl &pc,
unsigned song_id, uint8_t priority);
+ /**
+ * Sets the start_ms and end_ms attributes on the song
+ * with the specified id.
+ */
+ bool SetSongIdRange(PlayerControl &pc, unsigned id,
+ unsigned start_ms, unsigned end_ms,
+ Error &error);
+
bool AddSongIdTag(unsigned id, TagType tag_type, const char *value,
Error &error);
bool ClearSongIdTag(unsigned id, TagType tag_type, Error &error);
diff --git a/src/queue/PlaylistEdit.cxx b/src/queue/PlaylistEdit.cxx
index 4804a30aa..2ac015f6f 100644
--- a/src/queue/PlaylistEdit.cxx
+++ b/src/queue/PlaylistEdit.cxx
@@ -431,3 +431,60 @@ playlist::Shuffle(PlayerControl &pc, unsigned start, unsigned end)
UpdateQueuedSong(pc, queued_song);
OnModified();
}
+
+bool
+playlist::SetSongIdRange(PlayerControl &pc, unsigned id,
+ unsigned start_ms, unsigned end_ms,
+ Error &error)
+{
+ assert(end_ms == 0 || start_ms < end_ms);
+
+ int position = queue.IdToPosition(id);
+ if (position < 0) {
+ error.Set(playlist_domain, int(PlaylistResult::NO_SUCH_SONG),
+ "No such song");
+ return false;
+ }
+
+ if (playing) {
+ if (position == current) {
+ error.Set(playlist_domain, int(PlaylistResult::DENIED),
+ "Cannot edit the current song");
+ return false;
+ }
+
+ if (position == queued) {
+ /* if we're manipulating the "queued" song,
+ the decoder thread may be decoding it
+ already; cancel that */
+ pc.Cancel();
+ queued = -1;
+ }
+ }
+
+ DetachedSong &song = queue.Get(position);
+ if (song.GetTag().time > 0) {
+ /* validate the offsets */
+
+ const unsigned duration = song.GetTag().time;
+ if (start_ms / 1000u > duration) {
+ error.Set(playlist_domain,
+ int(PlaylistResult::BAD_RANGE),
+ "Invalid start offset");
+ return false;
+ }
+
+ if (end_ms / 1000u > duration)
+ end_ms = 0;
+ }
+
+ /* edit it */
+ song.SetStartMS(start_ms);
+ song.SetEndMS(end_ms);
+
+ /* announce the change to all interested subsystems */
+ UpdateQueuedSong(pc, nullptr);
+ queue.ModifyAtPosition(position);
+ OnModified();
+ return true;
+}