2014-05-12 23:14:07 +00:00
|
|
|
/*
|
|
|
|
* This file is part of mpv.
|
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2014-05-12 23:14:07 +00:00
|
|
|
*
|
|
|
|
* mpv is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2014-05-12 23:14:07 +00:00
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2014-05-12 23:14:07 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
2014-07-10 06:28:03 +00:00
|
|
|
#include <strings.h>
|
2014-05-12 23:14:07 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <assert.h>
|
2020-02-19 21:18:15 +00:00
|
|
|
#include <unistd.h>
|
2014-05-12 23:14:07 +00:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "osdep/io.h"
|
2020-02-19 21:18:15 +00:00
|
|
|
#include "osdep/subprocess.h"
|
2014-10-19 21:32:34 +00:00
|
|
|
#include "osdep/threads.h"
|
2014-05-12 23:14:07 +00:00
|
|
|
|
|
|
|
#include "common/common.h"
|
|
|
|
#include "common/msg.h"
|
2020-02-19 21:18:15 +00:00
|
|
|
#include "input/input.h"
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
#include "options/m_config.h"
|
|
|
|
#include "options/parse_configfile.h"
|
2014-05-12 23:14:07 +00:00
|
|
|
#include "options/path.h"
|
2014-08-29 10:09:04 +00:00
|
|
|
#include "misc/bstr.h"
|
2014-05-12 23:14:07 +00:00
|
|
|
#include "core.h"
|
|
|
|
#include "client.h"
|
|
|
|
#include "libmpv/client.h"
|
|
|
|
|
|
|
|
extern const struct mp_scripting mp_scripting_lua;
|
2017-01-12 16:37:11 +00:00
|
|
|
extern const struct mp_scripting mp_scripting_cplugin;
|
2014-12-13 16:27:47 +00:00
|
|
|
extern const struct mp_scripting mp_scripting_js;
|
2020-02-19 21:18:15 +00:00
|
|
|
extern const struct mp_scripting mp_scripting_run;
|
2014-05-12 23:14:07 +00:00
|
|
|
|
2014-06-10 21:56:05 +00:00
|
|
|
static const struct mp_scripting *const scripting_backends[] = {
|
2014-05-12 23:14:07 +00:00
|
|
|
#if HAVE_LUA
|
|
|
|
&mp_scripting_lua,
|
2017-01-12 16:37:11 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_CPLUGINS
|
|
|
|
&mp_scripting_cplugin,
|
2014-12-13 16:27:47 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_JAVASCRIPT
|
|
|
|
&mp_scripting_js,
|
2014-05-12 23:14:07 +00:00
|
|
|
#endif
|
2020-02-19 21:18:15 +00:00
|
|
|
&mp_scripting_run,
|
2014-05-12 23:14:07 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static char *script_name_from_filename(void *talloc_ctx, const char *fname)
|
|
|
|
{
|
|
|
|
fname = mp_basename(fname);
|
|
|
|
if (fname[0] == '@')
|
|
|
|
fname += 1;
|
|
|
|
char *name = talloc_strdup(talloc_ctx, fname);
|
|
|
|
// Drop file extension
|
|
|
|
char *dot = strrchr(name, '.');
|
|
|
|
if (dot)
|
|
|
|
*dot = '\0';
|
|
|
|
// Turn it into a safe identifier - this is used with e.g. dispatching
|
|
|
|
// input via: "send scriptname ..."
|
|
|
|
for (int n = 0; name[n]; n++) {
|
|
|
|
char c = name[n];
|
|
|
|
if (!(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') &&
|
|
|
|
!(c >= '0' && c <= '9'))
|
|
|
|
name[n] = '_';
|
|
|
|
}
|
|
|
|
return talloc_asprintf(talloc_ctx, "%s", name);
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:18:15 +00:00
|
|
|
static void run_script(struct mp_script_args *arg)
|
2014-05-12 23:14:07 +00:00
|
|
|
{
|
2014-10-19 21:32:34 +00:00
|
|
|
char name[90];
|
2017-01-14 15:47:53 +00:00
|
|
|
snprintf(name, sizeof(name), "%s (%s)", arg->backend->name,
|
|
|
|
mpv_client_name(arg->client));
|
2014-10-19 21:32:34 +00:00
|
|
|
mpthread_set_name(name);
|
|
|
|
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
if (arg->backend->load(arg) < 0)
|
|
|
|
MP_ERR(arg, "Could not load %s %s\n", arg->backend->name, arg->filename);
|
2014-05-12 23:14:07 +00:00
|
|
|
|
2018-03-09 10:27:46 +00:00
|
|
|
mpv_destroy(arg->client);
|
2014-05-12 23:14:07 +00:00
|
|
|
talloc_free(arg);
|
2020-02-19 21:18:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *script_thread(void *p)
|
|
|
|
{
|
|
|
|
pthread_detach(pthread_self());
|
|
|
|
|
|
|
|
struct mp_script_args *arg = p;
|
|
|
|
run_script(arg);
|
|
|
|
|
2014-05-12 23:14:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-26 22:58:09 +00:00
|
|
|
static int64_t mp_load_script(struct MPContext *mpctx, const char *fname)
|
2014-05-12 23:14:07 +00:00
|
|
|
{
|
|
|
|
char *ext = mp_splitext(fname, NULL);
|
2020-01-19 18:25:54 +00:00
|
|
|
if (ext && strcasecmp(ext, "disable") == 0)
|
|
|
|
return 0;
|
|
|
|
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
void *tmp = talloc_new(NULL);
|
|
|
|
|
|
|
|
const char *path = NULL;
|
2020-02-06 18:38:22 +00:00
|
|
|
char *script_name = NULL;
|
2014-05-12 23:14:07 +00:00
|
|
|
const struct mp_scripting *backend = NULL;
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2020-02-06 18:38:22 +00:00
|
|
|
|
|
|
|
script_name = talloc_strdup(tmp, path);
|
|
|
|
mp_path_strip_trailing_separator(script_name);
|
|
|
|
script_name = mp_basename(script_name);
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
} 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;
|
|
|
|
}
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
2020-02-06 18:38:22 +00:00
|
|
|
script_name = script_name_from_filename(tmp, fname);
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!backend) {
|
2020-01-19 18:25:54 +00:00
|
|
|
MP_ERR(mpctx, "Can't load unknown script: %s\n", fname);
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
talloc_free(tmp);
|
2016-09-22 18:43:33 +00:00
|
|
|
return -1;
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
|
|
|
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
struct mp_script_args *arg = talloc_ptrtype(NULL, arg);
|
|
|
|
*arg = (struct mp_script_args){
|
|
|
|
.mpctx = mpctx,
|
|
|
|
.filename = talloc_strdup(arg, fname),
|
|
|
|
.path = talloc_strdup(arg, path),
|
2014-05-12 23:14:07 +00:00
|
|
|
.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.
|
2020-02-06 18:38:22 +00:00
|
|
|
.client = mp_new_client(mpctx->clients, script_name),
|
2014-05-12 23:14:07 +00:00
|
|
|
};
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
|
|
|
|
talloc_free(tmp);
|
|
|
|
|
2014-05-12 23:14:07 +00:00
|
|
|
if (!arg->client) {
|
2020-02-06 18:38:22 +00:00
|
|
|
MP_ERR(mpctx, "Failed to create client for script: %s\n", fname);
|
2014-05-12 23:14:07 +00:00
|
|
|
talloc_free(arg);
|
2016-09-22 18:43:33 +00:00
|
|
|
return -1;
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
|
2018-03-09 05:00:51 +00:00
|
|
|
mp_client_set_weak(arg->client);
|
2014-09-06 15:02:47 +00:00
|
|
|
arg->log = mp_client_get_log(arg->client);
|
2020-03-26 22:58:09 +00:00
|
|
|
int64_t id = mpv_client_id(arg->client);
|
2014-09-06 15:02:47 +00:00
|
|
|
|
2017-09-28 09:53:57 +00:00
|
|
|
MP_DBG(arg, "Loading %s %s...\n", backend->name, fname);
|
2014-05-12 23:14:07 +00:00
|
|
|
|
2020-02-19 21:18:15 +00:00
|
|
|
if (backend->no_thread) {
|
|
|
|
run_script(arg);
|
|
|
|
} else {
|
|
|
|
pthread_t thread;
|
|
|
|
if (pthread_create(&thread, NULL, script_thread, arg)) {
|
|
|
|
mpv_destroy(arg->client);
|
|
|
|
talloc_free(arg);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-04-30 19:57:08 +00:00
|
|
|
}
|
2014-05-12 23:14:07 +00:00
|
|
|
|
2020-03-26 22:58:09 +00:00
|
|
|
return id;
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 22:58:09 +00:00
|
|
|
int64_t mp_load_user_script(struct MPContext *mpctx, const char *fname)
|
2017-06-30 13:53:33 +00:00
|
|
|
{
|
|
|
|
char *path = mp_get_user_path(NULL, mpctx->global, fname);
|
2020-03-26 22:58:09 +00:00
|
|
|
int64_t ret = mp_load_script(mpctx, path);
|
2017-06-30 13:53:33 +00:00
|
|
|
talloc_free(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-05-12 23:14:07 +00:00
|
|
|
static int compare_filename(const void *pa, const void *pb)
|
|
|
|
{
|
|
|
|
char *a = (char *)pa;
|
|
|
|
char *b = (char *)pb;
|
|
|
|
return strcmp(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char **list_script_files(void *talloc_ctx, char *path)
|
|
|
|
{
|
|
|
|
char **files = NULL;
|
|
|
|
int count = 0;
|
|
|
|
DIR *dp = opendir(path);
|
|
|
|
if (!dp)
|
|
|
|
return NULL;
|
|
|
|
struct dirent *ep;
|
|
|
|
while ((ep = readdir(dp))) {
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
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);
|
|
|
|
}
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
|
|
|
closedir(dp);
|
2014-08-27 22:12:43 +00:00
|
|
|
if (files)
|
|
|
|
qsort(files, count, sizeof(char *), compare_filename);
|
2014-05-12 23:14:07 +00:00
|
|
|
MP_TARRAY_APPEND(talloc_ctx, files, count, NULL);
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
2020-03-26 22:58:09 +00:00
|
|
|
static void load_builtin_script(struct MPContext *mpctx, int slot, bool enable,
|
2016-09-19 22:59:54 +00:00
|
|
|
const char *fname)
|
|
|
|
{
|
2020-03-26 22:58:09 +00:00
|
|
|
assert(slot < MP_ARRAY_SIZE(mpctx->builtin_script_ids));
|
|
|
|
int64_t *pid = &mpctx->builtin_script_ids[slot];
|
|
|
|
if (*pid > 0 && !mp_client_id_exists(mpctx, *pid))
|
|
|
|
*pid = 0; // died
|
|
|
|
if ((*pid > 0) != enable) {
|
2016-09-19 22:59:54 +00:00
|
|
|
if (enable) {
|
2020-03-26 22:58:09 +00:00
|
|
|
*pid = mp_load_script(mpctx, fname);
|
2016-09-19 22:59:54 +00:00
|
|
|
} else {
|
2020-03-26 22:58:09 +00:00
|
|
|
char *name = mp_tprintf(22, "@%"PRIi64, *pid);
|
scripting: change when/how player waits for scripts being loaded
Fundamentally, scripts are loaded asynchronously, but as a feature,
there was code to wait until a script is loaded (for a certain arbitrary
definition of "loaded"). This was done in scripting.c with the
wait_loaded() function.
This called mp_idle(), and since there are commands to load/unload
scripts, it meant the player core loop could be entered recursively. I
think this is a major complication and has some problems. For example,
if you had a script that does 'os.execute("sleep inf")', then every time
you ran a command to load an instance of the script would add a new
stack frame of mp_idle(). This would lead to some sort of reentrancy
horror that is hard to debug. Also misc/dispatch.c contains a somewhat
tricky mess to support such recursive invocations. There were also some
bugs due to this and due to unforeseen interactions with other messes.
This scripting stuff was the only thing making use of that reentrancy,
and future commands that have "logical" waiting for something should be
implemented differently. So get rid of it.
Change the code to wait only in the player initialization phase: the
only place where it really has to wait is before playback is started,
because scripts might want to set options or hooks that interact with
playback initialization. Unloading of builtin scripts (can happen with
e.g. "set osc no") is left asynchronous; the unloading wasn't too robust
anyway, and this change won't make a difference if someone is trying to
break it intentionally. Note that this is not in mp_initialize(),
because mpv_initialize() uses this by locking the core, which would have
the same problem.
In the future, commands which logically wait should use different
mechanisms. Originally I thought the current approach (that is removed
with this commit) should be used, but it's too much of a mess and can't
even be used in some cases. Examples are:
- "loadfile" should be made blocking (needs to run the normal player
code and manually unblock the thread issuing the command)
- "add-sub" should not freeze the player until the URL is opened (needs
to run opening on a separate thread)
Possibly the current scripting behavior could be restored once new
mechanisms exist, and if it turns out that anyone needs it.
With this commit there should be no further instances of recursive
playloop invocations (other than the case in the following commit),
since all mp_idle()/mp_wait_events() calls are done strictly from the
main thread (and not commands/properties or libmpv client API that
"lock" the main thread).
2018-04-15 08:14:00 +00:00
|
|
|
mp_client_send_event(mpctx, name, 0, MPV_EVENT_SHUTDOWN, NULL);
|
2016-09-19 22:59:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_load_builtin_scripts(struct MPContext *mpctx)
|
|
|
|
{
|
2020-03-26 22:58:09 +00:00
|
|
|
load_builtin_script(mpctx, 0, mpctx->opts->lua_load_osc, "@osc.lua");
|
|
|
|
load_builtin_script(mpctx, 1, mpctx->opts->lua_load_ytdl, "@ytdl_hook.lua");
|
|
|
|
load_builtin_script(mpctx, 2, mpctx->opts->lua_load_stats, "@stats.lua");
|
|
|
|
load_builtin_script(mpctx, 3, mpctx->opts->lua_load_console, "@console.lua");
|
2020-08-05 20:37:47 +00:00
|
|
|
load_builtin_script(mpctx, 4, mpctx->opts->lua_load_auto_profiles,
|
|
|
|
"@auto_profiles.lua");
|
2016-09-19 22:59:54 +00:00
|
|
|
}
|
|
|
|
|
2020-01-19 18:25:54 +00:00
|
|
|
bool mp_load_scripts(struct MPContext *mpctx)
|
2014-05-12 23:14:07 +00:00
|
|
|
{
|
2020-01-19 18:25:54 +00:00
|
|
|
bool ok = true;
|
|
|
|
|
2014-05-12 23:14:07 +00:00
|
|
|
// Load scripts from options
|
2014-12-14 23:31:30 +00:00
|
|
|
char **files = mpctx->opts->script_files;
|
2014-05-12 23:14:07 +00:00
|
|
|
for (int n = 0; files && files[n]; n++) {
|
2017-06-30 13:53:33 +00:00
|
|
|
if (files[n][0])
|
2020-01-19 18:25:54 +00:00
|
|
|
ok &= mp_load_user_script(mpctx, files[n]) >= 0;
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
|
|
|
if (!mpctx->opts->auto_load_scripts)
|
2020-01-19 18:25:54 +00:00
|
|
|
return ok;
|
2014-06-18 23:55:40 +00:00
|
|
|
|
2014-12-14 23:31:30 +00:00
|
|
|
// Load all scripts
|
2014-05-12 23:14:07 +00:00
|
|
|
void *tmp = talloc_new(NULL);
|
2015-05-09 13:04:05 +00:00
|
|
|
char **scriptsdir = mp_find_all_config_files(tmp, mpctx->global, "scripts");
|
|
|
|
for (int i = 0; scriptsdir && scriptsdir[i]; i++) {
|
|
|
|
files = list_script_files(tmp, scriptsdir[i]);
|
|
|
|
for (int n = 0; files && files[n]; n++)
|
2020-01-19 18:25:54 +00:00
|
|
|
ok &= mp_load_script(mpctx, files[n]) >= 0;
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
|
|
|
talloc_free(tmp);
|
2020-01-19 18:25:54 +00:00
|
|
|
|
|
|
|
return ok;
|
2014-05-12 23:14:07 +00:00
|
|
|
}
|
2017-01-12 16:37:11 +00:00
|
|
|
|
|
|
|
#if HAVE_CPLUGINS
|
|
|
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
|
|
|
#define MPV_DLOPEN_FN "mpv_open_cplugin"
|
|
|
|
typedef int (*mpv_open_cplugin)(mpv_handle *handle);
|
|
|
|
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
static int load_cplugin(struct mp_script_args *args)
|
2017-01-12 16:37:11 +00:00
|
|
|
{
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
void *lib = dlopen(args->filename, RTLD_NOW | RTLD_LOCAL);
|
2017-01-12 16:37:11 +00:00
|
|
|
if (!lib)
|
|
|
|
goto error;
|
2017-01-14 15:49:49 +00:00
|
|
|
// Note: once loaded, we never unload, as unloading the libraries linked to
|
|
|
|
// the plugin can cause random serious problems.
|
2017-01-12 16:37:11 +00:00
|
|
|
mpv_open_cplugin sym = (mpv_open_cplugin)dlsym(lib, MPV_DLOPEN_FN);
|
|
|
|
if (!sym)
|
|
|
|
goto error;
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
return sym(args->client) ? -1 : 0;
|
2017-10-31 20:39:15 +00:00
|
|
|
error: ;
|
|
|
|
char *err = dlerror();
|
|
|
|
if (err)
|
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.
2020-02-01 17:09:40 +00:00
|
|
|
MP_ERR(args, "C plugin error: '%s'\n", err);
|
2017-10-31 20:39:15 +00:00
|
|
|
return -1;
|
2017-01-12 16:37:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const struct mp_scripting mp_scripting_cplugin = {
|
2017-01-14 15:47:53 +00:00
|
|
|
.name = "SO plugin",
|
2017-01-12 16:37:11 +00:00
|
|
|
.file_ext = "so",
|
|
|
|
.load = load_cplugin,
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
2020-02-19 21:18:15 +00:00
|
|
|
|
|
|
|
static int load_run(struct mp_script_args *args)
|
|
|
|
{
|
2020-02-25 21:41:09 +00:00
|
|
|
// The arg->client object might die and with it args->log, so duplicate it.
|
|
|
|
args->log = mp_log_new(args, args->log, NULL);
|
|
|
|
|
2020-02-19 21:18:15 +00:00
|
|
|
int fds[2];
|
|
|
|
if (!mp_ipc_start_anon_client(args->mpctx->ipc_ctx, args->client, fds))
|
|
|
|
return -1;
|
|
|
|
args->client = NULL; // ownership lost
|
|
|
|
|
scripting: make socket FD number for subprocesses dynamic
Before this, we pretty much guaranteed that --mpv-ipc-fd=3 would be
passed. The FD was hardcoded, so scripts started by this mechanism
didn't need to actually parse the argument. Change this to using a
mostly random FD number instead.
I decided to do this because posix_spawnp() and the current replacement
cannot "guarantee" a FD layout. posix_spawn_file_actions_adddup2() just
runs dup2() calls, so it may be hard to set FD 3/4 if they are already
used by something else. For example imagine trying to map:
{.fd = 3, .src_fd = 4},
{.fd = 4, .src_fd = 3},
Then it'd do dup2(4, 3), dup2(3, 4) (reminder: dup2(src, dst)), and the
end result is that FD 4 really maps to the original FD 4.
While this was not a problem in the present code, it's too messy that I
don't want to pretend it can always done this way without an unholy
mess. So my assumption is that FDs 0-2 can be freely assigned because
they're never closed (probably...), while for all other FDs only
pass-through is reasonable.
2020-05-15 14:35:44 +00:00
|
|
|
char *fdopt = fds[1] >= 0 ? mp_tprintf(80, "--mpv-ipc-fd=%d:%d", fds[0], fds[1])
|
|
|
|
: mp_tprintf(80, "--mpv-ipc-fd=%d", fds[0]);
|
2020-02-19 21:18:15 +00:00
|
|
|
|
|
|
|
struct mp_subprocess_opts opts = {
|
|
|
|
.exe = (char *)args->filename,
|
|
|
|
.args = (char *[]){(char *)args->filename, fdopt, NULL},
|
|
|
|
.fds = {
|
|
|
|
// Keep terminal stuff
|
|
|
|
{.fd = 0, .src_fd = 0,},
|
|
|
|
{.fd = 1, .src_fd = 1,},
|
|
|
|
{.fd = 2, .src_fd = 2,},
|
2020-07-09 10:26:54 +00:00
|
|
|
// Just hope these don't step over each other (e.g. fds[1] could be
|
2020-02-19 21:18:15 +00:00
|
|
|
// below 4, if the std FDs are missing).
|
scripting: make socket FD number for subprocesses dynamic
Before this, we pretty much guaranteed that --mpv-ipc-fd=3 would be
passed. The FD was hardcoded, so scripts started by this mechanism
didn't need to actually parse the argument. Change this to using a
mostly random FD number instead.
I decided to do this because posix_spawnp() and the current replacement
cannot "guarantee" a FD layout. posix_spawn_file_actions_adddup2() just
runs dup2() calls, so it may be hard to set FD 3/4 if they are already
used by something else. For example imagine trying to map:
{.fd = 3, .src_fd = 4},
{.fd = 4, .src_fd = 3},
Then it'd do dup2(4, 3), dup2(3, 4) (reminder: dup2(src, dst)), and the
end result is that FD 4 really maps to the original FD 4.
While this was not a problem in the present code, it's too messy that I
don't want to pretend it can always done this way without an unholy
mess. So my assumption is that FDs 0-2 can be freely assigned because
they're never closed (probably...), while for all other FDs only
pass-through is reasonable.
2020-05-15 14:35:44 +00:00
|
|
|
{.fd = fds[0], .src_fd = fds[0], },
|
|
|
|
{.fd = fds[1], .src_fd = fds[1], },
|
2020-02-19 21:18:15 +00:00
|
|
|
},
|
2020-05-15 14:16:48 +00:00
|
|
|
.num_fds = fds[1] >= 0 ? 5 : 4,
|
2020-02-19 21:18:15 +00:00
|
|
|
.detach = true,
|
|
|
|
};
|
|
|
|
struct mp_subprocess_result res;
|
|
|
|
mp_subprocess2(&opts, &res);
|
|
|
|
|
|
|
|
// Closing these will (probably) make the client exit, if it really died.
|
|
|
|
// They _should_ be CLOEXEC, but are not, because
|
|
|
|
// posix_spawn_file_actions_adddup2() may not clear the CLOEXEC flag
|
|
|
|
// properly if by coincidence fd==src_fd.
|
|
|
|
close(fds[0]);
|
|
|
|
if (fds[1] >= 0)
|
|
|
|
close(fds[1]);
|
|
|
|
|
|
|
|
if (res.error < 0) {
|
|
|
|
MP_ERR(args, "Starting '%s' failed: %s\n", args->filename,
|
|
|
|
mp_subprocess_err_str(res.error));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct mp_scripting mp_scripting_run = {
|
|
|
|
.name = "spawned IPC process",
|
|
|
|
.file_ext = "run",
|
|
|
|
.no_thread = true,
|
|
|
|
.load = load_run,
|
|
|
|
};
|