There are three audio file selectors available:
- random
- - plm (playlist manager)
+ - playlist
- mysql
The first two of these are rather simple, and they are always
Choose an audio file selector
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
paraslash has three different audio file selectors: random (default),
-plm (the playlist manager) and mysql.
+playlist and mysql.
The random selector chooses files randomly from the given
directory.
o the new ipc subsystem
- o new audio file selector: plm, the playlist manager
+ o new audio file selector: playlist
o para_server: the dopey selector is now called "random",
and is the default selector. Use the --selector option to
All senders have the same set of commands that allow to
control the access permissions of the stream.
- para_server needs an "audio file selector" to work, mainly to
- determine which song to stream next. There are three selectors
- available: random, plm and mysql. The former chooses audio
- files randomly and plm, the playlist manager, can handle
+ para_server needs an "audio file selector" to work, mainly
+ to determine which song to stream next. There are three
+ selectors available: random, playlist and mysql. The former
+ chooses audio files randomly and playlist can handle, well,
playlists. Both are always supported.
- The (optional) mysql selector connects to a mysql server
- which holds information on your audio files. It has several
- unusual features, see README.mysql for details.
+ The optional mysql selector connects to a mysql server which
+ holds information on your audio files. It has several unusual
+ features, see README.mysql for details.
- para_client (obligatory):
server_cmdline_objs="server.cmdline"
server_errlist_objs="server mp3 afs command net string signal random_dbtool time daemon stat
- crypt http_send db close_on_fork plm_dbtool ipc"
+ crypt http_send db close_on_fork playlist_selector ipc"
server_ldflags=""
########################################################################### ssl
};
int mysql_selector_init(struct audio_file_selector*);
-int plm_selector_init(struct audio_file_selector*);
+int playlist_selector_init(struct audio_file_selector*);
int random_selector_init(struct audio_file_selector*);
SS_NET, SS_ORTP_RECV, SS_AUDIOD, SS_EXEC, SS_CLOSE_ON_FORK, SS_SIGNAL,
SS_STRING, SS_DAEMON, SS_STAT, SS_TIME, SS_GRAB_CLIENT, SS_HTTP_RECV,
SS_RECV_COMMON, SS_FILTER_CHAIN, SS_WAV, SS_COMPRESS, SS_OGGDEC, SS_FILTER,
- SS_COMMAND, SS_RANDOM_DBTOOL, SS_PLM_DBTOOL, SS_CRYPT, SS_HTTP_SEND, SS_ORTP_SEND, SS_DB, SS_OGG,
+ SS_COMMAND, SS_RANDOM_DBTOOL, SS_PLAYLIST_SELECTOR, SS_CRYPT,
+ SS_HTTP_SEND, SS_ORTP_SEND, SS_DB, SS_OGG,
SS_MP3, SS_MP3DEC, SS_SERVER, SS_AFS, SS_MYSQL, SS_IPC, SS_RINGBUFFER};
#define NUM_SS (SS_RINGBUFFER + 1)
extern const char **para_errlist[];
PARA_ERROR(LOCK, "lock error"), \
PARA_ERROR(SENDER_CMD, "command not supported by this sender"), \
-#define PLM_DBTOOL_ERRORS \
+#define PLAYLIST_SELECTOR_ERRORS \
PARA_ERROR(LOAD_PLAYLIST, "failed to load playlist"), \
SS_ENUM(AFS);
SS_ENUM(COMMAND);
SS_ENUM(RANDOM_DBTOOL);
-SS_ENUM(PLM_DBTOOL);
+SS_ENUM(PLAYLIST_SELECTOR);
SS_ENUM(CRYPT);
SS_ENUM(HTTP_SEND);
SS_ENUM(ORTP_SEND);
--- /dev/null
+/*
+ * Copyright (C) 2006 Andre Noll <maan@systemlinux.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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, USA.
+ */
+
+/** \file playlist_selector.c The playlist audio file selector of paraslash */
+
+#include "server.h"
+#include "db.h"
+#include "error.h"
+#include "net.h"
+#include "string.h"
+#include "ipc.h"
+
+/**
+ * structure used for transmission of the playlist
+ *
+ * There's one such struct which gets initialized during startup. It lives in
+ * shared memory and is used by com_lpl().
+ */
+struct pls_client_data {
+/** allocated and set by com_lpl() (child) */
+ int shm_id;
+/** the size of the shared memory area identified by \a shm_id */
+ size_t size;
+/** initially locked, gets unlocked by parent when it is done */
+ int mutex;
+/** return value, set by parent */
+ int retval;
+};
+
+/** data specific to the playlist selector */
+struct private_pls_data {
+/** guards against concurrent client access */
+ int client_mutex;
+/** guards against concurrent parent-child access */
+ int server_mutex;
+/** pointer to the client data */
+ struct pls_client_data *client_data;
+/** id of the shm corresponding to \a client_data */
+ int client_data_shm_id;
+};
+
+/** we refuse to load playlists bigger than that */
+#define MAX_PLAYLIST_BYTES (1024 * 1024)
+
+static unsigned playlist_len, playlist_size, current_playlist_entry;
+static char **playlist;
+static struct audio_file_selector *self;
+
+static int com_ppl(int, int, char **);
+static int com_lpl(int, int, char **);
+extern struct misc_meta_data *mmd;
+
+/* array of commands that are supported by this database tool */
+static struct server_command cmds[] = {
+{
+.name = "ppl",
+.handler = com_ppl,
+.perms = DB_READ,
+.description = "print playlist",
+.synopsis = "ppl",
+.help =
+"Print out the current playlist"
+}, {
+.name = "lpl",
+.handler = com_lpl,
+.perms = DB_WRITE,
+.description = "load playlist",
+.synopsis = "lpl",
+.help =
+"Read a new playlist from stdin. Example:\n"
+"\tfind /audio -name '*.mp3' | para_client lpl"
+}, {
+.name = NULL,
+}
+};
+
+static void playlist_add(char *path)
+{
+ if (playlist_len >= playlist_size) {
+ playlist_size = 2 * playlist_size + 1;
+ playlist = para_realloc(playlist, playlist_size * sizeof(char *));
+ }
+ PARA_DEBUG_LOG("adding #%d/%d: %s\n", playlist_len, playlist_size, path);
+ playlist[playlist_len++] = para_strdup(path);
+}
+
+static int send_playlist_to_server(const char *buf, size_t size)
+{
+ struct private_pls_data *ppd = self->private_data;
+ int ret, shm_mutex = -1, shm_id = -1;
+ void *shm = NULL;
+
+ PARA_DEBUG_LOG("new playlist (%d bytes)\n", size);
+
+ ret = mutex_new();
+ if (ret < 0)
+ return ret;
+ shm_mutex = ret;
+
+ ret = shm_new(size);
+ if (ret < 0)
+ goto out;
+ shm_id = ret;
+
+ ret = shm_attach(shm_id, ATTACH_RW, &shm);
+ if (ret < 0)
+ goto out;
+ mutex_lock(shm_mutex);
+ memcpy(shm, buf, size);
+ mutex_lock(ppd->client_mutex);
+ mutex_lock(ppd->server_mutex);
+ ppd->client_data->size = size;
+ ppd->client_data->shm_id = shm_id;
+ ppd->client_data->mutex = shm_mutex;
+ kill(getppid(), SIGUSR1); /* wake up the server */
+ mutex_unlock(ppd->server_mutex);
+ mutex_lock(shm_mutex); /* wait until server is done */
+ mutex_unlock(shm_mutex);
+ ret = ppd->client_data->retval;
+ mutex_unlock(ppd->client_mutex);
+ shm_detach(shm);
+out:
+ if (shm_id >= 0)
+ shm_destroy(shm_id);
+ mutex_destroy(shm_mutex);
+ PARA_DEBUG_LOG("returning %d\n", ret);
+ return ret;
+}
+
+static int com_lpl(int fd, __unused int argc, __unused char *argv[])
+{
+ unsigned loaded = 0;
+ size_t bufsize = 4096; /* guess that's enough */
+ char *buf = para_malloc(bufsize);
+ ssize_t ret;
+ ret = send_buffer(fd, AWAITING_DATA_MSG);
+ if (ret < 0)
+ goto out;
+again:
+ ret = recv_bin_buffer(fd, buf + loaded, bufsize - loaded);
+ if (ret < 0)
+ goto out;
+ if (!ret) {
+ ret = send_playlist_to_server(buf, loaded);
+ goto out;
+ }
+ loaded += ret;
+ ret = -E_LOAD_PLAYLIST;
+ if (loaded >= MAX_PLAYLIST_BYTES)
+ goto out;
+ if (loaded >= bufsize) {
+ bufsize *= 2;
+ buf = para_realloc(buf, bufsize);
+ }
+ goto again;
+out:
+ free(buf);
+ return ret;
+}
+
+static int com_ppl(int fd, __unused int argc, __unused char *argv[])
+{
+ unsigned i;
+
+ PARA_DEBUG_LOG("sending playlist to client (%d entries)\n", playlist_len);
+ for (i = 0; i < playlist_len; i++) {
+ int ret = send_va_buffer(fd, "%s\n", playlist[
+ (i + current_playlist_entry) % playlist_len]);
+ if (ret < 0)
+ return ret;
+ }
+ return 1;
+}
+
+static char **pls_get_audio_file_list(unsigned int num)
+{
+ char **file_list;
+ unsigned i;
+
+ num = MIN(num, playlist_len);
+ if (!num)
+ return NULL;
+ file_list = para_malloc((num + 1) * sizeof(char *));
+ for (i = 0; i < num; i++) {
+ unsigned j = (current_playlist_entry + i) % playlist_len;
+ file_list[i] = para_strdup(playlist[j]);
+ }
+ file_list[i] = NULL;
+ return file_list;
+}
+
+static void free_playlist_contents(void)
+{
+ int i;
+
+ PARA_DEBUG_LOG("freeing playlist (%d entries)\n", playlist_len);
+ for (i = 0; i < playlist_len; i++)
+ free(playlist[i]);
+ current_playlist_entry = 0;
+ playlist_len = 0;
+}
+
+static void pls_shutdown(void)
+{
+ struct private_pls_data *ppd = self->private_data;
+
+ shm_detach(ppd->client_data);
+ shm_destroy(ppd->client_data_shm_id);
+ mutex_destroy(ppd->server_mutex);
+ mutex_destroy(ppd->client_mutex);
+ free(ppd);
+ free_playlist_contents();
+ free(playlist);
+ playlist = NULL;
+ playlist_len = 0;
+ playlist_size = 0;
+}
+
+static void pls_post_select(__unused fd_set *rfds, __unused fd_set *wfds)
+{
+ struct private_pls_data *ppd = self->private_data;
+ struct pls_client_data *pcd = ppd->client_data;
+ int ret;
+ void *shm;
+
+ mutex_lock(ppd->server_mutex);
+ if (!pcd->size)
+ goto out;
+ free_playlist_contents();
+ ret = shm_attach(pcd->shm_id, ATTACH_RW, &shm);
+ if (ret < 0) {
+ PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+ goto out;
+ }
+ PARA_DEBUG_LOG("loading new playlist (%d bytes)\n", pcd->size);
+ ret = for_each_line((char *)shm, pcd->size, &playlist_add);
+ shm_detach(shm);
+ PARA_NOTICE_LOG("new playlist (%d entries)\n", playlist_len);
+ pcd->retval = 1;
+ pcd->size = 0;
+ mutex_unlock(pcd->mutex);
+out:
+ mutex_unlock(ppd->server_mutex);
+}
+
+void pls_update_audio_file(char *audio_file)
+{
+ unsigned i;
+
+ for (i = 0; i < playlist_len; i++) {
+ unsigned j = (current_playlist_entry + i) % playlist_len;
+ if (strcmp(playlist[j], audio_file))
+ continue;
+ current_playlist_entry = (j + 1) % playlist_len;
+ }
+}
+
+/**
+ * the init function for the playlist selector
+ *
+ * Init all function pointers of \a db
+ *
+ * \sa struct audio_file_selector, misc_meta_data::dbinfo, mysql.c random_dbtool.c
+ */
+int playlist_selector_init(struct audio_file_selector *db)
+{
+ int ret;
+ struct private_pls_data *ppd = NULL;
+ void *shm = NULL;
+
+ self = db;
+ db->cmd_list = cmds;
+ db->get_audio_file_list = pls_get_audio_file_list;
+ db->shutdown = pls_shutdown;
+ db->post_select = pls_post_select;
+ db->update_audio_file = pls_update_audio_file;
+ ppd = para_calloc(sizeof(struct private_pls_data));
+ db->private_data = ppd;
+
+ ppd->client_mutex = -1;
+ ppd->server_mutex = -1;
+ ppd->client_data_shm_id = -1;
+ ppd->client_data = NULL;
+
+ ret = mutex_new();
+ if (ret < 0)
+ goto err_out;
+ ppd->client_mutex = ret;
+
+ ret = mutex_new();
+ if (ret < 0)
+ goto err_out;
+ ppd->server_mutex = ret;
+
+ ret = shm_new(sizeof(struct pls_client_data));
+ if (ret < 0)
+ goto err_out;
+ ppd->client_data_shm_id = ret;
+
+ ret = shm_attach(ppd->client_data_shm_id, ATTACH_RW, &shm);
+ if (ret < 0)
+ goto err_out;
+ ppd->client_data = shm;
+ ppd->client_data->size = 0;
+ sprintf(mmd->dbinfo, "playlist selector initialized");
+ return 1;
+err_out:
+ if (ppd->client_data_shm_id >= 0)
+ shm_destroy(ppd->client_data_shm_id);
+ if (ppd->client_mutex >= 0)
+ mutex_destroy(ppd->client_mutex);
+ if (ppd->server_mutex >= 0)
+ mutex_destroy(ppd->server_mutex);
+ free(ppd);
+ return ret;
+}
+++ /dev/null
-/*
- * Copyright (C) 2006 Andre Noll <maan@systemlinux.org>
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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, USA.
- */
-
-/** \file plm_dbtool.c Playlist manager for paraslash */
-
-#include "server.h"
-#include "db.h"
-#include "error.h"
-#include "net.h"
-#include "string.h"
-#include "ipc.h"
-
-/**
- * structure used for transmission of the playlist
- *
- * There's one such struct which gets initialized during startup. It lives in
- * shared memory and is used by com_lpl().
- */
-struct plm_client_data {
-/** allocated and set by com_lpl() (child) */
- int shm_id;
-/** the size of the shared memory area identified by \a shm_id */
- size_t size;
-/** initially locked, gets unlocked by parent when it is done */
- int mutex;
-/** return value, set by parent */
- int retval;
-};
-
-/** data specific to the plm database tool */
-struct private_plm_data {
-/** guards against concurrent client access */
- int client_mutex;
-/** guards against concurrent parent-child access */
- int server_mutex;
-/** pointer to the client data */
- struct plm_client_data *client_data;
-/** id of the shm corresponding to \a client_data */
- int client_data_shm_id;
-};
-
-/** we refuse to load playlists bigger than that */
-#define MAX_PLAYLIST_BYTES (1024 * 1024)
-
-static unsigned playlist_len, playlist_size, current_playlist_entry;
-static char **playlist;
-static struct audio_file_selector *self;
-
-static int com_ppl(int, int, char **);
-static int com_lpl(int, int, char **);
-extern struct misc_meta_data *mmd;
-
-/* array of commands that are supported by this database tool */
-static struct server_command cmds[] = {
-{
-.name = "ppl",
-.handler = com_ppl,
-.perms = DB_READ,
-.description = "print playlist",
-.synopsis = "ppl",
-.help =
-"Print out the current playlist"
-}, {
-.name = "lpl",
-.handler = com_lpl,
-.perms = DB_WRITE,
-.description = "load playlist",
-.synopsis = "lpl",
-.help =
-"Read a new playlist from stdin. Example:\n"
-"\tfind /audio -name '*.mp3' | para_client lpl"
-}, {
-.name = NULL,
-}
-};
-
-static void playlist_add(char *path)
-{
- if (playlist_len >= playlist_size) {
- playlist_size = 2 * playlist_size + 1;
- playlist = para_realloc(playlist, playlist_size * sizeof(char *));
- }
- PARA_DEBUG_LOG("adding #%d/%d: %s\n", playlist_len, playlist_size, path);
- playlist[playlist_len++] = para_strdup(path);
-}
-
-static int send_playlist_to_server(const char *buf, size_t size)
-{
- struct private_plm_data *ppd = self->private_data;
- int ret, shm_mutex = -1, shm_id = -1;
- void *shm = NULL;
-
- PARA_DEBUG_LOG("new playlist (%d bytes)\n", size);
-
- ret = mutex_new();
- if (ret < 0)
- return ret;
- shm_mutex = ret;
-
- ret = shm_new(size);
- if (ret < 0)
- goto out;
- shm_id = ret;
-
- ret = shm_attach(shm_id, ATTACH_RW, &shm);
- if (ret < 0)
- goto out;
- mutex_lock(shm_mutex);
- memcpy(shm, buf, size);
- mutex_lock(ppd->client_mutex);
- mutex_lock(ppd->server_mutex);
- ppd->client_data->size = size;
- ppd->client_data->shm_id = shm_id;
- ppd->client_data->mutex = shm_mutex;
- kill(getppid(), SIGUSR1); /* wake up the server */
- mutex_unlock(ppd->server_mutex);
- mutex_lock(shm_mutex); /* wait until server is done */
- mutex_unlock(shm_mutex);
- ret = ppd->client_data->retval;
- mutex_unlock(ppd->client_mutex);
- shm_detach(shm);
-out:
- if (shm_id >= 0)
- shm_destroy(shm_id);
- mutex_destroy(shm_mutex);
- PARA_DEBUG_LOG("returning %d\n", ret);
- return ret;
-}
-
-static int com_lpl(int fd, __unused int argc, __unused char *argv[])
-{
- unsigned loaded = 0;
- size_t bufsize = 4096; /* guess that's enough */
- char *buf = para_malloc(bufsize);
- ssize_t ret;
- ret = send_buffer(fd, AWAITING_DATA_MSG);
- if (ret < 0)
- goto out;
-again:
- ret = recv_bin_buffer(fd, buf + loaded, bufsize - loaded);
- if (ret < 0)
- goto out;
- if (!ret) {
- ret = send_playlist_to_server(buf, loaded);
- goto out;
- }
- loaded += ret;
- ret = -E_LOAD_PLAYLIST;
- if (loaded >= MAX_PLAYLIST_BYTES)
- goto out;
- if (loaded >= bufsize) {
- bufsize *= 2;
- buf = para_realloc(buf, bufsize);
- }
- goto again;
-out:
- free(buf);
- return ret;
-}
-
-static int com_ppl(int fd, __unused int argc, __unused char *argv[])
-{
- unsigned i;
-
- PARA_DEBUG_LOG("sending playlist to client (%d entries)\n", playlist_len);
- for (i = 0; i < playlist_len; i++) {
- int ret = send_va_buffer(fd, "%s\n", playlist[
- (i + current_playlist_entry) % playlist_len]);
- if (ret < 0)
- return ret;
- }
- return 1;
-}
-
-static char **plm_get_audio_file_list(unsigned int num)
-{
- char **file_list;
- unsigned i;
-
- num = MIN(num, playlist_len);
- if (!num)
- return NULL;
- file_list = para_malloc((num + 1) * sizeof(char *));
- for (i = 0; i < num; i++) {
- unsigned j = (current_playlist_entry + i) % playlist_len;
- file_list[i] = para_strdup(playlist[j]);
- }
- file_list[i] = NULL;
- return file_list;
-}
-
-static void free_playlist_contents(void)
-{
- int i;
-
- PARA_DEBUG_LOG("freeing playlist (%d entries)\n", playlist_len);
- for (i = 0; i < playlist_len; i++)
- free(playlist[i]);
- current_playlist_entry = 0;
- playlist_len = 0;
-}
-
-static void plm_shutdown(void)
-{
- struct private_plm_data *ppd = self->private_data;
-
- shm_detach(ppd->client_data);
- shm_destroy(ppd->client_data_shm_id);
- mutex_destroy(ppd->server_mutex);
- mutex_destroy(ppd->client_mutex);
- free(ppd);
- free_playlist_contents();
- free(playlist);
- playlist = NULL;
- playlist_len = 0;
- playlist_size = 0;
-}
-
-static void plm_post_select(__unused fd_set *rfds, __unused fd_set *wfds)
-{
- struct private_plm_data *ppd = self->private_data;
- struct plm_client_data *pcd = ppd->client_data;
- int ret;
- void *shm;
-
- mutex_lock(ppd->server_mutex);
- if (!pcd->size)
- goto out;
- free_playlist_contents();
- ret = shm_attach(pcd->shm_id, ATTACH_RW, &shm);
- if (ret < 0) {
- PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
- goto out;
- }
- PARA_DEBUG_LOG("loading new playlist (%d bytes)\n", pcd->size);
- ret = for_each_line((char *)shm, pcd->size, &playlist_add);
- shm_detach(shm);
- PARA_NOTICE_LOG("new playlist (%d entries)\n", playlist_len);
- pcd->retval = 1;
- pcd->size = 0;
- mutex_unlock(pcd->mutex);
-out:
- mutex_unlock(ppd->server_mutex);
-}
-
-void plm_update_audio_file(char *audio_file)
-{
- unsigned i;
-
- for (i = 0; i < playlist_len; i++) {
- unsigned j = (current_playlist_entry + i) % playlist_len;
- if (strcmp(playlist[j], audio_file))
- continue;
- current_playlist_entry = (j + 1) % playlist_len;
- }
-}
-
-/**
- * the init function for the plm database tool
- *
- * Init all function pointers of \a db
- *
- * \sa struct audio_file_selector, misc_meta_data::dbinfo, mysql.c random_dbtool.c
- */
-int plm_selector_init(struct audio_file_selector *db)
-{
- int ret;
- struct private_plm_data *ppd = NULL;
- void *shm = NULL;
-
- self = db;
- db->cmd_list = cmds;
- db->get_audio_file_list = plm_get_audio_file_list;
- db->shutdown = plm_shutdown;
- db->post_select = plm_post_select;
- db->update_audio_file = plm_update_audio_file;
- ppd = para_calloc(sizeof(struct private_plm_data));
- db->private_data = ppd;
-
- ppd->client_mutex = -1;
- ppd->server_mutex = -1;
- ppd->client_data_shm_id = -1;
- ppd->client_data = NULL;
-
- ret = mutex_new();
- if (ret < 0)
- goto err_out;
- ppd->client_mutex = ret;
-
- ret = mutex_new();
- if (ret < 0)
- goto err_out;
- ppd->server_mutex = ret;
-
- ret = shm_new(sizeof(struct plm_client_data));
- if (ret < 0)
- goto err_out;
- ppd->client_data_shm_id = ret;
-
- ret = shm_attach(ppd->client_data_shm_id, ATTACH_RW, &shm);
- if (ret < 0)
- goto err_out;
- ppd->client_data = shm;
- ppd->client_data->size = 0;
- sprintf(mmd->dbinfo, "plm initialized");
- return 1;
-err_out:
- if (ppd->client_data_shm_id >= 0)
- shm_destroy(ppd->client_data_shm_id);
- if (ppd->client_mutex >= 0)
- mutex_destroy(ppd->client_mutex);
- if (ppd->server_mutex >= 0)
- mutex_destroy(ppd->server_mutex);
- free(ppd);
- return ret;
-}
.update_audio_file = NULL,
},
{
- .name = "plm",
- .init = plm_selector_init,
+ .name = "playlist",
+ .init = playlist_selector_init,
.update_audio_file = NULL,
.pre_select = NULL,
.post_select = NULL,