neulab/tldr huggingface dataset:
option-info/<name>/min, option-info/<name>/max Integer minimum and maximum values allowed for the option. Only available if the options are numeric, and the minimum/maximum has been set internally. It's also possible that only one of these is set.
option-info/<name>/choices If the option is a choice option, the possible choices. Choices that are integers may or may not be included (they can be implied by min and max). Note that options which behave like choice options, but are not actual choice options internally, may not have this info available.
property-list The list of top-level properties.
profile-list The list of profiles and their contents. This is highly implementation-specific, and may change any time. Currently, it returns an array of options for each profile. Each option has a name and a value, with the value currently always being a string. Note that the options array is not a map, as order matters and duplicate entries are possible. Recursive profiles are not expanded, and show up as special profile options.
command-list The list of input commands. This returns an array of maps, where each map node represents a command. This map currently only has a single entry: name for the name of the command. (This property is supposed to be a replacement for --input-cmdlist. The option dumps some more information, but it's a valid feature request to extend this property if needed.)
input-bindings The list of current input key bindings. This returns an array of maps, where each map node represents a binding for a single key/command. This map has the following entries:
key    The key name. This is normalized and may look slightly different from how it was specified in the source (e.g. in input.conf).
cmd    The command mapped to the key. (Currently, this is exactly the same string as specified in the source, other than stripping whitespace and comments. It's possible that it will be normalized in the future.)
is_weak If set to true, any existing and active user bindings will take priority.
owner  If this entry exists, the name of the script (or similar) which added this binding.
section Name of the section this binding is part of. This is a rarely used mechanism. This entry may be removed or change meaning in the future.
priority A number. Bindings with a higher value are preferred over bindings with a lower value. If the value is negative, this binding is inactive and will not be triggered by input. Note that mpv does not use this value internally, and matching of bindings may work slightly differently in some cases. In addition, this value is dynamic and can change around at runtime.
comment If available, the comment following the command on the same line. (For example, the input.conf entry f cycle bla # toggle bla would result in an entry with comment = "toggle bla", cmd = "cycle bla".)
This property is read-only, and change notification is not supported.  Currently, there is no mechanism to change key bindings at runtime, other than scripts adding or removing their own bindings.
Inconsistencies between options and properties You can access (almost) all options as properties, though there are some caveats with some properties (due to historical reasons):
vid, aid, sid While playback is active, these return the actually active tracks. For example, if you set aid=5, and the currently played file contains no audio track with ID 5, the aid property will return no.
Before mpv 0.31.0, you could set existing tracks at runtime only.
display-fps This inconsistent behavior is deprecated. Post-deprecation, the reported value and the option value are cleanly separated (override-display-fps for the option value).
vf, af If you set the properties during playback, and the filter chain fails to reinitialize, the option will be set, but the runtime filter chain does not change. On the other hand, the next video to be played will fail, because the initial filter chain cannot be created.
This behavior changed in mpv 0.31.0. Before this, the new value was rejected iff a video (for vf) or an audio (for af) track was active. If playback was not active, the behavior was the same as the current one.
playlist The property is read-only and returns the current internal playlist. The option is for loading playlist during command line parsing. For client API uses, you should use the loadlist command instead.
profile, include These are write-only, and will perform actions as they are written to, exactly as if they were used on the mpv CLI commandline. Their only use is when using libmpv before mpv_initialize(), which in turn is probably only useful in encoding mode. Normal libmpv users should use other mechanisms, such as the apply-profile command, and the mpv_load_config_file API function. Avoid these properties.
Property Expansion All string arguments to input commands as well as certain options (like --term-playing-msg) are subject to property expansion. Note that property expansion does not work in places where e.g. numeric parameters are expected.  (For example, the add command does not do property expansion. The set command is an exception and not a general rule.)
i show-text Filename: ${filename} shows the filename of the current file when pressing the i key
Whether property expansion is enabled by default depends on which API is used (see Flat command syntax, Commands specified as arrays and Named arguments), but it can always be enabled with the expand-properties prefix or disabled with the raw prefix, as described in Input Command Prefixes.
The following expansions are supported:
${NAME} Expands to the value of the property NAME. If retrieving the property fails, expand to an error string. (Use ${NAME:} with a trailing : to expand to an empty string instead.)  If NAME is prefixed with =, expand to the raw value of the property (see section below).
${NAME:STR} Expands to the value of the property NAME, or STR if the property cannot be retrieved. STR is expanded recursively.
${?NAME:STR} Expands to STR (recursively) if the property NAME is available.
${!NAME:STR} Expands to STR (recursively) if the property NAME cannot be retrieved.
${?NAME==VALUE:STR} Expands to STR (recursively) if the property NAME expands to a string equal to VALUE. You can prefix NAME with = in order to compare the raw value of a property (see section below). If the property is unavailable, or other errors happen when retrieving it, the value is never considered equal.  Note that VALUE can't contain any of the characters : or }.  Also, it is possible that escaping with " or % might be added in the future, should the need arise.
${!NAME==VALUE:STR} Same as with the ? variant, but STR is expanded if the value is not equal. (Using the same semantics as with ?.)
$$     Expands to $.
$}     Expands to }. (To produce this character inside recursive expansion.)
$>     Disable property expansion and special handling of $ for the rest of the string.
In places where property expansion is allowed, C-style escapes are often accepted as well. Example:
• \n becomes a newline character
• \\ expands to \
Raw and Formatted Properties Normally, properties are formatted as human-readable text, meant to be displayed on OSD or on the terminal. It is possible to retrieve an unformatted (raw) value from a property by prefixing its name with =. These raw values can be parsed by other programs and follow the same conventions as the options associated with the properties.
• ${time-pos} expands to 00:14:23 (if playback position is at 14 minutes 23 seconds)
• ${=time-pos} expands to 863.4 (same time, plus 400 milliseconds - milliseconds are normally not shown in the formatted case)
Sometimes, the difference in amount of information carried by raw and formatted property values can be rather big. In some cases, raw values have more information, like higher precision than seconds with time-pos. Sometimes it is the other way around, e.g. aid shows track title and language in the formatted case, but only the track number if it is raw.
The On Screen Controller (short: OSC) is a minimal GUI integrated with mpv to offer basic mouse-controllability. It is intended to make interaction easier for new users and to enable precise and direct seeking.
The OSC is enabled by default if mpv was compiled with Lua support. It can be disabled entirely using the --osc=no option.
Using the OSC By default, the OSC will show up whenever the mouse is moved inside the player window and will hide if the mouse is not moved outside the OSC for 0.5 seconds or if the mouse leaves the window.
The Interface +---------+----------+------------------------------------------+----------+ | pl prev | pl next  |  title                                   |    cache | +------+--+---+------+---------+-----------+------+-------+-----+-----+----+ | play | skip | skip | time    |  seekbar  | time | audio | sub | vol | fs | |      | back | frwd | elapsed |           | left |       |     |     |    | +------+------+------+---------+-----------+------+-------+-----+-----+----+
pl prev
┌──────────────┬───────────────────────┐ │left-click    │ play previous file in │ │              │ playlist              │ ├──────────────┼───────────────────────┤ │right-click   │ show playlist         │ ├──────────────┼───────────────────────┤ │shift+L-click │ show playlist         │ └──────────────┴───────────────────────┘
pl next
┌──────────────┬────────────────────────────┐ │left-click    │ play next file in playlist │ ├──────────────┼────────────────────────────┤ │right-click   │ show playlist              │ ├──────────────┼────────────────────────────┤ │shift+L-click │ show playlist              │ └──────────────┴────────────────────────────┘
title Displays current media-title, filename, custom title, or target chapter name while hovering the seekbar.
┌────────────┬────────────────────────────┐ │left-click  │ show playlist position and │ │            │ length and full title      │ ├────────────┼────────────────────────────┤ │right-click │ show filename              │ └────────────┴────────────────────────────┘
cache Shows current cache fill status
┌───────────┬───────────────────┐ │left-click │ toggle play/pause │ └───────────┴───────────────────┘
skip back
┌──────────────┬────────────────────────────┐ │left-click    │ go to beginning of chapter │ │              │ / previous chapter         │ ├──────────────┼────────────────────────────┤ │right-click   │ show chapters              │ ├──────────────┼────────────────────────────┤ │shift+L-click │ show chapters              │ └──────────────┴────────────────────────────┘
skip frwd
┌──────────────┬────────────────────┐ │left-click    │ go to next chapter │ ├──────────────┼────────────────────┤ │right-click   │ show chapters      │ ├──────────────┼────────────────────┤ │shift+L-click │ show chapters      │ └──────────────┴────────────────────┘
time elapsed Shows current playback position timestamp
┌───────────┬─────────────────────────────┐ │left-click │ toggle displaying timecodes │ │           │ with milliseconds           │ └───────────┴─────────────────────────────┘
seekbar Indicates current playback position and position of chapters
┌───────────┬──────────────────┐ │left-click │ seek to position │ └───────────┴──────────────────┘
time left Shows remaining playback time timestamp
┌───────────┬──────────────────────────┐ │left-click │ toggle between total and │ │           │ remaining time           │ └───────────┴──────────────────────────┘
audio and sub Displays selected track and amount of available tracks
┌──────────────┬──────────────────────────┐ │left-click    │ cycle audio/sub tracks   │ │              │ forward                  │ ├──────────────┼──────────────────────────┤ │right-click   │ cycle audio/sub tracks   │ │              │ backwards                │ ├──────────────┼──────────────────────────┤ │shift+L-click │ show available audio/sub │ │              │ tracks                   │ └──────────────┴──────────────────────────┘
┌────────────┬────────────────┐ │left-click  │ toggle mute    │ ├────────────┼────────────────┤ │mouse wheel │ volume up/down │ └────────────┴────────────────┘
┌───────────┬───────────────────┐ │left-click │ toggle fullscreen │ └───────────┴───────────────────┘
Key Bindings These key bindings are active by default if nothing else is already bound to these keys. In case of collision, the function needs to be bound to a different key. See the Script Commands section.
┌────┬─────────────────────────────┐ │del │ Cycles visibility between   │ │    │ never / auto (mouse-move) / │ │    │ always                      │ └────┴─────────────────────────────┘
Configuration The OSC offers limited configuration through a config file script-opts/osc.conf placed in mpv's user dir and through the --script-opts command-line option. Options provided through the command-line will override those from the config file.
Config Syntax The config file must exactly follow the following syntax:
# this is a comment optionA=value1 optionB=value2
# can only be used at the beginning of a line and there may be no spaces around the = or anywhere else.
Command-line Syntax To avoid collisions with other scripts, all options need to be prefixed with osc-.
--script-opts=osc-optionA=value1,osc-optionB=value2
Configurable Options layout Default: bottombar
The layout for the OSC. Currently available are: box, slimbox, bottombar and topbar. Default pre-0.21.0 was 'box'.
seekbarstyle Default: bar
Sets the style of the playback position marker and overall shape of the seekbar: bar, diamond or knob.
seekbarhandlesize Default: 0.6
Size ratio of the seek handle if seekbarstyle is set to dimaond or knob. This is relative to the full height of the seekbar.
seekbarkeyframes Default: yes
Controls the mode used to seek when dragging the seekbar. If set to yes, default seeking mode is used (usually keyframes, but player defaults and heuristics can change it to exact). If set to no, exact seeking on mouse drags will be used instead. Keyframes are preferred, but exact seeks may be useful in cases where keyframes cannot be found. Note that using exact seeks can potentially make mouse dragging much slower.
seekrangestyle Default: inverted
Display seekable ranges on the seekbar. bar shows them on the full height of the bar, line as a thick line and inverted as a thin line that is inverted over playback position markers. none will hide them. Additionally, slider will show a permanent handle inside the seekbar with cached ranges marked inside. Note that these will look differently based on the seekbarstyle option. Also, slider does not work with seekbarstyle set to bar.
seekrangeseparate Default: yes
Controls whether to show line-style seekable ranges on top of the seekbar or separately if seekbarstyle is set to bar.
seekrangealpha Default: 200
Alpha of the seekable ranges, 0 (opaque) to 255 (fully transparent).
deadzonesize Default: 0.5
Size of the deadzone. The deadzone is an area that makes the mouse act like leaving the window. Movement there won't make the OSC show up and it will hide immediately if the mouse enters it. The deadzone starts at the window border opposite to the OSC and the size controls how much of the window it will span. Values between 0.0 and 1.0, where 0 means the OSC will always popup with mouse movement in the window, and 1 means the OSC will only show up when the mouse hovers it. Default pre-0.21.0 was 0.
minmousemove Default: 0
Minimum amount of pixels the mouse has to move between ticks to make the OSC show up. Default pre-0.21.0 was 3.
showwindowed Default: yes
Enable the OSC when windowed
showfullscreen Default: yes
Enable the OSC when fullscreen
scalewindowed Default: 1.0
Scale factor of the OSC when windowed.
scalefullscreen Default: 1.0
Scale factor of the OSC when fullscreen
scaleforcedwindow Default: 2.0
Scale factor of the OSC when rendered on a forced (dummy) window
vidscale Default: yes
Scale the OSC with the video no tries to keep the OSC size constant as much as the window size allows
valign Default: 0.8
Vertical alignment, -1 (top) to 1 (bottom)
halign Default: 0.0
Horizontal alignment, -1 (left) to 1 (right)
barmargin Default: 0
Margin from bottom (bottombar) or top (topbar), in pixels
boxalpha Default: 80
Alpha of the background box, 0 (opaque) to 255 (fully transparent)
hidetimeout Default: 500
Duration in ms until the OSC hides if no mouse movement, must not be negative
fadeduration Default: 200
Duration of fade out in ms, 0 = no fade
title  Default: ${media-title}
String that supports property expansion that will be displayed as OSC title.  ASS tags are escaped, and newlines and trailing slashes are stripped.
tooltipborder Default: 1
Size of the tooltip outline when using bottombar or topbar layouts
timetotal Default: no
Show total time instead of time remaining
timems Default: no
Display timecodes with milliseconds
visibility Default: auto (auto hide/show on mouse move)
Also supports never and always
boxmaxchars Default: 80
Max chars for the osc title at the box layout. mpv does not measure the text width on screen and so it needs to limit it by number of chars. The default is conservative to allow wide fonts to be used without overflow.  However, with many common fonts a bigger number can be used. YMMV.
boxvideo Default: no
Whether to overlay the osc over the video (no), or to box the video within the areas not covered by the osc (yes). If this option is set, the osc may overwrite the --video-margin-ratio-* options, even if the user has set them. (It will not overwrite them if all of them are set to default values.) Additionally, visibility must be set to always.  Otherwise, this option does nothing.
Currently, this is supported for the bottombar and topbar layout only. The other layouts do not change if this option is set. Separately, if window controls are present (see below), they will be affected regardless of which osc layout is in use.
The border is static and appears even if the OSC is configured to appear only on mouse interaction. If the OSC is invisible, the border is simply filled with the background color (black by default).
This currently still makes the OSC overlap with subtitles (if the --sub-use-margins option is set to yes, the default). This may be fixed later.
This does not work correctly with video outputs like --vo=xv, which render OSD into the unscaled video.
windowcontrols Default: auto (Show window controls if there is no window border)
Whether to show window management controls over the video, and if so, which side of the window to place them. This may be desirable when the window has no decorations, either because they have been explicitly disabled (border=no) or because the current platform doesn't support them (eg: gnome-shell with wayland).
The set of window controls is fixed, offering minimize, maximize, and quit. Not all platforms implement minimize and maximize, but quit will always work.
windowcontrols_alignment Default: right
If window controls are shown, indicates which side should they be aligned to.
Supports left and right which will place the controls on those respective sides.
greenandgrumpy Default: no
Set to yes to reduce festivity (i.e. disable santa hat in December.)
livemarkers Default: yes
Update chapter markers positions on duration changes, e.g. live streams.  The updates are unoptimized - consider disabling it on very low-end systems.
Script Commands The OSC script listens to certain script commands. These commands can bound in input.conf, or sent by other scripts.
osc-message Show a message on screen using the OSC. First argument is the message, second the duration in seconds.
osc-visibility Controls visibility mode never / auto (on mouse move) / always and also cycle to cycle between the modes
You could put this into input.conf to hide the OSC with the a key and to set auto mode (the default) with b:
a script-message osc-visibility never b script-message osc-visibility auto
osc-playlist, osc-chapterlist, osc-tracklist Shows a limited view of the respective type of list using the OSC. First argument is duration in seconds.
This builtin script displays information and statistics for the currently played file. It is enabled by default if mpv was compiled with Lua support.  It can be disabled entirely using the --load-stats-overlay=no option.
Usage The following key bindings are active by default unless something else is already bound to them:
┌──┬───────────────────────────┐ │i │ Show stats for a fixed    │ │  │ duration                  │ ├──┼───────────────────────────┤ │I │ Toggle stats (shown until │ │  │ toggled again)            │ └──┴───────────────────────────┘
While the stats are visible on screen the following key bindings are active, regardless of existing bindings. They allow you to switch between pages of stats:
┌──┬─────────────────────────────┐ │1 │ Show usual stats            │ ├──┼─────────────────────────────┤ │2 │ Show frame timings (scroll) │ ├──┼─────────────────────────────┤ │3 │ Input cache stats           │ ├──┼─────────────────────────────┤ │4 │ Active key bindings         │ │  │ (scroll)                    │ ├──┼─────────────────────────────┤ │0 │ Internal stuff (scroll)     │ └──┴─────────────────────────────┘
On pages which support scroll, these key bindings are also active:
┌─────┬──────────────────────┐ │UP   │ Scroll one line up   │ ├─────┼──────────────────────┤ │DOWN │ Scroll one line down │ └─────┴──────────────────────┘
Font For optimal visual experience, a font with support for many font weights and monospaced digits is recommended. By default, the open source font Source Sans Pro is used.
Configuration This script can be customized through a config file script-opts/stats.conf placed in mpv's user directory and through the --script-opts command-line option. The configuration syntax is described in ON SCREEN CONTROLLER.
Configurable Options key_page_1 Default: 1
key_page_2 Default: 2
key_page_3 Default: 3
key_page_4 Default: 4
key_page_0 Default: 0
Key bindings for page switching while stats are displayed.
key_scroll_up Default: UP
key_scroll_down Default: DOWN
scroll_lines Default: 1
Scroll key bindings and number of lines to scroll on pages which support it.
duration Default: 4
How long the stats are shown in seconds (oneshot).
redraw_delay Default: 1
How long it takes to refresh the displayed stats in seconds (toggling).
persistent_overlay Default: no
When no, other scripts printing text to the screen can overwrite the displayed stats. When yes, displayed stats are persistently shown for the respective duration. This can result in overlapping text when multiple scripts decide to print text at the same time.
plot_perfdata Default: yes
Show graphs for performance data (page 2).
plot_vsync_ratio Default: yes
plot_vsync_jitter Default: yes
Show graphs for vsync and jitter values (page 1). Only when toggled.
flush_graph_data Default: yes
Clear data buffers used for drawing graphs when toggling.
font   Default: Source Sans Pro
Font name. Should support as many font weights as possible for optimal visual experience.
font_mono Default: Source Sans Pro
Font name for parts where monospaced characters are necessary to align text. Currently, monospaced digits are sufficient.
font_size Default: 8
Font size used to render text.
font_color Default: FFFFFF
Font color.
border_size Default: 0.8
Size of border drawn around the font.
border_color Default: 262626
Color of drawn border.
alpha  Default: 11
Transparency for drawn text.
plot_bg_border_color Default: 0000FF
Border color used for drawing graphs.
plot_bg_color Default: 262626
Background color used for drawing graphs.
plot_color Default: FFFFFF
Color used for drawing graphs.
Note: colors are given as hexadecimal values and use ASS tag order: BBGGRR (blue green red).
Different key bindings Additional keys can be configured in input.conf to display the stats:
e script-binding stats/display-stats E script-binding stats/display-stats-toggle
And to display a certain page directly:
i script-binding stats/display-page-1 e script-binding stats/display-page-2
Active key bindings page Lists the active key bindings and the commands they're bound to, excluding the interactive keys of the stats script itself. See also --input-test for more detailed view of each binding.
The keys are grouped automatically using a simple analysis of the command string, and one should not expect documentation-level grouping accuracy, however, it should still be reasonably useful.
Using --idle --script-opts=stats-bindlist=yes will print the list to the terminal and quit immediately. By default long lines are shortened to 79 chars, and terminal escape sequences are enabled. A different length limit can be set by changing yes to a number (at least 40), and escape sequences can be disabled by adding - before the value, e.g. ...=-yes or ...=-120.
Like with --input-test, the list includes bindings from input.conf and from user scripts. Use --no-config to list only built-in bindings.
Internal stuff page Most entries shown on this page have rather vague meaning. Likely none of this is useful for you. Don't attempt to use it. Forget its existence.
Selecting this for the first time will start collecting some internal performance data. That means performance will be slightly lower than normal for the rest of the time the player is running (even if the stats page is closed).  Note that the stats page itself uses a lot of CPU and even GPU resources, and may have a heavy impact on performance.
The displayed information is accumulated over the redraw delay (shown as poll-time field).
This adds entries for each Lua script. If there are too many scripts running, parts of the list will simply be out of the screen, but it can be scrolled.
If the underlying platform does not support pthread per thread times, the displayed times will be 0 or something random (I suspect that at time of this writing, only Linux provides the correct via pthread APIs for per thread times).
Most entries are added lazily and only during data collection, which is why entries may pop up randomly after some time. It's also why the memory usage entries for scripts that have been inactive since the start of data collection are missing.
Memory usage is approximate and does not reflect internal fragmentation.
JS scripts memory reporting is disabled by default because collecting the data at the JS side has an overhead. It can be enabled by exporting the env var MPV_LEAK_REPORT=1 before starting mpv, and will increase JS memory usage.
If entries have /time and /cpu variants, the former gives the real time (monotonic clock), while the latter the thread CPU time (only if the corresponding pthread API works and is supported).
The console is a REPL for mpv input commands. It is displayed on the video window. It also shows log messages. It can be disabled entirely using the --load-osd-console=no option.
Keybindings `      Show the console.
ESC    Hide the console.
ENTER, Ctrl+J and Ctrl+M Run the typed command.
Shift+ENTER Type a literal newline character.
LEFT and Ctrl+B Move the cursor to the previous character.
RIGHT and Ctrl+F Move the cursor to the next character.
Ctrl+LEFT and Alt+B Move the cursor to the beginning of the current word, or if between words, to the beginning of the previous word.
Ctrl+RIGHT and Alt+F Move the cursor to the end of the current word, or if between words, to the end of the next word.
HOME and Ctrl+A Move the cursor to the start of the current line.
END and Ctrl+E Move the cursor to the end of the current line.
BACKSPACE and Ctrl+H Delete the previous character.
Ctrl+D Hide the console if the current line is empty, otherwise delete the next character.
Ctrl+BACKSPACE and Ctrl+W Delete text from the cursor to the beginning of the current word, or if between words, to the beginning of the previous word.
Ctrl+DEL and Alt+D Delete text from the cursor to the end of the current word, or if between words, to the end of the next word.
Ctrl+U Delete text from the cursor to the beginning of the current line.
Ctrl+K Delete text from the cursor to the end of the current line.
Ctrl+C Clear the current line.
UP and Ctrl+P Move back in the command history.
DOWN and Ctrl+N Move forward in the command history.
PGUP   Go to the first command in the history.
PGDN   Stop navigating the command history.
INSERT Toggle insert mode.
Ctrl+V Paste text (uses the clipboard on X11 and Wayland).
Shift+INSERT Paste text (uses the primary selection on X11 and Wayland).
TAB and Ctrl+I Complete the command or property name at the cursor.
Ctrl+L Clear all log messages from the console.
Commands script-message-to console type <text> [<cursor_pos>] Show the console and pre-fill it with the provided text, optionally specifying the initial cursor position as a positive integer starting from 1.
% script-message-to console type "seek absolute-percent" 6
Known issues • Pasting text is slow on Windows
• Non-ASCII keyboard input has restrictions
• The cursor keys move between Unicode code-points, not grapheme clusters
Configuration This script can be customized through a config file script-opts/console.conf placed in mpv's user directory and through the --script-opts command-line option. The configuration syntax is described in ON SCREEN CONTROLLER.
Key bindings can be changed in a standard way, see for example stats.lua documentation.
Configurable Options scale  Default: 1
All drawing is scaled by this value, including the text borders and the cursor.
If the VO backend in use has HiDPI scale reporting implemented, the option value is scaled with the reported HiDPI scale.
font   Default: unset (picks a hardcoded font depending on detected platform)
Set the font used for the REPL and the console. This probably doesn't have to be a monospaced font.
font_size Default: 16
Set the font size used for the REPL and the console. This will be multiplied by "scale."
mpv can load Lua scripts. (See Script location.)
mpv provides the built-in module mp, which contains functions to send commands to the mpv core and to retrieve information about playback state, user settings, file information, and so on.
These scripts can be used to control mpv in a similar way to slave mode. Technically, the Lua code uses the client API internally.
Example A script which leaves fullscreen mode when the player is paused:
function on_pause_change(name, value) if value == true then mp.set_property("fullscreen", "no") end end mp.observe_property("pause", "bool", on_pause_change)
Script location Scripts can be passed to the --script option, and are automatically loaded from the scripts subdirectory of the mpv configuration directory (usually ~/.config/mpv/scripts/).
A script can be a single file. The file extension is used to select the scripting backend to use for it. For Lua, it is .lua. If the extension is not recognized, an error is printed. (If an error happens, the extension is either mistyped, or the backend was not compiled into your mpv binary.)
mpv internally loads the script's name by stripping the .lua extension and replacing all nonalphanumeric characters with _. E.g., my-tools.lua becomes my_tools. If there are several scripts with the same name, it is made unique by appending a number. This is the name returned by mp.get_script_name().
Entries with .disable extension are always ignored.
If a script is a directory (either if a directory is passed to --script, or any sub-directories in the script directory, such as for example ~/.config/mpv/scripts/something/), then the directory represents a single script. The player will try to load a file named main.x, where x is replaced with the file extension. For example, if main.lua exists, it is loaded with the Lua scripting backend.
You must not put any other files or directories that start with main. into the script's top level directory. If the script directory contains for example both main.lua and main.js, only one of them will be loaded (and which one depends on mpv internals that may change any time). Likewise, if there is for example main.foo, your script will break as soon as mpv adds a backend that uses the .foo file extension.
mpv also appends the top level directory of the script to the start of Lua's package path so you can import scripts from there too. Be aware that this will shadow Lua libraries that use the same package path. (Single file scripts do not include mpv specific directory the Lua package path. This was silently changed in mpv 0.32.0.)
Using a script directory is the recommended way to package a script that consists of multiple source files, or requires other files (you can use mp.get_script_directory() to get the location and e.g. load data files).
Making a script a git repository, basically a repository which contains a main.lua` file in the root directory, makes scripts easily updateable (without the dangers of auto-updates). Another suggestion is to use git submodules to share common files or libraries.
Details on the script initialization and lifecycle Your script will be loaded by the player at program start from the scripts configuration subdirectory, or from a path specified with the --script option. Some scripts are loaded internally (like --osc). Each script runs in its own thread. Your script is first run "as is", and once that is done, the event loop is entered. This event loop will dispatch events received by mpv and call your own event handlers which you have registered with mp.register_event, or timers added with mp.add_timeout or similar. Note that since the script starts execution concurrently with player initialization, some properties may not be populated with meaningful values until the relevant subsystems have initialized.
When the player quits, all scripts will be asked to terminate. This happens via a shutdown event, which by default will make the event loop return. If your script got into an endless loop, mpv will probably behave fine during playback, but it won't terminate when quitting, because it's waiting on your script.
Internally, the C code will call the Lua function mp_event_loop after loading a Lua script. This function is normally defined by the default prelude loaded before your script (see player/lua/defaults.lua in the mpv sources).  The event loop will wait for events and dispatch events registered with mp.register_event. It will also handle timers added with mp.add_timeout and similar (by waiting with a timeout).
Since mpv 0.6.0, the player will wait until the script is fully loaded before continuing normal operation. The player considers a script as fully loaded as soon as it starts waiting for mpv events (or it exits). In practice this means the player will more or less hang until the script returns from the main chunk (and mp_event_loop is called), or the script calls mp_event_loop or mp.dispatch_events directly. This is done to make it possible for a script to fully setup event handlers etc. before playback actually starts. In older mpv versions, this happened asynchronously. With mpv 0.29.0, this changes slightly, and it merely waits for scripts to be loaded in this manner before starting playback as part of the player initialization phase. Scripts run though initialization in parallel. This might change again.
mp functions The mp module is preloaded, although it can be loaded manually with require 'mp'. It provides the core client API.
mp.command(string) Run the given command. This is similar to the commands used in input.conf.  See List of Input Commands.
By default, this will show something on the OSD (depending on the command), as if it was used in input.conf. See Input Command Prefixes how to influence OSD usage per command.
Returns true on success, or nil, error on error.
mp.commandv(arg1, arg2, ...) Similar to mp.command, but pass each command argument as separate parameter. This has the advantage that you don't have to care about quoting and escaping in some cases.
mp.command("loadfile " .. filename .. " append") mp.commandv("loadfile", filename, "append")
These two commands are equivalent, except that the first version breaks if the filename contains spaces or certain special characters.
Note that properties are not expanded.  You can use either mp.command, the expand-properties prefix, or the mp.get_property family of functions.
Unlike mp.command, this will not use OSD by default either (except for some OSD-specific commands).
mp.command_native(table [,def]) Similar to mp.commandv, but pass the argument list as table. This has the advantage that in at least some cases, arguments can be passed as native types. It also allows you to use named argument.
If the table is an array, each array item is like an argument in mp.commandv() (but can be a native type instead of a string).
If the table contains string keys, it's interpreted as command with named arguments. This requires at least an entry with the key name to be present, which must be a string, and contains the command name. The special entry _flags is optional, and if present, must be an array of Input Command Prefixes to apply. All other entries are interpreted as arguments.
Returns a result table on success (usually empty), or def, error on error. def is the second parameter provided to the function, and is nil if it's missing.
mp.command_native_async(table [,fn]) Like mp.command_native(), but the command is ran asynchronously (as far as possible), and upon completion, fn is called. fn has three arguments: fn(success, result, error):
success Always a Boolean and is true if the command was successful, otherwise false.
result The result value (can be nil) in case of success, nil otherwise (as returned by mp.command_native()).
error  The error string in case of an error, nil otherwise.
Returns a table with undefined contents, which can be used as argument for mp.abort_async_command.
If starting the command failed for some reason, nil, error is returned, and fn is called indicating failure, using the same error value.
mp.abort_async_command(t) Abort a mp.command_native_async call. The argument is the return value of that command (which starts asynchronous execution of the command).  Whether this works and how long it takes depends on the command and the situation. The abort call itself is asynchronous. Does not return anything.
mp.get_property(name [,def]) Return the value of the given property as string. These are the same properties as used in input.conf. See Properties for a list of properties. The returned string is formatted similar to ${=name} (see Property Expansion).
Returns the string on success, or def, error on error. def is the second parameter provided to the function, and is nil if it's missing.
mp.get_property_osd(name [,def]) Similar to mp.get_property, but return the property value formatted for OSD. This is the same string as printed with ${name} when used in input.conf.
Returns the string on success, or def, error on error. def is the second parameter provided to the function, and is an empty string if it's missing. Unlike get_property(), assigning the return value to a variable 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.
mp.set_property(name, value) Set the given property to the given string value. See mp.get_property and Properties for more information about properties.
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.set_property_native(name, value) Similar to mp.set_property, but set the given property using its native type.
Since there are several data types which cannot represented natively in Lua, this might not always work as expected. For example, while the Lua wrapper can do some guesswork to decide whether a Lua table is an array or a map, this would fail with empty tables. Also, there are not many properties for which it makes sense to use this, instead of set_property, set_property_bool, set_property_number.  For these reasons, this function should probably be avoided for now, except for properties that use tables natively.
mp.get_time() Return the current mpv internal time in seconds as a number. This is basically the system time, with an arbitrary offset.
mp.add_key_binding(key, name|fn [,fn [,flags]]) Register callback to be run on a key binding. The binding will be mapped to the given key, which is a string describing the physical key. This uses the same key names as in input.conf, and also allows combinations (e.g. ctrl+a). If the key is empty or nil, no physical key is registered, but the user still can create own bindings (see below).
After calling this function, key presses will cause the function fn to be called (unless the user remapped the key with another binding).
The name argument should be a short symbolic string. It allows the user to remap the key binding via input.conf using the script-message command, and the name of the key binding (see below for an example). The name should be unique across other bindings in the same script - if not, the previous binding with the same name will be overwritten. You can omit the name, in which case a random name is generated internally. (Omitting works as follows: either pass nil for name, or pass the fn argument in place of the name. The latter is not recommended and is handled for compatibility only.)
The last argument is used for optional flags. This is a table, which can have the following entries:
repeatable If set to true, enables key repeat for this specific binding.
complex If set to true, then fn is called on both key up and down events (as well as key repeat, if enabled), with the first argument being a table. This table has the following entries (and may contain undocumented ones):
event  Set to one of the strings down, repeat, up or press (the latter if key up/down can't be tracked).
is_mouse Boolean Whether the event was caused by a mouse button.
key_name The name of they key that triggered this, or nil if invoked artificially. If the key name is unknown, it's an empty string.
key_text Text if triggered by a text key, otherwise nil. See description of script-binding command for details (this field is equivalent to the 5th argument).
Internally, key bindings are dispatched via the script-message-to or script-binding input commands and mp.register_script_message.
Trying to map multiple commands to a key will essentially prefer a random binding, while the other bindings are not called. It is guaranteed that user defined bindings in the central input.conf are preferred over bindings added with this function (but see mp.add_forced_key_binding).
function something_handler() print("the key was pressed") end mp.add_key_binding("x", "something", something_handler)
This will print the message the key was pressed when x was pressed.
The user can remap these key bindings. Then the user has to put the following into their input.conf to remap the command to the y key:
y script-binding something
This will print the message when the key y is pressed. (x will still work, unless the user remaps it.)
You can also explicitly send a message to a named script only. Assume the above script was using the filename fooscript.lua:
y script-binding fooscript/something
mp.add_forced_key_binding(...) This works almost the same as mp.add_key_binding, but registers the key binding in a way that will overwrite the user's custom bindings in their input.conf. (mp.add_key_binding overwrites default key bindings only, but not those by the user's input.conf.)
mp.remove_key_binding(name) Remove a key binding added with mp.add_key_binding or mp.add_forced_key_binding. Use the same name as you used when adding the bindings. It's not possible to remove bindings for which you omitted the name.
mp.register_event(name, fn) Call a specific function when an event happens. The event name is a string, and the function fn is a Lua function value.
Some events have associated data. This is put into a Lua table and passed as argument to fn. The Lua table by default contains a name field, which is a string containing the event name. If the event has an error associated, the error field is set to a string describing the error, on success it's not set.
If multiple functions are registered for the same event, they are run in registration order, which the first registered function running before all the other ones.
Returns true if such an event exists, false otherwise.
See Events and List of events for details.
mp.unregister_event(fn) Undo mp.register_event(..., fn). This removes all event handlers that are equal to the fn parameter. This uses normal Lua == comparison, so be careful when dealing with closures.
mp.observe_property(name, type, fn) Watch a property for changes. If the property name is changed, then the function fn(name) will be called. type can be nil, or be set to one of none, native, bool, string, or number.  none is the same as nil. For all other values, the new value of the property will be passed as second argument to fn, using mp.get_property_<type> to retrieve it. This means if type is for example string, fn is roughly called as in fn(name, mp.get_property_string(name)).
If possible, change events are coalesced. If a property is changed a bunch of times in a row, only the last change triggers the change function. (The exact behavior depends on timing and other things.)
If a property is unavailable, or on error, the value argument to fn is nil. (The observe_property() call always succeeds, even if a property does not exist.)
In some cases the function is not called even if the property changes.  This depends on the property, and it's a valid feature request to ask for better update handling of a specific property.
If the type is none or nil, sporadic property change events are possible. This means the change function fn can be called even if the property doesn't actually change.
You always get an initial change notification. This is meant to initialize the user's state to the current value of the property.
mp.unobserve_property(fn) Undo mp.observe_property(..., fn). This removes all property handlers that are equal to the fn parameter. This uses normal Lua == comparison, so be careful when dealing with closures.
mp.add_timeout(seconds, fn) Call the given function fn when the given number of seconds has elapsed.  Note that the number of seconds can be fractional. For now, the timer's resolution may be as low as 50 ms, although this will be improved in the future.
This is a one-shot timer: it will be removed when it's fired.
Returns a timer object. See mp.add_periodic_timer for details.
mp.add_periodic_timer(seconds, fn) Call the given function periodically. This is like mp.add_timeout, but the timer is re-added after the function fn is run.
Returns a timer object. The timer object provides the following methods:
stop() Disable the timer. Does nothing if the timer is already disabled.  This will remember the current elapsed time when stopping, so that resume() essentially unpauses the timer.
kill() Disable the timer. Resets the elapsed time. resume() will restart the timer.
resume() Restart the timer. If the timer was disabled with stop(), this will resume at the time it was stopped. If the timer was disabled with kill(), or if it's a previously fired one-shot timer (added with add_timeout()), this starts the timer from the beginning, using the initially configured timeout.
is_enabled() Whether the timer is currently enabled or was previously disabled (e.g. by stop() or kill()).
timeout (RW) This field contains the current timeout period. This value is not updated as time progresses. It's only used to calculate when the timer should fire next when the timer expires.
If you write this, you can call t:kill() ; t:resume() to reset the current timeout to the new one. (t:stop() won't use the new timeout.)