chiark / gitweb /
remove action; better findtrack; more template fiddling
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 11 May 2008 12:55:21 +0000 (13:55 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 11 May 2008 12:55:21 +0000 (13:55 +0100)
server/actions.c
server/disorder-cgi.h
server/lookup.c
server/macros-disorder.c
templates/credits.tmpl
templates/macros.tmpl
templates/options.labels
templates/playing.tmpl
templates/topbarend.tmpl

index 1a6f7c9a74e0267d6c5feadc2af2643ed159891c..8e975e447451731d91455ad9ed0b0711e474dab9 100644 (file)
@@ -119,6 +119,37 @@ static void act_random_enable(void) {
   redirect(0);
 }
 
   redirect(0);
 }
 
+static void act_remove(void) {
+  const char *id;
+  struct queue_entry *q;
+
+  if(dcgi_client) {
+    if(!(id = cgi_get("id")))
+      error(0, "missing 'id' argument");
+    else if(!(q = dcgi_findtrack(id)))
+      error(0, "unknown queue id %s", id);
+    else switch(q->state) {
+    case playing_isscratch:
+    case playing_failed:
+    case playing_no_player:
+    case playing_ok:
+    case playing_quitting:
+    case playing_scratched:
+      error(0, "does not make sense to scratch %s", id);
+      break;
+    case playing_paused:                /* started but paused */
+    case playing_started:               /* started to play */
+      disorder_scratch(dcgi_client, id);
+      break;
+    case playing_random:                /* unplayed randomly chosen track */
+    case playing_unplayed:              /* haven't played this track yet */
+      disorder_remove(dcgi_client, id);
+      break;
+    }
+  }
+  redirect(0);
+}
+
 /** @brief Table of actions */
 static const struct action {
   /** @brief Action name */
 /** @brief Table of actions */
 static const struct action {
   /** @brief Action name */
@@ -132,6 +163,7 @@ static const struct action {
   { "playing", act_playing },
   { "random-disable", act_random_disable },
   { "random-enable", act_random_enable },
   { "playing", act_playing },
   { "random-disable", act_random_disable },
   { "random-enable", act_random_enable },
+  { "remove", act_remove },
 };
 
 /** @brief Expand a template
 };
 
 /** @brief Expand a template
index a85b9f9b2e697fcc61e7b104ee35e927476483c0..95b36c66053df516130ca03cd280042c0dd716cb 100644 (file)
@@ -70,6 +70,7 @@ void dcgi_expansions(void);
 char *dcgi_cookie_header(void);
 void dcgi_login(void);
 void dcgi_get_cookie(void);
 char *dcgi_cookie_header(void);
 void dcgi_login(void);
 void dcgi_get_cookie(void);
+struct queue_entry *dcgi_findtrack(const char *id);
 
 void option_set(const char *name, const char *value);
 const char *option_label(const char *key);
 
 void option_set(const char *name, const char *value);
 const char *option_label(const char *key);
index cb28f2c292e44a2ccf201d2f0fb264036488510a..452cd5309c06325e2cdd36aa833f424f773010b1 100644 (file)
@@ -28,6 +28,9 @@
 /** @brief Cached data */
 static unsigned flags;
 
 /** @brief Cached data */
 static unsigned flags;
 
+/** @brief Map of hashes to queud data */
+static hash *queuemap;
+
 struct queue_entry *dcgi_queue;
 struct queue_entry *dcgi_playing;
 struct queue_entry *dcgi_recent;
 struct queue_entry *dcgi_queue;
 struct queue_entry *dcgi_playing;
 struct queue_entry *dcgi_recent;
@@ -43,6 +46,13 @@ rights_type dcgi_rights;
 int dcgi_enabled;
 int dcgi_random_enabled;
 
 int dcgi_enabled;
 int dcgi_random_enabled;
 
+static void queuemap_add(struct queue_entry *q) {
+  if(!queuemap)
+    queuemap = hash_new(sizeof (struct queue_entry *));
+  for(; q; q = q->next)
+    hash_add(queuemap, q->id, &q, HASH_INSERT_OR_REPLACE);
+}
+
 /** @brief Fetch cachable data */
 void dcgi_lookup(unsigned want) {
   unsigned need = want ^ (flags & want);
 /** @brief Fetch cachable data */
 void dcgi_lookup(unsigned want) {
   unsigned need = want ^ (flags & want);
@@ -54,10 +64,14 @@ void dcgi_lookup(unsigned want) {
 
   if(!dcgi_client || !need)
     return;
 
   if(!dcgi_client || !need)
     return;
-  if(need & DCGI_QUEUE)
+  if(need & DCGI_QUEUE) {
     disorder_queue(dcgi_client, &dcgi_queue);
     disorder_queue(dcgi_client, &dcgi_queue);
-  if(need & DCGI_PLAYING)
+    queuemap_add(dcgi_queue);
+  }
+  if(need & DCGI_PLAYING) {
     disorder_playing(dcgi_client, &dcgi_playing);
     disorder_playing(dcgi_client, &dcgi_playing);
+    queuemap_add(dcgi_playing);
+  }
   if(need & DCGI_NEW)
     disorder_new_tracks(dcgi_client, &dcgi_new, &dcgi_nnew, 0);
   if(need & DCGI_RECENT) {
   if(need & DCGI_NEW)
     disorder_new_tracks(dcgi_client, &dcgi_new, &dcgi_nnew, 0);
   if(need & DCGI_RECENT) {
@@ -69,6 +83,7 @@ void dcgi_lookup(unsigned want) {
       dcgi_recent = r;
       r = rnext;
     }
       dcgi_recent = r;
       r = rnext;
     }
+    queuemap_add(dcgi_recent);
   }
   if(need & DCGI_VOLUME)
     disorder_get_volume(dcgi_client,
   }
   if(need & DCGI_VOLUME)
     disorder_get_volume(dcgi_client,
@@ -102,9 +117,28 @@ void dcgi_lookup(unsigned want) {
   flags |= need;
 }
 
   flags |= need;
 }
 
+/** @brief Locate a track by ID */
+struct queue_entry *dcgi_findtrack(const char *id) {
+  struct queue_entry *q, **qq;
+
+  if(queuemap && (qq = hash_find(id)))
+    return *q;
+  dcgi_lookup(DCGI_PLAYING);
+  if(queuemap && (qq = hash_find(id)))
+    return *q;
+  dcgi_lookup(DCGI_QUEUE);
+  if(queuemap && (qq = hash_find(id)))
+    return *q;
+  dcgi_lookup(DCGI_RECENT);
+  if(queuemap && (qq = hash_find(id)))
+    return *q;
+  return NULL;
+}
+
 void dcgi_lookup_reset(void) {
   /* Forget everything we knew */
   flags = 0;
 void dcgi_lookup_reset(void) {
   /* Forget everything we knew */
   flags = 0;
+  queuemap = 0;
   dcgi_recent = 0;
   dcgi_queue = 0;
   dcgi_playing = 0;
   dcgi_recent = 0;
   dcgi_queue = 0;
   dcgi_playing = 0;
index e58324bf6cc3bdf0f0b719fb3c5e68631ea5a1ca..6c81d56136011ffbb8a2f57984de0bb1484f8c97 100644 (file)
 /** @brief For error template */
 char *dcgi_error_string;
 
 /** @brief For error template */
 char *dcgi_error_string;
 
-/** @brief Locate a track by ID */
-static struct queue_entry *findtrack(const char *id) {
-  struct queue_entry *q;
-
-  dcgi_lookup(DCGI_PLAYING);
-  if(dcgi_playing && !strcmp(dcgi_playing->id, id))
-    return dcgi_playing;
-  dcgi_lookup(DCGI_QUEUE);
-  for(q = dcgi_queue; q; q = q->next)
-    if(!strcmp(q->id, id))
-      return q;
-  dcgi_lookup(DCGI_RECENT);
-  for(q = dcgi_recent; q; q = q->next)
-    if(!strcmp(q->id, id))
-      return q;
-  return NULL;
-}
-
 /** @brief Return @p i as a string */
 static const char *make_index(int i) {
   char *s;
 /** @brief Return @p i as a string */
 static const char *make_index(int i) {
   char *s;
@@ -150,7 +132,7 @@ static int exp_part(int nargs,
   char *s;
 
   if(track[0] != '/') {
   char *s;
 
   if(track[0] != '/') {
-    struct queue_entry *q = findtrack(track);
+    struct queue_entry *q = dcgi_findtrack(track);
 
     if(q)
       track = q->track;
 
     if(q)
       track = q->track;
@@ -187,7 +169,7 @@ static int exp_who(int attribute((unused)) nargs,
                    char **args,
                    struct sink *output,
                    void attribute((unused)) *u) {
                    char **args,
                    struct sink *output,
                    void attribute((unused)) *u) {
-  struct queue_entry *q = findtrack(args[0]);
+  struct queue_entry *q = dcgi_findtrack(args[0]);
 
   if(q && q->submitter)
     return sink_writes(output, cgi_sgmlquote(q->submitter)) < 0 ? -1 : 0;
 
   if(q && q->submitter)
     return sink_writes(output, cgi_sgmlquote(q->submitter)) < 0 ? -1 : 0;
@@ -203,7 +185,7 @@ static int exp_when(int attribute((unused)) nargs,
                    char **args,
                    struct sink *output,
                     void attribute((unused)) *u) {
                    char **args,
                    struct sink *output,
                     void attribute((unused)) *u) {
-  struct queue_entry *q = findtrack(args[0]);
+  struct queue_entry *q = dcgi_findtrack(args[0]);
   const struct tm *w = 0;
 
   if(q) {
   const struct tm *w = 0;
 
   if(q) {
@@ -250,7 +232,7 @@ static int exp_length(int attribute((unused)) nargs,
     name = args[0];
   else {
     /* Track identified by queue ID */
     name = args[0];
   else {
     /* Track identified by queue ID */
-    if(!(q = findtrack(args[0])))
+    if(!(q = dcgi_findtrack(args[0])))
       return 0;
     if(q->state == playing_started || q->state == playing_paused)
       if(sink_printf(output, "%ld:%02ld/", q->sofar / 60, q->sofar % 60) < 0)
       return 0;
     if(q->state == playing_started || q->state == playing_paused)
       if(sink_printf(output, "%ld:%02ld/", q->sofar / 60, q->sofar % 60) < 0)
@@ -272,7 +254,7 @@ static int exp_removable(int attribute((unused)) nargs,
                          char **args,
                          struct sink *output,
                          void attribute((unused)) *u) {
                          char **args,
                          struct sink *output,
                          void attribute((unused)) *u) {
-  struct queue_entry *q = findtrack(args[0]);
+  struct queue_entry *q = dcgi_findtrack(args[0]);
   /* TODO would be better to reject recent */
 
   if(!q || !dcgi_client)
   /* TODO would be better to reject recent */
 
   if(!q || !dcgi_client)
@@ -291,7 +273,7 @@ static int exp_movable(int attribute((unused)) nargs,
                        char **args,
                        struct sink *output,
                        void attribute((unused)) *u) {
                        char **args,
                        struct sink *output,
                        void attribute((unused)) *u) {
-  struct queue_entry *q = findtrack(args[0]);
+  struct queue_entry *q = dcgi_findtrack(args[0]);
   /* TODO would be better to recent playing/recent */
 
   if(!q || !dcgi_client)
   /* TODO would be better to recent playing/recent */
 
   if(!q || !dcgi_client)
@@ -668,7 +650,7 @@ static int exp_state(int attribute((unused)) nargs,
                      char **args,
                      struct sink *output,
                      void attribute((unused)) *u) {
                      char **args,
                      struct sink *output,
                      void attribute((unused)) *u) {
-  struct queue_entry *q = findtrack(args[0]);
+  struct queue_entry *q = dcgi_findtrack(args[0]);
 
   if(q)
     return sink_writes(output, playing_states[q->state]) < 0 ? -1 : 0;
 
   if(q)
     return sink_writes(output, playing_states[q->state]) < 0 ? -1 : 0;
index 8bdadcac3857905f65acae9ed2467d79c178b131..cb8d48f14350b80f519bad6d40f504c8afdcfa73 100644 (file)
@@ -1,9 +1,4 @@
-<p class=credits><a
-href="http://www.greenend.org.uk/rjk/disorder/"
-title="DisOrder web site">DisOrder
-version @version@</a> &copy; 2003-2008 Richard Kettlewell</p>
-@@
-<!--
+@discard{
 This file is part of DisOrder.
 Copyright (C) 2004-2008 Richard Kettlewell
 
 This file is part of DisOrder.
 Copyright (C) 2004-2008 Richard Kettlewell
 
@@ -22,3 +17,10 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 -->
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 -->
+}@#
+<p class=credits>
+  <a href="http://www.greenend.org.uk/rjk/disorder/"
+     title="DisOrder web site">DisOrder
+     version @version</a>
+  &copy; 2003-2008 Richard Kettlewell et al
+</p>
index cb763b27a956c0a673fc503efccca7b1817e1e6c..8714a08c00516683488ab939e763dbd44bfc64dd 100644 (file)
@@ -18,9 +18,61 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 
-@define {ifmanage} {yes} {no}
-        {@if {@eq {@arg{action}}{manage}}
-             {@yes}
-             {@no}}
+@# Expand to @yes for the Manage page and @no for the playing page
+@define {ifmanage} {yes no}
+         {@if {@eq {@arg{action}}{manage}}
+              {@yes}
+              {@no}}
 
 
-}@@@
+@# Expand to &back=manage or to nothing
+@define {back} {}
+        {@ifmanage{&amp;back=manage}{}}
+
+@# Expand to the time that @id will be played
+@define {mwhen} {what id}
+        {@when{@id}</td>}
+
+@# Expand to the 'who' field for @id
+@define {mwho} {what id}
+        {@if{@eq{@who{@id}}{}}
+            {@if{@eq{@state{@id}}{random}}
+                {@label{@what.randomtrack}}
+                 {&nbsp;}}
+            {@who{@id}}}
+
+@# Expand to the artist for @track
+@define {martist} {what track}
+        {@right{play}
+               {<a class=directory
+                   href="@url?action=choose&amp;directory=@urlquote{@dirname{@dirname{@track}}}"
+                   title="@label{@what.artistverbose}">@part{@track}{short}{artist}</a>}
+               {<span class=directory
+                      title="@part{@track}{artist}@">@part{@track}{short}{artist}</span>}}
+
+@# Expand to the album for @track
+@define {malbum} {what track}
+        {@right{play}
+               {<a class=directory
+                   href="@url?action=choose&amp;directory=@urlquote{@dirname{@track}}"
+                   title="@label{@what.albumverbose}">@part{@track}{short}{album}</a>}
+               {<span class=directory
+                      title="@part{@track}{album}@">@part{@track}{short}{album}</span>}}
+
+@# Expand to the title for @track
+@define {mtitle} {what track}
+        {<span title="@part{@track}{title}">@part{@track}{short}{title}</span>}
+
+@# Expand to the remove/scratch entry for @id
+@define {mremove} {what id}
+        {@if{@removable{@id}}
+            {<a class=imgbutton
+                href="@url?action=remove&#38;id=@id@back">
+               <img class=button src="@image{remove}"
+                    title="@label{@what.removeverbose}"
+                    alt="@label{@what.scratch}">
+             </a>}
+            {<img class=button src="@image{noremove}"
+                  title="@label{@what.removeverbose}"
+                  alt="@label{@what.scratch}">}}
+
+}@#
index 55d661a538ed7ae5c5624cf26a404b67ae4cf12b..ef6272d6424831ddc971e660e8f793f1cedd5f16 100644 (file)
@@ -15,12 +15,12 @@ label       playing.randomtrack     &nbsp;
 label  queue.randomtrack       random
 
 # Short and long text for scratch (remove playing track) button
 label  queue.randomtrack       random
 
 # Short and long text for scratch (remove playing track) button
-label  playing.scratch         Scratch
-label  playing.scratchverbose  "stop playing this track"
+label  playing.remove          Scratch
+label  playing.removeverbose   "stop playing this track"
 
 # Short and long text for remove queued track button
 
 # Short and long text for remove queued track button
-label  playing.remove          Remove
-label  playing.removeverbose   "remove track from queue"
+label  queue.remove            Remove
+label  queue.removeverbose     "remove track from queue"
 
 # Text for banner above currently playing track
 label  playing.now             "Now playing"
 
 # Text for banner above currently playing track
 label  playing.now             "Now playing"
@@ -239,8 +239,8 @@ label       heading.length          Length
 # Role images.  See the documentation for @images:NAME@.
 label   images.enabled          tick.png
 label   images.disabled         cross.png
 # Role images.  See the documentation for @images:NAME@.
 label   images.enabled          tick.png
 label   images.disabled         cross.png
-label   images.scratch          cross.png
-label   images.noscratch        nocross.png
+label   images.remove           cross.png
+label   images.noremove         nocross.png
 label   images.noup             noup.png
 label   images.upall            upup.png
 label   images.noupall          noupup.png
 label   images.noup             noup.png
 label   images.upall            upup.png
 label   images.noupall          noupup.png
index 084f5c3c5553fe8470ea2667d4488f5f262256d5..d0e000081c2bc41cd537828868d2ea8326772564 100644 (file)
@@ -19,12 +19,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 -->
 @discard{
 USA
 -->
 @discard{
-  @define {ifmanage} {yes no}
-         {@if {@eq {@arg{action}}{manage}}
-              {@yes}
-              {@no}}
-  @define {back} {}
-          {@ifmanage{&amp;back=manage}{}}
   @include{macros.tmpl}
 }@#
 <html>
   @include{macros.tmpl}
 }@#
 <html>
@@ -154,39 +148,13 @@ USA
       <td colspan=@ifmanage{11}{7}>@label{playing.now}</td>
      </tr>
      <tr class=playing>
       <td colspan=@ifmanage{11}{7}>@label{playing.now}</td>
      </tr>
      <tr class=playing>
-      <td class=when>@when{@id}</td>
-      <td class=who>@if{@eq{@who{@id}}{}}
-                       {@if{@eq{@state{@id}}{random}}
-                           {@label{playing.randomtrack}}
-                           {&nbsp;}}
-                       {@who{@id}}
-      </td>
-      <td class=artist>@right{play}
-                             {<a class=directory
-                                 href="@url?action=choose&amp;directory=@urlquote{@dirname{@dirname{@track}}}"
-                                 title="@label{playing.artistverbose}">@part{@id}{short}{artist}</a>}
-                             {<span class=directory
-                                    title="@part{artist}@">@part{short}{artist}</span>}
-      </td>
-      <td class=album>@right{play}
-                            {<a class=directory
-                                href="@url?action=choose&amp;directory=@urlquote{@dirname{@track}}"
-                                title="@label{playing.albumverbose}">@part{short}{album}</a>}
-                            {<span class=directory
-                                   title="@part{album}@">@part{short}{album}</span>}
-      </td>
-      <td class=title><span title="@part{@id}{title}">@part{@id}{short}{title}</span></td>
+      <td class=when>@mwhen{playing}{@id}</td>
+      <td class=who>@mwho{playing}{@id}</td>
+      <td class=artist>@martist{playing}{@track}</td>
+      <td class=album>@malbum{playing}{@track}</td>
+      <td class=title>@mtitle{playing}{@track}</td>
       <td class=length>@length{@id}</td>
       <td class=length>@length{@id}</td>
-      <td class=imgbutton>@if{@removabl{@id}}
-                             {<a class=imgbutton
-                                 href="@url?action=scratch&#38;id=@id@back">
-                              <img class=button src="@image{scratch}"
-                                   title="@label{playing.scratchverbose}"
-                                   alt="@label{playing.scratch}"></a>}
-                             {<img class=button src="@image{noscratch}"
-                                   title="@label{playing.scratchverbose}"
-                                   alt="@label{playing.scratch}">}
-      </td>
+      <td class=imgbutton>@mremove{playing}{@id}</td>
       @ifmanage{
       <td class=imgbutton>&nbsp;</td>
       <td class=imgbutton>&nbsp;</td>
       @ifmanage{
       <td class=imgbutton>&nbsp;</td>
       <td class=imgbutton>&nbsp;</td>
@@ -202,31 +170,13 @@ USA
      }
      @queue{
      <tr class=@parity@>
      }
      @queue{
      <tr class=@parity@>
-      <td class=when>@when</td>
-      <td class=who>@if{@eq{@who@}{}@}{@if{@eq{@state@}{random}@}{@label{queue.randomtrack}}{&nbsp;}@}{@who@}</td>
-      <td class=artist>@right{play}{<a class=directory
-       title="@part{@id}{artist}@"
-       href="@url?action=choose&amp;directory=@urlquote{@dirname{@dirname{@track}@}@}@"
-       >@part{@id}{short}{artist}</a>}{<span class=directory
-       title="@part{@id}{artist}@"
-       >@part{@id}{short}{artist}</span>}</td>
-      <td class=album>@right{play}{<a class=directory
-       title="@part{@id}{album}@"
-       href="@url?action=choose&amp;directory=@urlquote{@dirname{@track}@}@"
-       >@part{@id}{short}{album}</a>}{<span class=directory
-       title="@part{@id}{album}@"
-       >@part{@id}{short}{album}@}</td>
-      <td class=title><span
-       title="@part{@id}{title}@">@part{@id}{short}{title}</span></td>
+      <td class=when>@mwhen{queue}{@id}</td>
+      <td class=who>@mwho{queue}{@id}</td>
+      <td class=artist>@martist{queue}{@track}</td>
+      <td class=album>@malbum{queue}{@track}</td>
+      <td class=title>@mtitle{queue}{@track}</td>
       <td class=length>@length</td>
       <td class=length>@length</td>
-      <td class=imgbutton>@if{@removable@}{<a class=imgbutton
-       href="@url?action=remove&#38;id=@id@@back"><img
-       class=button src="@image{scratch}"
-       title="@label{playing.removeverbose}" 
-       alt="@label{playing.remove}"></a>}{<img
-       class=button src="@image{noscratch}"
-       title="@label{playing.removeverbose}"
-       alt="@label{playing.remove}">}</td>
+      <td class=imgbutton>@mremove{queue}{@id}</td>
 
       @if{@eq{@arg{action}}{manage}}{
       @if{@or{@isfirst@}
 
       @if{@eq{@arg{action}}{manage}}{
       @if{@or{@isfirst@}
@@ -286,7 +236,7 @@ USA
    </table>
 }
 
    </table>
 }
 
-@include{topbarend}@#
+@include{topbarend.tmpl}@#
  </body>
 </html>
 @discard{
  </body>
 </html>
 @discard{
index 5eca359d954ba665e0cd9f46e5204763c4bed9f3..887dba282a20918d106030f36a14fd49a0b85406 100644 (file)
@@ -1,8 +1,6 @@
-@include:credits@
-@@
-<!--
+@discard{
 This file is part of DisOrder.
 This file is part of DisOrder.
-Copyright (C) 2005 Richard Kettlewell
+Copyright (C) 2005, 2008 Richard Kettlewell
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,4 +16,5 @@ You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
--->
+}@#
+@include{credits.tmpl}@#