node-mpv
Version:
A Node module for MPV
192 lines (178 loc) • 6.11 kB
JavaScript
const execSync = require('child_process').execSync;
// Lodash for some nice stuff
const _ = require('lodash');
const util = {
// Finds the correct command to start the IPC socket for mpv. It looks at the
// output of 'mpv --version' and uses Regular Expressions to determine the mpv
// version.
// With mpv version 0.17.0 the command changed from "--input-unix-socket" to
// "--input-ipc-server"
//
// @param binary
// The binary path for the mpv executable
//
// @ return
// The ipc command flag used by mpv
//
findIPCCommand: function(options) {
// if the ipc Command was set by the user, use that
if(options.ipc_command){
if(!(options.ipc_command == "--input-ipc-server" || options.ipc_command == "--input-unix-socket")){
console.log('Warning: ipcCommand was neither "--input-unix-socket" nor "--input-ipc-server", using the up to date "--input-ipc-server"');
}
return "--input-ipc-server";
}
// determine the ipc command according to the version number
else{
// the name of the ipc command was changed in mpv version 0.17.0 to "--input-ipc-server"
// that's why we have to check which mpv version is running
// asks for the mpv version
const output = execSync((options.binary ? '"' + options.binary + '"' + " --version" : "mpv --version"), {encoding: 'utf8'});
// Version Number found
if(output.match(/UNKNOWN/) == null){
// get the version part of the output
// looking for mpv 0.XX.Y
const regex_match = output.match(/(mpv) \d+.\d+.\d+/)
// check if there actually was a match
if(regex_match){
const match = regex_match[0];
// split at the whitespace to get the numbers
// split at the dot and look at the middle one to check for the
// critical version number
const versionNumber = parseInt(match.split(" ")[1].split(".")[1]);
// Verison 0.17.0 and higher
if(versionNumber >= 17){
return "--input-ipc-server";
}
// Version 0.16.0 and below
else{
return "--input-unix-socket";
}
}
// when MPV is built from source it sometimes has a git hash as
// the version number
// In this case assume it's a newer version and use the new command
else{
return "--input-ipc-server";
}
}
// when compiling mpv from source the displayed version number is "UNKNOWN"
// I assume that version that is compiled from source is the latest version
// and use the new command
else{
return "--input-ipc-server";
}
}
},
// Merges the options input by the user with the default options, giving
// the user input options priority
//
// @param options
// node-mpv options object input by the user
//
// @ return
// Merged options object (UserInput with DefaultOptions)
//
mergeDefaultOptions: function(userInputOptions) {
// the default options to start the socket with
let defaultOptions = {
"debug": false,
"verbose": false,
// Windows and UNIX defaults
"socket": process.platform === "win32" ? "\\\\.\\pipe\\mpvserver" : "/tmp/node-mpv.sock",
"audio_only": false,
"time_update": 1,
"binary": null
}
// merge the default options with the one specified by the user
return _.defaults(userInputOptions || {}, defaultOptions);
},
// Determies the properties observed by default
// If the player is NOT set to audio only, video properties are observed
// as well
//
// @param adioOnlyOption
// Flag if mpv should be started in audio only mode
//
// @return
// Observed properties object
//
observedProperties: function(audioOnlyOption) {
// basic observed properties
let basicObserved = {
"mute": false,
"pause": false,
"duration": null,
"volume": 100,
"filename": null,
"path": null,
"media-title": null,
"playlist-pos": null,
"playlist-count": null,
"loop": "no"
};
// video related properties (not required in audio-only mode)
const observedVideo = {
"fullscreen": false,
"sub-visibility": false,
}
// add the video properties if not set to audio only
if(!audioOnlyOption){
basicObserved = _.merge(basicObserved, observedVideo);
}
return basicObserved;
},
// Determines the arguments to start mpv with
// These consist of some default arguments and user input arguments
// @param options
// node-mpv options object
// @param userInputArguments
// mpv arguments input by the user
//
// @return
// list of arguments for mpv
mpvArguments: function(options, userInputArguments) {
// determine the IPC argument
const ipcCommand = this.findIPCCommand(options);
// default Arguments
// --ipcCommand (--ipc-input-server / --input-unix-socket) IPC socket to communicate with mpv
// --idle always run in the background
// --really-quite no console prompts. Buffer might overflow otherwise
let defaultArgs = [ipcCommand + "=" + options.socket, '--idle', '--really-quiet'];
// audio_only option aditional arguments
// --no-video no video will be displayed
// --audio-display prevents album covers embedded in audio files from being displayed
if(options.audio_only){
defaultArgs = _.concat(defaultArgs, ['--no-video', '--no-audio-display']);
}
// add the user specified arguments if specified
if(userInputArguments){
defaultArgs = _.union(defaultArgs, userInputArguments);
}
return defaultArgs;
},
// takes an options list consisting of strings of the following pattern
// option=value
// => ["option1=value1", "option2=value2"]
// and formats into a JSON object such that the mpv JSON api accepts it
// => {"option1": "value1", "option2": "value2"}
// @param options
// list of options
//
// @return
// correctly formatted JSON object with the options
formatOptions: function(options) {
// JSON Options object
let optionJSON = {}
// each options is of the form options=value and has to be splited
let splitted = []
// iterate through every options
for(let i = 0; i < options.length; i++){
splitted = options[i].split('=')
optionJSON[splitted[0]] = splitted[1]
}
return optionJSON;
}
}
module.exports = util;
;