summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demux/demux_playlist.c54
-rw-r--r--stream/stream.h1
-rw-r--r--stream/stream_file.c8
3 files changed, 58 insertions, 5 deletions
diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c
index 381b50f269..6f73bea5ba 100644
--- a/demux/demux_playlist.c
+++ b/demux/demux_playlist.c
@@ -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;
diff --git a/stream/stream.h b/stream/stream.h
index 387006cb8f..7b4751450c 100644
--- a/stream/stream.h
+++ b/stream/stream.h
@@ -31,6 +31,7 @@
enum streamtype {
STREAMTYPE_GENERIC = 0,
STREAMTYPE_FILE,
+ STREAMTYPE_DIR,
STREAMTYPE_DVB,
STREAMTYPE_DVD,
STREAMTYPE_BLURAY,
diff --git a/stream/stream_file.c b/stream/stream_file.c
index 01e983fa31..83d90b902b 100644
--- a/stream/stream_file.c
+++ b/stream/stream_file.c
@@ -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;