mp module that lets scripts send commands, read and write properties, react to events, and register key bindings. Internally, Lua scripts use the same client API as any other mpv controller.
Script location
Scripts are loaded from two places:- Automatically: any
.luafile in~/.config/mpv/scripts/ - Explicitly: passed with the
--scriptflag:mpv --script=/path/to/myscript.lua file.mkv
.lua extension and replacing non-alphanumeric characters with _. For example, my-tools.lua becomes my_tools. If multiple scripts share the same derived name, a number is appended to make it unique.
Files with a .disable extension are always ignored.
Directory scripts
A script can be a directory instead of a single file. mpv looks formain.lua inside that directory. This is the recommended layout for scripts that span multiple source files or need to load data files:
mp.get_script_directory() inside the script to locate the directory at runtime. The directory is also prepended to Lua’s package.path, so you can require modules from it directly.
Lifecycle
Each script runs in its own thread. On startup:- mpv executes the script’s top-level code.
- The built-in event loop (
mp_event_loop) starts, dispatching events to registered handlers.
shutdown event, which makes the event loop return.
mp.observe_property instead.Quick example
A script that exits fullscreen whenever playback is paused:~/.config/mpv/scripts/exit-fullscreen-on-pause.lua and it will be loaded automatically.
mp module
Themp module is preloaded. You can also load it explicitly with require 'mp'.
Commands
mp.command(string)
mp.command(string)
input.conf, including OSD display.Returns true on success, or nil, error on failure.mp.commandv(arg1, arg2, ...)
mp.commandv(arg1, arg2, ...)
mp.command, but each argument is passed separately — no quoting or escaping needed. OSD is not shown by default.mp.get_property to read values first.mp.command_native(table [, def])
mp.command_native(table [, def])
mp.commandv, but arguments are passed as a Lua table. Supports native types (booleans, numbers) and named arguments.For named arguments, include a name key with the command name:def, error on failure.mp.command_native_async(table [, fn])
mp.command_native_async(table [, fn])
mp.command_native, but runs asynchronously. fn(success, result, error) is called on completion.mp.abort_async_command.mp.abort_async_command(handle)
mp.abort_async_command(handle)
mp.command_native_async. Whether the abort succeeds depends on the command.Properties
mp.get_property(name [, def])
mp.get_property(name [, def])
${=name}). Returns def, error on failure (def defaults to nil).mp.get_property_osd(name [, def])
mp.get_property_osd(name [, def])
${name} in input.conf). Always returns a string (empty string on error unless def is set).mp.get_property_bool(name [, def])
mp.get_property_bool(name [, def])
def, error on failure.mp.get_property_number(name [, def])
mp.get_property_number(name [, def])
def, error on failure.mp.get_property_native(name [, def])
mp.get_property_native(name [, def])
chapter-list are returned as tables.mp.set_property(name, value)
mp.set_property(name, value)
true on success, nil, error on failure.mp.set_property_bool(name, value)
mp.set_property_bool(name, value)
mp.set_property_number(name, value)
mp.set_property_number(name, value)
mp.set_property_native(name, value)
mp.set_property_native(name, value)
mp.del_property(name)
mp.del_property(name)
true on success, nil, error on failure.mp.observe_property(name, type, fn)
mp.observe_property(name, type, fn)
fn(name, value) whenever name changes. type controls how the value is retrieved: "bool", "string", "number", "native", or nil/"none" (no value passed).You always receive an initial notification with the current value.mp.unobserve_property(fn)
mp.unobserve_property(fn)
Key bindings
mp.add_key_binding(key, name, fn [, flags])
mp.add_key_binding(key, name, fn [, flags])
fn to be called when key is pressed. key uses the same names as input.conf (e.g. "ctrl+a", "F5"). name is a unique symbolic name for the binding.Users can remap the binding in their input.conf:flags table accepts:| Key | Type | Description |
|---|---|---|
repeatable | boolean | Enable key repeat |
complex | boolean | Call fn on key down, repeat, and up events |
scalable | boolean | Enable scaling (only with complex = true) |
mp.add_forced_key_binding(...)
mp.add_forced_key_binding(...)
mp.add_key_binding, but this binding overrides even user-defined bindings in input.conf. Use sparingly.mp.remove_key_binding(name)
mp.remove_key_binding(name)
mp.add_key_binding or mp.add_forced_key_binding by name.Events
mp.register_event(name, fn)
mp.register_event(name, fn)
fn(event) when the named event occurs. event is a table with at least an event field (the event name string). Returns true if the event exists, false otherwise.mp.unregister_event(fn)
mp.unregister_event(fn)
fn. Uses Lua == comparison — be careful with closures.Timers
mp.add_timeout(seconds, fn [, disabled])
mp.add_timeout(seconds, fn [, disabled])
fn once after seconds seconds. Returns a timer object. If disabled is true, the timer starts in a paused state and must be started manually with :resume().mp.add_periodic_timer(seconds, fn [, disabled])
mp.add_periodic_timer(seconds, fn [, disabled])
fn repeatedly every seconds seconds. Returns a timer object with these methods:| Method | Description |
|---|---|
stop() | Pause the timer, remembering elapsed time |
kill() | Stop and reset the timer |
resume() | Start or unpause the timer |
is_enabled() | Check if the timer is active |
timeout (RW) and oneshot (RW) fields.Script identity and messaging
| Function | Description |
|---|---|
mp.get_script_name() | Returns the script’s internal name (e.g. my_script) |
mp.get_script_directory() | Returns the script directory path (directory scripts only) |
mp.get_time() | Returns current mpv internal time in seconds |
mp.osd_message(text [, duration]) | Show text on the OSD; duration in seconds |
mp.get_opt(key) | Read a value from --script-opts |
Script messages
Hooks
Hooks let scripts run synchronous code at specific points in the player’s lifecycle. Usemp.add_hook to register them.
priority is an integer; 50 is the recommended neutral default. Lower values run first.
Available hook types:
| Hook | Description |
|---|---|
on_load | Before a file is opened |
on_load_fail | After a file fails to open |
on_preloaded | After open, before track selection |
on_loaded | After tracks selected, before playback starts |
on_unload | Before a file is closed |
on_before_start_file | Before start-file event |
on_after_end_file | After end-file event |
mp.msg module
Load withrequire 'mp.msg' or use via mp.msg.*.
fatal, error, warn, info, v, debug, trace. By default, v, debug, and trace are hidden unless the user enables verbose output.
msg.log(level, ...) is the generic form; all others are shortcuts.
mp.options module
Parse options from a config file and/or--script-opts on the command line.
~/.config/mpv/script-opts/myscript.conf:
on_update callback as the third argument to read_options to react to runtime changes via the script-opts property.
mp.utils module
File system
File system
Subprocess
Subprocess
JSON
JSON
Other utilities
Other utilities
mp.input module
Prompt the user for text input using the mpv console.input.get(table) options
| Key | Type | Description |
|---|---|---|
prompt | string | Text shown before the input field |
submit | function(text) | Called when user presses Enter |
edited | function(text) | Called on each keystroke |
complete | function(text_before_cursor, respond) | Called for tab completion |
closed | function(text, cursor_pos) | Called when console closes |
keep_open | boolean | Keep console open after submit (default: false) |
default_text | string | Pre-fill the input field |
cursor_position | integer | Initial cursor position (1-based) |
history_path | string | Path for persisting input history |
input.select(table) — selection list
Other functions
| Function | Description |
|---|---|
input.terminate() | Close the active input console |
input.log(message, style, terminal_style) | Append a line to the log buffer |
input.set_log(log) | Replace the entire log buffer |
Events reference
Register handlers withmp.register_event(name, fn).
start-file
playlist_entry_id.file-loaded
end-file
reason (eof, stop, quit, error, redirect), playlist_entry_id.seek
playback-restart
shutdown
log-message
mp.enable_messages(level). Fields: prefix, level, text.property-change
name, data.video-reconfig
audio-reconfig
Script-opts configuration
Each script can have a dedicated config file at:key=value syntax. # begins a comment. Booleans are yes/no.
mp.options.read_options.