Skip to main content
mpv supports JavaScript scripts via the MuJS embedded interpreter (ECMAScript 5). The JavaScript scripting interface is nearly identical to the Lua interface — the same mp, mp.utils, mp.msg, mp.options, and mp.input modules are available with the same APIs. This page covers the differences and JavaScript-specific additions.
This page focuses on what is different from Lua scripting. Refer to the Lua scripting reference for full API documentation.

Script location

Use the .js extension. Everything else — script directories, main.js entry points, loading from ~/.config/mpv/scripts/, and the --script flag — is the same as Lua.

Quick example

A script that exits fullscreen whenever playback is paused:

Differences from Lua

No module imports required

All modules are preloaded. There is no require call needed to access mp, mp.utils, mp.msg, mp.options, or mp.input:

Error handling

Where Lua returns nil, error on failure, JavaScript returns undefined and makes the error available via mp.last_error():
API functions marked with (LE) support this pattern. An empty string from mp.last_error() means success.

Standard JS APIs replace some Lua equivalents

No standard library

There is no access to fs, process, or other Node.js-style built-ins. Filesystem interaction goes through mp.utils, and subprocess execution through mp.command_native.

Language features: ECMAScript 5

The MuJS interpreter implements ES5. Standard ES5 methods like String.prototype.substring work; non-standard extensions like String.prototype.substr do not. Consult the MuJS documentation for details.

Timers

Standard HTML/Node.js-style timers are available globally:
All signatures:
duration defaults to 0. Timers always fire asynchronously — setTimeout(fn) will never call fn before returning, and setInterval never fires twice in the same event loop iteration.
setTimeout(fn) with no duration (or duration 0) fires at the end of the current event loop iteration. This makes it useful as a one-time idle observer.

CommonJS modules and require

mpv’s JavaScript supports CommonJS-style modules. A module is a .js file that assigns properties to its pre-existing exports object:

Module resolution

  • Paths starting with ./ or ../ are relative to the calling script.
  • Absolute paths (e.g. ~/foo or /usr/local/lib/foo) are resolved directly.
  • All other IDs are looked up as global module IDs in mp.module_paths.
A .js extension is always appended to the ID. For example, require("./foo") loads ./foo.js.

mp.module_paths

A global array of directories searched for top-level module IDs. Empty by default, except for directory scripts where it includes <script-dir>/modules/.

Notes

  • Modules are cached: calling require for the same ID twice returns the same exports object.
  • global is not defined, but the top-level this is the global object.
  • Functions and variables declared at the module level do not pollute the global object.
  • Some Node.js-compatible modules with minimal dependencies may work, but most will not.

Custom initialization

Before loading any script, mpv looks for init.js in the mpv configuration directory (e.g. ~/.config/mpv/init.js). Code there runs in the same environment as scripts and can modify global state for all scripts, such as adding to mp.module_paths:
Do not overwrite mp.module_paths entirely (mp.module_paths = [...]). Use push to add paths, or you will remove the <script-dir>/modules path set for directory scripts.
The init file is ignored when mpv is started with --no-config.

Additional JavaScript-only APIs

mp.last_error()

Returns an empty string if the last (LE)-marked API call succeeded, or a non-empty error reason string on failure.

Error.stack

Stack traces are available inside catch blocks when the error was created with the Error constructor:

exit()

Exits the script at the end of the current event loop iteration (registered for the shutdown event). Does not terminate mpv or other scripts.

mp.get_time_ms()

Same as mp.get_time() but returns milliseconds instead of seconds.

mp.get_script_file()

Returns the filename of the current script.

mp.utils.getenv(name)

Returns the value of an environment variable, or undefined if not set.

mp.utils.get_user_path(path)

Expands mpv meta-paths (like ~~desktop/ or ~~home/) into a platform-specific filesystem path.

File I/O

read_file, write_file, and append_file expand mpv meta-paths internally and throw on errors. They handle text content only.

mp.utils.compile_js(fname, content_str)

Compiles JavaScript source code from a string without loading from the filesystem. Returns a callable function:

Scripting API quick reference

All of the following are available to JavaScript with the same behavior as Lua. Functions marked (LE) support mp.last_error() for error checking.

The event loop

The built-in event loop polls mpv events, processes timers, and waits for new events. You can replace it by defining a global mp_event_loop function:
exit() is internally registered for the shutdown event and sets mp.keep_running = false.