UNPKG

node-red-contrib-castv2

Version:

A Node-Red node that provides basic Google Cast functionality based on the node-castv2-client package.

242 lines (187 loc) 7.24 kB
"use strict"; const util = require('util'); const castv2Cli = require('castv2-client'); const RequestResponseController = castv2Cli.RequestResponseController; function MediaController(client, sourceId, destinationId) { RequestResponseController.call(this, client, sourceId, destinationId, 'urn:x-cast:com.google.cast.media'); this.currentSession = null; this.on('message', onmessage); this.once('close', onclose); var self = this; function onmessage(data, broadcast) { if (data.type === 'MEDIA_STATUS' && broadcast) { var status = data.status[0]; // Sometimes an empty status array can come through; if so don't emit it if (!status) return; self.currentSession = status; self.emit('status', status); } } function onclose() { self.removeListener('message', onmessage); } } util.inherits(MediaController, RequestResponseController); MediaController.prototype.getStatus = function(callback) { var self = this; this.request({ type: 'GET_STATUS' }, function(err, response) { if (err) return callback(err); var status = response.status[0]; self.currentSession = status; callback(null, status); }); }; MediaController.prototype.load = function(media, options, callback) { if (typeof options === 'function' || typeof options === 'undefined') { callback = options; options = {}; } var data = { type: 'LOAD' }; data.autoplay = (typeof options.autoplay !== 'undefined') ? options.autoplay : false; data.currentTime = (typeof options.currentTime !== 'undefined') ? options.currentTime : 0; data.activeTrackIds = (typeof options.activeTrackIds !== 'undefined') ? options.activeTrackIds : []; data.repeatMode = (typeof options.repeatMode === "string" && typeof options.repeatMode !== 'undefined') ? options.repeatMode : "REPEAT_OFF"; data.media = media; this.request(data, function(err, response) { if (err) return callback(err); if (response.type === 'LOAD_FAILED') { return callback(new Error('Load failed')); } if (response.type === 'LOAD_CANCELLED') { return callback(new Error('Load cancelled')); } var status = response.status[0]; callback(null, status); }); }; function noop() {} MediaController.prototype.sessionRequest = function(data, callback) { data.mediaSessionId = this.currentSession.mediaSessionId; callback = callback || noop; this.request(data, function(err, response) { if (err) return callback(err); var status = response.status[0]; callback(null, status); }); }; MediaController.prototype.play = function(callback) { this.sessionRequest({ type: 'PLAY' }, callback); }; MediaController.prototype.pause = function(callback) { this.sessionRequest({ type: 'PAUSE' }, callback); }; MediaController.prototype.stop = function(callback) { this.sessionRequest({ type: 'STOP' }, callback); }; MediaController.prototype.seek = function(currentTime, callback) { var data = { type: 'SEEK', currentTime: currentTime }; this.sessionRequest(data, callback); }; //Load a queue of items to play (playlist) //See https://developers.google.com/cast/docs/reference/chrome/chrome.cast.media.QueueLoadRequest MediaController.prototype.queueLoad = function(items, options, callback) { if (typeof options === 'function' || typeof options === 'undefined') { callback = options; options = {}; } var data = { type: 'QUEUE_LOAD' }; //REPEAT_OFF, REPEAT_ALL, REPEAT_SINGLE, REPEAT_ALL_AND_SHUFFLE data.repeatMode = (typeof options.repeatMode === "string" && typeof options.repeatMode !== 'undefined') ? options.repeatMode : "REPEAT_OFF"; data.currentTime = (typeof options.currentTime !== 'undefined') ? options.currentTime : 0; data.startIndex = (typeof options.startIndex !== 'undefined') ? options.startIndex : 0; data.items = items; this.request(data, function(err, response) { if (err) return callback(err); if (response.type === 'LOAD_FAILED') { return callback(new Error('queueLoad failed')); } if (response.type === 'LOAD_CANCELLED') { return callback(new Error('queueLoad cancelled')); } var status = response.status[0]; callback(null, status); }); }; MediaController.prototype.queueInsert = function(items, options, callback) { if (typeof options === 'function' || typeof options === 'undefined') { callback = options; options = {}; } var data = { type: 'QUEUE_INSERT', currentItemId: options.currentItemId, //Item ID to play after this request or keep same item if undefined currentItemIndex: options.currentItemIndex, //Item Index to play after this request or keep same item if undefined currentTime: options.currentTime, //Seek in seconds for current stream insertBefore: options.insertBefore, //ID or append if undefined items: items }; this.sessionRequest(data, callback); }; MediaController.prototype.queueRemove = function(itemIds, options, callback) { if (typeof options === 'function' || typeof options === 'undefined') { callback = options; options = {}; } var data = { type: 'QUEUE_REMOVE', currentItemId: options.currentItemId, currentTime: options.currentTime, itemIds: itemIds }; this.sessionRequest(data, callback); }; MediaController.prototype.queueReorder = function(itemIds, options, callback) { if (typeof options === 'function' || typeof options === 'undefined') { callback = options; options = {}; } var data = { type: 'QUEUE_REORDER', currentItemId: options.currentItemId, currentTime: options.currentTime, insertBefore: options.insertBefore, itemIds: itemIds }; this.sessionRequest(data, callback); }; MediaController.prototype.queueUpdate = function(items, options, callback) { if (typeof options === 'function' || typeof options === 'undefined') { callback = options; options = {}; } var data = { type: 'QUEUE_UPDATE', currentItemId: options.currentItemId, currentTime: options.currentTime, jump: options.jump, //Skip or go back (if negative) number of items repeatMode: options.repeatMode, items: items }; this.sessionRequest(data, callback); }; MediaController.prototype.queueNext = function(callback) { this.sessionRequest({ type: 'QUEUE_UPDATE', jump: 1 }, callback); }; MediaController.prototype.queuePrev = function(callback) { this.sessionRequest({ type: 'QUEUE_UPDATE', jump: -1 }, callback); }; module.exports = MediaController;