sink_writes(ev_writer_sink(c->w), "550 cannot resolve track\n");
return 1;
}
- q = queue_add(track, c->who, WHERE_BEFORE_RANDOM, origin_picked);
+ q = queue_add(track, c->who, WHERE_BEFORE_RANDOM, NULL, origin_picked);
queue_write();
- /* If we added the first track, and something is playing, then prepare the
- * new track. If nothing is playing then we don't bother as it wouldn't gain
- * anything. */
- if(q == qhead.next && playing)
- prepare(c->ev, q);
sink_printf(ev_writer_sink(c->w), "252 %s\n", q->id);
+ /* We make sure the track at the head of the queue is prepared, just in case
+ * we added it. We could be more subtle but prepare() will ensure we don't
+ * prepare the same track twice so there's no point. */
+ if(qhead.next != &qhead)
+ prepare(c->ev, qhead.next);
/* If the queue was empty but we are for some reason paused then
* unpause. */
if(!playing) resume_playing(0);
return 1; /* completed */
}
+static int c_playafter(struct conn *c, char **vec,
+ int attribute((unused)) nvec) {
+ const char *track;
+ struct queue_entry *q;
+ const char *afterme = vec[0];
+
+ for(int n = 1; n < nvec; ++n) {
+ if(!trackdb_exists(vec[n])) {
+ sink_writes(ev_writer_sink(c->w), "550 track is not in database\n");
+ return 1;
+ }
+ if(!(track = trackdb_resolve(vec[n]))) {
+ sink_writes(ev_writer_sink(c->w), "550 cannot resolve track\n");
+ return 1;
+ }
+ q = queue_add(track, c->who, WHERE_AFTER, afterme, origin_picked);
+ if(!q) {
+ sink_printf(ev_writer_sink(c->w), "550 No such ID\n");
+ return 1;
+ }
+ info("added %s as %s after %s", track, q->id, afterme);
+ afterme = q->id;
+ }
+ queue_write();
+ sink_printf(ev_writer_sink(c->w), "252 OK\n");
+ /* We make sure the track at the head of the queue is prepared, just in case
+ * we added it. We could be more subtle but prepare() will ensure we don't
+ * prepare the same track twice so there's no point. */
+ if(qhead.next != &qhead) {
+ prepare(c->ev, qhead.next);
+ info("prepared %s", qhead.next->id);
+ }
+ /* If the queue was empty but we are for some reason paused then
+ * unpause. */
+ if(!playing)
+ resume_playing(0);
+ play(c->ev);
+ return 1; /* completed */
+}
+
static int c_remove(struct conn *c, char **vec,
int attribute((unused)) nvec) {
struct queue_entry *q;
queue_fix_sofar(playing);
if((l = trackdb_get(playing->track, "_length"))
&& (length = atol(l))) {
- time(&when);
+ xtime(&when);
when += length - playing->sofar + config->gap;
}
} else
/* Nothing is playing but playing is enabled, so whatever is
* first in the queue can be expected to start immediately. */
- time(&when);
+ xtime(&when);
}
for(q = qhead.next; q != &qhead; q = q->next) {
/* fill in estimated start time */
return;
}
sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" %s\n",
- (uintmax_t)time(0), msg);
+ (uintmax_t)xtime(0), msg);
}
static int c_log(struct conn *c,
sink_writes(ev_writer_sink(c->w), "254 OK\n");
/* pump out initial state */
- time(&now);
+ xtime(&now);
sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" state %s\n",
(uintmax_t)now,
playing_is_enabled() ? "enable_play" : "disable_play");
if(d->lo)
sink_printf(ev_writer_sink(d->w),
"%"PRIxMAX" rights_changed %s\n",
- (uintmax_t)time(0),
+ (uintmax_t)xtime(0),
quoteutf8(new_rights));
}
}
if(!last_reminder)
last_reminder = hash_new(sizeof (time_t));
last = hash_find(last_reminder, vec[0]);
- time(&now);
+ xtime(&now);
if(last && now < *last + config->reminder_interval) {
error(0, "sent a password reminder to '%s' too recently", vec[0]);
sink_writes(ev_writer_sink(c->w), "550 Cannot send a reminder email\n");
{ "part", 3, 3, c_part, RIGHT_READ },
{ "pause", 0, 0, c_pause, RIGHT_PAUSE },
{ "play", 1, 1, c_play, RIGHT_PLAY },
+ { "playafter", 2, INT_MAX, c_playafter, RIGHT_PLAY },
{ "playing", 0, 0, c_playing, RIGHT_READ },
{ "playlist-delete", 1, 1, c_playlist_delete, RIGHT_PLAY },
{ "playlist-get", 1, 1, c_playlist_get, RIGHT_READ },