mpv.js

repository·master·Indexed 19 days ago

https://github.com/kagami/mpv.js

An embeddable media player for Electron and NW.js applications powered by the libmpv library. Version 0.3.0 provides a Pepper plugin and a ReactMPV component for integrating high-performance video playback into desktop web-tech applications, allowing developers to control the player via commands, properties, and observations.

Tokens
2K
Snippets
6
Records
9
Agent score
16%

What's inside mpv.js

  1. Install libmpv dependency

    master

    Before using mpv.js, you must install the libmpv library on your system:

    • Windows: Download mpv-dev, unpack it, and place the corresponding mpv-1.dll into C:\Windows\system32.
    • macOS: Use Homebrew: brew install mpv.
    • Linux: Use your package manager: apt-get install libmpv1 libavformat-dev.
  2. Load the mpv.js plugin in Electron (Main Process)

    master

    To use mpv.js in an Electron application, you must load the plugin in the main process and enable the plugins feature in the BrowserWindow web preferences.

    Note on Pathing: Due to Chromium restrictions regarding non-ASCII characters in plugin paths, you should use getPluginEntry and potentially change the working directory for non-Linux platforms.

    Note on Electron Flags: You must append the no-sandbox switch and use getPluginEntry to register the Pepper plugin.

    const path = require("path");
    const {app} = require("electron");
    const {getPluginEntry} = require("mpv.js");
    
    // Absolute path to the plugin directory.
    const pluginDir = path.join(path.dirname(require.resolve("mpv.js")), "build", "Release");
    
    // See pitfalls section for details.
    if (process.platform !== "linux") {process.chdir(pluginDir);}
    
    // Fix for latest Electron.
    app.commandLine.appendSwitch("no-sandbox");
    // To support a broader number of systems.
    app.commandLine.appendSwitch("ignore-gpu-blacklist");
    app.commandLine.appendSwitch("register-pepper-plugins", getPluginEntry(pluginDir));
    
    // When creating your BrowserWindow, enable plugins:
    // const win = new BrowserWindow({
    //   webPreferences: {plugins: true}
    // });
  3. Package mpv.js for distribution

    master

    To ship your application, you need to include mpvjs.node and the mpv library. Crucially, ensure that mpvjs.node, the mpv library, and your Electron/NW.js distribution all share the same bitness (e.g., all 64-bit).

    • Windows: Copy mpv-1.dll to the same directory as mpvjs.node.
    • macOS: Use collect-dylib-deps (provided in the repo) to find and package necessary dylibs.
    • Linux: Either require users to install libmpv1 via a package manager, or compile a static libmpv.so using mpv-build.
  4. Troubleshoot Linux libmpv and Electron symbol conflicts

    master

    On Linux, plugins loaded via register-pepper-plugins inherit symbols from the Electron binary. This can cause libmpv to incorrectly use Electron's libffmpeg, which is unsupported.

    To fix this, you can either:

    1. Replace libffmpeg.so with an empty wrapper linked to libav* using gcc.
    2. Use a version of libmpv that has libav* statically linked.
    gcc -Wl,--no-as-needed -shared -lavformat -o /path/to/libffmpeg.so
  5. Use the ReactMPV component

    master

    The library provides a ReactMPV component for React applications. You can interact with the player via the onReady callback, which provides the mpv instance. This instance allows you to observe properties, run commands, and manipulate property values.

    const React = require("react");
    const {ReactMPV} = require("mpv.js");
    
    class Player extends React.PureComponent {
      constructor(props) {
        super(props);
        this.mpv = null;
        this.state = {pause: true, "time-pos": 0};
      }
      handleMPVReady(mpv) {
        this.mpv = mpv;
        this.mpv.observe("pause");
        this.mpv.observe("time-pos");
        this.mpv.command("loadfile", "/path/to/video.mkv");
      }
      handlePropertyChange(name, value) {
        this.setState({[name]: value});
      }
      togglePause() {
        this.mpv.property("pause", !this.state.pause);
      }
      render() {
        return (
          <ReactMPV
            className="player"
            onReady={this.handleMPVReady.bind(this)}
            onPropertyChange={this.handlePropertyChange.bind(this)}
            onMouseDown={this.togglePause.bind(this)}
          />
        );
      }
    }
  6. Control the player via ReactMPV instance

    master

    Once the onReady callback is triggered, you can use the provided component instance to control the mpv player.

    Methods

    • command(cmd, ...args): Sends a command to the player. All arguments are converted to strings.
    • property(name, value): Sets an mpv property to a specific value.
    • observe(name): Tells mpv to start sending notifications whenever the specified property changes.
    • keypress({key, shiftKey, ctrlKey, altKey}): Simulates a keyboard event. It filters out modifier-only keys and certain exit keys (like q, ESC, STOP) to prevent accidental player termination. It also handles arrow key mapping (e.g., ArrowUp becomes UP).
    • fullscreen(): Triggers the browser's fullscreen request on the player node.
    • destroy(): Synchronously removes the plugin DOM node to clean up resources.
    • node(): Returns the underlying HTMLEmbedElement.
    <ReactMPV 
      onReady={(mpv) => {
        // Send a command
        mpv.command('set_pause', 'yes');
    
        // Set a property
        mpv.property('volume', 50);
    
        // Observe a property
        mpv.observe('pause');
    
        // Simulate a keypress
        mpv.keypress({ key: 'ArrowLeft', ctrlKey: true }); // Sends Ctrl+LEFT
    
        // Enter fullscreen
        mpv.fullscreen();
      }} 
    />
  7. Get the plugin entry for register-pepper-plugins

    master

    Use getPluginEntry to generate the formatted string required by the register-pepper-plugins switch. This function handles platform-specific pathing (like the ./ requirement on Linux) and ensures the correct MIME type (application/x-mpvjs) is appended.

    Note: The plugin path must not contain non-ASCII characters. If the absolute path contains non-ASCII characters but a relative path does not, the function will attempt to use the relative path.

    const { getPluginEntry } = require('mpv.js');
    
    const entry = getPluginEntry('/path/to/plugin/dir', 'mpvjs.node');
    // Returns something like: './mpvjs.node;application/x-mpvjs'