summaryrefslogtreecommitdiffstats
path: root/common/playlist.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-12-17 02:39:45 +0100
committerwm4 <wm4@nowhere>2013-12-17 02:39:45 +0100
commit0112143fdaae0a6264d9e02355e9dc0ca4f7741c (patch)
treebbbe9527d1e1490e37b67d97398c5bc19c7794cd /common/playlist.c
parent73a5417950a2d21a397597c05521725f3d125993 (diff)
downloadmpv-0112143fdaae0a6264d9e02355e9dc0ca4f7741c.tar.bz2
mpv-0112143fdaae0a6264d9e02355e9dc0ca4f7741c.tar.xz
Split mpvcore/ into common/, misc/, bstr/
Diffstat (limited to 'common/playlist.c')
-rw-r--r--common/playlist.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/common/playlist.c b/common/playlist.c
new file mode 100644
index 0000000000..297cb4d379
--- /dev/null
+++ b/common/playlist.c
@@ -0,0 +1,241 @@
+/*
+ * 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 "common/common.h"
+#include "talloc.h"
+#include "options/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->num_params, p);
+}
+
+void playlist_entry_add_params(struct playlist_entry *e,
+ struct playlist_param *params,
+ int num_params)
+{
+ for (int n = 0; n < num_params; 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;
+}
+
+// Moves entry such that entry->prev = at (even if at is NULL)
+void playlist_move(struct playlist *pl, struct playlist_entry *entry,
+ struct playlist_entry *at)
+{
+ struct playlist_entry *save_current = pl->current;
+ bool save_replaced = pl->current_was_replaced;
+
+ playlist_unlink(pl, entry);
+ playlist_insert(pl, at ? at->prev : pl->last, entry);
+
+ pl->current = save_current;
+ pl->current_was_replaced = save_replaced;
+}
+
+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) {
+ if (!mp_is_url(bstr0(e->filename))) {
+ 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 after the current entry
+// 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)
+{
+ struct playlist_entry *add_after = pl->current;
+ if (pl->current && pl->current_was_replaced)
+ add_after = pl->current->next;
+ if (!add_after)
+ add_after = pl->last;
+
+ while (source_pl->first) {
+ struct playlist_entry *e = source_pl->first;
+ playlist_unlink(source_pl, e);
+ playlist_insert(pl, add_after, e);
+ add_after = e;
+ }
+}
+
+// Return number of entries between list start and e.
+// Return -1 if e is not on the list, or if e is NULL.
+int playlist_entry_to_index(struct playlist *pl, struct playlist_entry *e)
+{
+ struct playlist_entry *cur = pl->first;
+ int pos = 0;
+ if (!e)
+ return -1;
+ while (cur && cur != e) {
+ cur = cur->next;
+ pos++;
+ }
+ return cur == e ? pos : -1;
+}
+
+int playlist_entry_count(struct playlist *pl)
+{
+ return playlist_entry_to_index(pl, pl->last) + 1;
+}
+
+// Return entry for which playlist_entry_to_index() would return index.
+// Return NULL if not found.
+struct playlist_entry *playlist_entry_from_index(struct playlist *pl, int index)
+{
+ struct playlist_entry *e = pl->first;
+ for (int n = 0; ; n++) {
+ if (!e || n == index)
+ return e;
+ e = e->next;
+ }
+}
+