@sebbo2002/pyatv-mqtt-bridge 8.1.1-develop.1 → 8.1.1-develop.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,13 +44,13 @@ You can also use the provided Docker container to run `pyatv-mqtt-bridge` within
44
44
 
45
45
  3. Start pyatv
46
46
 
47
- - By command line :
47
+ - By command line :
48
48
 
49
49
  ```bash
50
50
  pyatv-mqtt-bridge /home/eve/pyatv-mqtt-bridge.json
51
51
  ```
52
52
 
53
- - or use the Docker container :
53
+ - or use the Docker container :
54
54
 
55
55
  ```bash
56
56
  docker run -d --restart=always --name=pyatv-mqtt-bridge \
@@ -58,7 +58,7 @@ docker run -d --restart=always --name=pyatv-mqtt-bridge \
58
58
  sebbo2002/pyatv-mqtt-bridge
59
59
  ```
60
60
 
61
- - or just run the Docker container from the [`docker-compose.yml`](docker-compose.yml) file with :
61
+ - or just run the Docker container from the [`docker-compose.yml`](docker-compose.yml) file with :
62
62
 
63
63
  ```bash
64
64
  docker-compose up -d
@@ -76,13 +76,13 @@ pip3 install pyatv
76
76
 
77
77
  You just need to add the `--debug` option.
78
78
 
79
- - In command line :
79
+ - In command line :
80
80
 
81
81
  ```bash
82
82
  pyatv-mqtt-bridge --debug /home/eve/pyatv-mqtt-bridge.json
83
83
  ```
84
84
 
85
- - or while using the Docker container :
85
+ - or while using the Docker container :
86
86
 
87
87
  ```bash
88
88
  docker run -d --restart=always --name=pyatv-mqtt-bridge \
@@ -91,7 +91,7 @@ docker run -d --restart=always --name=pyatv-mqtt-bridge \
91
91
  pyatv-mqtt-bridge --debug /app/config.json
92
92
  ```
93
93
 
94
- - or while using the [`docker-compose.yml`](docker-compose.yml) file :
94
+ - or while using the [`docker-compose.yml`](docker-compose.yml) file :
95
95
 
96
96
  ```yaml
97
97
  command: pyatv-mqtt-bridge --debug /app/config.json
@@ -107,7 +107,7 @@ command: pyatv-mqtt-bridge --debug /app/config.json
107
107
 
108
108
  To execute a command send any message to the topic `$device/$command`. `$device` is the configured topic of the device
109
109
  and `$command` is a command from [this list](https://github.com/sebbo2002/node-pyatv/blob/develop/src/lib/types.ts#L49).
110
- Example: `/home/living/appletv/menu`. To launch an app, send it's unique id (e.g. `com.google.ios.youtube`) to the topic
110
+ Example: `/home/living/appletv/menu`. To launch an app, send it's unique id (e.g. `com.google.ios.youtube`) to the topic
111
111
  `$device/launch`
112
112
 
113
113
  #### How to check the current Apple TV power state and other status information ?
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/cli.ts","../../src/lib/index.ts"],"sourcesContent":["#!/usr/bin/env node\n'use strict';\n\nimport {existsSync, readFileSync} from 'fs';\nimport {resolve} from 'path';\nimport PyAtvMqttBridge from '../lib/index.js';\nimport {type LogParam} from '../lib/types.js';\n\nconsole.log('# pyatv-mqtt-bridge');\nconsole.log('----------------------------');\n\nconst debug = process.argv.indexOf('--debug') > -1;\nconst configPath = resolve(process.cwd(), process.argv[process.argv.length - 1]);\nif (!existsSync(configPath)) {\n console.log('Usage: pyatv-mqtt-bridge [--debug] ~/pyatv-mqtt-bridge-config.json');\n process.exit(1);\n}\n\nlet config;\ntry {\n config = JSON.parse(readFileSync(configPath, 'utf8'));\n}\ncatch (err) {\n console.log('Unable to parse configuration file:');\n console.log(err);\n console.log('\\nHave you removed the comments?\\n');\n process.exit(1);\n}\n\ntry {\n if (debug) {\n Object.assign(config, {\n log: (msg: LogParam) => {\n let string = `[${msg.level}]`;\n if (msg.host) {\n string += `[${msg.host}]`;\n }\n string += ' ';\n if (msg.message) {\n string += msg.message;\n }\n if (msg.message && msg.error) {\n string += ': ';\n }\n if (msg.error && msg.error.stack) {\n string += msg.error.stack;\n }\n if (msg.error) {\n string += msg.error.toString();\n }\n\n console.log(string);\n }\n });\n }\n\n new PyAtvMqttBridge(config);\n} catch (err) {\n console.log('Unable to start bridge:');\n console.log(err);\n}\n","'use strict';\n\nimport type {Config, ConfigDevice, LogParam} from './types.js';\nimport {connect, MqttClient} from 'mqtt';\nimport pyatv, {NodePyATVDeviceEvent, NodePyATVKeys} from '@sebbo2002/node-pyatv';\n\nexport default class PyAtvMqttBridge {\n private mqttClient: MqttClient | null = null;\n private readonly options: Config;\n private readonly teardown: Array<() => Promise<void>> = [];\n\n constructor(options: Config) {\n if (!options.broker) {\n throw new Error('options.broker is not set!');\n }\n if (!Array.isArray(options.devices) || !options.devices.length) {\n throw new Error('options.devices is not set!');\n }\n if (options.devices.find(d => typeof d.topic !== 'string')) {\n throw new Error('options.devices.topic is not set!');\n }\n if (options.devices.find(d => typeof d.host !== 'string')) {\n throw new Error('options.devices.host is not set!');\n }\n if (options.devices.find(d => typeof d.name !== 'string')) {\n throw new Error('options.devices.name is not set!');\n }\n\n this.options = options;\n this.teardown = [];\n\n this.start().catch(err => {\n this.log({\n level: 'error',\n host: null,\n message: 'Unable to start bridge',\n error: err\n });\n });\n }\n\n private log(msg: LogParam) {\n if (this.options.log) {\n try {\n this.options.log.apply(this, [msg]);\n } catch (err) {\n console.log('Unable to call custom log function:');\n console.log(err);\n }\n }\n }\n\n private async start() {\n const errorListener = (error: Error) => this.log({\n level: 'error',\n host: null,\n message: 'MQTT error',\n error\n });\n\n // this.mqttClient = connect(this.options.broker);\n if (typeof this.options.broker === 'string') {\n this.mqttClient = connect(this.options.broker);\n } else {\n this.mqttClient = connect(this.options.broker);\n }\n\n this.mqttClient.on('error', errorListener);\n this.teardown.unshift(async () => {\n if (this.mqttClient) {\n this.mqttClient.off('error', errorListener);\n await new Promise(resolve => {\n if (this.mqttClient) {\n this.mqttClient.end(false, () => resolve(undefined));\n }\n });\n }\n });\n\n await Promise.all(\n this.options.devices.map(device => this.startDevice(device))\n );\n }\n\n private async startDevice(device: ConfigDevice) {\n this.log({\n level: 'info',\n host: device.host,\n message: 'Setup device…'\n });\n\n const atv = pyatv.device(Object.assign({}, device, {\n debug: (message: string) => this.log({\n level: 'info',\n host: device.host,\n message\n })\n }));\n\n\n /* MQTT <-- PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.publish(device.topic + '/host', device.host, {retain: true});\n this.mqttClient.publish(device.topic + '/name', device.name, {retain: true});\n this.mqttClient.publish(device.topic + '/id', device.id || '', {retain: true});\n }\n\n const updateListener = (event: NodePyATVDeviceEvent | Error) => {\n if(event instanceof NodePyATVDeviceEvent) {\n this.log({\n level: 'info',\n host: device.host,\n message: JSON.stringify(event)\n });\n\n if (this.mqttClient) {\n const value = event.value === null ? '' : String(event.value);\n this.mqttClient.publish(device.topic + '/' + event.key, value, {retain: true});\n }\n }\n };\n const errorListener = (error: Error | NodePyATVDeviceEvent) => {\n if (error instanceof Error) {\n this.log({\n level: 'error',\n host: device.host,\n message: 'Push Error',\n error\n });\n }\n };\n\n atv.on('update', updateListener);\n atv.on('error', errorListener);\n this.teardown.unshift(async () => {\n atv.off('update', updateListener);\n atv.off('error', errorListener);\n });\n\n\n /* MQTT --> PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.subscribe(device.topic + '/+');\n this.teardown.unshift(() => {\n return new Promise((resolve, reject) => {\n if(this.mqttClient) {\n this.mqttClient.unsubscribe(device.topic + '/+', error => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n }\n });\n });\n\n this.mqttClient.on('message', (topic, body) => {\n if (device.topic + '/launch' === topic) {\n const id = body.toString();\n atv.launchApp(id).catch(error => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to launch app \"${id}\"`,\n error\n });\n });\n return;\n }\n\n const key = Object\n .keys(NodePyATVKeys)\n .find(key => device.topic + '/' + key === topic) as NodePyATVKeys | undefined;\n\n if(key) {\n atv.pressKey(key).catch(error => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to press key \"${key}\"`,\n error\n });\n });\n }\n });\n }\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.teardown);\n }\n}\n"],"mappings":"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","names":["import_fs","import_path","import_mqtt","import_node_pyatv","PyAtvMqttBridge","options","d","err","msg","errorListener","error","resolve","device","atv","pyatv","message","updateListener","event","value","reject","topic","body","id","key","debug","configPath","config","err","msg","string","PyAtvMqttBridge"]}
1
+ {"version":3,"sources":["../../src/bin/cli.ts","../../src/lib/index.ts"],"sourcesContent":["#!/usr/bin/env node\n'use strict';\n\nimport { existsSync, readFileSync } from 'fs';\nimport { resolve } from 'path';\nimport PyAtvMqttBridge from '../lib/index.js';\nimport { type LogParam } from '../lib/types.js';\n\nconsole.log('# pyatv-mqtt-bridge');\nconsole.log('----------------------------');\n\nconst debug = process.argv.indexOf('--debug') > -1;\nconst configPath = resolve(\n process.cwd(),\n process.argv[process.argv.length - 1],\n);\nif (!existsSync(configPath)) {\n console.log(\n 'Usage: pyatv-mqtt-bridge [--debug] ~/pyatv-mqtt-bridge-config.json',\n );\n process.exit(1);\n}\n\nlet config;\ntry {\n config = JSON.parse(readFileSync(configPath, 'utf8'));\n} catch (err) {\n console.log('Unable to parse configuration file:');\n console.log(err);\n console.log('\\nHave you removed the comments?\\n');\n process.exit(1);\n}\n\ntry {\n if (debug) {\n Object.assign(config, {\n log: (msg: LogParam) => {\n let string = `[${msg.level}]`;\n if (msg.host) {\n string += `[${msg.host}]`;\n }\n string += ' ';\n if (msg.message) {\n string += msg.message;\n }\n if (msg.message && msg.error) {\n string += ': ';\n }\n if (msg.error && msg.error.stack) {\n string += msg.error.stack;\n }\n if (msg.error) {\n string += msg.error.toString();\n }\n\n console.log(string);\n },\n });\n }\n\n new PyAtvMqttBridge(config);\n} catch (err) {\n console.log('Unable to start bridge:');\n console.log(err);\n}\n","'use strict';\n\nimport type { Config, ConfigDevice, LogParam } from './types.js';\nimport { connect, MqttClient } from 'mqtt';\nimport pyatv, {\n NodePyATVDeviceEvent,\n NodePyATVKeys,\n} from '@sebbo2002/node-pyatv';\n\nexport default class PyAtvMqttBridge {\n private mqttClient: MqttClient | null = null;\n private readonly options: Config;\n private readonly teardown: Array<() => Promise<void>> = [];\n\n constructor(options: Config) {\n if (!options.broker) {\n throw new Error('options.broker is not set!');\n }\n if (!Array.isArray(options.devices) || !options.devices.length) {\n throw new Error('options.devices is not set!');\n }\n if (options.devices.find((d) => typeof d.topic !== 'string')) {\n throw new Error('options.devices.topic is not set!');\n }\n if (options.devices.find((d) => typeof d.host !== 'string')) {\n throw new Error('options.devices.host is not set!');\n }\n if (options.devices.find((d) => typeof d.name !== 'string')) {\n throw new Error('options.devices.name is not set!');\n }\n\n this.options = options;\n this.teardown = [];\n\n this.start().catch((err) => {\n this.log({\n level: 'error',\n host: null,\n message: 'Unable to start bridge',\n error: err,\n });\n });\n }\n\n private log(msg: LogParam) {\n if (this.options.log) {\n try {\n this.options.log.apply(this, [msg]);\n } catch (err) {\n console.log('Unable to call custom log function:');\n console.log(err);\n }\n }\n }\n\n private async start() {\n const errorListener = (error: Error) =>\n this.log({\n level: 'error',\n host: null,\n message: 'MQTT error',\n error,\n });\n\n // this.mqttClient = connect(this.options.broker);\n if (typeof this.options.broker === 'string') {\n this.mqttClient = connect(this.options.broker);\n } else {\n this.mqttClient = connect(this.options.broker);\n }\n\n this.mqttClient.on('error', errorListener);\n this.teardown.unshift(async () => {\n if (this.mqttClient) {\n this.mqttClient.off('error', errorListener);\n await new Promise((resolve) => {\n if (this.mqttClient) {\n this.mqttClient.end(false, () => resolve(undefined));\n }\n });\n }\n });\n\n await Promise.all(\n this.options.devices.map((device) => this.startDevice(device)),\n );\n }\n\n private async startDevice(device: ConfigDevice) {\n this.log({\n level: 'info',\n host: device.host,\n message: 'Setup device…',\n });\n\n const atv = pyatv.device(\n Object.assign({}, device, {\n debug: (message: string) =>\n this.log({\n level: 'info',\n host: device.host,\n message,\n }),\n }),\n );\n\n /* MQTT <-- PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.publish(device.topic + '/host', device.host, {\n retain: true,\n });\n this.mqttClient.publish(device.topic + '/name', device.name, {\n retain: true,\n });\n this.mqttClient.publish(device.topic + '/id', device.id || '', {\n retain: true,\n });\n }\n\n const updateListener = (event: NodePyATVDeviceEvent | Error) => {\n if (event instanceof NodePyATVDeviceEvent) {\n this.log({\n level: 'info',\n host: device.host,\n message: JSON.stringify(event),\n });\n\n if (this.mqttClient) {\n const value =\n event.value === null ? '' : String(event.value);\n this.mqttClient.publish(\n device.topic + '/' + event.key,\n value,\n { retain: true },\n );\n }\n }\n };\n const errorListener = (error: Error | NodePyATVDeviceEvent) => {\n if (error instanceof Error) {\n this.log({\n level: 'error',\n host: device.host,\n message: 'Push Error',\n error,\n });\n }\n };\n\n atv.on('update', updateListener);\n atv.on('error', errorListener);\n this.teardown.unshift(async () => {\n atv.off('update', updateListener);\n atv.off('error', errorListener);\n });\n\n /* MQTT --> PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.subscribe(device.topic + '/+');\n this.teardown.unshift(() => {\n return new Promise((resolve, reject) => {\n if (this.mqttClient) {\n this.mqttClient.unsubscribe(\n device.topic + '/+',\n (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n },\n );\n }\n });\n });\n\n this.mqttClient.on('message', (topic, body) => {\n if (device.topic + '/launch' === topic) {\n const id = body.toString();\n atv.launchApp(id).catch((error) => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to launch app \"${id}\"`,\n error,\n });\n });\n return;\n }\n\n const key = Object.keys(NodePyATVKeys).find(\n (key) => device.topic + '/' + key === topic,\n ) as NodePyATVKeys | undefined;\n\n if (key) {\n atv.pressKey(key).catch((error) => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to press key \"${key}\"`,\n error,\n });\n });\n }\n });\n }\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.teardown);\n }\n}\n"],"mappings":"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","names":["import_fs","import_path","import_mqtt","import_node_pyatv","PyAtvMqttBridge","options","d","err","msg","errorListener","error","resolve","device","atv","pyatv","message","updateListener","event","value","reject","topic","body","id","key","debug","configPath","config","err","msg","string","PyAtvMqttBridge"]}
package/dist/bin/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{a as t}from"../chunk-UHWFNSNC.js";import{existsSync as c,readFileSync as n}from"fs";import{resolve as i}from"path";console.log("# pyatv-mqtt-bridge");console.log("----------------------------");var l=process.argv.indexOf("--debug")>-1,s=i(process.cwd(),process.argv[process.argv.length-1]);c(s)||(console.log("Usage: pyatv-mqtt-bridge [--debug] ~/pyatv-mqtt-bridge-config.json"),process.exit(1));var r;try{r=JSON.parse(n(s,"utf8"))}catch(o){console.log("Unable to parse configuration file:"),console.log(o),console.log(`
2
+ import{a as t}from"../chunk-WNLLGDC3.js";import{existsSync as c,readFileSync as n}from"fs";import{resolve as i}from"path";console.log("# pyatv-mqtt-bridge");console.log("----------------------------");var l=process.argv.indexOf("--debug")>-1,s=i(process.cwd(),process.argv[process.argv.length-1]);c(s)||(console.log("Usage: pyatv-mqtt-bridge [--debug] ~/pyatv-mqtt-bridge-config.json"),process.exit(1));var r;try{r=JSON.parse(n(s,"utf8"))}catch(o){console.log("Unable to parse configuration file:"),console.log(o),console.log(`
3
3
  Have you removed the comments?
4
4
  `),process.exit(1)}try{l&&Object.assign(r,{log:o=>{let e=`[${o.level}]`;o.host&&(e+=`[${o.host}]`),e+=" ",o.message&&(e+=o.message),o.message&&o.error&&(e+=": "),o.error&&o.error.stack&&(e+=o.error.stack),o.error&&(e+=o.error.toString()),console.log(e)}}),new t(r)}catch(o){console.log("Unable to start bridge:"),console.log(o)}
5
5
  //# sourceMappingURL=cli.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n'use strict';\n\nimport {existsSync, readFileSync} from 'fs';\nimport {resolve} from 'path';\nimport PyAtvMqttBridge from '../lib/index.js';\nimport {type LogParam} from '../lib/types.js';\n\nconsole.log('# pyatv-mqtt-bridge');\nconsole.log('----------------------------');\n\nconst debug = process.argv.indexOf('--debug') > -1;\nconst configPath = resolve(process.cwd(), process.argv[process.argv.length - 1]);\nif (!existsSync(configPath)) {\n console.log('Usage: pyatv-mqtt-bridge [--debug] ~/pyatv-mqtt-bridge-config.json');\n process.exit(1);\n}\n\nlet config;\ntry {\n config = JSON.parse(readFileSync(configPath, 'utf8'));\n}\ncatch (err) {\n console.log('Unable to parse configuration file:');\n console.log(err);\n console.log('\\nHave you removed the comments?\\n');\n process.exit(1);\n}\n\ntry {\n if (debug) {\n Object.assign(config, {\n log: (msg: LogParam) => {\n let string = `[${msg.level}]`;\n if (msg.host) {\n string += `[${msg.host}]`;\n }\n string += ' ';\n if (msg.message) {\n string += msg.message;\n }\n if (msg.message && msg.error) {\n string += ': ';\n }\n if (msg.error && msg.error.stack) {\n string += msg.error.stack;\n }\n if (msg.error) {\n string += msg.error.toString();\n }\n\n console.log(string);\n }\n });\n }\n\n new PyAtvMqttBridge(config);\n} catch (err) {\n console.log('Unable to start bridge:');\n console.log(err);\n}\n"],"mappings":";yCAGA,OAAQ,cAAAA,EAAY,gBAAAC,MAAmB,KACvC,OAAQ,WAAAC,MAAc,OAItB,QAAQ,IAAI,qBAAqB,EACjC,QAAQ,IAAI,8BAA8B,EAE1C,IAAMC,EAAQ,QAAQ,KAAK,QAAQ,SAAS,EAAI,GAC1CC,EAAaC,EAAQ,QAAQ,IAAI,EAAG,QAAQ,KAAK,QAAQ,KAAK,OAAS,CAAC,CAAC,EAC1EC,EAAWF,CAAU,IACtB,QAAQ,IAAI,oEAAoE,EAChF,QAAQ,KAAK,CAAC,GAGlB,IAAIG,EACJ,GAAI,CACAA,EAAS,KAAK,MAAMC,EAAaJ,EAAY,MAAM,CAAC,CACxD,OACOK,EAAK,CACR,QAAQ,IAAI,qCAAqC,EACjD,QAAQ,IAAIA,CAAG,EACf,QAAQ,IAAI;AAAA;AAAA,CAAoC,EAChD,QAAQ,KAAK,CAAC,CAClB,CAEA,GAAI,CACIN,GACA,OAAO,OAAOI,EAAQ,CAClB,IAAMG,GAAkB,CACpB,IAAIC,EAAS,IAAID,EAAI,KAAK,IACtBA,EAAI,OACJC,GAAU,IAAID,EAAI,IAAI,KAE1BC,GAAU,IACND,EAAI,UACJC,GAAUD,EAAI,SAEdA,EAAI,SAAWA,EAAI,QACnBC,GAAU,MAEVD,EAAI,OAASA,EAAI,MAAM,QACvBC,GAAUD,EAAI,MAAM,OAEpBA,EAAI,QACJC,GAAUD,EAAI,MAAM,SAAS,GAGjC,QAAQ,IAAIC,CAAM,CACtB,CACJ,CAAC,EAGL,IAAIC,EAAgBL,CAAM,CAC9B,OAASE,EAAK,CACV,QAAQ,IAAI,yBAAyB,EACrC,QAAQ,IAAIA,CAAG,CACnB","names":["existsSync","readFileSync","resolve","debug","configPath","resolve","existsSync","config","readFileSync","err","msg","string","PyAtvMqttBridge"]}
1
+ {"version":3,"sources":["../../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n'use strict';\n\nimport { existsSync, readFileSync } from 'fs';\nimport { resolve } from 'path';\nimport PyAtvMqttBridge from '../lib/index.js';\nimport { type LogParam } from '../lib/types.js';\n\nconsole.log('# pyatv-mqtt-bridge');\nconsole.log('----------------------------');\n\nconst debug = process.argv.indexOf('--debug') > -1;\nconst configPath = resolve(\n process.cwd(),\n process.argv[process.argv.length - 1],\n);\nif (!existsSync(configPath)) {\n console.log(\n 'Usage: pyatv-mqtt-bridge [--debug] ~/pyatv-mqtt-bridge-config.json',\n );\n process.exit(1);\n}\n\nlet config;\ntry {\n config = JSON.parse(readFileSync(configPath, 'utf8'));\n} catch (err) {\n console.log('Unable to parse configuration file:');\n console.log(err);\n console.log('\\nHave you removed the comments?\\n');\n process.exit(1);\n}\n\ntry {\n if (debug) {\n Object.assign(config, {\n log: (msg: LogParam) => {\n let string = `[${msg.level}]`;\n if (msg.host) {\n string += `[${msg.host}]`;\n }\n string += ' ';\n if (msg.message) {\n string += msg.message;\n }\n if (msg.message && msg.error) {\n string += ': ';\n }\n if (msg.error && msg.error.stack) {\n string += msg.error.stack;\n }\n if (msg.error) {\n string += msg.error.toString();\n }\n\n console.log(string);\n },\n });\n }\n\n new PyAtvMqttBridge(config);\n} catch (err) {\n console.log('Unable to start bridge:');\n console.log(err);\n}\n"],"mappings":";yCAGA,OAAS,cAAAA,EAAY,gBAAAC,MAAoB,KACzC,OAAS,WAAAC,MAAe,OAIxB,QAAQ,IAAI,qBAAqB,EACjC,QAAQ,IAAI,8BAA8B,EAE1C,IAAMC,EAAQ,QAAQ,KAAK,QAAQ,SAAS,EAAI,GAC1CC,EAAaC,EACf,QAAQ,IAAI,EACZ,QAAQ,KAAK,QAAQ,KAAK,OAAS,CAAC,CACxC,EACKC,EAAWF,CAAU,IACtB,QAAQ,IACJ,oEACJ,EACA,QAAQ,KAAK,CAAC,GAGlB,IAAIG,EACJ,GAAI,CACAA,EAAS,KAAK,MAAMC,EAAaJ,EAAY,MAAM,CAAC,CACxD,OAASK,EAAK,CACV,QAAQ,IAAI,qCAAqC,EACjD,QAAQ,IAAIA,CAAG,EACf,QAAQ,IAAI;AAAA;AAAA,CAAoC,EAChD,QAAQ,KAAK,CAAC,CAClB,CAEA,GAAI,CACIN,GACA,OAAO,OAAOI,EAAQ,CAClB,IAAMG,GAAkB,CACpB,IAAIC,EAAS,IAAID,EAAI,KAAK,IACtBA,EAAI,OACJC,GAAU,IAAID,EAAI,IAAI,KAE1BC,GAAU,IACND,EAAI,UACJC,GAAUD,EAAI,SAEdA,EAAI,SAAWA,EAAI,QACnBC,GAAU,MAEVD,EAAI,OAASA,EAAI,MAAM,QACvBC,GAAUD,EAAI,MAAM,OAEpBA,EAAI,QACJC,GAAUD,EAAI,MAAM,SAAS,GAGjC,QAAQ,IAAIC,CAAM,CACtB,CACJ,CAAC,EAGL,IAAIC,EAAgBL,CAAM,CAC9B,OAASE,EAAK,CACV,QAAQ,IAAI,yBAAyB,EACrC,QAAQ,IAAIA,CAAG,CACnB","names":["existsSync","readFileSync","resolve","debug","configPath","resolve","existsSync","config","readFileSync","err","msg","string","PyAtvMqttBridge"]}
@@ -1,2 +1,2 @@
1
1
  import{connect as h}from"mqtt";import c,{NodePyATVDeviceEvent as p,NodePyATVKeys as m}from"@sebbo2002/node-pyatv";var n=class{mqttClient=null;options;teardown=[];constructor(t){if(!t.broker)throw new Error("options.broker is not set!");if(!Array.isArray(t.devices)||!t.devices.length)throw new Error("options.devices is not set!");if(t.devices.find(e=>typeof e.topic!="string"))throw new Error("options.devices.topic is not set!");if(t.devices.find(e=>typeof e.host!="string"))throw new Error("options.devices.host is not set!");if(t.devices.find(e=>typeof e.name!="string"))throw new Error("options.devices.name is not set!");this.options=t,this.teardown=[],this.start().catch(e=>{this.log({level:"error",host:null,message:"Unable to start bridge",error:e})})}log(t){if(this.options.log)try{this.options.log.apply(this,[t])}catch(e){console.log("Unable to call custom log function:"),console.log(e)}}async start(){let t=e=>this.log({level:"error",host:null,message:"MQTT error",error:e});typeof this.options.broker=="string"?this.mqttClient=h(this.options.broker):this.mqttClient=h(this.options.broker),this.mqttClient.on("error",t),this.teardown.unshift(async()=>{this.mqttClient&&(this.mqttClient.off("error",t),await new Promise(e=>{this.mqttClient&&this.mqttClient.end(!1,()=>e(void 0))}))}),await Promise.all(this.options.devices.map(e=>this.startDevice(e)))}async startDevice(t){this.log({level:"info",host:t.host,message:"Setup device\u2026"});let e=c.device(Object.assign({},t,{debug:s=>this.log({level:"info",host:t.host,message:s})}));this.mqttClient&&(this.mqttClient.publish(t.topic+"/host",t.host,{retain:!0}),this.mqttClient.publish(t.topic+"/name",t.name,{retain:!0}),this.mqttClient.publish(t.topic+"/id",t.id||"",{retain:!0}));let l=s=>{if(s instanceof p&&(this.log({level:"info",host:t.host,message:JSON.stringify(s)}),this.mqttClient)){let r=s.value===null?"":String(s.value);this.mqttClient.publish(t.topic+"/"+s.key,r,{retain:!0})}},a=s=>{s instanceof Error&&this.log({level:"error",host:t.host,message:"Push Error",error:s})};e.on("update",l),e.on("error",a),this.teardown.unshift(async()=>{e.off("update",l),e.off("error",a)}),this.mqttClient&&(this.mqttClient.subscribe(t.topic+"/+"),this.teardown.unshift(()=>new Promise((s,r)=>{this.mqttClient&&this.mqttClient.unsubscribe(t.topic+"/+",i=>{i?r(i):s()})})),this.mqttClient.on("message",(s,r)=>{if(t.topic+"/launch"===s){let o=r.toString();e.launchApp(o).catch(f=>{this.log({level:"error",host:t.host,message:`Unable to launch app "${o}"`,error:f})});return}let i=Object.keys(m).find(o=>t.topic+"/"+o===s);i&&e.pressKey(i).catch(o=>{this.log({level:"error",host:t.host,message:`Unable to press key "${i}"`,error:o})})}))}async stop(){await Promise.all(this.teardown)}};export{n as a};
2
- //# sourceMappingURL=chunk-UHWFNSNC.js.map
2
+ //# sourceMappingURL=chunk-WNLLGDC3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/index.ts"],"sourcesContent":["'use strict';\n\nimport type { Config, ConfigDevice, LogParam } from './types.js';\nimport { connect, MqttClient } from 'mqtt';\nimport pyatv, {\n NodePyATVDeviceEvent,\n NodePyATVKeys,\n} from '@sebbo2002/node-pyatv';\n\nexport default class PyAtvMqttBridge {\n private mqttClient: MqttClient | null = null;\n private readonly options: Config;\n private readonly teardown: Array<() => Promise<void>> = [];\n\n constructor(options: Config) {\n if (!options.broker) {\n throw new Error('options.broker is not set!');\n }\n if (!Array.isArray(options.devices) || !options.devices.length) {\n throw new Error('options.devices is not set!');\n }\n if (options.devices.find((d) => typeof d.topic !== 'string')) {\n throw new Error('options.devices.topic is not set!');\n }\n if (options.devices.find((d) => typeof d.host !== 'string')) {\n throw new Error('options.devices.host is not set!');\n }\n if (options.devices.find((d) => typeof d.name !== 'string')) {\n throw new Error('options.devices.name is not set!');\n }\n\n this.options = options;\n this.teardown = [];\n\n this.start().catch((err) => {\n this.log({\n level: 'error',\n host: null,\n message: 'Unable to start bridge',\n error: err,\n });\n });\n }\n\n private log(msg: LogParam) {\n if (this.options.log) {\n try {\n this.options.log.apply(this, [msg]);\n } catch (err) {\n console.log('Unable to call custom log function:');\n console.log(err);\n }\n }\n }\n\n private async start() {\n const errorListener = (error: Error) =>\n this.log({\n level: 'error',\n host: null,\n message: 'MQTT error',\n error,\n });\n\n // this.mqttClient = connect(this.options.broker);\n if (typeof this.options.broker === 'string') {\n this.mqttClient = connect(this.options.broker);\n } else {\n this.mqttClient = connect(this.options.broker);\n }\n\n this.mqttClient.on('error', errorListener);\n this.teardown.unshift(async () => {\n if (this.mqttClient) {\n this.mqttClient.off('error', errorListener);\n await new Promise((resolve) => {\n if (this.mqttClient) {\n this.mqttClient.end(false, () => resolve(undefined));\n }\n });\n }\n });\n\n await Promise.all(\n this.options.devices.map((device) => this.startDevice(device)),\n );\n }\n\n private async startDevice(device: ConfigDevice) {\n this.log({\n level: 'info',\n host: device.host,\n message: 'Setup device…',\n });\n\n const atv = pyatv.device(\n Object.assign({}, device, {\n debug: (message: string) =>\n this.log({\n level: 'info',\n host: device.host,\n message,\n }),\n }),\n );\n\n /* MQTT <-- PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.publish(device.topic + '/host', device.host, {\n retain: true,\n });\n this.mqttClient.publish(device.topic + '/name', device.name, {\n retain: true,\n });\n this.mqttClient.publish(device.topic + '/id', device.id || '', {\n retain: true,\n });\n }\n\n const updateListener = (event: NodePyATVDeviceEvent | Error) => {\n if (event instanceof NodePyATVDeviceEvent) {\n this.log({\n level: 'info',\n host: device.host,\n message: JSON.stringify(event),\n });\n\n if (this.mqttClient) {\n const value =\n event.value === null ? '' : String(event.value);\n this.mqttClient.publish(\n device.topic + '/' + event.key,\n value,\n { retain: true },\n );\n }\n }\n };\n const errorListener = (error: Error | NodePyATVDeviceEvent) => {\n if (error instanceof Error) {\n this.log({\n level: 'error',\n host: device.host,\n message: 'Push Error',\n error,\n });\n }\n };\n\n atv.on('update', updateListener);\n atv.on('error', errorListener);\n this.teardown.unshift(async () => {\n atv.off('update', updateListener);\n atv.off('error', errorListener);\n });\n\n /* MQTT --> PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.subscribe(device.topic + '/+');\n this.teardown.unshift(() => {\n return new Promise((resolve, reject) => {\n if (this.mqttClient) {\n this.mqttClient.unsubscribe(\n device.topic + '/+',\n (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n },\n );\n }\n });\n });\n\n this.mqttClient.on('message', (topic, body) => {\n if (device.topic + '/launch' === topic) {\n const id = body.toString();\n atv.launchApp(id).catch((error) => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to launch app \"${id}\"`,\n error,\n });\n });\n return;\n }\n\n const key = Object.keys(NodePyATVKeys).find(\n (key) => device.topic + '/' + key === topic,\n ) as NodePyATVKeys | undefined;\n\n if (key) {\n atv.pressKey(key).catch((error) => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to press key \"${key}\"`,\n error,\n });\n });\n }\n });\n }\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.teardown);\n }\n}\n"],"mappings":"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","names":["connect","pyatv","NodePyATVDeviceEvent","NodePyATVKeys","PyAtvMqttBridge","options","d","err","msg","errorListener","error","resolve","device","atv","message","updateListener","event","value","reject","topic","body","id","key"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/index.ts"],"sourcesContent":["'use strict';\n\nimport type {Config, ConfigDevice, LogParam} from './types.js';\nimport {connect, MqttClient} from 'mqtt';\nimport pyatv, {NodePyATVDeviceEvent, NodePyATVKeys} from '@sebbo2002/node-pyatv';\n\nexport default class PyAtvMqttBridge {\n private mqttClient: MqttClient | null = null;\n private readonly options: Config;\n private readonly teardown: Array<() => Promise<void>> = [];\n\n constructor(options: Config) {\n if (!options.broker) {\n throw new Error('options.broker is not set!');\n }\n if (!Array.isArray(options.devices) || !options.devices.length) {\n throw new Error('options.devices is not set!');\n }\n if (options.devices.find(d => typeof d.topic !== 'string')) {\n throw new Error('options.devices.topic is not set!');\n }\n if (options.devices.find(d => typeof d.host !== 'string')) {\n throw new Error('options.devices.host is not set!');\n }\n if (options.devices.find(d => typeof d.name !== 'string')) {\n throw new Error('options.devices.name is not set!');\n }\n\n this.options = options;\n this.teardown = [];\n\n this.start().catch(err => {\n this.log({\n level: 'error',\n host: null,\n message: 'Unable to start bridge',\n error: err\n });\n });\n }\n\n private log(msg: LogParam) {\n if (this.options.log) {\n try {\n this.options.log.apply(this, [msg]);\n } catch (err) {\n console.log('Unable to call custom log function:');\n console.log(err);\n }\n }\n }\n\n private async start() {\n const errorListener = (error: Error) => this.log({\n level: 'error',\n host: null,\n message: 'MQTT error',\n error\n });\n\n // this.mqttClient = connect(this.options.broker);\n if (typeof this.options.broker === 'string') {\n this.mqttClient = connect(this.options.broker);\n } else {\n this.mqttClient = connect(this.options.broker);\n }\n\n this.mqttClient.on('error', errorListener);\n this.teardown.unshift(async () => {\n if (this.mqttClient) {\n this.mqttClient.off('error', errorListener);\n await new Promise(resolve => {\n if (this.mqttClient) {\n this.mqttClient.end(false, () => resolve(undefined));\n }\n });\n }\n });\n\n await Promise.all(\n this.options.devices.map(device => this.startDevice(device))\n );\n }\n\n private async startDevice(device: ConfigDevice) {\n this.log({\n level: 'info',\n host: device.host,\n message: 'Setup device…'\n });\n\n const atv = pyatv.device(Object.assign({}, device, {\n debug: (message: string) => this.log({\n level: 'info',\n host: device.host,\n message\n })\n }));\n\n\n /* MQTT <-- PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.publish(device.topic + '/host', device.host, {retain: true});\n this.mqttClient.publish(device.topic + '/name', device.name, {retain: true});\n this.mqttClient.publish(device.topic + '/id', device.id || '', {retain: true});\n }\n\n const updateListener = (event: NodePyATVDeviceEvent | Error) => {\n if(event instanceof NodePyATVDeviceEvent) {\n this.log({\n level: 'info',\n host: device.host,\n message: JSON.stringify(event)\n });\n\n if (this.mqttClient) {\n const value = event.value === null ? '' : String(event.value);\n this.mqttClient.publish(device.topic + '/' + event.key, value, {retain: true});\n }\n }\n };\n const errorListener = (error: Error | NodePyATVDeviceEvent) => {\n if (error instanceof Error) {\n this.log({\n level: 'error',\n host: device.host,\n message: 'Push Error',\n error\n });\n }\n };\n\n atv.on('update', updateListener);\n atv.on('error', errorListener);\n this.teardown.unshift(async () => {\n atv.off('update', updateListener);\n atv.off('error', errorListener);\n });\n\n\n /* MQTT --> PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.subscribe(device.topic + '/+');\n this.teardown.unshift(() => {\n return new Promise((resolve, reject) => {\n if(this.mqttClient) {\n this.mqttClient.unsubscribe(device.topic + '/+', error => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n }\n });\n });\n\n this.mqttClient.on('message', (topic, body) => {\n if (device.topic + '/launch' === topic) {\n const id = body.toString();\n atv.launchApp(id).catch(error => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to launch app \"${id}\"`,\n error\n });\n });\n return;\n }\n\n const key = Object\n .keys(NodePyATVKeys)\n .find(key => device.topic + '/' + key === topic) as NodePyATVKeys | undefined;\n\n if(key) {\n atv.pressKey(key).catch(error => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to press key \"${key}\"`,\n error\n });\n });\n }\n });\n }\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.teardown);\n }\n}\n"],"mappings":"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","names":["lib_exports","__export","PyAtvMqttBridge","__toCommonJS","import_mqtt","import_node_pyatv","options","d","err","msg","errorListener","error","resolve","device","atv","pyatv","message","updateListener","event","value","reject","topic","body","id","key"]}
1
+ {"version":3,"sources":["../../src/lib/index.ts"],"sourcesContent":["'use strict';\n\nimport type { Config, ConfigDevice, LogParam } from './types.js';\nimport { connect, MqttClient } from 'mqtt';\nimport pyatv, {\n NodePyATVDeviceEvent,\n NodePyATVKeys,\n} from '@sebbo2002/node-pyatv';\n\nexport default class PyAtvMqttBridge {\n private mqttClient: MqttClient | null = null;\n private readonly options: Config;\n private readonly teardown: Array<() => Promise<void>> = [];\n\n constructor(options: Config) {\n if (!options.broker) {\n throw new Error('options.broker is not set!');\n }\n if (!Array.isArray(options.devices) || !options.devices.length) {\n throw new Error('options.devices is not set!');\n }\n if (options.devices.find((d) => typeof d.topic !== 'string')) {\n throw new Error('options.devices.topic is not set!');\n }\n if (options.devices.find((d) => typeof d.host !== 'string')) {\n throw new Error('options.devices.host is not set!');\n }\n if (options.devices.find((d) => typeof d.name !== 'string')) {\n throw new Error('options.devices.name is not set!');\n }\n\n this.options = options;\n this.teardown = [];\n\n this.start().catch((err) => {\n this.log({\n level: 'error',\n host: null,\n message: 'Unable to start bridge',\n error: err,\n });\n });\n }\n\n private log(msg: LogParam) {\n if (this.options.log) {\n try {\n this.options.log.apply(this, [msg]);\n } catch (err) {\n console.log('Unable to call custom log function:');\n console.log(err);\n }\n }\n }\n\n private async start() {\n const errorListener = (error: Error) =>\n this.log({\n level: 'error',\n host: null,\n message: 'MQTT error',\n error,\n });\n\n // this.mqttClient = connect(this.options.broker);\n if (typeof this.options.broker === 'string') {\n this.mqttClient = connect(this.options.broker);\n } else {\n this.mqttClient = connect(this.options.broker);\n }\n\n this.mqttClient.on('error', errorListener);\n this.teardown.unshift(async () => {\n if (this.mqttClient) {\n this.mqttClient.off('error', errorListener);\n await new Promise((resolve) => {\n if (this.mqttClient) {\n this.mqttClient.end(false, () => resolve(undefined));\n }\n });\n }\n });\n\n await Promise.all(\n this.options.devices.map((device) => this.startDevice(device)),\n );\n }\n\n private async startDevice(device: ConfigDevice) {\n this.log({\n level: 'info',\n host: device.host,\n message: 'Setup device…',\n });\n\n const atv = pyatv.device(\n Object.assign({}, device, {\n debug: (message: string) =>\n this.log({\n level: 'info',\n host: device.host,\n message,\n }),\n }),\n );\n\n /* MQTT <-- PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.publish(device.topic + '/host', device.host, {\n retain: true,\n });\n this.mqttClient.publish(device.topic + '/name', device.name, {\n retain: true,\n });\n this.mqttClient.publish(device.topic + '/id', device.id || '', {\n retain: true,\n });\n }\n\n const updateListener = (event: NodePyATVDeviceEvent | Error) => {\n if (event instanceof NodePyATVDeviceEvent) {\n this.log({\n level: 'info',\n host: device.host,\n message: JSON.stringify(event),\n });\n\n if (this.mqttClient) {\n const value =\n event.value === null ? '' : String(event.value);\n this.mqttClient.publish(\n device.topic + '/' + event.key,\n value,\n { retain: true },\n );\n }\n }\n };\n const errorListener = (error: Error | NodePyATVDeviceEvent) => {\n if (error instanceof Error) {\n this.log({\n level: 'error',\n host: device.host,\n message: 'Push Error',\n error,\n });\n }\n };\n\n atv.on('update', updateListener);\n atv.on('error', errorListener);\n this.teardown.unshift(async () => {\n atv.off('update', updateListener);\n atv.off('error', errorListener);\n });\n\n /* MQTT --> PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.subscribe(device.topic + '/+');\n this.teardown.unshift(() => {\n return new Promise((resolve, reject) => {\n if (this.mqttClient) {\n this.mqttClient.unsubscribe(\n device.topic + '/+',\n (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n },\n );\n }\n });\n });\n\n this.mqttClient.on('message', (topic, body) => {\n if (device.topic + '/launch' === topic) {\n const id = body.toString();\n atv.launchApp(id).catch((error) => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to launch app \"${id}\"`,\n error,\n });\n });\n return;\n }\n\n const key = Object.keys(NodePyATVKeys).find(\n (key) => device.topic + '/' + key === topic,\n ) as NodePyATVKeys | undefined;\n\n if (key) {\n atv.pressKey(key).catch((error) => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to press key \"${key}\"`,\n error,\n });\n });\n }\n });\n }\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.teardown);\n }\n}\n"],"mappings":"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","names":["lib_exports","__export","PyAtvMqttBridge","__toCommonJS","import_mqtt","import_node_pyatv","options","d","err","msg","errorListener","error","resolve","device","atv","pyatv","message","updateListener","event","value","reject","topic","body","id","key"]}
@@ -3,7 +3,7 @@ import { IClientOptions } from 'mqtt';
3
3
 
4
4
  interface Config {
5
5
  broker: string | IClientOptions;
6
- log?: (msg: LogParam) => (void);
6
+ log?: (msg: LogParam) => void;
7
7
  devices: ConfigDevice[];
8
8
  }
9
9
  interface ConfigDevice extends NodePyATVDeviceOptions {
@@ -3,7 +3,7 @@ import { IClientOptions } from 'mqtt';
3
3
 
4
4
  interface Config {
5
5
  broker: string | IClientOptions;
6
- log?: (msg: LogParam) => (void);
6
+ log?: (msg: LogParam) => void;
7
7
  devices: ConfigDevice[];
8
8
  }
9
9
  interface ConfigDevice extends NodePyATVDeviceOptions {
package/dist/lib/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{a}from"../chunk-UHWFNSNC.js";export{a as default};
1
+ import{a}from"../chunk-WNLLGDC3.js";export{a as default};
2
2
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,70 +1,74 @@
1
1
  {
2
- "author": "Sebastian Pekarek <mail@sebbo.net>",
3
- "bin": {
4
- "pyatv-mqtt-bridge": "./dist/bin/cli.js"
5
- },
6
- "bugs": {
7
- "email": "peithosoreixookierah@e.sebbo.net",
8
- "url": "https://github.com/sebbo2002/pyatv-mqtt-bridge/issues"
9
- },
10
- "dependencies": {
11
- "@sebbo2002/node-pyatv": "^8.1.2",
12
- "mqtt": "^5.11.0"
13
- },
14
- "description": "Bridge which allows you to control your Apple TV via MQTT",
15
- "devDependencies": {
16
- "@eslint/js": "^9.25.0",
17
- "@qiwi/semantic-release-gh-pages-plugin": "^5.4.3",
18
- "@sebbo2002/semantic-release-docker": "^5.0.4",
19
- "@semantic-release/changelog": "^6.0.3",
20
- "@semantic-release/exec": "^7.0.3",
21
- "@semantic-release/git": "^10.0.1",
22
- "@semantic-release/github": "^11.0.1",
23
- "@semantic-release/npm": "^12.0.1",
24
- "@types/mocha": "^10.0.10",
25
- "@types/node": "^22.14.0",
26
- "@types/ws": "^8.18.1",
27
- "c8": "^10.1.3",
28
- "eslint": "^9.24.0",
29
- "eslint-plugin-jsonc": "^2.20.0",
30
- "esm": "^3.2.25",
31
- "license-checker": "^25.0.1",
32
- "semantic-release": "^24.2.3",
33
- "semantic-release-license": "^1.0.3",
34
- "source-map-support": "^0.5.21",
35
- "tsup": "^8.4.0",
36
- "tsx": "^4.19.3",
37
- "typedoc": "^0.28.2",
38
- "typescript": "^5.8.3",
39
- "typescript-eslint": "^8.29.0"
40
- },
41
- "engines": {
42
- "node": "18 || 20 || >=22.0.0"
43
- },
44
- "exports": {
45
- "import": "./dist/lib/index.js",
46
- "require": "./dist/lib/index.cjs"
47
- },
48
- "files": [
49
- "/dist"
50
- ],
51
- "homepage": "https://github.com/sebbo2002/pyatv-mqtt-bridge#readme",
52
- "license": "MIT",
53
- "main": "./dist/lib/index.cjs",
54
- "module": "./dist/lib/index.js",
55
- "name": "@sebbo2002/pyatv-mqtt-bridge",
56
- "repository": {
57
- "type": "git",
58
- "url": "https://github.com/sebbo2002/pyatv-mqtt-bridge.git"
59
- },
60
- "scripts": {
61
- "build": "tsup && cp ./dist/lib/index.d.ts ./dist/lib/index.d.cts",
62
- "build-all": "./.github/workflows/build.sh",
63
- "develop": "tsx src/bin/cli.ts",
64
- "license-check": "license-checker --production --summary",
65
- "lint": "eslint .",
66
- "start": "node ./dist/bin/cli.js"
67
- },
68
- "type": "module",
69
- "version": "8.1.1-develop.1"
2
+ "author": "Sebastian Pekarek <mail@sebbo.net>",
3
+ "bin": {
4
+ "pyatv-mqtt-bridge": "./dist/bin/cli.js"
5
+ },
6
+ "bugs": {
7
+ "email": "peithosoreixookierah@e.sebbo.net",
8
+ "url": "https://github.com/sebbo2002/pyatv-mqtt-bridge/issues"
9
+ },
10
+ "dependencies": {
11
+ "@sebbo2002/node-pyatv": "^8.1.2",
12
+ "mqtt": "^5.11.0"
13
+ },
14
+ "description": "Bridge which allows you to control your Apple TV via MQTT",
15
+ "devDependencies": {
16
+ "@eslint/js": "^9.25.0",
17
+ "@qiwi/semantic-release-gh-pages-plugin": "^5.4.3",
18
+ "@sebbo2002/semantic-release-docker": "^5.0.4",
19
+ "@semantic-release/changelog": "^6.0.3",
20
+ "@semantic-release/exec": "^7.0.3",
21
+ "@semantic-release/git": "^10.0.1",
22
+ "@semantic-release/github": "^11.0.1",
23
+ "@semantic-release/npm": "^12.0.1",
24
+ "@types/mocha": "^10.0.10",
25
+ "@types/node": "^22.14.0",
26
+ "@types/ws": "^8.18.1",
27
+ "c8": "^10.1.3",
28
+ "eslint": "^9.24.0",
29
+ "eslint-config-prettier": "^10.1.2",
30
+ "eslint-plugin-jsonc": "^2.20.0",
31
+ "eslint-plugin-perfectionist": "^4.12.3",
32
+ "esm": "^3.2.25",
33
+ "husky": "^9.1.7",
34
+ "license-checker": "^25.0.1",
35
+ "prettier": "^3.5.3",
36
+ "semantic-release": "^24.2.3",
37
+ "semantic-release-license": "^1.0.3",
38
+ "source-map-support": "^0.5.21",
39
+ "tsup": "^8.4.0",
40
+ "tsx": "^4.19.3",
41
+ "typedoc": "^0.28.2",
42
+ "typescript": "^5.8.3",
43
+ "typescript-eslint": "^8.29.0"
44
+ },
45
+ "engines": {
46
+ "node": "18 || 20 || >=22.0.0"
47
+ },
48
+ "exports": {
49
+ "import": "./dist/lib/index.js",
50
+ "require": "./dist/lib/index.cjs"
51
+ },
52
+ "files": [
53
+ "/dist"
54
+ ],
55
+ "homepage": "https://github.com/sebbo2002/pyatv-mqtt-bridge#readme",
56
+ "license": "MIT",
57
+ "main": "./dist/lib/index.cjs",
58
+ "module": "./dist/lib/index.js",
59
+ "name": "@sebbo2002/pyatv-mqtt-bridge",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/sebbo2002/pyatv-mqtt-bridge.git"
63
+ },
64
+ "scripts": {
65
+ "build": "tsup && cp ./dist/lib/index.d.ts ./dist/lib/index.d.cts",
66
+ "build-all": "./.github/workflows/build.sh",
67
+ "develop": "tsx src/bin/cli.ts",
68
+ "license-check": "license-checker --production --summary",
69
+ "lint": "npx eslint . --fix && npx prettier . --write",
70
+ "start": "node ./dist/bin/cli.js"
71
+ },
72
+ "type": "module",
73
+ "version": "8.1.1-develop.2"
70
74
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/index.ts"],"sourcesContent":["'use strict';\n\nimport type {Config, ConfigDevice, LogParam} from './types.js';\nimport {connect, MqttClient} from 'mqtt';\nimport pyatv, {NodePyATVDeviceEvent, NodePyATVKeys} from '@sebbo2002/node-pyatv';\n\nexport default class PyAtvMqttBridge {\n private mqttClient: MqttClient | null = null;\n private readonly options: Config;\n private readonly teardown: Array<() => Promise<void>> = [];\n\n constructor(options: Config) {\n if (!options.broker) {\n throw new Error('options.broker is not set!');\n }\n if (!Array.isArray(options.devices) || !options.devices.length) {\n throw new Error('options.devices is not set!');\n }\n if (options.devices.find(d => typeof d.topic !== 'string')) {\n throw new Error('options.devices.topic is not set!');\n }\n if (options.devices.find(d => typeof d.host !== 'string')) {\n throw new Error('options.devices.host is not set!');\n }\n if (options.devices.find(d => typeof d.name !== 'string')) {\n throw new Error('options.devices.name is not set!');\n }\n\n this.options = options;\n this.teardown = [];\n\n this.start().catch(err => {\n this.log({\n level: 'error',\n host: null,\n message: 'Unable to start bridge',\n error: err\n });\n });\n }\n\n private log(msg: LogParam) {\n if (this.options.log) {\n try {\n this.options.log.apply(this, [msg]);\n } catch (err) {\n console.log('Unable to call custom log function:');\n console.log(err);\n }\n }\n }\n\n private async start() {\n const errorListener = (error: Error) => this.log({\n level: 'error',\n host: null,\n message: 'MQTT error',\n error\n });\n\n // this.mqttClient = connect(this.options.broker);\n if (typeof this.options.broker === 'string') {\n this.mqttClient = connect(this.options.broker);\n } else {\n this.mqttClient = connect(this.options.broker);\n }\n\n this.mqttClient.on('error', errorListener);\n this.teardown.unshift(async () => {\n if (this.mqttClient) {\n this.mqttClient.off('error', errorListener);\n await new Promise(resolve => {\n if (this.mqttClient) {\n this.mqttClient.end(false, () => resolve(undefined));\n }\n });\n }\n });\n\n await Promise.all(\n this.options.devices.map(device => this.startDevice(device))\n );\n }\n\n private async startDevice(device: ConfigDevice) {\n this.log({\n level: 'info',\n host: device.host,\n message: 'Setup device…'\n });\n\n const atv = pyatv.device(Object.assign({}, device, {\n debug: (message: string) => this.log({\n level: 'info',\n host: device.host,\n message\n })\n }));\n\n\n /* MQTT <-- PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.publish(device.topic + '/host', device.host, {retain: true});\n this.mqttClient.publish(device.topic + '/name', device.name, {retain: true});\n this.mqttClient.publish(device.topic + '/id', device.id || '', {retain: true});\n }\n\n const updateListener = (event: NodePyATVDeviceEvent | Error) => {\n if(event instanceof NodePyATVDeviceEvent) {\n this.log({\n level: 'info',\n host: device.host,\n message: JSON.stringify(event)\n });\n\n if (this.mqttClient) {\n const value = event.value === null ? '' : String(event.value);\n this.mqttClient.publish(device.topic + '/' + event.key, value, {retain: true});\n }\n }\n };\n const errorListener = (error: Error | NodePyATVDeviceEvent) => {\n if (error instanceof Error) {\n this.log({\n level: 'error',\n host: device.host,\n message: 'Push Error',\n error\n });\n }\n };\n\n atv.on('update', updateListener);\n atv.on('error', errorListener);\n this.teardown.unshift(async () => {\n atv.off('update', updateListener);\n atv.off('error', errorListener);\n });\n\n\n /* MQTT --> PYATV */\n\n if (this.mqttClient) {\n this.mqttClient.subscribe(device.topic + '/+');\n this.teardown.unshift(() => {\n return new Promise((resolve, reject) => {\n if(this.mqttClient) {\n this.mqttClient.unsubscribe(device.topic + '/+', error => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n }\n });\n });\n\n this.mqttClient.on('message', (topic, body) => {\n if (device.topic + '/launch' === topic) {\n const id = body.toString();\n atv.launchApp(id).catch(error => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to launch app \"${id}\"`,\n error\n });\n });\n return;\n }\n\n const key = Object\n .keys(NodePyATVKeys)\n .find(key => device.topic + '/' + key === topic) as NodePyATVKeys | undefined;\n\n if(key) {\n atv.pressKey(key).catch(error => {\n this.log({\n level: 'error',\n host: device.host,\n message: `Unable to press key \"${key}\"`,\n error\n });\n });\n }\n });\n }\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.teardown);\n }\n}\n"],"mappings":"AAGA,OAAQ,WAAAA,MAA0B,OAClC,OAAOC,GAAQ,wBAAAC,EAAsB,iBAAAC,MAAoB,wBAEzD,IAAqBC,EAArB,KAAqC,CACzB,WAAgC,KACvB,QACA,SAAuC,CAAC,EAEzD,YAAYC,EAAiB,CACzB,GAAI,CAACA,EAAQ,OACT,MAAM,IAAI,MAAM,4BAA4B,EAEhD,GAAI,CAAC,MAAM,QAAQA,EAAQ,OAAO,GAAK,CAACA,EAAQ,QAAQ,OACpD,MAAM,IAAI,MAAM,6BAA6B,EAEjD,GAAIA,EAAQ,QAAQ,KAAKC,GAAK,OAAOA,EAAE,OAAU,QAAQ,EACrD,MAAM,IAAI,MAAM,mCAAmC,EAEvD,GAAID,EAAQ,QAAQ,KAAKC,GAAK,OAAOA,EAAE,MAAS,QAAQ,EACpD,MAAM,IAAI,MAAM,kCAAkC,EAEtD,GAAID,EAAQ,QAAQ,KAAKC,GAAK,OAAOA,EAAE,MAAS,QAAQ,EACpD,MAAM,IAAI,MAAM,kCAAkC,EAGtD,KAAK,QAAUD,EACf,KAAK,SAAW,CAAC,EAEjB,KAAK,MAAM,EAAE,MAAME,GAAO,CACtB,KAAK,IAAI,CACL,MAAO,QACP,KAAM,KACN,QAAS,yBACT,MAAOA,CACX,CAAC,CACL,CAAC,CACL,CAEQ,IAAIC,EAAe,CACvB,GAAI,KAAK,QAAQ,IACb,GAAI,CACA,KAAK,QAAQ,IAAI,MAAM,KAAM,CAACA,CAAG,CAAC,CACtC,OAASD,EAAK,CACV,QAAQ,IAAI,qCAAqC,EACjD,QAAQ,IAAIA,CAAG,CACnB,CAER,CAEA,MAAc,OAAQ,CAClB,IAAME,EAAiBC,GAAiB,KAAK,IAAI,CAC7C,MAAO,QACP,KAAM,KACN,QAAS,aACT,MAAAA,CACJ,CAAC,EAGG,OAAO,KAAK,QAAQ,QAAW,SAC/B,KAAK,WAAaV,EAAQ,KAAK,QAAQ,MAAM,EAE7C,KAAK,WAAaA,EAAQ,KAAK,QAAQ,MAAM,EAGjD,KAAK,WAAW,GAAG,QAASS,CAAa,EACzC,KAAK,SAAS,QAAQ,SAAY,CAC1B,KAAK,aACL,KAAK,WAAW,IAAI,QAASA,CAAa,EAC1C,MAAM,IAAI,QAAQE,GAAW,CACrB,KAAK,YACL,KAAK,WAAW,IAAI,GAAO,IAAMA,EAAQ,MAAS,CAAC,CAE3D,CAAC,EAET,CAAC,EAED,MAAM,QAAQ,IACV,KAAK,QAAQ,QAAQ,IAAIC,GAAU,KAAK,YAAYA,CAAM,CAAC,CAC/D,CACJ,CAEA,MAAc,YAAYA,EAAsB,CAC5C,KAAK,IAAI,CACL,MAAO,OACP,KAAMA,EAAO,KACb,QAAS,oBACb,CAAC,EAED,IAAMC,EAAMZ,EAAM,OAAO,OAAO,OAAO,CAAC,EAAGW,EAAQ,CAC/C,MAAQE,GAAoB,KAAK,IAAI,CACjC,MAAO,OACP,KAAMF,EAAO,KACb,QAAAE,CACJ,CAAC,CACL,CAAC,CAAC,EAKE,KAAK,aACL,KAAK,WAAW,QAAQF,EAAO,MAAQ,QAASA,EAAO,KAAM,CAAC,OAAQ,EAAI,CAAC,EAC3E,KAAK,WAAW,QAAQA,EAAO,MAAQ,QAASA,EAAO,KAAM,CAAC,OAAQ,EAAI,CAAC,EAC3E,KAAK,WAAW,QAAQA,EAAO,MAAQ,MAAOA,EAAO,IAAM,GAAI,CAAC,OAAQ,EAAI,CAAC,GAGjF,IAAMG,EAAkBC,GAAwC,CAC5D,GAAGA,aAAiBd,IAChB,KAAK,IAAI,CACL,MAAO,OACP,KAAMU,EAAO,KACb,QAAS,KAAK,UAAUI,CAAK,CACjC,CAAC,EAEG,KAAK,YAAY,CACjB,IAAMC,EAAQD,EAAM,QAAU,KAAO,GAAK,OAAOA,EAAM,KAAK,EAC5D,KAAK,WAAW,QAAQJ,EAAO,MAAQ,IAAMI,EAAM,IAAKC,EAAO,CAAC,OAAQ,EAAI,CAAC,CACjF,CAER,EACMR,EAAiBC,GAAwC,CACvDA,aAAiB,OACjB,KAAK,IAAI,CACL,MAAO,QACP,KAAME,EAAO,KACb,QAAS,aACT,MAAAF,CACJ,CAAC,CAET,EAEAG,EAAI,GAAG,SAAUE,CAAc,EAC/BF,EAAI,GAAG,QAASJ,CAAa,EAC7B,KAAK,SAAS,QAAQ,SAAY,CAC9BI,EAAI,IAAI,SAAUE,CAAc,EAChCF,EAAI,IAAI,QAASJ,CAAa,CAClC,CAAC,EAKG,KAAK,aACL,KAAK,WAAW,UAAUG,EAAO,MAAQ,IAAI,EAC7C,KAAK,SAAS,QAAQ,IACX,IAAI,QAAQ,CAACD,EAASO,IAAW,CACjC,KAAK,YACJ,KAAK,WAAW,YAAYN,EAAO,MAAQ,KAAMF,GAAS,CAClDA,EACAQ,EAAOR,CAAK,EAEZC,EAAQ,CAEhB,CAAC,CAET,CAAC,CACJ,EAED,KAAK,WAAW,GAAG,UAAW,CAACQ,EAAOC,IAAS,CAC3C,GAAIR,EAAO,MAAQ,YAAcO,EAAO,CACpC,IAAME,EAAKD,EAAK,SAAS,EACzBP,EAAI,UAAUQ,CAAE,EAAE,MAAMX,GAAS,CAC7B,KAAK,IAAI,CACL,MAAO,QACP,KAAME,EAAO,KACb,QAAS,yBAAyBS,CAAE,IACpC,MAAAX,CACJ,CAAC,CACL,CAAC,EACD,MACJ,CAEA,IAAMY,EAAM,OACP,KAAKnB,CAAa,EAClB,KAAKmB,GAAOV,EAAO,MAAQ,IAAMU,IAAQH,CAAK,EAEhDG,GACCT,EAAI,SAASS,CAAG,EAAE,MAAMZ,GAAS,CAC7B,KAAK,IAAI,CACL,MAAO,QACP,KAAME,EAAO,KACb,QAAS,wBAAwBU,CAAG,IACpC,MAAAZ,CACJ,CAAC,CACL,CAAC,CAET,CAAC,EAET,CAEA,MAAM,MAAsB,CACxB,MAAM,QAAQ,IAAI,KAAK,QAAQ,CACnC,CACJ","names":["connect","pyatv","NodePyATVDeviceEvent","NodePyATVKeys","PyAtvMqttBridge","options","d","err","msg","errorListener","error","resolve","device","atv","message","updateListener","event","value","reject","topic","body","id","key"]}