mirror of
https://github.com/mpv-player/mpv
synced 2024-08-24 07:21:49 +02:00
![wm4](/assets/img/avatar_default.png)
The entries of a playlist file usually refer either to local files (in the same directory as the playlist), or absolute paths like URLs. In the first case, you want to add the base path of the playlist file to the files, so that mplayer can find the files. In the second case, the URLs should not be changed. Unfortunately, mp_path_join() recognizes URLs as relative paths, and changes them. E.g. it tried to play /path/to/playlist/http://entry. Add some code to deal with this properly. The added code uses the same approach as m_option_type_custom_url in m_option.c, but because it's so short and trivial, it's perhaps better not to rely on the option parser code. It's also unclear whether mp_path_join() should contain this logic, but maybe it's better to keep the logic of that function clean.
193 lines
5.4 KiB
C
193 lines
5.4 KiB
C
/*
|
|
* 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->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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static bool might_be_an_url(bstr f)
|
|
{
|
|
return bstr_find0(f, "://") >= 0;
|
|
}
|
|
|
|
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 (!might_be_an_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 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);
|
|
}
|
|
}
|