Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DOCS/interface-changes/msg-prefix.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add `msg-prefix` command
1 change: 1 addition & 0 deletions DOCS/interface-changes/msg.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add `msg` command
14 changes: 14 additions & 0 deletions DOCS/man/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,20 @@ Text Manipulation

This line of Lua prints "foo \\{bar}" on the OSD.

``msg <level> <message> [...]``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not extend print-text command with optional arguments? It can be aliased to msg if preferred, but both do the same thing.

Write a log message. ``level`` must be one of the log levels accepted by the
``mp.msg.log`` Lua function. The ``message`` arguments are separated from
each other with a space. A newline is added to the end of the message.

This command has a variable number of arguments, and cannot be used with
named arguments.

.. note:: Lua and JS code should use the provided ``mp.msg`` modules.

``msg-prefix <level> <prefix> <message> [...]``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want that? I would say we don't let clients to change their prefix.

Or it may be additional arg in msg, but instead of replacing the existing prefix, it should create sub logger, to form <client_name>/<perfix> form.

Same as ``msg``, but allows writing messages using ``prefix`` as the prefix
instead of the name of the client that sent the command.

Configuration Commands
~~~~~~~~~~~~~~~~~~~~~~

Expand Down
45 changes: 45 additions & 0 deletions player/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -7104,6 +7104,44 @@ static void cmd_notify_property(void *p)
mp_notify_property(mpctx, cmd->args[0].v.s);
}

static void cmd_msg(void *p)
{
struct mp_cmd_ctx *cmd = p;
struct MPContext *mpctx = cmd->mpctx;

if (cmd->num_args < 2)
return;

int level = mp_msg_find_level(cmd->args[0].v.s);
if (level < 0)
return;

struct mp_log *log = mp_log_new(NULL, mpctx->log, cmd->cmd->sender);
Copy link
Member

@kasper93 kasper93 Oct 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to create logger during client init and set it in cmd, same as cmd->cmd->sender. sender field can be made a struct with char *name and mp_log log.

for (int i = 1; i < cmd->num_args; i++)
mp_msg(log, level, (i == 1 ? "%s" : " %s"), cmd->args[i].v.s);
mp_msg(log, level, "\n");
talloc_free(log);
}

static void cmd_msg_prefix(void *p)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicated code above, it should be made single function/command.

{
struct mp_cmd_ctx *cmd = p;
struct MPContext *mpctx = cmd->mpctx;

if (cmd->num_args < 3)
return;

int level = mp_msg_find_level(cmd->args[0].v.s);
if (level < 0)
return;

struct mp_log *log = mp_log_new(NULL, mpctx->log, cmd->args[1].v.s);
for (int i = 2; i < cmd->num_args; i++)
mp_msg(log, level, (i == 2 ? "%s" : " %s"), cmd->args[i].v.s);
mp_msg(log, level, "\n");
talloc_free(log);
}

/* This array defines all known commands.
* The first field the command name used in libmpv and input.conf.
* The second field is the handler function (see mp_cmd_def.handler and
Expand Down Expand Up @@ -7623,6 +7661,13 @@ const struct mp_cmd_def mp_cmds[] = {

{ "notify-property", cmd_notify_property, { {"property", OPT_STRING(v.s)} } },

{ "msg", cmd_msg, { {"level", OPT_STRING(v.s)}, {"message", OPT_STRING(v.s)} },
.is_noisy = true, .vararg = true },
{ "msg-prefix", cmd_msg_prefix, { {"level", OPT_STRING(v.s)},
{"prefix", OPT_STRING(v.s)},
{"message", OPT_STRING(v.s)} },
.is_noisy = true, .vararg = true },

{0}
};

Expand Down
17 changes: 0 additions & 17 deletions player/javascript.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include "common/common.h"
#include "options/m_property.h"
#include "common/msg.h"
#include "common/msg_control.h"
#include "common/stats.h"
#include "options/m_option.h"
#include "input/input.h"
Expand Down Expand Up @@ -565,21 +564,6 @@ static int checkopt(js_State *J, int idx, const char *def, const char *opts[],
js_error(J, "Invalid %s '%s'", desc, opt);
}

// args: level as string and a variable numbers of args to print. adds final \n
static void script_log(js_State *J)
{
const char *level = js_tostring(J, 1);
int msgl = mp_msg_find_level(level);
if (msgl < 0)
js_error(J, "Invalid log level '%s'", level);

struct mp_log *log = jctx(J)->log;
for (int top = js_gettop(J), i = 2; i < top; i++)
mp_msg(log, msgl, (i == 2 ? "%s" : " %s"), js_tostring(J, i));
mp_msg(log, msgl, "\n");
push_success(J);
}

static void script_find_config_file(js_State *J, void *af)
{
const char *fname = js_tostring(J, 1);
Expand Down Expand Up @@ -1155,7 +1139,6 @@ struct fn_entry {
// Names starting with underscore are wrapped at @defaults.js
// FN_ENTRY is a normal js C function, AF_ENTRY is an autofree js C function.
static const struct fn_entry main_fns[] = {
FN_ENTRY(log, 1),
AF_ENTRY(wait_event, 1),
FN_ENTRY(_request_event, 2),
AF_ENTRY(find_config_file, 1),
Expand Down
7 changes: 7 additions & 0 deletions player/javascript/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
// - The names of function expressions are not required, but are used in stack
// traces. We name them where useful to show up (fname:#line always shows).

mp.log = function(level) {
var cmd = ["msg", level];
for (var i = 1; i < arguments.length; i++)
cmd.push(String(arguments[i]))
mp.command_native(cmd);
}

mp.msg = { log: mp.log };
mp.msg.verbose = mp.log.bind(null, "v");
var levels = ["fatal", "error", "warn", "info", "debug", "trace"];
Expand Down
35 changes: 0 additions & 35 deletions player/lua.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "common/common.h"
#include "options/m_property.h"
#include "common/msg.h"
#include "common/msg_control.h"
#include "common/stats.h"
#include "options/m_option.h"
#include "input/input.h"
Expand Down Expand Up @@ -499,39 +498,6 @@ static int load_lua(struct mp_script_args *args)
return r;
}

static int check_loglevel(lua_State *L, int arg)
{
const char *level = luaL_checkstring(L, arg);
int n = mp_msg_find_level(level);
if (n >= 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);

int msgl = check_loglevel(L, 1);

int last = lua_gettop(L);
lua_getglobal(L, "tostring"); // args... tostring
for (int i = 2; i <= last; i++) {
lua_pushvalue(L, -1); // args... tostring tostring
lua_pushvalue(L, i); // args... tostring tostring args[i]
lua_call(L, 1, 1); // args... tostring str
const char *s = lua_tostring(L, -1);
if (s == NULL)
return luaL_error(L, "Invalid argument");
mp_msg(ctx->log, msgl, (i == 2 ? "%s" : " %s"), s);
lua_pop(L, 1); // args... tostring
}
mp_msg(ctx->log, msgl, "\n");

return 0;
}

static int script_find_config_file(lua_State *L)
{
struct MPContext *mpctx = get_mpctx(L);
Expand Down Expand Up @@ -1226,7 +1192,6 @@ struct fn_entry {
};

static const struct fn_entry main_fns[] = {
FN_ENTRY(log),
AF_ENTRY(raw_wait_event),
FN_ENTRY(request_event),
FN_ENTRY(find_config_file),
Expand Down
8 changes: 8 additions & 0 deletions player/lua/defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,14 @@ end
-- sent by "script-binding"
mp.register_script_message("key-binding", dispatch_key_binding)

function mp.log(level, ...)
local cmd = {"msg", level}
for i = 1, select("#", ...) do
cmd[#cmd + 1] = tostring(select(i, ...))
end
mp.command_native(cmd)
end

mp.msg = {
log = mp.log,
fatal = function(...) return mp.log("fatal", ...) end,
Expand Down