X-Git-Url: https://git.distorted.org.uk/~mdw/disorder/blobdiff_plain/c9467b7a34160c4e25580a2dc82087c5ae0bb2d0..23d0e9637b6ffa80a8181f4ed47f24b266bef173:/server/server.c diff --git a/server/server.c b/server/server.c index ce45a1d..6866764 100644 --- a/server/server.c +++ b/server/server.c @@ -242,14 +242,14 @@ static int c_play(struct conn *c, char **vec, 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); @@ -257,6 +257,46 @@ static int c_play(struct conn *c, char **vec, 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; @@ -590,13 +630,13 @@ static int c_queue(struct conn *c, 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 */ @@ -943,7 +983,7 @@ static void logclient(const char *msg, void *user) { 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, @@ -953,7 +993,7 @@ 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"); @@ -1315,7 +1355,7 @@ static int c_edituser(struct conn *c, 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)); } } @@ -1486,7 +1526,7 @@ static int c_reminder(struct conn *c, 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"); @@ -1833,6 +1873,7 @@ static const struct command { { "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 },