chiark / gitweb /
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 7c89a8f5bfa785dfedb7db6b31e5615d4b1f25e7..f5fd10c9037673ac0836e0fc111854bc8829907e 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 9c8a493317cd3f48ff8aa53970889948048f8387..743bb51b2b4f1ea7ef36ed835a6b06435bfa7fd8 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 5648b43a427bdeeac87acf7f9841a7bcc6de9aa0..1bf4088c59db2a7f4155b05e9da13288e93e75b9 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 34f8d53842473a5785ca7f8b7e203bc6515db2f8..3ca9a737775cd7973f95a66e91866e132db4f378 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 c5cc2e125fe0a51ef54f4cdfd3455910c0b14e42..4ef7862071aa0479222899ab2be7313bc5ce6fd9 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 57496e64a9f0a10bdbbbdb5da85f5e17537c5623..1c526de937d1a8ed55f2be4b17ad540ec053ebd7 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 d7e0afbbb43d672fe85da5d30b05e10e2d922a09..4134111f4140b7579ce08c8821ffd0d7c9261fe7 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 1b7386c20c9402afe33cf1059e968d7d2aec688f..fe51ade0677c7c07f9e0bc4b834787b7f269df82 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 a419ab02c1e5731015ec96c738ea62856789aeca..48337ea5d5082dc9ce3f59ac1e1ba76086ef9420 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 53c566c1b977509959c1427597b257b65a9c2021..aaa5f93604bedb26fc35f5f0358d6833c9c4f45b 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;