mirror of
https://github.com/mpv-player/mpv
synced 2025-04-29 06:42:55 +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/>.
|
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "options/options.h"
|
#include "options/options.h"
|
||||||
@ -23,6 +26,7 @@
|
|||||||
#include "common/playlist.h"
|
#include "common/playlist.h"
|
||||||
#include "options/path.h"
|
#include "options/path.h"
|
||||||
#include "stream/stream.h"
|
#include "stream/stream.h"
|
||||||
|
#include "osdep/io.h"
|
||||||
#include "demux.h"
|
#include "demux.h"
|
||||||
|
|
||||||
#define PROBE_SIZE (8 * 1024)
|
#define PROBE_SIZE (8 * 1024)
|
||||||
@ -47,6 +51,7 @@ struct pl_parser {
|
|||||||
bool error;
|
bool error;
|
||||||
bool probing;
|
bool probing;
|
||||||
bool force;
|
bool force;
|
||||||
|
bool add_base;
|
||||||
enum demux_check check_level;
|
enum demux_check check_level;
|
||||||
struct stream *real_stream;
|
struct stream *real_stream;
|
||||||
};
|
};
|
||||||
@ -204,6 +209,51 @@ static int parse_txt(struct pl_parser *p)
|
|||||||
return 0;
|
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(...) \
|
#define MIME_TYPES(...) \
|
||||||
.mime_types = (const char*const[]){__VA_ARGS__, NULL}
|
.mime_types = (const char*const[]){__VA_ARGS__, NULL}
|
||||||
|
|
||||||
@ -214,6 +264,7 @@ struct pl_format {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct pl_format formats[] = {
|
static const struct pl_format formats[] = {
|
||||||
|
{"directory", parse_dir},
|
||||||
{"m3u", parse_m3u,
|
{"m3u", parse_m3u,
|
||||||
MIME_TYPES("audio/mpegurl", "audio/x-mpegurl", "application/x-mpegurl")},
|
MIME_TYPES("audio/mpegurl", "audio/x-mpegurl", "application/x-mpegurl")},
|
||||||
{"ini", parse_ref_init},
|
{"ini", parse_ref_init},
|
||||||
@ -248,6 +299,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check)
|
|||||||
p->log = demuxer->log;
|
p->log = demuxer->log;
|
||||||
p->pl = talloc_zero(p, struct playlist);
|
p->pl = talloc_zero(p, struct playlist);
|
||||||
p->real_stream = demuxer->stream;
|
p->real_stream = demuxer->stream;
|
||||||
|
p->add_base = true;
|
||||||
|
|
||||||
bstr probe_buf = stream_peek(demuxer->stream, PROBE_SIZE);
|
bstr probe_buf = stream_peek(demuxer->stream, PROBE_SIZE);
|
||||||
p->s = open_memory_stream(probe_buf.start, probe_buf.len);
|
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->s = demuxer->stream;
|
||||||
p->utf16 = stream_skip_bom(p->s);
|
p->utf16 = stream_skip_bom(p->s);
|
||||||
bool ok = fmt->parse(p) >= 0 && !p->error;
|
bool ok = fmt->parse(p) >= 0 && !p->error;
|
||||||
if (ok)
|
if (p->add_base)
|
||||||
playlist_add_base_path(p->pl, mp_dirname(demuxer->filename));
|
playlist_add_base_path(p->pl, mp_dirname(demuxer->filename));
|
||||||
demuxer->playlist = talloc_steal(demuxer, p->pl);
|
demuxer->playlist = talloc_steal(demuxer, p->pl);
|
||||||
demuxer->filetype = fmt->name;
|
demuxer->filetype = fmt->name;
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
enum streamtype {
|
enum streamtype {
|
||||||
STREAMTYPE_GENERIC = 0,
|
STREAMTYPE_GENERIC = 0,
|
||||||
STREAMTYPE_FILE,
|
STREAMTYPE_FILE,
|
||||||
|
STREAMTYPE_DIR,
|
||||||
STREAMTYPE_DVB,
|
STREAMTYPE_DVB,
|
||||||
STREAMTYPE_DVD,
|
STREAMTYPE_DVD,
|
||||||
STREAMTYPE_BLURAY,
|
STREAMTYPE_BLURAY,
|
||||||
|
@ -238,6 +238,7 @@ static int open_f(stream_t *stream)
|
|||||||
.fd = -1
|
.fd = -1
|
||||||
};
|
};
|
||||||
stream->priv = priv;
|
stream->priv = priv;
|
||||||
|
stream->type = STREAMTYPE_FILE;
|
||||||
|
|
||||||
bool write = stream->mode == STREAM_WRITE;
|
bool write = stream->mode == STREAM_WRITE;
|
||||||
int m = O_CLOEXEC | (write ? O_RDWR | O_CREAT | O_TRUNC : O_RDONLY);
|
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;
|
struct stat st;
|
||||||
if (fstat(fd, &st) == 0) {
|
if (fstat(fd, &st) == 0) {
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
MP_ERR(stream, "File is a directory: '%s'\n", filename);
|
stream->type = STREAMTYPE_DIR;
|
||||||
close(fd);
|
stream->allow_caching = false;
|
||||||
return STREAM_ERROR;
|
MP_INFO(stream, "This is a directory - adding to playlist.\n");
|
||||||
}
|
}
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
if (S_ISREG(st.st_mode)) {
|
if (S_ISREG(st.st_mode)) {
|
||||||
@ -302,7 +303,6 @@ static int open_f(stream_t *stream)
|
|||||||
stream->seekable = true;
|
stream->seekable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->type = STREAMTYPE_FILE;
|
|
||||||
stream->fast_skip = true;
|
stream->fast_skip = true;
|
||||||
stream->fill_buffer = fill_buffer;
|
stream->fill_buffer = fill_buffer;
|
||||||
stream->write_buffer = write_buffer;
|
stream->write_buffer = write_buffer;
|
||||||
|
Loading…
Reference in New Issue
Block a user