homebridge-appletv-enhanced
Version:
Plugin that exposes the Apple TV to HomeKit with much richer features than the vanilla Apple TV implementation of HomeKit.
249 lines • 8.98 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const enums_1 = require("./enums");
const PrefixLogger_1 = __importDefault(require("./PrefixLogger"));
const node_pyatv_1 = require("@sebbo2002/node-pyatv");
class RocketRemote {
mac;
atvremotePath;
airplayCredentials;
companionCredentials;
avadaKedavraSequence;
heartbeatInterval;
lastCommandSend = 0;
log;
onCloseCallable = undefined;
onHomeCallable = undefined;
process;
stderrListener = this.stderrLog.bind(this);
stdoutListener = this.stdoutLog.bind(this);
constructor(mac, atvremotePath, airplayCredentials, companionCredentials, logger, avadaKedavraNumberOfApps) {
this.mac = mac;
this.atvremotePath = atvremotePath;
this.airplayCredentials = airplayCredentials;
this.companionCredentials = companionCredentials;
this.log = new PrefixLogger_1.default(logger, 'Rocket Remote');
this.log.debug('creating');
this.avadaKedavraSequence = this.generateAvadaKedavraSequence(avadaKedavraNumberOfApps);
this.process = this.spawnATVRemote(['cli']);
this.initHeartbeat();
}
addOutputDevices(identifiers, hideLog = false) {
const i = identifiers.join(',');
this.sendCommand(`add_output_devices=${i}`, hideLog);
}
avadaKedavra() {
this.log.info('Avada Kedavra');
this.log.debug(`Avada Kedavra sequence: ${this.avadaKedavraSequence.join(', ')}`);
this.spawnATVRemote(this.avadaKedavraSequence);
}
channelDown(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.CHANNEL_DOWN, hideLog);
}
channelUp(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.CHANNEL_UP, hideLog);
}
down(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.DOWN, hideLog);
}
home(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.HOME, hideLog);
}
homeHold(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.HOME_HOLD, hideLog);
}
left(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.LEFT, hideLog);
}
menu(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.MENU, hideLog);
}
next(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.NEXT, hideLog);
}
onClose(f) {
this.onCloseCallable = f;
this.process.once('close', () => {
this.process.stdout.removeListener('data', this.stdoutListener);
this.process.stderr.removeListener('data', this.stderrListener);
clearInterval(this.heartbeatInterval);
this.log.warn('Lost connection. Trying to reconnect ...');
if (this.onCloseCallable) {
void this.onCloseCallable();
}
});
}
onHome(f) {
this.onHomeCallable = f;
}
openApp(id, hideLog = false) {
this.sendCommand(`launch_app=${id}`, hideLog);
}
pause(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.PAUSE, hideLog);
}
play(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.PLAY, hideLog);
}
playPause(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.PLAY_PAUSE, hideLog);
}
previous(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.PREVIOUS, hideLog);
}
removeOutputDevices(identifiers, hideLog = false) {
const i = identifiers.join(',');
this.sendCommand(`remove_output_devices=${i}`, hideLog);
}
right(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.RIGHT, hideLog);
}
screensaver(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.SCREENSAVER, hideLog);
}
select(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.SELECT, hideLog);
}
sendCommand(cmd, hideLog = false, dedicatedProcess = false) {
if (hideLog) {
this.log.debug(cmd);
}
else {
this.log.info(cmd);
}
if (this.onHomeCallable !== undefined && cmd === 'home') {
void this.onHomeCallable();
}
if (dedicatedProcess === true) {
this.spawnATVRemote(cmd.split(' '));
}
else {
this.process.stdin.write(`${cmd}\n`);
this.lastCommandSend = Date.now();
}
}
setOutputDevices(identifiers, hideLog = false) {
const i = identifiers.join(',');
this.sendCommand(`set_output_devices=${i}`, hideLog);
}
setRepeat(state, hideLog = false) {
let repeatState = 0;
switch (state) {
case node_pyatv_1.NodePyATVRepeatState.off:
repeatState = 0;
break;
case node_pyatv_1.NodePyATVRepeatState.track:
repeatState = 1;
break;
case node_pyatv_1.NodePyATVRepeatState.all:
repeatState = 2;
break;
}
this.sendCommand(`set_repeat=${repeatState}`, hideLog);
}
setShuffle(state, hideLog = false) {
let shuffleState = 0;
switch (state) {
case node_pyatv_1.NodePyATVShuffleState.off:
shuffleState = 0;
break;
case node_pyatv_1.NodePyATVShuffleState.albums:
shuffleState = 1;
break;
case node_pyatv_1.NodePyATVShuffleState.songs:
shuffleState = 2;
break;
}
this.sendCommand(`set_shuffle=${shuffleState}`, hideLog);
}
setVolume(percentage, hideLog = false) {
this.sendCommand(`set_volume=${percentage}`, hideLog);
}
skipBackward(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.SKIP_BACKWARD, hideLog);
}
skipForward(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.SKIP_FORWARD, hideLog);
}
stop(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.STOP, hideLog);
}
topMenu(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.TOP_MENU, hideLog);
}
turnOff(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.TURN_OFF, hideLog);
}
turnOn(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.TURN_ON, hideLog);
}
up(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.UP, hideLog);
}
volumeDown(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.VOLUME_DOWN, hideLog);
}
volumeUp(hideLog = false) {
this.sendCommand(enums_1.RocketRemoteKey.VOLUME_UP, hideLog);
}
generateAvadaKedavraSequence(numberOfApps) {
let sequence = [
'home', 'delay=100', 'home', 'delay=800', 'left', 'delay=300',
];
for (let i = 0; i < numberOfApps; i++) {
sequence = sequence.concat(['up', 'delay=50', 'up', 'delay=600']);
}
sequence.push('home');
return sequence;
}
initHeartbeat() {
this.heartbeatInterval = setInterval(() => {
if (this.lastCommandSend + 45000 < Date.now()) {
this.sendCommand('power_state', true);
}
else {
const secondsFromLastCommand = Math.round((Date.now() - this.lastCommandSend) / 1000);
this.log.debug(`Skipping heartbeat since last command was only ${secondsFromLastCommand}s before.`);
}
}, 60000);
}
spawnATVRemote(args, options) {
const finalArgs = [
'--id', this.mac,
'--companion-credentials', this.companionCredentials,
'--airplay-credentials', this.airplayCredentials,
];
if (args !== undefined) {
finalArgs.push(...args);
}
const process = (0, child_process_1.spawn)(this.atvremotePath, finalArgs, options);
process.stdout.setEncoding('utf8');
process.stderr.setEncoding('utf8');
process.stdout.on('data', this.stdoutListener);
process.stderr.on('data', this.stderrListener);
return process;
}
stderrLog(data) {
this.log.error(data);
this.process.kill();
}
stdoutLog(data) {
const toLog = data.replace('pyatv>', '').trim();
if (toLog.toUpperCase().includes('ERROR')) {
this.stderrLog(toLog);
}
else if (toLog.includes('Enter commands and press enter')) {
this.log.debug(toLog);
this.log.success('Connected');
}
else if (toLog !== '') {
this.log.debug(toLog);
}
}
}
exports.default = RocketRemote;
//# sourceMappingURL=RocketRemote.js.map