src/browser/main/host.js
/**
*
* A class in charge of communicating back and forth with the native app.
*
* There should be no need to modify/extend this class
* as it uses {@link Playback} to build the messages to send
* and as the receiver of all messages from the MPRIS2 interfase
*
*/
class Host {
/**
*
* @param {Playback} playback - the playback of the current site
* @param {Carrier} carrier
* @param {Object} port - see {@link https://developer.chrome.com/apps/runtime#type-Port}
*/
constructor (playback, carrier, port) {
/**
* The playback to interact with
* @type {Playback}
*/
this.playback = playback;
/**
* A carrier for caching and building the payloads
* @type {Carrier}
*/
this.carrier = carrier;
/**
* A chrome.runtime.Port
* @see https://developer.chrome.com/apps/runtime#type-Port
* @type {Object}
*/
this.port = port;
/**
* The default Payload.Identity for the MPRIS2 Interface
* @type {string}
*/
this.source = 'browser';
this.port.onMessage.addListener((r, s, sr) => this.messageListener(r));
}
/**
* Send a message to host app
*
* @param {MessageType} type
* @param {Object|number} [payload]
*/
sendMessage (type, payload) {
this.port.postMessage({
source: this.source,
type: type,
args: [payload]
});
}
/**
* Send a change message to host app
*/
change () {
if (this.playback.activePlayer) {
let payload = this.carrier.requestPayload(this.playback);
if (Object.keys(payload || {}).length)
this.sendMessage(
MessageType.CHANGE,
payload
);
}
}
/**
* Set player as active player and send data to native app
*
* @param {Player} player
*/
start (player) {
this.playback.setActivePlayer(player);
this.change();
}
/**
*
* @param {MessageMethod} method
* @param {*} args
*/
return (method, args) {
this.port.postMessage({
source: this.source,
type: MessageType.RETURN,
method, args
});
}
/**
* Send a seeked message to host
*
* @param {Player} player
*/
seeked (player) {
this.sendMessage(
MessageType.SEEK,
player.getPosition()
);
}
/**
* Send a quit message to host
*/
quit () {
this.carrier.clear();
this.sendMessage(
MessageType.QUIT
);
}
/**
* Listener for messages from native application (aka: mpris interface)
*
* @param {Object} request
* @param {MessageMethod} request.method
* @param {Array} request.args
*/
messageListener (request) {
let result;
if (request.method === MessageMethod.GET) {
result = this.get(...request.args);
} else if (request.method === MessageMethod.SET) {
result = this.set(...request.args);
} else {
result = this.command(request.method, ...request.args);
}
this.return(request.method, result);
}
/**
* Native application wants to Get a property from client
*
* @param {string} _ - org.mpris.MediaPlayer2.Player
* @param {MessageProperty} propName - property that should be returned
* @returns {number|void}
*/
get (_, propName) {
if (propName === MessageProperty.POSITION) {
return this.playback.getPosition() || 0;
}
}
/**
* Native application wants to Set a property
* in the client.
*
* @param {string} _ - org.mpris.MediaPlayer2.Player
* @param {MessageProperty} propName - property to set
* @param {number|LoopStatus|boolean} [newValue] - depends on the property to set
*/
set (_, propName, newValue) {
switch (propName) {
case MessageProperty.RATE:
this.playback.setRate(Number(newValue));
break;
case MessageProperty.VOLUME:
this.playback.setVolume(Number(newValue));
break;
case MessageProperty.SHUFFLE:
this.playback.setShuffle(Boolean(newValue));
break;
case MessageProperty.LOOP_STATUS:
this.playback.setLoopStatus(Object.values(LoopStatus).find(e => e === newValue));
break;
case MessageProperty.FULL_SCREEN:
this.playback.toggleFullScreen();
break;
}
}
/**
* Native application wants to run a command on playback
*
* @param {MessageMethod} name
*/
command (name) {
switch (name) {
case MessageMethod.PLAY:
this.playback.play();
break;
case MessageMethod.PAUSE:
this.playback.pause();
break;
case MessageMethod.TOGGLE:
this.playback.togglePlayback();
break;
case MessageMethod.STOP:
this.playback.stop();
break;
case MessageMethod.NEXT:
this.playback.next();
break;
case MessageMethod.PREVIOUS:
this.playback.previous();
break;
case MessageMethod.SEEK:
this.playback.seek(arguments[1]);
break;
case MessageMethod.SET_POSITION: //why is this not in set?
this.playback.setPosition(arguments[1], arguments[2]);
break;
}
}
}