demux_playlist: read directories recursive

demux_playlist.c recognizes if the source stream points to a directory,
and adds its directory entries. Until now, only 1 level was added.
During playback, further directory entries could be resolved as
directory paths were "played".

While this worked fine, it lead to frequent user confusion, because
playlist resuming and other things didn't work as expected. So just
recursively scan everything.

I'm unsure whether it's a good fix, but at least it gets rid of the
complaints. (And probably will add others.)
This commit is contained in:
wm4 2016-04-18 22:08:18 +02:00
parent 382bafcb13
commit 503dada42f
1 changed files with 57 additions and 17 deletions

View File

@ -20,6 +20,7 @@
#include <strings.h>
#include <dirent.h>
#include "config.h"
#include "common/common.h"
#include "options/options.h"
#include "common/msg.h"
@ -209,6 +210,59 @@ static int parse_txt(struct pl_parser *p)
return 0;
}
#define MAX_DIR_STACK 20
static bool same_st(struct stat *st1, struct stat *st2)
{
return HAVE_POSIX && st1->st_dev == st2->st_dev && st1->st_ino == st2->st_ino;
}
// Return true if this was a readable directory.
static bool scan_dir(struct pl_parser *p, char *path,
struct stat *dir_stack, int num_dir_stack,
char ***files, int *num_files)
{
if (strlen(path) >= 8192 || num_dir_stack == MAX_DIR_STACK)
return false; // things like mount bind loops
DIR *dp = opendir(path);
if (!dp) {
MP_ERR(p, "Could not read directory.\n");
return false;
}
struct dirent *ep;
while ((ep = readdir(dp))) {
if (ep->d_name[0] == '.')
continue;
if (mp_cancel_test(p->s->cancel))
break;
char *file = mp_path_join(p, path, ep->d_name);
struct stat st;
if (stat(file, &st) == 0 && S_ISDIR(st.st_mode)) {
for (int n = 0; n < num_dir_stack; n++) {
if (same_st(&dir_stack[n], &st)) {
MP_VERBOSE(p, "Skip recursive entry: %s\n", file);
goto skip;
}
}
dir_stack[num_dir_stack] = st;
scan_dir(p, file, dir_stack, num_dir_stack + 1, files, num_files);
} else {
MP_TARRAY_APPEND(p, *files, *num_files, file);
}
skip: ;
}
closedir(dp);
return true;
}
static int cmp_filename(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
@ -222,32 +276,18 @@ static int parse_dir(struct pl_parser *p)
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 stat dir_stack[MAX_DIR_STACK];
struct dirent *ep;
while ((ep = readdir(dp))) {
if (ep->d_name[0] == '.')
continue;
MP_TARRAY_APPEND(p, files, num_files, talloc_strdup(p, ep->d_name));
}
scan_dir(p, path, dir_stack, 0, &files, &num_files);
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, path, files[n]));
closedir(dp);
playlist_add_file(p->pl, files[n]);
p->add_base = false;