mirror of https://github.com/mpv-player/mpv
lua: allow scripts to snoop messages
Adds the following Lua function to enable message events: mp.enable_messages(size, level) size is the maximum number of messages the ringbuffer consists of. level is the minimum log level for a message to be added to the ringbuffer, and uses the same values as the mp.log() function. (Actually not yet, but this will be fixed in the following commit.) The messages will be delivered via the mp_event() in the user script, using "message" as event name. The event argument is a table with the following fields: level: log level of the message (string as in mp.log()) prefix: string identifying the module of origin text: contents of the message As of currently, the message text will contain newline characters. A message can consist of several lines. It is also possible that a message doesn't end with a newline, and a caller can use multiple messages to "build" a line. Most messages will contain exactly 1 line ending with a single newline character, though. If the message buffer overflows (messages are not read quickly enough), new messages are lost until the queued up messages are read. At the point of the overflow, a special overflow message is inserted. It will have prefix set to "overflow", and the message text is set to "". Care should be taken not to print any messages from the message event handler. This would lead to an infinite loop (the event handler would be called again after returning, because a new message is available). This includes mp.log() and all mp.msg.* functions. Keep in mind that the Lua print() function is mapped to mp.msg.info().
This commit is contained in:
parent
8c5ea38cda
commit
d646d78ccb
70
player/lua.c
70
player/lua.c
|
@ -10,6 +10,7 @@
|
|||
#include "common/common.h"
|
||||
#include "options/m_property.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/msg_control.h"
|
||||
#include "options/m_option.h"
|
||||
#include "input/input.h"
|
||||
#include "options/path.h"
|
||||
|
@ -39,6 +40,7 @@ static const char *builtin_lua_scripts[][2] = {
|
|||
struct script_ctx {
|
||||
const char *name;
|
||||
lua_State *state;
|
||||
struct mp_log_buffer *messages;
|
||||
struct mp_log *log;
|
||||
struct MPContext *mpctx;
|
||||
};
|
||||
|
@ -244,6 +246,8 @@ static void kill_script(struct script_ctx *ctx)
|
|||
if (!ctx)
|
||||
return;
|
||||
struct lua_ctx *lctx = ctx->mpctx->lua_ctx;
|
||||
if (ctx->messages)
|
||||
mp_msg_log_buffer_destroy(ctx->messages);
|
||||
lua_close(ctx->state);
|
||||
for (int n = 0; n < lctx->num_scripts; n++) {
|
||||
if (lctx->scripts[n] == ctx) {
|
||||
|
@ -263,20 +267,22 @@ static const char *log_level[] = {
|
|||
[MSGL_DEBUG] = "debug",
|
||||
};
|
||||
|
||||
static int check_loglevel(lua_State *L, int arg)
|
||||
{
|
||||
const char *level = luaL_checkstring(L, arg);
|
||||
for (int n = 0; n < MP_ARRAY_SIZE(log_level); n++) {
|
||||
if (log_level[n] && strcasecmp(log_level[n], level) == 0)
|
||||
return n;
|
||||
}
|
||||
luaL_error(L, "Invalid log level '%s'", level);
|
||||
abort();
|
||||
}
|
||||
|
||||
static int script_log(lua_State *L)
|
||||
{
|
||||
struct script_ctx *ctx = get_ctx(L);
|
||||
|
||||
const char *level = luaL_checkstring(L, 1);
|
||||
int msgl = -1;
|
||||
for (int n = 0; n < MP_ARRAY_SIZE(log_level); n++) {
|
||||
if (log_level[n] && strcasecmp(log_level[n], level) == 0) {
|
||||
msgl = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (msgl < 0)
|
||||
luaL_error(L, "Invalid log level '%s'", level);
|
||||
int msgl = check_loglevel(L, 1);
|
||||
|
||||
int last = lua_gettop(L);
|
||||
lua_getglobal(L, "tostring"); // args... tostring
|
||||
|
@ -319,6 +325,34 @@ static int run_event(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void poll_messages(struct script_ctx *ctx)
|
||||
{
|
||||
lua_State *L = ctx->state;
|
||||
|
||||
if (!ctx->messages)
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
struct mp_log_buffer_entry *msg = mp_msg_log_buffer_read(ctx->messages);
|
||||
if (!msg)
|
||||
break;
|
||||
|
||||
lua_pushstring(L, "message"); // msg
|
||||
lua_newtable(L); // msg t
|
||||
lua_pushstring(L, msg->prefix); // msg t s
|
||||
lua_setfield(L, -2, "prefix"); // msg t
|
||||
lua_pushstring(L, mp_log_levels[msg->level]); // msg t s
|
||||
lua_setfield(L, -2, "level"); // msg t
|
||||
lua_pushstring(L, msg->text); // msg t s
|
||||
lua_setfield(L, -2, "text"); // msg t
|
||||
|
||||
if (mp_cpcall(L, run_event, 2) != 0)
|
||||
report_error(L);
|
||||
|
||||
talloc_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_lua_event(struct MPContext *mpctx, const char *name, const char *arg)
|
||||
{
|
||||
// There is no proper subscription mechanism yet, so all scripts get it.
|
||||
|
@ -334,9 +368,24 @@ void mp_lua_event(struct MPContext *mpctx, const char *name, const char *arg)
|
|||
}
|
||||
if (mp_cpcall(L, run_event, 2) != 0)
|
||||
report_error(L);
|
||||
poll_messages(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static int script_enable_messages(lua_State *L)
|
||||
{
|
||||
struct script_ctx *ctx = get_ctx(L);
|
||||
if (ctx->messages)
|
||||
luaL_error(L, "messages already enabled");
|
||||
|
||||
int size = luaL_checkinteger(L, 1);
|
||||
int level = check_loglevel(L, 2);
|
||||
if (size < 2 || size > 100000)
|
||||
luaL_error(L, "size argument out of range");
|
||||
ctx->messages = mp_msg_log_buffer_new(ctx->mpctx->global, size, level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_script_dispatch(lua_State *L)
|
||||
{
|
||||
int id = lua_tointeger(L, 1);
|
||||
|
@ -661,6 +710,7 @@ static struct fn_entry fn_list[] = {
|
|||
FN_ENTRY(input_disable_section),
|
||||
FN_ENTRY(input_set_section_mouse_area),
|
||||
FN_ENTRY(format_time),
|
||||
FN_ENTRY(enable_messages),
|
||||
};
|
||||
|
||||
// On stack: mp table
|
||||
|
|
Loading…
Reference in New Issue