compress build dep table a bit
[disorder] / server / server.c
index ce45a1d..6866764 100644 (file)
@@ -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 },