UNPKG

homebridge-appletv-enhanced

Version:

Plugin that exposes the Apple TV to HomeKit with much richer features than the vanilla Apple TV implementation of HomeKit.

265 lines 9.47 kB
"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; closed = false; 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); } async close() { this.closed = true; this.log.info('Closing connection ...'); this.sendCommand('exit', true); } 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.cleanUp(); if (this.closed === false) { this.log.warn('Lost connection. Trying to reconnect ...'); if (this.onCloseCallable) { void this.onCloseCallable(); } } else { this.log.success('Closed connection successfully.'); this.log.debug('Skipping to reconnect since it was closed on purpose.'); } }); } 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); } cleanUp() { clearInterval(this.heartbeatInterval); this.process.stdout.removeListener('data', this.stdoutListener); this.process.stderr.removeListener('data', this.stderrListener); } 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, '--storage', 'none', ]; 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