/** \file playlist.c Functions for loading and saving playlists. */
-/** Structure used for adding entries to a playlist. */
+/**
+ * The state of a playlist instance.
+ *
+ * A structure of this type is allocated and initialized at playlist load time.
+ */
struct playlist_instance {
/** The name of the playlist. */
char *name;
/** The number of entries currently in the playlist. */
unsigned length;
+ /** Contains all valid paths of the playlist. */
+ struct osl_table *score_table;
};
static struct playlist_instance current_playlist;
static int add_playlist_entry(char *path, void *data)
{
- struct playlist_instance *playlist = data;
+ struct playlist_instance *pi = data;
struct osl_row *aft_row;
int ret = aft_get_row_of_path(path, &aft_row);
PARA_NOTICE_LOG("%s: %s\n", path, para_strerror(-ret));
return 1;
}
- ret = score_add(aft_row, -playlist->length);
+ ret = score_add(aft_row, -pi->length, pi->score_table);
if (ret < 0) {
PARA_ERROR_LOG("failed to add %s: %s\n", path, para_strerror(-ret));
return ret;
}
- playlist->length++;
+ pi->length++;
return 1;
}
check_playlist));
}
-/** Free all resources of the current playlist, if any. */
-void playlist_unload(void)
+/**
+ * Free all resources of the given/current playlist.
+ *
+ * \param pi NULL means to unload the current playlist.
+ */
+void playlist_unload(struct playlist_instance *pi)
{
+ if (pi) {
+ score_close(pi->score_table);
+ free(pi->name);
+ free(pi);
+ return;
+ }
if (!current_playlist.name)
return;
+ score_clear();
free(current_playlist.name);
current_playlist.name = NULL;
current_playlist.length = 0;
* corresponding row of the audio file table is added to the score table.
*
* \param name The name of the playlist to load.
+ * \param result Opaque, refers to the underlying score table.
* \param msg Error message or playlist info is returned here.
*
* \return The length of the loaded playlist on success, negative error code
* else. Files which are listed in the playlist, but are not contained in the
* database are ignored. This is not considered an error.
*/
-int playlist_load(const char *name, char **msg)
+int playlist_load(const char *name, struct playlist_instance **result, char **msg)
{
int ret;
- struct playlist_instance *playlist = ¤t_playlist;
+ struct playlist_instance *pi;
struct osl_object playlist_def;
- ret = pl_get_def_by_name(name, &playlist_def);
- if (ret < 0) {
- *msg = make_message("could not read playlist %s\n", name);
- return ret;
+ if (!name || !*name) {
+ if (msg)
+ *msg = make_message("empty playlist name\n");
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
}
- playlist_unload();
+ ret = pl_get_def_by_name(name, &playlist_def);
+ if (ret < 0)
+ goto err;
+ pi = zalloc(sizeof(*pi));
+ if (result)
+ score_open(&pi->score_table);
ret = for_each_line(FELF_READ_ONLY, playlist_def.data,
- playlist_def.size, add_playlist_entry, playlist);
+ playlist_def.size, add_playlist_entry, pi);
osl_close_disk_object(&playlist_def);
if (ret < 0)
- goto err;
+ goto close_score_table;
ret = -E_PLAYLIST_EMPTY;
- if (!playlist->length)
- goto err;
- playlist->name = para_strdup(name);
- *msg = make_message("loaded playlist %s (%u files)\n", playlist->name,
- playlist->length);
+ if (pi->length == 0)
+ goto close_score_table;
/* success */
- return current_playlist.length;
+ if (msg)
+ *msg = make_message("loaded playlist %s (%u files)\n", name,
+ pi->length);
+ pi->name = para_strdup(name);
+ if (result)
+ *result = pi;
+ else {
+ playlist_unload(NULL);
+ current_playlist = *pi;
+ }
+ return pi->length;
+close_score_table:
+ if (result)
+ score_close(pi->score_table);
+ free(pi);
err:
PARA_NOTICE_LOG("unable to load playlist %s\n", name);
- *msg = make_message("unable to load playlist %s\n", name);
+ if (msg)
+ *msg = make_message("unable to load playlist %s\n", name);
return ret;
}
+/**
+ * Iterate over all admissible audio files of a playlist instance.
+ *
+ * This wrapper around \ref score_loop() is the playlist counterpart of \ref
+ * mood_loop().
+ *
+ * \param pi Determines the score table to iterate. Must not be NULL.
+ * \param func See \ref score_loop().
+ * \param data See \ref score_loop().
+ *
+ * \return See \ref score_loop(), \ref mood_loop().
+ */
+int playlist_loop(struct playlist_instance *pi, osl_rbtree_loop_func *func, void *data)
+{
+ return score_loop(func, pi->score_table, data);
+}
+
static int search_path(char *path, void *data)
{
if (strcmp(path, data))
}
/* !was_admissible && is_admissible */
current_playlist.length++;
- return score_add(row, 0); /* play it immediately */
+ return score_add(row, 0, NULL); /* play it immediately */
}
/**