mirror of
https://github.com/mpv-player/mpv
synced 2025-04-17 20:58:20 +00: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:
parent
01cfcd6814
commit
1d36955f70
@ -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;
|
||||
|
@ -31,6 +31,7 @@
|
||||
enum streamtype {
|
||||
STREAMTYPE_GENERIC = 0,
|
||||
STREAMTYPE_FILE,
|
||||
STREAMTYPE_DIR,
|
||||
STREAMTYPE_DVB,
|
||||
STREAMTYPE_DVD,
|
||||
STREAMTYPE_BLURAY,
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user