mirror of https://github.com/mpv-player/mpv
lua: add a bunch of functions to get/set properties by their native type
There are some complications because the client API distinguishes between integers and floats, while Lua has only "numbers" (which are usually floats). But I think this should work now.
This commit is contained in:
parent
942fb43d0c
commit
f628d5e859
|
@ -93,12 +93,50 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||||
missing. Unlike ``get_property()``, assigning the return value to a variable
|
missing. Unlike ``get_property()``, assigning the return value to a variable
|
||||||
will always result in a string.
|
will always result in a string.
|
||||||
|
|
||||||
|
``mp.get_property_bool(name [,def])``
|
||||||
|
Similar to ``mp.get_property``, but return the property value as boolean.
|
||||||
|
|
||||||
|
Returns a boolean on success, or ``def, error`` on error.
|
||||||
|
|
||||||
|
``mp.get_property_number(name [,def])``
|
||||||
|
Similar to ``mp.get_property``, but return the property value as number.
|
||||||
|
|
||||||
|
Note that while Lua does not distinguish between integers and floats,
|
||||||
|
mpv internals do. This function simply request a double float from mpv,
|
||||||
|
and mpv will usually convert integer property values to float.
|
||||||
|
|
||||||
|
Returns a number on success, or ``def, error`` on error.
|
||||||
|
|
||||||
|
``mp.get_property_native(name [,def])``
|
||||||
|
Similar to ``mp.get_property``, but return the property value using the best
|
||||||
|
Lua type for the property. Most time, this will return a string, boolean,
|
||||||
|
or number. Some properties (for example ``chapter-list``) are returned as
|
||||||
|
tables.
|
||||||
|
|
||||||
|
Returns a value on success, or ``def, error`` on error. Note that ``nil``
|
||||||
|
might be a possible, valid value too in some corner cases.
|
||||||
|
|
||||||
|
(There is no ``mp.set_property_native`` yet.)
|
||||||
|
|
||||||
``mp.set_property(name, value)``
|
``mp.set_property(name, value)``
|
||||||
Set the given property to the given value. See ``mp.get_property`` and
|
Set the given property to the given string value. See ``mp.get_property``
|
||||||
`Properties`_ for more information about properties.
|
and `Properties`_ for more information about properties.
|
||||||
|
|
||||||
Returns true on success, or ``nil, error`` on error.
|
Returns true on success, or ``nil, error`` on error.
|
||||||
|
|
||||||
|
``mp.set_property_bool(name, value)``
|
||||||
|
Similar to ``mp.set_property``, but set the given property to the given
|
||||||
|
boolean value.
|
||||||
|
|
||||||
|
``mp.set_property_number(name, value)``
|
||||||
|
Similar to ``mp.set_property``, but set the given property to the given
|
||||||
|
numeric value.
|
||||||
|
|
||||||
|
Note that while Lua does not distinguish between integers and floats,
|
||||||
|
mpv internals do. This function will test whether the number can be
|
||||||
|
represented as integer, and if so, it will pass an integer value to mpv,
|
||||||
|
otherwise a double float.
|
||||||
|
|
||||||
``mp.get_time()``
|
``mp.get_time()``
|
||||||
Return the current mpv internal time in seconds as a number. This is
|
Return the current mpv internal time in seconds as a number. This is
|
||||||
basically the system time, with an arbitrary offset.
|
basically the system time, with an arbitrary offset.
|
||||||
|
|
155
player/lua.c
155
player/lua.c
|
@ -2,6 +2,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "osdep/io.h"
|
#include "osdep/io.h"
|
||||||
|
|
||||||
|
@ -232,8 +233,16 @@ static void *lua_thread(void *p)
|
||||||
lua_pushstring(L, ctx->name); // mp name
|
lua_pushstring(L, ctx->name); // mp name
|
||||||
lua_setfield(L, -2, "script_name"); // mp
|
lua_setfield(L, -2, "script_name"); // mp
|
||||||
|
|
||||||
|
// used by pushnode()
|
||||||
|
lua_newtable(L); // mp table
|
||||||
|
lua_pushvalue(L, -1); // mp table table
|
||||||
|
lua_setfield(L, LUA_REGISTRYINDEX, "UNKNOWN_TYPE"); // mp table
|
||||||
|
lua_setfield(L, -2, "UNKNOWN_TYPE"); // mp
|
||||||
|
|
||||||
lua_pop(L, 1); // -
|
lua_pop(L, 1); // -
|
||||||
|
|
||||||
|
assert(lua_gettop(L) == 0);
|
||||||
|
|
||||||
// Add a preloader for each builtin Lua module
|
// Add a preloader for each builtin Lua module
|
||||||
lua_getglobal(L, "package"); // package
|
lua_getglobal(L, "package"); // package
|
||||||
assert(lua_type(L, -1) == LUA_TTABLE);
|
assert(lua_type(L, -1) == LUA_TTABLE);
|
||||||
|
@ -500,6 +509,33 @@ static int script_set_property(lua_State *L)
|
||||||
return check_error(L, mpv_set_property_string(ctx->client, p, v));
|
return check_error(L, mpv_set_property_string(ctx->client, p, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int script_set_property_bool(lua_State *L)
|
||||||
|
{
|
||||||
|
struct script_ctx *ctx = get_ctx(L);
|
||||||
|
const char *p = luaL_checkstring(L, 1);
|
||||||
|
int v = lua_toboolean(L, 2);
|
||||||
|
|
||||||
|
return check_error(L, mpv_set_property(ctx->client, p, MPV_FORMAT_FLAG, &v));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int script_set_property_number(lua_State *L)
|
||||||
|
{
|
||||||
|
struct script_ctx *ctx = get_ctx(L);
|
||||||
|
const char *p = luaL_checkstring(L, 1);
|
||||||
|
double d = luaL_checknumber(L, 2);
|
||||||
|
// If the number might be an integer, then set it as integer. The mpv core
|
||||||
|
// will (probably) convert INT64 to DOUBLE when setting, but not the other
|
||||||
|
// way around.
|
||||||
|
int64_t v = d;
|
||||||
|
int res;
|
||||||
|
if (d == (double)v) {
|
||||||
|
res = mpv_set_property(ctx->client, p, MPV_FORMAT_INT64, &v);
|
||||||
|
} else {
|
||||||
|
res = mpv_set_property(ctx->client, p, MPV_FORMAT_DOUBLE, &d);
|
||||||
|
}
|
||||||
|
return check_error(L, res);
|
||||||
|
}
|
||||||
|
|
||||||
static int script_property_list(lua_State *L)
|
static int script_property_list(lua_State *L)
|
||||||
{
|
{
|
||||||
const struct m_option *props = mp_get_property_list();
|
const struct m_option *props = mp_get_property_list();
|
||||||
|
@ -518,8 +554,6 @@ static int script_get_property(lua_State *L)
|
||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
int type = lua_tointeger(L, lua_upvalueindex(1))
|
int type = lua_tointeger(L, lua_upvalueindex(1))
|
||||||
? MPV_FORMAT_OSD_STRING : MPV_FORMAT_STRING;
|
? MPV_FORMAT_OSD_STRING : MPV_FORMAT_STRING;
|
||||||
char *def_fallback = type == MPV_FORMAT_OSD_STRING ? "" : NULL;
|
|
||||||
char *def = (char *)luaL_optstring(L, 2, def_fallback);
|
|
||||||
|
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
int err = mpv_get_property(ctx->client, name, type, &result);
|
int err = mpv_get_property(ctx->client, name, type, &result);
|
||||||
|
@ -527,13 +561,119 @@ static int script_get_property(lua_State *L)
|
||||||
lua_pushstring(L, result);
|
lua_pushstring(L, result);
|
||||||
talloc_free(result);
|
talloc_free(result);
|
||||||
return 1;
|
return 1;
|
||||||
|
} else {
|
||||||
|
if (lua_isnoneornil(L, 2) && type == MPV_FORMAT_OSD_STRING) {
|
||||||
|
lua_pushstring(L, "");
|
||||||
|
} else {
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
}
|
}
|
||||||
if (def) {
|
|
||||||
lua_pushstring(L, def);
|
|
||||||
lua_pushstring(L, mpv_error_string(err));
|
lua_pushstring(L, mpv_error_string(err));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
return check_error(L, err);
|
}
|
||||||
|
|
||||||
|
static int script_get_property_bool(lua_State *L)
|
||||||
|
{
|
||||||
|
struct script_ctx *ctx = get_ctx(L);
|
||||||
|
const char *name = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
int err = mpv_get_property(ctx->client, name, MPV_FORMAT_FLAG, &result);
|
||||||
|
if (err >= 0) {
|
||||||
|
lua_pushboolean(L, !!result);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushstring(L, mpv_error_string(err));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int script_get_property_number(lua_State *L)
|
||||||
|
{
|
||||||
|
struct script_ctx *ctx = get_ctx(L);
|
||||||
|
const char *name = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
// Note: the mpv core will (hopefully) convert INT64 to DOUBLE
|
||||||
|
double result = 0;
|
||||||
|
int err = mpv_get_property(ctx->client, name, MPV_FORMAT_DOUBLE, &result);
|
||||||
|
if (err >= 0) {
|
||||||
|
lua_pushnumber(L, result);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushstring(L, mpv_error_string(err));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pushnode(lua_State *L, mpv_node *node, int depth)
|
||||||
|
{
|
||||||
|
depth--;
|
||||||
|
if (depth < 0)
|
||||||
|
return false;
|
||||||
|
luaL_checkstack(L, 6, "stack overflow");
|
||||||
|
|
||||||
|
switch (node->format) {
|
||||||
|
case MPV_FORMAT_STRING:
|
||||||
|
lua_pushstring(L, node->u.string);
|
||||||
|
break;
|
||||||
|
case MPV_FORMAT_INT64:
|
||||||
|
lua_pushnumber(L, node->u.int64);
|
||||||
|
break;
|
||||||
|
case MPV_FORMAT_DOUBLE:
|
||||||
|
lua_pushnumber(L, node->u.double_);
|
||||||
|
break;
|
||||||
|
case MPV_FORMAT_NONE:
|
||||||
|
lua_pushnil(L);
|
||||||
|
break;
|
||||||
|
case MPV_FORMAT_FLAG:
|
||||||
|
lua_pushboolean(L, node->u.flag);
|
||||||
|
break;
|
||||||
|
case MPV_FORMAT_NODE_ARRAY:
|
||||||
|
lua_newtable(L); // table
|
||||||
|
for (int n = 0; n < node->u.list->num; n++) {
|
||||||
|
if (!pushnode(L, &node->u.list->values[n], depth)) // table value
|
||||||
|
return false;
|
||||||
|
lua_rawseti(L, -2, n + 1); // table
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MPV_FORMAT_NODE_MAP:
|
||||||
|
lua_newtable(L); // table
|
||||||
|
for (int n = 0; n < node->u.list->num; n++) {
|
||||||
|
lua_pushstring(L, node->u.list->keys[n]); // table key
|
||||||
|
if (!pushnode(L, &node->u.list->values[n], depth)) // table key value
|
||||||
|
return false;
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// unknown value - what do we do?
|
||||||
|
// for now, set a unique dummy value
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, "UNKNOWN_TYPE");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int script_get_property_native(lua_State *L)
|
||||||
|
{
|
||||||
|
struct script_ctx *ctx = get_ctx(L);
|
||||||
|
const char *name = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
mpv_node node;
|
||||||
|
int err = mpv_get_property(ctx->client, name, MPV_FORMAT_NODE, &node);
|
||||||
|
const char *errstr = mpv_error_string(err);
|
||||||
|
if (err >= 0) {
|
||||||
|
bool ok = pushnode(L, &node, 50);
|
||||||
|
mpv_free_node_contents(&node);
|
||||||
|
if (ok)
|
||||||
|
return 1;
|
||||||
|
errstr = "value too large";
|
||||||
|
}
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushstring(L, errstr);
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int script_set_osd_ass(lua_State *L)
|
static int script_set_osd_ass(lua_State *L)
|
||||||
|
@ -781,7 +921,12 @@ static struct fn_entry fn_list[] = {
|
||||||
FN_ENTRY(find_config_file),
|
FN_ENTRY(find_config_file),
|
||||||
FN_ENTRY(command),
|
FN_ENTRY(command),
|
||||||
FN_ENTRY(commandv),
|
FN_ENTRY(commandv),
|
||||||
|
FN_ENTRY(get_property_bool),
|
||||||
|
FN_ENTRY(get_property_number),
|
||||||
|
FN_ENTRY(get_property_native),
|
||||||
FN_ENTRY(set_property),
|
FN_ENTRY(set_property),
|
||||||
|
FN_ENTRY(set_property_bool),
|
||||||
|
FN_ENTRY(set_property_number),
|
||||||
FN_ENTRY(property_list),
|
FN_ENTRY(property_list),
|
||||||
FN_ENTRY(set_osd_ass),
|
FN_ENTRY(set_osd_ass),
|
||||||
FN_ENTRY(get_osd_resolution),
|
FN_ENTRY(get_osd_resolution),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
mp.UNKNOWN_TYPE = "this value is inserted if the C type is not supported"
|
||||||
|
|
||||||
function mp.get_script_name()
|
function mp.get_script_name()
|
||||||
return mp.script_name
|
return mp.script_name
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue