diff options
Diffstat (limited to 'playlist.c')
-rw-r--r-- | playlist.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/playlist.c b/playlist.c new file mode 100644 index 0000000000..908baa9096 --- /dev/null +++ b/playlist.c @@ -0,0 +1,185 @@ +/* + * This file is part of mplayer. + * + * mplayer 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. + * + * mplayer 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 mplayer. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include "config.h" +#include "playlist.h" +#include "mpcommon.h" +#include "talloc.h" +#include "path.h" + +struct playlist_entry *playlist_entry_new(const char *filename) +{ + struct playlist_entry *e = talloc_zero(NULL, struct playlist_entry); + e->filename = talloc_strdup(e, filename); + return e; +} + +void playlist_entry_add_param(struct playlist_entry *e, bstr name, bstr value) +{ + struct playlist_param p = {bstrdup(e, name), bstrdup(e, value)}; + MP_TARRAY_APPEND(e, e->params, e->params_count, p); +} + +void playlist_entry_add_params(struct playlist_entry *e, + struct playlist_param *params, + int params_count) +{ + for (int n = 0; n < params_count; n++) + playlist_entry_add_param(e, params[n].name, params[n].value); +} + +// Add entry "add" after entry "after". +// If "after" is NULL, add as first entry. +// Post condition: add->prev == after +void playlist_insert(struct playlist *pl, struct playlist_entry *after, + struct playlist_entry *add) +{ + assert(pl && add->pl == NULL && add->next == NULL && add->prev == NULL); + if (after) { + assert(after->pl == pl); + assert(pl->first && pl->last); + } + add->prev = after; + if (after) { + add->next = after->next; + after->next = add; + } else { + add->next = pl->first; + pl->first = add; + } + if (add->next) { + add->next->prev = add; + } else { + pl->last = add; + } + add->pl = pl; + talloc_steal(pl, add); +} + +void playlist_add(struct playlist *pl, struct playlist_entry *add) +{ + playlist_insert(pl, pl->last, add); +} + +static void playlist_unlink(struct playlist *pl, struct playlist_entry *entry) +{ + assert(pl && entry->pl == pl); + + if (pl->current == entry) { + pl->current = entry->next; + pl->current_was_replaced = true; + } + + if (entry->next) { + entry->next->prev = entry->prev; + } else { + pl->last = entry->prev; + } + if (entry->prev) { + entry->prev->next = entry->next; + } else { + pl->first = entry->next; + } + entry->next = entry->prev = NULL; + // xxx: we'd want to reset the talloc parent of entry + entry->pl = NULL; +} + +void playlist_remove(struct playlist *pl, struct playlist_entry *entry) +{ + playlist_unlink(pl, entry); + talloc_free(entry); +} + +void playlist_clear(struct playlist *pl) +{ + while (pl->first) + playlist_remove(pl, pl->first); + assert(!pl->current); + pl->current_was_replaced = false; +} + +void playlist_add_file(struct playlist *pl, const char *filename) +{ + playlist_add(pl, playlist_entry_new(filename)); +} + +static int playlist_count(struct playlist *pl) +{ + int c = 0; + for (struct playlist_entry *e = pl->first; e; e = e->next) + c++; + return c; +} + +void playlist_shuffle(struct playlist *pl) +{ + struct playlist_entry *save_current = pl->current; + bool save_replaced = pl->current_was_replaced; + int count = playlist_count(pl); + struct playlist_entry **arr = talloc_array(NULL, struct playlist_entry *, + count); + for (int n = 0; n < count; n++) { + arr[n] = pl->first; + playlist_unlink(pl, pl->first); + } + for (int n = 0; n < count; n++) { + int other = (int)((double)(count) * rand() / (RAND_MAX + 1.0)); + struct playlist_entry *tmp = arr[n]; + arr[n] = arr[other]; + arr[other] = tmp; + } + for (int n = 0; n < count; n++) + playlist_add(pl, arr[n]); + talloc_free(arr); + pl->current = save_current; + pl->current_was_replaced = save_replaced; +} + +struct playlist_entry *playlist_get_next(struct playlist *pl, int direction) +{ + assert(direction == -1 || direction == +1); + if (!pl->current) + return NULL; + assert(pl->current->pl == pl); + if (direction < 0) + return pl->current->prev; + return pl->current_was_replaced ? pl->current : pl->current->next; +} + +void playlist_add_base_path(struct playlist *pl, bstr base_path) +{ + if (base_path.len == 0 || bstrcmp0(base_path, ".") == 0) + return; + for (struct playlist_entry *e = pl->first; e; e = e->next) { + char *new_file = mp_path_join(e, base_path, bstr0(e->filename)); + talloc_free(e->filename); + e->filename = new_file; + } +} + +// Move all entries from source_pl to pl, appending them at the end of pl. +// source_pl will be empty, and all entries have changed ownership to pl. +void playlist_transfer_entries(struct playlist *pl, struct playlist *source_pl) +{ + while (source_pl->first) { + struct playlist_entry *e = source_pl->first; + playlist_unlink(source_pl, e); + playlist_add(pl, e); + } +} |