j-holub / Node-MPV

A NodeJs Module for MPV Player
https://www.npmjs.com/package/node-mpv
MIT License
116 stars 73 forks source link
api audio mpv music node nodejs npm video

Node-MPV 2

A wrapper, that allows you, to comfortably use mpv player with NodeJs. It offers an API for the most relevant functionalities and is highly flexible. The module keeps an instance of MPV running in the background (using MVP's --idle) and communicates over MPV's JSON IPC (Inter-Process Communication) API.

However, it doesn't stop there, it also provides direct access to the IPC socket itself. Thus this module is not limited to the methods it provides, but can used with the full extent of what MPV has to offer, even if some command is not supported by Node-MPV.

Works on UNIX and Windows.

This module requires mpv to be installed on your system to work. For streaming playback from sources such as YouTube and SoundCloud youtube-dl is required.

Support me

Open-source software and this module is and should always be free. I have put countless hours of my free time into creating this NPM module, if you feel like donating the equivalent of a coffee as a token of gratitude, I'd appreciate that. Of course, it's perfectly fine if you choose not to as well.

ko-fi

Node-MPV 1

If you are looking for source code of the original Version 1 of this package, you can find it here. Furthermore, you can install the latest 1.x.x version using

npm install node-mpv@"^1.x.x"

This will install and update to the latest 1.x.x version, but never to anything >= 2.x.x. With this, you will automatically get bug fixes for version 1, without having to worry about any API breaking changes. Keep in mind, that I most likely won't add any new features to Version 1, but only provide bug fixes. Also, you should consider switching to Version 2, there even is a handy migration guide.

Migration to Node-MPV 2

If you're already using Node-MPV 1 please refer to this Migration Guide to see how to migrate your application to Node-MPV 2.

Table of Contents

Install

As of now, Version 2 is still in beta, but has been used by many people over the last 2 years. It's very very close to a stable version.

npm install node-mpv@beta

Dependencies

At least mpv is required, but youtube-dl is recommended as well. youtube-dl is only required if you want to stream videos or music from YouTube, SoundCloud or other websites supported by youtube-dl. See here for a list of supported websites.

macOS

brew install mpv youtube-dl

Linux (Ubuntu/Debian)

sudo apt-get install mpv youtube-dl

Windows

Go to the respective websites mpv and youtube-dl and follow the install instructions.

Usage

Every single method of Node-MPV returns a Promise, more on that later. The following example assumes, that it is put within an async function. For an example using the old .then() way, look a little further below

// where you import your packages
const mpvAPI = require('node-mpv');
// where you want to initialise the API
const mpv = new mpvAPI();

// somewhere within an async context
// starts MPV
try{
  await mpv.start()
  // loads a file
  await mpv.load('your/favorite/song.mp3');
  // file is playing
  // sets volume to 70%
  await mpv.volume(70);
}
catch (error) {
  // handle errors here
  console.log(error);
}

You can optionally pass a JSON object with options to the constructor. Possible options, along with their default values are the following

{
    "audio_only": false,
    "auto_restart": true,
    "binary": null,
    "debug": false,
    "ipcCommand": null,   
    "socket": "/tmp/node-mpv.sock", // UNIX
    "socket": "\\\\.\\pipe\\mpvserver", // Windows
    "time_update": 1,
    "verbose": false,
}

You can also provide an optional second argument, an Array containing mpv command line options. A list of available arguments can be found in the documentation

const mpv = new mpvAPI({
  "verbose": true,
  "audio_only": true
},
[
  "--fullscreen",
  "--fps=60"
])

await mpv.start()
// Code controlling mpv

mpv is then easily controllable via simple function calls.

await mpv.loadFile("/path/to/your/favorite/song.mp3");
await mpv.volume(70);

Events are used to detect changes.

mpv.on('status', (status) => {
  console.log(status);
});

mpv.on('stopped', () => {
  console.log("Gimme more music");
});

Promises

If, for some reason, you don't want to use the async/await syntax, you can use Promises the old fashioned way. Every single method of Node-MPV returns a Promise. This means you will have to create a promise chain to control the player. The promise will be resolved if everything went fine and possibly returns some information and it will be rejected with a proper error message if something went wrong.

mpv.start()
.then(() => {
    return mpv.load('/path/to/video.mkv');
})
.then(() => {
    return mpv.getDuration();
})
.then((duration) => {
    console.log(duration);
    return mpv.getProperty('someProperty');
})
.then((property) => {
    console.log(property);
})
// catches all possible errors from above
.catch((error) => {
    // Maybe the mpv player could not be started
    // Maybe the video file does not exist or couldn't be loaded
    // Maybe someProperty is not a valid property
    console.log(error);
})

Starting from Node 8.0.0 Async/Await is fully supported. If you're within an async function you can use await for better readability and code structure. The promise code from above becomes this

someAsyncFunction = asnyc () => {
    try{
        await mpv.start();
        await mpv.load('path/to/video.mkv');
        console.log(await mpv.getDuration());
        console.log(await mpv.getProperty('someProperty'));
    }
    catch (error) {
        // Maybe the mpv player could not be started
        // Maybe the video file does not exist or couldn't be loaded
        // Maybe someProperty is not a valid property
        console.log(error);
    }
}

Hooking into a Running Instance of MPV

Using the options you can specify the IPC socket, that should be created to handle the communication between MPV and this module. If there is already an instance of MPV running, that has been started with --idle and --input-ipc-server=</tmp/somesocket.sock>, you can hook into that instance by specifying socket=</tmp/somesocket.sock>. In this case, Node-MPV will not create its own instance of MPV but use the already running one.

However, it is not possible to enable auto_restart or any error handling for an external MPV instance. That has to be handled by that instance itself.

Since it is not possible to determine if an MPV instance, that has been started externally, has crashed or was properly quit, both events crashed and quit will be emitted if hooking into an existing instance. See the Events section for more.

API

Starting & Stopping

Load Content

Controlling MPV

Information

Playlists

Audio

Video

Subtitles

Properties

These methods can be used to alter properties or send arbitrary commands to the running MPV player. Information about what commands and properties are available can be found in the list of commands and list of properties sections of the MPV documentation.

The most common commands are already covered by this module. However, this part enables you to send any command you want over the IPC socket. Using this, you aren't limited to the methods defined by this module.

Observing

Node-MPV allows you to observe any property the mpv API offers you, by simply using the observeProperty function.

Events

The Node-MPV module provides various events to notify about changes of the MPV player's state.

Note

Error Handling

Because the JSON IPC API of MPV does not provide any useful error messages, except for it worked or it didn't work, I created an error object, that should help you to figure out what went wrong, and hint you into the right direction for fixing the issue.

If there is an error with a method of this library, it will throw an exception (reject the promise) with an error object, that looks like the following.

{
    'errcode': Error Code
    'verbose': Verbal version of the Error Code
    'method': Method that raised the error
    'arguments': List of arguments the method was called with
    'errmessage': More specific error message
    'options': JSON object with valid options for the method if possible
    'stackTrace': The error stack trace
}

The following Error Codes are available

Example

const mpvAPI = require('node-mpv');
const mpv = new mpvAPI();

// Start the player
mpv.start()
.then(() => {
    // This will load and start the song
    return mpv.load('/path/to/your/favorite/song.mp3')
})
.then(() => {
    // Set the volume to 50%
    return mpv.volume(50);
})
// this catches every arror from above
.catch((error) => {
    console.log(error);
});

// This will bind this function to the stopped event
mpv.on('stopped', () => {
    console.log("Your favorite song just finished, let's start it again!");
    mpv.loadFile('/path/to/your/favorite/song.mp3');
});

Known Issues

Old MPV Version on Debian

Debian took their stable policy a little to far and MPV is still on version 0.6.0. Unfortunately the IPC functionality was only introduced with version 0.7.0. Thus this module will not work with the Debian packaged MPV. The dependencies to build MPV are also too old on Debian. Luckily there is this project, that helps you to build the dependencies and MPV afterwards. Using this you can easily get the latest stable MPV Player on Debian.

IPC Command

The command-line argument to start the IPC socket has changed in MPV version 0.17.0 from --input-unix-socket to --input-ipc-server. This module uses regular expressions to find the version number from the mpv --version output. If MPV was compiled from source, the version number is stated as UNKNOWN and this module will assume, that you use the latest version and use the new command.

If you use self compiled version stating UNKNOWN as the version number below mpv version 0.17.0 you have to use the ipc_command option with '--input-unix-socket'.

To check this enter the following in your command shell

mpv --version

Bug with observing playlist-count in MPV Player 0.17.0

In mpv version 0.17.0, the playlist-count property is not updated on playlistRemove and append.

I filed an Issue and this is fixed with 0.17.1

MPV Player 0.18.1

MPV Player version 0.18.1 has some issues that the player crashes sometimes when sending commands through the ipc socket. If you're using version 0.18.1 try to use a newer (or older) version.

To check your version number enter the following in your command shell

mpv --version

MPV Hanging or Crashing

If your JS code is correct but you are still experiencing crashes, a good place to start debugging is by disabling the default config and/or plugins.

mpvPlayer = new mpv({
 ...
},
[
 "--no-config",
 "--load-scripts=no"
]);

For example, autoload.lua is known to cause problems when loading files in quick succession from a folder with many files.

Changelog

See changelog for more information or API breaking changes