homebridge-kodi
Version:
Kodi plugin for Homebridge
561 lines • 34.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TelevisionAccessory = void 0;
const internal_1 = require("../../internal");
const kodi = require("../kodi");
// =======================
// = TelevisionAccessory =
// =======================
class TelevisionAccessory extends internal_1.KodiTelevisionAccessory {
constructor(platform, accessory, log, config, name, version, type, inputNames, inputIdentifiers) {
super();
this.platform = platform;
this.accessory = accessory;
this.log = log;
this.config = config;
this.name = name;
this.version = version;
this.type = type;
this.inputNames = inputNames;
this.inputIdentifiers = inputIdentifiers;
this.log.info('Adding Television' + type + 'Accessory');
this.accessory.category = 31 /* this.platform.api.hap.Categories.TELEVISION */;
this.accessory.getService(this.platform.Service.AccessoryInformation)
.setCharacteristic(this.platform.Characteristic.Name, name)
.setCharacteristic(this.platform.Characteristic.Manufacturer, 'github.com DeutscheMark')
.setCharacteristic(this.platform.Characteristic.Model, 'Homebridge-Kodi Television' + type)
.setCharacteristic(this.platform.Characteristic.SerialNumber, this.platform.api.hap.uuid.generate(name))
.setCharacteristic(this.platform.Characteristic.FirmwareRevision, version);
this.televisionService = new this.platform.api.hap.Service.Television(name, 'televisionService' + name);
this.televisionService.setCharacteristic(this.platform.Characteristic.Name, name);
this.televisionService.setCharacteristic(this.platform.Characteristic.ConfiguredName, name);
this.televisionService.setCharacteristic(this.platform.Characteristic.SleepDiscoveryMode, this.platform.Characteristic.SleepDiscoveryMode.ALWAYS_DISCOVERABLE);
this.televisionService.getCharacteristic(this.platform.Characteristic.Active)
.onGet(async () => {
switch (this.type) {
case internal_1.TelevisionAccessoryType.Controls:
return kodi.getStatus(this.config)
.then(status => {
this.log.debug('Getting ' + this.name + ': ' + status);
return status;
})
.catch(error => {
this.log.error('Getting ' + this.name + ' - Error: ' + error.message);
return false;
});
case internal_1.TelevisionAccessoryType.Channels:
return kodi.tvIsPlaying(this.config)
.then(tvisplaying => {
this.log.debug('Getting ' + this.name + ': ' + tvisplaying);
return tvisplaying;
})
.catch(error => {
this.log.error('Getting ' + this.name + ' - Error: ' + error.message);
return false;
});
}
})
.onSet(async (active) => {
let cmd = null;
if (this.config.power.on && active) {
cmd = this.config.power.on;
}
else if (this.config.power.off && !active) {
cmd = this.config.power.off;
}
switch (this.type) {
case internal_1.TelevisionAccessoryType.Controls:
if (cmd) {
this.executeShellCommand(active, cmd);
this.platform.closedByPlugin = !active;
}
else {
kodi.getStatus(this.config)
.then(status => {
this.log.debug('Setting ' + this.name + ': ' + status);
this.updateValue(status);
})
.catch(error => {
this.log.error('Setting ' + this.name + ': ' + active + ' - Error: ' + error);
this.updateValue(false);
});
}
break;
case internal_1.TelevisionAccessoryType.Channels:
if (active) {
kodi.closeFavoritesWindowIfOpened(this.config, this.log)
.then(() => {
kodi.tvGetChannels(this.config)
.then(result => {
if (result && result.channels) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let channeltostart = null;
for (let index = 0; index < result.channels.length; index++) {
const channel = result.channels[index];
if (channel.label ===
this.inputNames[this.televisionService
.getCharacteristic(this.platform.api.hap.Characteristic.ActiveIdentifier).value - 1]) {
channeltostart = channel;
}
}
if (channeltostart) {
kodi.getActionResult(this.config, 'Player.Open', { 'item': { 'channelid': channeltostart.channelid } })
.then(() => {
this.log
.debug('Setting ' + this.name + ' Channel: ' + channeltostart.channelid + ' ("' + channeltostart.label + '")');
})
.catch(error => {
this.log
.error('Setting ' + this.name + ' Channel: ' + channeltostart.channelid +
' ("' + channeltostart.label + '") - Error: ' + error.message);
});
}
else {
this.log.error('Setting ' + this.name + ' Channel - Error: channel not found');
}
}
else {
this.log.error('Setting ' + this.name + ' Channel - Error: no channels found');
}
})
.catch(error => {
this.log.error('Setting ' + this.name + ': false - Error: ' + error.message);
});
})
.catch(error => {
this.log.error('Setting ' + this.name + ': false - Error: ' + error.message);
});
}
else {
kodi.playerGetActivePlayers(this.config)
.then(playerid => {
if (playerid !== null && playerid !== -1) {
kodi.playerStop(this.config, playerid)
.then(result => {
if (result) {
setTimeout(() => {
this.log.debug('Setting ' + this.name + ': false - Stopped!');
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.On).updateValue(false);
}, 100);
this.log.debug('Setting ' + this.name + ': ' + active);
}
else {
setTimeout(() => {
this.log.debug('Setting ' + this.name + ': false - Stopped!');
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.On).updateValue(false);
}, 100);
}
})
.catch(error => {
this.log.error('Setting ' + this.name + ': false - Error: ' + error.message);
});
}
else {
setTimeout(() => {
this.log.debug('Setting ' + this.name + ': false - Stopped!');
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.On).updateValue(false);
}, 100);
}
})
.catch(error => {
this.log.error('Setting ' + this.name + ': false - Error: ' + error.message);
});
}
break;
}
});
this.televisionService.setCharacteristic(this.platform.Characteristic.ActiveIdentifier, 999999);
this.televisionService.getCharacteristic(this.platform.Characteristic.ActiveIdentifier)
.onGet(async () => {
switch (this.type) {
case internal_1.TelevisionAccessoryType.Controls:
this.log.debug('Getting ' + this.name + ' Active Identifier: 1 (Home)');
return 1;
case internal_1.TelevisionAccessoryType.Channels:
return kodi.tvIsPlaying(this.config)
.then(tvisplaying => {
if (tvisplaying) {
return kodi.playerGetActivePlayers(this.config)
.then(playerid => {
if (playerid !== null && playerid !== -1) {
return kodi.playerGetItem(this.config, playerid, [])
.then(itemresult => {
if (itemresult && itemresult.item) {
const itemtype = itemresult.item.type !== '' ? itemresult.item.type : '-';
if (itemtype === 'channel') {
let inputName;
let activeIdentifier;
for (let index = 0; index < this.inputNames.length; index++) {
if (itemresult.item.label === this.inputNames[index]) {
inputName = this.inputNames[index];
activeIdentifier = this.inputIdentifiers[index];
}
}
this.log.debug('Getting ' + this.name + ' Active Identifier: ' + activeIdentifier + ' ("' + inputName + '")');
if (activeIdentifier) {
return activeIdentifier;
}
else {
return 1;
}
}
else {
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.Active).updateValue(false);
return 1;
}
}
else {
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.Active).updateValue(false);
return 1;
}
})
.catch(error => {
this.log.error('Getting ' + this.name + ' Active Identifier - Error: ' + error.message);
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.Active).updateValue(false);
return 1;
});
}
else {
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.Active).updateValue(false);
return 1;
}
})
.catch(error => {
this.log.error('Getting ' + this.name + ' Active Identifier - Error: ' + error.message);
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.Active).updateValue(false);
return 1;
});
}
else {
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.Active).updateValue(false);
return 1;
}
})
.catch(error => {
this.log.error('Getting ' + this.name + ' Active Identifier - Error: ' + error.message);
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.Active).updateValue(false);
return 1;
});
default:
return 1;
}
})
.onSet(async (activeIdentifier) => {
switch (this.type) {
case internal_1.TelevisionAccessoryType.Controls:
kodi.closeFavoritesWindowIfOpened(this.config, this.log)
.then(() => {
switch (activeIdentifier) {
case 1:
this.activeIdentiferSet(this.name, activeIdentifier, 'Home', 'Input.Home', {});
break;
case 2:
this.activeIdentiferSet(this.name, activeIdentifier, 'Settings', 'GUI.ActivateWindow', { 'window': 'settings', 'parameters': ['Root'] });
break;
case 3:
this.activeIdentiferSet(this.name, activeIdentifier, 'Movies', 'GUI.ActivateWindow', { 'window': 'videos', 'parameters': ['MovieTitles'] });
break;
case 4:
this.activeIdentiferSet(this.name, activeIdentifier, 'TV shows', 'GUI.ActivateWindow', { 'window': 'videos', 'parameters': ['TVShowTitles'] });
break;
case 5:
this.activeIdentiferSet(this.name, activeIdentifier, 'TV', 'GUI.ActivateWindow', { 'window': 'tvchannels', 'parameters': ['Root'] });
break;
case 6:
this.activeIdentiferSet(this.name, activeIdentifier, 'Music', 'GUI.ActivateWindow', { 'window': 'music', 'parameters': ['Root'] });
break;
case 7:
this.activeIdentiferSet(this.name, activeIdentifier, 'Music videos', 'GUI.ActivateWindow', { 'window': 'videos', 'parameters': ['MusicVideoTitles'] });
break;
case 8:
this.activeIdentiferSet(this.name, activeIdentifier, 'Radio', 'GUI.ActivateWindow', { 'window': 'radiochannels', 'parameters': ['Root'] });
break;
case 9:
this.activeIdentiferSet(this.name, activeIdentifier, 'Games', 'GUI.ActivateWindow', { 'window': 'games', 'parameters': ['Root'] });
break;
case 10:
this.activeIdentiferSet(this.name, activeIdentifier, 'Add-ons', 'GUI.ActivateWindow', { 'window': 'videos', 'parameters': ['Video Add-ons'] });
break;
case 11:
this.activeIdentiferSet(this.name, activeIdentifier, 'Pictures', 'GUI.ActivateWindow', { 'window': 'pictures', 'parameters': ['Root'] });
break;
case 12:
this.activeIdentiferSet(this.name, activeIdentifier, 'Videos', 'GUI.ActivateWindow', { 'window': 'videos', 'parameters': ['Root'] });
break;
case 13:
this.activeIdentiferSet(this.name, activeIdentifier, 'Favorites', 'GUI.ActivateWindow', { 'window': 'favourites', 'parameters': ['Root'] });
break;
case 14:
this.activeIdentiferSet(this.name, activeIdentifier, 'Weather', 'GUI.ActivateWindow', { 'window': 'weather', 'parameters': ['Root'] });
break;
default:
break;
}
})
.catch(error => {
this.log.error('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier + ' - Error: ' + error.message);
});
break;
case internal_1.TelevisionAccessoryType.Channels:
this.log.debug('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier);
kodi.closeFavoritesWindowIfOpened(this.config, this.log)
.then(() => {
kodi.tvGetChannels(this.config)
.then(result => {
if (result.channels) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let channeltostart = null;
for (let index = 0; index < result.channels.length; index++) {
const channel = result.channels[index];
if (channel.label === this.inputNames[activeIdentifier - 1]) {
channeltostart = channel;
}
}
if (channeltostart) {
kodi.getActionResult(this.config, 'Player.Open', { 'item': { 'channelid': channeltostart.channelid } })
.then(([ok]) => {
if (ok) {
this.log
.debug('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier + ' ("' + channeltostart.label + '")');
}
else {
this.log.debug('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier +
' ("' + channeltostart.label + '") (not ok)');
}
})
.catch(error => {
this.log.error('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier + ' - Error: ' + error.message);
});
}
else {
this.log.error('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier + ' - Error: channel not found');
}
}
else {
this.log.error('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier + ' - Error: no channels found');
}
})
.catch(error => {
this.log.error('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier + ' - Error: ' + error.message);
});
})
.catch(error => {
this.log.error('Setting ' + this.name + ' Active Identifier: ' + activeIdentifier + ' - Error: ' + error.message);
});
break;
default:
break;
}
});
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.PictureMode)
.onSet(async (picturemode) => {
this.log.debug('Setting ' + name + ' PictureMode: ' + picturemode);
});
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.PowerModeSelection)
.onSet(async (picturemode) => {
kodi.getActionResult(config, 'Input.Home', {})
.then(() => {
this.log.debug('Setting ' + name + ' PowerModeSelection: ' + picturemode);
})
.catch(error => {
this.log.debug('Setting ' + name + ' PowerModeSelection: ' + picturemode + ' - Error: ' + error.message);
});
});
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.RemoteKey)
.onSet(async (remoteKey) => {
switch (remoteKey) {
case this.platform.api.hap.Characteristic.RemoteKey.REWIND:
kodi.playerGetActivePlayers(config)
.then(playerid => {
this.remoteKeyPressed('REWIND', 'Player.Seek', { 'playerid': playerid, 'value': 'smallbackward' });
})
.catch(error => {
this.log.error('Setting RemoteKey: REWIND - Error: ' + error.message);
});
break;
case this.platform.api.hap.Characteristic.RemoteKey.FAST_FORWARD:
kodi.playerGetActivePlayers(config)
.then(playerid => {
this.remoteKeyPressed('FAST_FORWARD', 'Player.Seek', { 'playerid': playerid, 'value': 'smallforward' });
})
.catch(error => {
this.log.error('Setting RemoteKey: FAST_FORWARD - Error: ' + error.message);
});
break;
case this.platform.api.hap.Characteristic.RemoteKey.NEXT_TRACK:
kodi.playerGetActivePlayers(config)
.then(playerid => {
this.remoteKeyPressed('NEXT_TRACK', 'Player.GoTo', { 'playerid': playerid, 'to': 'next' });
})
.catch(error => {
this.log.error('Setting RemoteKey: NEXT_TRACK - Error: ' + error.message);
});
break;
case this.platform.api.hap.Characteristic.RemoteKey.PREVIOUS_TRACK:
kodi.playerGetActivePlayers(config)
.then(playerid => {
this.remoteKeyPressed('PREVIOUS_TRACK', 'Player.GoTo', { 'playerid': playerid, 'to': 'previous' });
})
.catch(error => {
this.log.error('Setting RemoteKey: PREVIOUS_TRACK - Error: ' + error.message);
});
break;
case this.platform.api.hap.Characteristic.RemoteKey.ARROW_UP:
this.remoteKeyPressed('ARROW_UP', 'Input.Up', {});
break;
case this.platform.api.hap.Characteristic.RemoteKey.ARROW_DOWN:
this.remoteKeyPressed('ARROW_DOWN', 'Input.Down', {});
break;
case this.platform.api.hap.Characteristic.RemoteKey.ARROW_LEFT:
this.remoteKeyPressed('ARROW_LEFT', 'Input.Left', {});
break;
case this.platform.api.hap.Characteristic.RemoteKey.ARROW_RIGHT:
this.remoteKeyPressed('ARROW_RIGHT', 'Input.Right', {});
break;
case this.platform.api.hap.Characteristic.RemoteKey.SELECT:
this.remoteKeyPressed('SELECT', 'Input.Select', {});
break;
case this.platform.api.hap.Characteristic.RemoteKey.BACK:
this.remoteKeyPressed('BACK', 'Input.Back', {});
break;
case this.platform.api.hap.Characteristic.RemoteKey.EXIT:
this.remoteKeyPressed('EXIT', 'Input.Home', {});
break;
case this.platform.api.hap.Characteristic.RemoteKey.PLAY_PAUSE:
kodi.playerGetActivePlayers(config)
.then(playerid => {
this.remoteKeyPressed('PLAY_PAUSE', 'Player.PlayPause', { 'playerid': playerid });
})
.catch(error => {
this.log.error('Setting RemoteKey: PLAY_PAUSE - Error: ' + error.message);
});
break;
case this.platform.api.hap.Characteristic.RemoteKey.INFORMATION:
this.remoteKeyPressed('INFORMATION', 'Input.ShowOSD', {});
break;
default:
this.log.debug('Setting RemoteKey: Unknown key!');
break;
}
});
this.log.info('Adding Television' + type + ' - ' + name + ' Speaker');
const subType = name + ' Speaker';
let televisionSpeakerService = this.accessory.getServiceById(name, subType);
if (!televisionSpeakerService) {
this.log.debug('Adding new accessory: ' + name + ' Speaker');
televisionSpeakerService = new this.platform.api.hap.Service.TelevisionSpeaker(name, subType);
televisionSpeakerService.subtype = subType;
this.accessory.addService(televisionSpeakerService);
}
televisionSpeakerService
.setCharacteristic(this.platform.api.hap.Characteristic.Active, this.platform.api.hap.Characteristic.Active.ACTIVE)
.setCharacteristic(this.platform.api.hap.Characteristic.VolumeControlType, this.platform.api.hap.Characteristic.VolumeControlType.ABSOLUTE);
televisionSpeakerService.getCharacteristic(this.platform.api.hap.Characteristic.VolumeSelector)
.onSet(async (selector) => {
const volume = selector ? 'decrement' : 'increment';
kodi.applicationSetVolume(config, volume)
.then(result => {
if (result) {
this.log.debug('Setting ' + name + ': ' + volume);
}
else {
this.log.debug('Setting ' + name + ': ' + volume + ' (no result)');
}
})
.catch(error => {
this.log.debug('Setting ' + name + ': ' + volume + ' - Error: ' + error.message);
});
});
televisionSpeakerService.getCharacteristic(this.platform.api.hap.Characteristic.Volume)
.onGet(async () => {
return kodi.applicationGetProperties(config, ['volume'])
.then(result => {
if (result) {
const volume = result.volume ? result.volume : 0;
this.log.debug('Getting ' + name + ': ' + volume + ' %');
return volume;
}
else {
return 0;
}
})
.catch(error => {
this.log.error('Getting ' + name + ' - Error: ' + error.message);
return 0;
});
});
this.televisionService.addLinkedService(televisionSpeakerService);
const shownInputServices = [];
for (let index = 0; index < inputNames.length; index++) {
const inputName = inputNames[index];
const inputIdentifier = inputIdentifiers[index];
this.log.info('Adding Television' + type + ' - ' + 'Input' + name + ' ' + inputName);
const subType = 'Input' + inputName;
let inputService = this.accessory.getServiceById(name, subType);
if (!inputService) {
this.log.debug('Adding new accessory: ' + 'Input' + inputName);
inputService = new this.platform.api.hap.Service.InputSource(name, subType);
inputService.subtype = subType;
}
inputService
.setCharacteristic(this.platform.api.hap.Characteristic.Name, inputName)
.setCharacteristic(this.platform.api.hap.Characteristic.ConfiguredName, inputName)
.setCharacteristic(this.platform.api.hap.Characteristic.Identifier, inputIdentifier)
.setCharacteristic(this.platform.api.hap.Characteristic.IsConfigured, this.platform.api.hap.Characteristic.IsConfigured.CONFIGURED)
.setCharacteristic(this.platform.api.hap.Characteristic.InputSourceType, this.platform.api.hap.Characteristic.InputSourceType.APPLICATION)
.setCharacteristic(this.platform.api.hap.Characteristic.TargetVisibilityState, this.platform.api.hap.Characteristic.TargetVisibilityState.SHOWN)
.setCharacteristic(this.platform.api.hap.Characteristic.CurrentVisibilityState, this.platform.api.hap.Characteristic.CurrentVisibilityState.SHOWN);
this.accessory.addService(inputService);
this.televisionService.addLinkedService(inputService);
shownInputServices.push(inputService);
}
for (let index = 0; index < this.televisionService.linkedServices.length; index++) {
const service = this.televisionService.linkedServices[index];
const name = service.getCharacteristic(this.platform.api.hap.Characteristic.Name).value;
const shownInputService = shownInputServices.find(i => i.getCharacteristic(this.platform.api.hap.Characteristic.Name).value === name);
if (!shownInputService) {
this.log.debug('Removing accessory and linked service from television service: ' + this.televisionService.name + ' ' + name);
this.televisionService.removeLinkedService(service);
this.accessory.removeService(service);
}
}
this.accessory.addService(this.televisionService);
}
executeShellCommand(on, cmd) {
kodi.executeShellCommand(cmd)
.then(output => {
this.log.debug('Setting ' + this.name + ': ' + on + ' with output: ' + output);
this.platform.checkKodiStatus();
})
.catch(error => {
this.log.error('Setting ' + this.name + ': ' + on + ' - Error: ' + error.message);
});
}
updateValue(on) {
setTimeout(() => {
this.televisionService.getCharacteristic(this.platform.api.hap.Characteristic.Active).updateValue(on);
}, 100);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
remoteKeyPressed(name, method, parameters) {
kodi.getActionResult(this.config, method, parameters)
.then(() => {
this.log.debug('Setting RemoteKey: ' + name);
})
.catch(error => {
this.log.error('Setting RemoteKey: ' + name + ' - Error: ' + error.message);
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
activeIdentiferSet(name, activeIdentifier, inputname, method, parameters) {
kodi.getActionResult(this.config, method, parameters)
.then(() => {
this.log.debug('Setting ' + name + ' Active Identifier: ' + activeIdentifier + ' (' + inputname + ')');
})
.catch(error => {
this.log.error('Setting ' + name + ' Active Identifier: ' + activeIdentifier + ' (' + inputname + ') - Error: ' + error.message);
});
}
}
exports.TelevisionAccessory = TelevisionAccessory;
//# sourceMappingURL=kodiTelevisionAccessory.js.map