pattern based dispatch for tracklength plugins
authorRichard Kettlewell <rjk@greenend.org.uk>
Sat, 3 Nov 2007 12:44:55 +0000 (12:44 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sat, 3 Nov 2007 12:44:55 +0000 (12:44 +0000)
debian/etc.disorder.config
doc/disorder_config.5.in
examples/config.sample.in
lib/configuration.c
lib/configuration.h
lib/plugin.c
lib/plugin.h
plugins/Makefile.am
prepare
server/rescan.c

index 7c89a8f..f5fd10c 100644 (file)
@@ -19,6 +19,15 @@ player *.ogg execraw disorder-decode
 player *.wav execraw disorder-decode
 player *.flac execraw disorder-decode
 
 player *.wav execraw disorder-decode
 player *.flac execraw disorder-decode
 
+# Track length calculators
+#
+# If you add new formats then can add a plugin module to calculate the
+# length of a track.  See disorder(3) for the interface.
+tracklength *.mp3 disorder-tracklength
+tracklength *.ogg disorder-tracklength
+tracklength *.wav disorder-tracklength
+tracklength *.flac disorder-tracklength
+
 # Don't leave a gap between tracks.
 gap 0
 
 # Don't leave a gap between tracks.
 gap 0
 
index 9c8a493..743bb51 100644 (file)
@@ -320,6 +320,12 @@ the shell quoting rules.
 .RE
 .IP
 If multiple player commands match a track then the first match is used.
 .RE
 .IP
 If multiple player commands match a track then the first match is used.
+.IP
+For the server to be able to calculate track lengths, there should be a
+.B tracklength
+command corresponding to each
+.B player
+command.
 .TP
 .B prefsync \fISECONDS\fR
 The interval at which the preferences log file will be synchronised.  Defaults
 .TP
 .B prefsync \fISECONDS\fR
 The interval at which the preferences log file will be synchronised.  Defaults
@@ -329,6 +335,20 @@ to 3600, i.e. one hour.
 The target size of the queue.  If random play is enabled then randomly picked
 tracks will be added until the queue is at least this big.
 .TP
 The target size of the queue.  If random play is enabled then randomly picked
 tracks will be added until the queue is at least this big.
 .TP
+.B restrict \fR[\fBscratch\fR] [\fBremove\fR] [\fBmove\fR]
+Determine which operations are restricted to the submitter of a
+track.  By default, no operations are restricted, i.e. anyone can
+scratch or remove anything.
+.IP
+If \fBrestrict scratch\fR or \fBrestrict remove\fR are set then only the user
+that submitted a track can scratch or remove it, respectively.
+.IP
+If \fBrestrict move\fR is set then only trusted users can move tracks around in
+the queue.
+.IP
+If \fBrestrict\fR is used more than once then only the final use has any
+effect.
+.TP
 .B sample_format \fIBITS\fB/\fIRATE\fB/\fICHANNELS
 Describes the sample format expected by the \fBspeaker_command\fR (below).  The
 components of the format specification are as follows:
 .B sample_format \fIBITS\fB/\fIRATE\fB/\fICHANNELS
 Describes the sample format expected by the \fBspeaker_command\fR (below).  The
 components of the format specification are as follows:
@@ -413,20 +433,6 @@ is invoked to translate it.  If
 .B sox
 is not installed then this will not work.
 .TP
 .B sox
 is not installed then this will not work.
 .TP
-.B restrict \fR[\fBscratch\fR] [\fBremove\fR] [\fBmove\fR]
-Determine which operations are restricted to the submitter of a
-track.  By default, no operations are restricted, i.e. anyone can
-scratch or remove anything.
-.IP
-If \fBrestrict scratch\fR or \fBrestrict remove\fR are set then only the user
-that submitted a track can scratch or remove it, respectively.
-.IP
-If \fBrestrict move\fR is set then only trusted users can move tracks around in
-the queue.
-.IP
-If \fBrestrict\fR is used more than once then only the final use has any
-effect.
-.TP
 .B scratch \fIPATH\fR
 Specifies a scratch.  When a track is scratched, a scratch track is
 played at random.
 .B scratch \fIPATH\fR
 Specifies a scratch.  When a track is scratched, a scratch track is
 played at random.
@@ -438,6 +444,10 @@ UTF-8 (which means that ASCII will do).
 .B stopword \fIWORD\fR ...
 Specifies one or more stopwords that should not take part in searches
 over track names.
 .B stopword \fIWORD\fR ...
 Specifies one or more stopwords that should not take part in searches
 over track names.
+.TP
+.B tracklength \fIPATTERN\fR \fIMODULE\fR
+Specifies the module used to calculate the length of files matching
+\fIPATTERN\fR.  \fIMODULE\fR specifies which plugin module to use.
 .SS "Client Configuration"
 .TP
 .B connect \fIHOST SERVICE\fR
 .SS "Client Configuration"
 .TP
 .B connect \fIHOST SERVICE\fR
index 5648b43..1bf4088 100644 (file)
@@ -12,6 +12,15 @@ player *.ogg execraw disorder-decode
 player *.wav execraw disorder-decode
 player *.flac execraw disorder-decode
 
 player *.wav execraw disorder-decode
 player *.flac execraw disorder-decode
 
+# Track length calculators
+#
+# If you add new formats then can add a plugin module to calculate the
+# length of a track.  See disorder(3) for the interface.
+tracklength *.mp3 disorder-tracklength
+tracklength *.ogg disorder-tracklength
+tracklength *.wav disorder-tracklength
+tracklength *.flac disorder-tracklength
+
 # Use the fs module to list files under /export/mp3.  The encoding
 # is ISO-8859-1.
 collection fs ISO-8859-1 /export/mp3
 # Use the fs module to list files under /export/mp3.  The encoding
 # is ISO-8859-1.
 collection fs ISO-8859-1 /export/mp3
index 34f8d53..3ca9a73 100644 (file)
@@ -635,6 +635,17 @@ static int validate_player(const struct config_state *cs,
   return 0;
 }
 
   return 0;
 }
 
+static int validate_tracklength(const struct config_state *cs,
+                               int nvec,
+                               char attribute((unused)) **vec) {
+  if(nvec < 2) {
+    error(0, "%s:%d: should be at least 'tracklength PATTERN MODULE'",
+         cs->path, cs->line);
+    return -1;
+  }
+  return 0;
+}
+
 static int validate_allow(const struct config_state *cs,
                          int nvec,
                          char attribute((unused)) **vec) {
 static int validate_allow(const struct config_state *cs,
                          int nvec,
                          char attribute((unused)) **vec) {
@@ -903,6 +914,7 @@ static const struct conf conf[] = {
   { C(speaker_command),  &type_string,           validate_any },
   { C(stopword),         &type_string_accum,     validate_any },
   { C(templates),        &type_string_accum,     validate_isdir },
   { C(speaker_command),  &type_string,           validate_any },
   { C(stopword),         &type_string_accum,     validate_any },
   { C(templates),        &type_string_accum,     validate_isdir },
+  { C(tracklength),      &type_stringlist_accum, validate_tracklength },
   { C(transform),        &type_transform,        validate_any },
   { C(trust),            &type_string_accum,     validate_any },
   { C(url),              &type_string,           validate_url },
   { C(transform),        &type_transform,        validate_any },
   { C(trust),            &type_string_accum,     validate_any },
   { C(url),              &type_string,           validate_url },
index c5cc2e1..4ef7862 100644 (file)
@@ -102,6 +102,9 @@ struct config {
   /** @brief All players */
   struct stringlistlist player;
 
   /** @brief All players */
   struct stringlistlist player;
 
+  /** @brief All tracklength plugins */
+  struct stringlistlist tracklength;
+
   /** @brief Allowed users */
   struct stringlistlist allow;
 
   /** @brief Allowed users */
   struct stringlistlist allow;
 
index 57496e6..1c526de 100644 (file)
@@ -58,6 +58,7 @@ const struct plugin *open_plugin(const char *name,
   for(pl = plugins; pl && strcmp(pl->name, name); pl = pl->next)
     ;
   if(pl) return pl;
   for(pl = plugins; pl && strcmp(pl->name, name); pl = pl->next)
     ;
   if(pl) return pl;
+  /* Search the plugin path */
   for(n = 0; n <= config->plugins.n; ++n) {
     byte_xasprintf(&p, "%s/%s" SOSUFFIX,
                   n == config->plugins.n ? pkglibdir : config->plugins.s[n],
   for(n = 0; n <= config->plugins.n; ++n) {
     byte_xasprintf(&p, "%s/%s" SOSUFFIX,
                   n == config->plugins.n ? pkglibdir : config->plugins.s[n],
@@ -106,13 +107,18 @@ const void *get_plugin_object(const struct plugin *pl,
 
 typedef long tracklength_fn(const char *track, const char *path);
 
 
 typedef long tracklength_fn(const char *track, const char *path);
 
-long tracklength(const char *track, const char *path) {
-  static tracklength_fn *f = 0;
+/** Compute the length of a track
+ * @param plugin plugin to use, as configured
+ * @param track UTF-8 name of track
+ * @param path file system path or 0
+ * @return length of track in seconds, 0 for unknown, -1 for error
+ */
+long tracklength(const char *plugin, const char *track, const char *path) {
+  tracklength_fn *f = 0;
 
 
-  if(!f)
-    f = (tracklength_fn *)get_plugin_function(open_plugin("tracklength",
-                                                         PLUGIN_FATAL),
-                                             "disorder_tracklength");
+  f = (tracklength_fn *)get_plugin_function(open_plugin(plugin,
+                                                       PLUGIN_FATAL),
+                                           "disorder_tracklength");
   return (*f)(track, path);
 }
 
   return (*f)(track, path);
 }
 
index d7e0afb..4134111 100644 (file)
@@ -42,11 +42,7 @@ const void *get_plugin_object(const struct plugin *handle,
 
 /* track length computation ***************************************************/
 
 
 /* track length computation ***************************************************/
 
-long tracklength(const char *track, const char *path);
-/* compute the length of the track.  @track@ is the UTF-8 name of the
- * track, @path@ is the file system name (or 0 for tracks that don't
- * exist in the filesystem).  The return value should be a positive
- * number of seconds, 0 for unknown or -1 if an error occurred. */
+long tracklength(const char *plugin, const char *track, const char *path);
 
 /* collection interface *******************************************************/
 
 
 /* collection interface *******************************************************/
 
index 1b7386c..fe51ade 100644 (file)
 # USA
 #
 
 # USA
 #
 
-pkglib_LTLIBRARIES=tracklength.la fs.la notify.la exec.la shell.la \
+pkglib_LTLIBRARIES=disorder-tracklength.la fs.la notify.la exec.la shell.la \
                   execraw.la
 AM_CPPFLAGS=-I${top_srcdir}/lib
 
 notify_la_SOURCES=notify.c
 notify_la_LDFLAGS=-module
 
                   execraw.la
 AM_CPPFLAGS=-I${top_srcdir}/lib
 
 notify_la_SOURCES=notify.c
 notify_la_LDFLAGS=-module
 
-tracklength_la_SOURCES=tracklength.c mad.c madshim.h ../lib/wav.h ../lib/wav.c
-tracklength_la_LDFLAGS=-module
-tracklength_la_LIBADD=$(LIBVORBISFILE) $(LIBMAD) $(LIBFLAC)
+disorder_tracklength_la_SOURCES=tracklength.c mad.c madshim.h ../lib/wav.h ../lib/wav.c
+disorder_tracklength_la_LDFLAGS=-module
+disorder_tracklength_la_LIBADD=$(LIBVORBISFILE) $(LIBMAD) $(LIBFLAC)
 
 fs_la_SOURCES=fs.c
 fs_la_LDFLAGS=-module
 
 fs_la_SOURCES=fs.c
 fs_la_LDFLAGS=-module
diff --git a/prepare b/prepare
index a419ab0..48337ea 100755 (executable)
--- a/prepare
+++ b/prepare
@@ -42,4 +42,4 @@ autoheader
 automake -a || true            # for INSTALL
 automake --foreign -a
 cd "$here"
 automake -a || true            # for INSTALL
 automake --foreign -a
 cd "$here"
-$srcdir/configure "$@" --sysconfdir=/etc --localstatedir=/var
+$srcdir/configure --sysconfdir=/etc --localstatedir=/var "$@"
index 53c566c..aaa5f93 100644 (file)
@@ -198,8 +198,8 @@ static int recheck_callback(const char *track,
   const struct collection *c = cs->c;
   const char *path = kvp_get(data, "_path");
   char buffer[20];
   const struct collection *c = cs->c;
   const char *path = kvp_get(data, "_path");
   char buffer[20];
-  int err;
-  long n;
+  int err, n;
+  long length;
 
   if(aborted()) return EINTR;
   D(("rechecking %s", track));
 
   if(aborted()) return EINTR;
   D(("rechecking %s", track));
@@ -222,13 +222,20 @@ static int recheck_callback(const char *track,
   /* make sure we know the length */
   if(!kvp_get(data, "_length")) {
     D(("recalculating length of %s", track));
   /* make sure we know the length */
   if(!kvp_get(data, "_length")) {
     D(("recalculating length of %s", track));
-    n = tracklength(track, path);
-    if(n > 0) {
-      byte_snprintf(buffer, sizeof buffer, "%ld", n);
-      kvp_set(&data, "_length", buffer);
-      if((err = trackdb_putdata(trackdb_tracksdb, track, data, tid, 0)))
-        return err;
-      ++cs->nlength;
+    for(n = 0; n < config->tracklength.n; ++n)
+      if(fnmatch(config->tracklength.s[n].s[0], track, 0) == 0)
+        break;
+    if(n >= config->tracklength.n)
+      error(0, "no tracklength plugin found for %s", track);
+    else {
+      length = tracklength(config->tracklength.s[n].s[1], track, path);
+      if(length > 0) {
+        byte_snprintf(buffer, sizeof buffer, "%ld", length);
+        kvp_set(&data, "_length", buffer);
+        if((err = trackdb_putdata(trackdb_tracksdb, track, data, tid, 0)))
+          return err;
+        ++cs->nlength;
+      }
     }
   }
   return 0;
     }
   }
   return 0;