summaryrefslogtreecommitdiffstats
path: root/player/scripting.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-02-01 18:09:40 +0100
committerwm4 <wm4@nowhere>2020-02-01 18:09:40 +0100
commitda38caff9c0bec4745cef16b7904e26e51a4539b (patch)
tree39ea39729f109713d1871f0aed053a156f86c768 /player/scripting.c
parent66a979bd757f27739158023f44a943a406a59159 (diff)
downloadmpv-da38caff9c0bec4745cef16b7904e26e51a4539b.tar.bz2
mpv-da38caff9c0bec4745cef16b7904e26e51a4539b.tar.xz
scripting: load scripts from directories
The intention is to provide a slightly nicer way to distribute scripts. For example, you could put multiple source files into the directory, and then import them from the actual script file (this is still unimplemented). At first I wanted to require a config file (because you need to know at least which scripting backend it should use). This wouldn't have been too hard (could have reused/abused the mpv config file parsing mechanism, and I already had working code that was just 2 function calls). But probably better to do this without new config files, because it might become a pain in the distant future. So this just probes for "main.lua", "main.js", etc., until an existing file is found. Another important change is that this skips all directory entries whose name starts with ".". This automatically excludes the "." and ".." special directories, and is probably useful to exclude random crap that might be lying around in the directory (such as editor temporary files, or OSX, in its usual hrmful, annoying, and idiotic modus operandi, sharting all over any directories opened by "Finder"). Although the changelog mentions the docs, they're added only in a later commit.
Diffstat (limited to 'player/scripting.c')
-rw-r--r--player/scripting.c86
1 files changed, 59 insertions, 27 deletions
diff --git a/player/scripting.c b/player/scripting.c
index 5f1ae5ce96..bab34d0d03 100644
--- a/player/scripting.c
+++ b/player/scripting.c
@@ -30,6 +30,8 @@
#include "common/common.h"
#include "common/msg.h"
+#include "options/m_config.h"
+#include "options/parse_configfile.h"
#include "options/path.h"
#include "misc/bstr.h"
#include "core.h"
@@ -74,26 +76,19 @@ static char *script_name_from_filename(void *talloc_ctx, const char *fname)
return talloc_asprintf(talloc_ctx, "%s", name);
}
-struct thread_arg {
- struct mp_log *log;
- const struct mp_scripting *backend;
- mpv_handle *client;
- const char *fname;
-};
-
static void *script_thread(void *p)
{
pthread_detach(pthread_self());
- struct thread_arg *arg = p;
+ struct mp_script_args *arg = p;
char name[90];
snprintf(name, sizeof(name), "%s (%s)", arg->backend->name,
mpv_client_name(arg->client));
mpthread_set_name(name);
- if (arg->backend->load(arg->client, arg->fname) < 0)
- MP_ERR(arg, "Could not load %s %s\n", arg->backend->name, arg->fname);
+ if (arg->backend->load(arg) < 0)
+ MP_ERR(arg, "Could not load %s %s\n", arg->backend->name, arg->filename);
mpv_destroy(arg->client);
talloc_free(arg);
@@ -106,34 +101,70 @@ static int mp_load_script(struct MPContext *mpctx, const char *fname)
if (ext && strcasecmp(ext, "disable") == 0)
return 0;
+ void *tmp = talloc_new(NULL);
+
+ const char *path = NULL;
const struct mp_scripting *backend = NULL;
- for (int n = 0; scripting_backends[n]; n++) {
- const struct mp_scripting *b = scripting_backends[n];
- if (ext && strcasecmp(ext, b->file_ext) == 0) {
- backend = b;
- break;
+
+ struct stat s;
+ if (!stat(fname, &s) && S_ISDIR(s.st_mode)) {
+ path = fname;
+ fname = NULL;
+
+ for (int n = 0; scripting_backends[n]; n++) {
+ const struct mp_scripting *b = scripting_backends[n];
+ char *filename = mp_tprintf(80, "main.%s", b->file_ext);
+ fname = mp_path_join(tmp, path, filename);
+ if (!stat(fname, &s) && S_ISREG(s.st_mode)) {
+ backend = b;
+ break;
+ }
+ talloc_free((void *)fname);
+ fname = NULL;
+ }
+
+ if (!fname) {
+ MP_ERR(mpctx, "Cannot find main.* for any supported scripting "
+ "backend in: %s\n", path);
+ talloc_free(tmp);
+ return -1;
+ }
+ } else {
+ for (int n = 0; scripting_backends[n]; n++) {
+ const struct mp_scripting *b = scripting_backends[n];
+ if (ext && strcasecmp(ext, b->file_ext) == 0) {
+ backend = b;
+ break;
+ }
}
}
if (!backend) {
MP_ERR(mpctx, "Can't load unknown script: %s\n", fname);
+ talloc_free(tmp);
return -1;
}
- struct thread_arg *arg = talloc_ptrtype(NULL, arg);
+ struct mp_script_args *arg = talloc_ptrtype(NULL, arg);
char *name = script_name_from_filename(arg, fname);
- *arg = (struct thread_arg){
- .fname = talloc_strdup(arg, fname),
+ *arg = (struct mp_script_args){
+ .mpctx = mpctx,
+ .filename = talloc_strdup(arg, fname),
+ .path = talloc_strdup(arg, path),
.backend = backend,
// Create the client before creating the thread; otherwise a race
// condition could happen, where MPContext is destroyed while the
// thread tries to create the client.
.client = mp_new_client(mpctx->clients, name),
};
+
+ talloc_free(tmp);
+
if (!arg->client) {
talloc_free(arg);
return -1;
}
+
mp_client_set_weak(arg->client);
arg->log = mp_client_get_log(arg->client);
@@ -173,10 +204,12 @@ static char **list_script_files(void *talloc_ctx, char *path)
return NULL;
struct dirent *ep;
while ((ep = readdir(dp))) {
- char *fname = mp_path_join(talloc_ctx, path, ep->d_name);
- struct stat s;
- if (!stat(fname, &s) && S_ISREG(s.st_mode))
- MP_TARRAY_APPEND(talloc_ctx, files, count, fname);
+ if (ep->d_name[0] != '.') {
+ char *fname = mp_path_join(talloc_ctx, path, ep->d_name);
+ struct stat s;
+ if (!stat(fname, &s) && (S_ISREG(s.st_mode) || S_ISDIR(s.st_mode)))
+ MP_TARRAY_APPEND(talloc_ctx, files, count, fname);
+ }
}
closedir(dp);
if (files)
@@ -247,10 +280,9 @@ bool mp_load_scripts(struct MPContext *mpctx)
#define MPV_DLOPEN_FN "mpv_open_cplugin"
typedef int (*mpv_open_cplugin)(mpv_handle *handle);
-static int load_cplugin(struct mpv_handle *client, const char *fname)
+static int load_cplugin(struct mp_script_args *args)
{
- MPContext *ctx = mp_client_get_core(client);
- void *lib = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
+ void *lib = dlopen(args->filename, RTLD_NOW | RTLD_LOCAL);
if (!lib)
goto error;
// Note: once loaded, we never unload, as unloading the libraries linked to
@@ -258,11 +290,11 @@ static int load_cplugin(struct mpv_handle *client, const char *fname)
mpv_open_cplugin sym = (mpv_open_cplugin)dlsym(lib, MPV_DLOPEN_FN);
if (!sym)
goto error;
- return sym(client) ? -1 : 0;
+ return sym(args->client) ? -1 : 0;
error: ;
char *err = dlerror();
if (err)
- MP_ERR(ctx, "C plugin error: '%s'\n", err);
+ MP_ERR(args, "C plugin error: '%s'\n", err);
return -1;
}