X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=playlist.c;h=5f83b0fe0a35c9e5c31c97828bfa7af2bebc6208;hp=8f5c3d7d1089a7cc48352a70d6f1aaf6e8ee2aa0;hb=refs%2Fheads%2Fnext;hpb=462a71176aa847494a1a26826768b5fa52994f54 diff --git a/playlist.c b/playlist.c index 8f5c3d7d..c145b0fd 100644 --- a/playlist.c +++ b/playlist.c @@ -14,14 +14,20 @@ /** \file playlist.c Functions for loading and saving playlists. */ -/** Structure used for adding entries to a playlist. */ -struct playlist_info { +/** + * 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_info current_playlist; +static struct playlist_instance current_playlist; /** * Re-insert an audio file into the tree of admissible files. @@ -38,7 +44,7 @@ static int playlist_update_audio_file(const struct osl_row *aft_row) static int add_playlist_entry(char *path, void *data) { - struct playlist_info *playlist = data; + struct playlist_instance *pi = data; struct osl_row *aft_row; int ret = aft_get_row_of_path(path, &aft_row); @@ -46,42 +52,43 @@ static int add_playlist_entry(char *path, void *data) 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; } static int check_playlist_path(char *path, void *data) { - struct para_buffer *pb = data; + struct afs_callback_arg *aca = data; struct osl_row *aft_row; int ret = aft_get_row_of_path(path, &aft_row); if (ret < 0) - para_printf(pb, "%s: %s\n", path, para_strerror(-ret)); + afs_error(aca, "%s: %s\n", path, para_strerror(-ret)); return 1; /* do not fail the loop on bad paths */ } static int check_playlist(struct osl_row *row, void *data) { - struct para_buffer *pb = data; + struct afs_callback_arg *aca = data; + struct para_buffer *pb = &aca->pbout; struct osl_object playlist_def; char *playlist_name; int ret = pl_get_name_and_def_by_row(row, &playlist_name, &playlist_def); if (ret < 0) { /* log error, but continue */ - para_printf(pb, "failed to get playlist data: %s\n", + afs_error(aca, "failed to get playlist data: %s\n", para_strerror(-ret)); return 1; } if (*playlist_name) { /* skip dummy row */ para_printf(pb, "checking playlist %s...\n", playlist_name); for_each_line(FELF_READ_ONLY, playlist_def.data, - playlist_def.size, check_playlist_path, pb); + playlist_def.size, check_playlist_path, aca); } osl_close_disk_object(&playlist_def); return 1; @@ -98,19 +105,26 @@ static int check_playlist(struct osl_row *row, void *data) int playlist_check_callback(struct afs_callback_arg *aca) { para_printf(&aca->pbout, "checking playlists...\n"); - return osl(osl_rbtree_loop(playlists_table, BLOBCOL_ID, &aca->pbout, + return osl(osl_rbtree_loop(playlists_table, BLOBCOL_ID, aca, check_playlist)); } /** - * Close the current playlist. + * Free all resources of the given/current playlist. * - * \sa \ref playlist_open(). + * \param pi NULL means to unload the current playlist. */ -void playlist_close(void) +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; @@ -124,44 +138,79 @@ void playlist_close(void) * up in the audio file table. If the path lookup succeeds, a reference to the * corresponding row of the audio file table is added to the score table. * - * \param name The name of the playlist to open. + * \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_open(const char *name, char **msg) +int playlist_load(const char *name, struct playlist_instance **result, char **msg) { int ret; - struct playlist_info *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_close(); + 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)) @@ -199,7 +248,7 @@ static int handle_audio_file_event(enum afs_events event, void *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 */ } /**