0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

player: allow playing directories

If a directory is encountered, replace it with its contents in the
internal playlist.

This is messed into demux_playlist.c, because why not. STREAMTYPE_DIR
could be avoided by unconditonally trying opendir() in demux_playlist.c,
but it seems nicer not to do weird things like calling it on real files.

This does not work on Windows, because msvcrt is retarded.
This commit is contained in:
wm4 2015-04-17 22:56:19 +02:00
parent 01cfcd6814
commit 1d36955f70
3 changed files with 58 additions and 5 deletions

View File

@ -15,7 +15,10 @@
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <dirent.h>
#include "common/common.h"
#include "options/options.h"
@ -23,6 +26,7 @@
#include "common/playlist.h"
#include "options/path.h"
#include "stream/stream.h"
#include "osdep/io.h"
#include "demux.h"
#define PROBE_SIZE (8 * 1024)
@ -47,6 +51,7 @@ struct pl_parser {
bool error;
bool probing;
bool force;
bool add_base;
enum demux_check check_level;
struct stream *real_stream;
};
@ -204,6 +209,51 @@ static int parse_txt(struct pl_parser *p)
return 0;
}
static int cmp_filename(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}
static int parse_dir(struct pl_parser *p)
{
if (p->real_stream->type != STREAMTYPE_DIR)
return -1;
if (p->probing)
return 0;
char *path = mp_file_get_path(p, bstr0(p->real_stream->url));
if (strlen(path) >= 8192)
return -1; // things like mount bind loops
DIR *dp = opendir(path);
if (!dp) {
MP_ERR(p, "Could not read directory.\n");
return -1;
}
char **files = NULL;
int num_files = 0;
struct dirent *ep;
while ((ep = readdir(dp))) {
if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
continue;
MP_TARRAY_APPEND(p, files, num_files, talloc_strdup(p, ep->d_name));
}
if (files)
qsort(files, num_files, sizeof(files[0]), cmp_filename);
for (int n = 0; n < num_files; n++)
playlist_add_file(p->pl, mp_path_join(p, bstr0(path), bstr0(files[n])));
closedir(dp);
p->add_base = false;
return num_files > 0 ? 0 : -1;
}
#define MIME_TYPES(...) \
.mime_types = (const char*const[]){__VA_ARGS__, NULL}
@ -214,6 +264,7 @@ struct pl_format {
};
static const struct pl_format formats[] = {
{"directory", parse_dir},
{"m3u", parse_m3u,
MIME_TYPES("audio/mpegurl", "audio/x-mpegurl", "application/x-mpegurl")},
{"ini", parse_ref_init},
@ -248,6 +299,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
p->log = demuxer->log;
p->pl = talloc_zero(p, struct playlist);
p->real_stream = demuxer->stream;
p->add_base = true;
bstr probe_buf = stream_peek(demuxer->stream, PROBE_SIZE);
p->s = open_memory_stream(probe_buf.start, probe_buf.len);
@ -269,7 +321,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
p->s = demuxer->stream;
p->utf16 = stream_skip_bom(p->s);
bool ok = fmt->parse(p) >= 0 && !p->error;
if (ok)
if (p->add_base)
playlist_add_base_path(p->pl, mp_dirname(demuxer->filename));
demuxer->playlist = talloc_steal(demuxer, p->pl);
demuxer->filetype = fmt->name;

View File

@ -31,6 +31,7 @@
enum streamtype {
STREAMTYPE_GENERIC = 0,
STREAMTYPE_FILE,
STREAMTYPE_DIR,
STREAMTYPE_DVB,
STREAMTYPE_DVD,
STREAMTYPE_BLURAY,

View File

@ -238,6 +238,7 @@ static int open_f(stream_t *stream)
.fd = -1
};
stream->priv = priv;
stream->type = STREAMTYPE_FILE;
bool write = stream->mode == STREAM_WRITE;
int m = O_CLOEXEC | (write ? O_RDWR | O_CREAT | O_TRUNC : O_RDONLY);
@ -278,9 +279,9 @@ static int open_f(stream_t *stream)
struct stat st;
if (fstat(fd, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
MP_ERR(stream, "File is a directory: '%s'\n", filename);
close(fd);
return STREAM_ERROR;
stream->type = STREAMTYPE_DIR;
stream->allow_caching = false;
MP_INFO(stream, "This is a directory - adding to playlist.\n");
}
#ifndef __MINGW32__
if (S_ISREG(st.st_mode)) {
@ -302,7 +303,6 @@ static int open_f(stream_t *stream)
stream->seekable = true;
}
stream->type = STREAMTYPE_FILE;
stream->fast_skip = true;
stream->fill_buffer = fill_buffer;
stream->write_buffer = write_buffer;