@sebbo2002/pyatv-mqtt-bridge 9.0.1-develop.2 → 9.0.1-develop.4
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/dist/bin/cli.cjs +1 -1
- package/dist/bin/cli.cjs.map +1 -1
- package/dist/bin/cli.js +1 -1
- package/dist/{chunk-WNLLGDC3.js → chunk-DZ7PWRQL.js} +2 -2
- package/dist/chunk-DZ7PWRQL.js.map +1 -0
- package/dist/lib/index.cjs +1 -1
- package/dist/lib/index.cjs.map +1 -1
- package/dist/lib/index.d.cts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +1 -1
- package/package.json +9 -9
- package/dist/chunk-WNLLGDC3.js.map +0 -1
package/dist/bin/cli.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var v=Object.create;var m=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var P=(e,t,o,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of C(t))!w.call(e,s)&&s!==o&&m(e,s,{get:()=>t[s],enumerable:!(a=b(t,s))||a.enumerable});return e};var E=(e,t,o)=>(o=e!=null?v(q(e)):{},P(t||!e||!e.__esModule?m(o,"default",{value:e,enumerable:!0}):o,e));var f=require("fs"),u=require("path");var p=require("mqtt"),l=E(require("@sebbo2002/node-pyatv"),1),c=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(o=>typeof o.topic!="string"))throw new Error("options.devices.topic is not set!");if(t.devices.find(o=>typeof o.host!="string"))throw new Error("options.devices.host is not set!");if(t.devices.find(o=>typeof o.name!="string"))throw new Error("options.devices.name is not set!");this.options=t,this.teardown=[],this.start().catch(o=>{this.log({level:"error",host:null,message:"Unable to start bridge",error:o})})}log(t){if(this.options.log)try{this.options.log.apply(this,[t])}catch(o){console.log("Unable to call custom log function:"),console.log(o)}}async start(){let t=o=>this.log({level:"error",host:null,message:"MQTT error",error:o});typeof this.options.broker=="string"?this.mqttClient=(0,p.connect)(this.options.broker):this.mqttClient=(0,p.connect)(this.options.broker),this.mqttClient.on("error",t),this.teardown.unshift(async()=>{this.mqttClient&&(this.mqttClient.off("error",t),await new Promise(o=>{this.mqttClient&&this.mqttClient.end(!1,()=>o(void 0))}))}),await Promise.all(this.options.devices.map(o=>this.startDevice(o)))}async startDevice(t){this.log({level:"info",host:t.host,message:"Setup device\u2026"});let o=l.default.device(Object.assign({},t,{debug:r=>this.log({level:"info",host:t.host,message:r})}));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 a=r=>{if(r instanceof l.NodePyATVDeviceEvent&&(this.log({level:"info",host:t.host,message:JSON.stringify(r)}),this.mqttClient)){let h=r.value===null?"":String(r.value);this.mqttClient.publish(t.topic+"/"+r.key,h,{retain:!0})}},s=r=>{r instanceof Error&&this.log({level:"error",host:t.host,message:"Push Error",error:r})};o.on("update",a),o.on("error",s),this.teardown.unshift(async()=>{o.off("update",a),o.off("error",s)}),this.mqttClient&&(this.mqttClient.subscribe(t.topic+"/+"),this.teardown.unshift(()=>new Promise((r,h)=>{this.mqttClient&&this.mqttClient.unsubscribe(t.topic+"/+",i=>{i?h(i):r()})})),this.mqttClient.on("message",(r,h)=>{if(t.topic+"/launch"===r){let n=h.toString();o.launchApp(n).catch(d=>{this.log({level:"error",host:t.host,message:`Unable to launch app "${n}"`,error:d})});return}let i=Object.keys(l.NodePyATVKeys).find(n=>t.topic+"/"+n===r);i&&o.pressKey(i).catch(n=>{this.log({level:"error",host:t.host,message:`Unable to press key "${i}"`,error:n})})}))}async stop(){await Promise.all(this.teardown)}};console.log("# pyatv-mqtt-bridge");console.log("----------------------------");var k=process.argv.indexOf("--debug")>-1,y=(0,u.resolve)(process.cwd(),process.argv[process.argv.length-1]);(0,f.existsSync)(y)||(console.log("Usage: pyatv-mqtt-bridge [--debug] ~/pyatv-mqtt-bridge-config.json"),process.exit(1));var g;try{g=JSON.parse((0,f.readFileSync)(y,"utf8"))}catch(e){console.log("Unable to parse configuration file:"),console.log(e),console.log(`
|
|
2
|
+
"use strict";var v=Object.create;var m=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var P=(e,t,o,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of C(t))!w.call(e,s)&&s!==o&&m(e,s,{get:()=>t[s],enumerable:!(a=b(t,s))||a.enumerable});return e};var E=(e,t,o)=>(o=e!=null?v(q(e)):{},P(t||!e||!e.__esModule?m(o,"default",{value:e,enumerable:!0}):o,e));var f=require("fs"),u=require("path");var p=require("mqtt"),l=E(require("@sebbo2002/node-pyatv"),1),c=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(o=>typeof o.topic!="string"))throw new Error("options.devices.topic is not set!");if(t.devices.find(o=>typeof o.host!="string"))throw new Error("options.devices.host is not set!");if(t.devices.find(o=>typeof o.name!="string"))throw new Error("options.devices.name is not set!");this.options=t,this.teardown=[],this.start().catch(o=>{this.log({level:"error",host:null,message:"Unable to start bridge",error:o})})}log(t){if(this.options.log)try{this.options.log.apply(this,[t])}catch(o){console.log("Unable to call custom log function:"),console.log(o)}}async start(){let t=o=>this.log({level:"error",host:null,message:"MQTT error",error:o});typeof this.options.broker=="string"?this.mqttClient=(0,p.connect)(this.options.broker):this.mqttClient=(0,p.connect)(this.options.broker),this.mqttClient.on("error",t),this.teardown.unshift(async()=>{this.mqttClient&&(this.mqttClient.off("error",t),await new Promise(o=>{this.mqttClient&&this.mqttClient.end(!1,()=>o(void 0))}))}),await Promise.all(this.options.devices.map(o=>this.startDevice(o)))}async startDevice(t){this.log({level:"info",host:t.host,message:"Setup device\u2026"});let o=l.default.device(Object.assign({},t,{debug:r=>this.log({level:"info",host:t.host,message:r})}));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 a=r=>{if(r instanceof l.NodePyATVDeviceEvent&&(this.log({level:"info",host:t.host,message:JSON.stringify(r)}),this.mqttClient)){let h=r.value===null?"":String(r.value);this.mqttClient.publish(t.topic+"/"+r.key,h,{retain:!0})}},s=r=>{r instanceof Error&&this.log({level:"error",host:t.host,message:"Push Error",error:r})};o.on("update",a),o.on("error",s),this.teardown.unshift(async()=>{o.off("update",a),o.off("error",s)}),this.mqttClient&&(this.mqttClient.subscribe(t.topic+"/+"),this.teardown.unshift(()=>new Promise((r,h)=>{this.mqttClient&&this.mqttClient.unsubscribe(t.topic+"/+",i=>{i?h(i):r()})})),this.mqttClient.on("message",(r,h)=>{if(t.topic+"/launch"===r){let n=h.toString();o.launchApp(n).catch(d=>{this.log({level:"error",host:t.host,message:`Unable to launch app "${n}"`,error:d})});return}let i=Object.keys(l.NodePyATVKeys).find(n=>t.topic+"/"+n===r);i&&o.pressKey(i).catch(n=>{this.log({level:"error",host:t.host,message:`Unable to press key "${i}"`,error:n})})}))}async stop(){await Promise.all(this.teardown)}};console.log("# pyatv-mqtt-bridge");console.log("----------------------------");var k=process.argv.indexOf("--debug")>-1,y=(0,u.resolve)(process.cwd(),process.argv[process.argv.length-1]);(0,f.existsSync)(y)||(console.log("Usage: pyatv-mqtt-bridge [--debug] ~/pyatv-mqtt-bridge-config.json"),process.exit(1));var g;try{g=JSON.parse((0,f.readFileSync)(y,"utf8"))}catch(e){console.log("Unable to parse configuration file:"),console.log(e),console.log(`
|
|
3
3
|
Have you removed the comments?
|
|
4
4
|
`),process.exit(1)}try{k&&Object.assign(g,{log:e=>{let t=`[${e.level}]`;e.host&&(t+=`[${e.host}]`),t+=" ",e.message&&(t+=e.message),e.message&&e.error&&(t+=": "),e.error&&e.error.stack&&(t+=e.error.stack),e.error&&(t+=e.error.toString()),console.log(t)}}),new c(g)}catch(e){console.log("Unable to start bridge:"),console.log(e)}
|
|
5
5
|
//# sourceMappingURL=cli.cjs.map
|
package/dist/bin/cli.cjs.map
CHANGED
|
@@ -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(\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"]}
|
|
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-
|
|
2
|
+
import{a as t}from"../chunk-DZ7PWRQL.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,2 +1,2 @@
|
|
|
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-
|
|
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-DZ7PWRQL.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"]}
|
package/dist/lib/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var u=Object.create;var f=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var C=Object.getPrototypeOf,b=Object.prototype.hasOwnProperty;var v=(s,t)=>{for(var e in t)f(s,e,{get:t[e],enumerable:!0})},m=(s,t,e,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of d(t))!b.call(s,o)&&o!==e&&f(s,o,{get:()=>t[o],enumerable:!(a=y(t,o))||a.enumerable});return s};var w=(s,t,e)=>(e=s!=null?u(C(s)):{},m(t||!s||!s.__esModule?f(e,"default",{value:s,enumerable:!0}):e,s)),q=s=>m(f({},"__esModule",{value:!0}),s);var E={};v(E,{default:()=>c});module.exports=q(E);var p=require("mqtt"),l=w(require("@sebbo2002/node-pyatv"),1),c=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=(0,p.connect)(this.options.broker):this.mqttClient=(0,p.connect)(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=l.default.device(Object.assign({},t,{debug:i=>this.log({level:"info",host:t.host,message:i})}));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 a=i=>{if(i instanceof l.NodePyATVDeviceEvent&&(this.log({level:"info",host:t.host,message:JSON.stringify(i)}),this.mqttClient)){let h=i.value===null?"":String(i.value);this.mqttClient.publish(t.topic+"/"+i.key,h,{retain:!0})}},o=i=>{i instanceof Error&&this.log({level:"error",host:t.host,message:"Push Error",error:i})};e.on("update",a),e.on("error",o),this.teardown.unshift(async()=>{e.off("update",a),e.off("error",o)}),this.mqttClient&&(this.mqttClient.subscribe(t.topic+"/+"),this.teardown.unshift(()=>new Promise((i,h)=>{this.mqttClient&&this.mqttClient.unsubscribe(t.topic+"/+",r=>{r?h(r):i()})})),this.mqttClient.on("message",(i,h)=>{if(t.topic+"/launch"===i){let n=h.toString();e.launchApp(n).catch(g=>{this.log({level:"error",host:t.host,message:`Unable to launch app "${n}"`,error:g})});return}let r=Object.keys(l.NodePyATVKeys).find(n=>t.topic+"/"+n===i);r&&e.pressKey(r).catch(n=>{this.log({level:"error",host:t.host,message:`Unable to press key "${r}"`,error:n})})}))}async stop(){await Promise.all(this.teardown)}};
|
|
1
|
+
"use strict";var u=Object.create;var f=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var C=Object.getPrototypeOf,b=Object.prototype.hasOwnProperty;var v=(s,t)=>{for(var e in t)f(s,e,{get:t[e],enumerable:!0})},m=(s,t,e,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of d(t))!b.call(s,o)&&o!==e&&f(s,o,{get:()=>t[o],enumerable:!(a=y(t,o))||a.enumerable});return s};var w=(s,t,e)=>(e=s!=null?u(C(s)):{},m(t||!s||!s.__esModule?f(e,"default",{value:s,enumerable:!0}):e,s)),q=s=>m(f({},"__esModule",{value:!0}),s);var E={};v(E,{default:()=>c});module.exports=q(E);var p=require("mqtt"),l=w(require("@sebbo2002/node-pyatv"),1),c=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=(0,p.connect)(this.options.broker):this.mqttClient=(0,p.connect)(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=l.default.device(Object.assign({},t,{debug:i=>this.log({level:"info",host:t.host,message:i})}));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 a=i=>{if(i instanceof l.NodePyATVDeviceEvent&&(this.log({level:"info",host:t.host,message:JSON.stringify(i)}),this.mqttClient)){let h=i.value===null?"":String(i.value);this.mqttClient.publish(t.topic+"/"+i.key,h,{retain:!0})}},o=i=>{i instanceof Error&&this.log({level:"error",host:t.host,message:"Push Error",error:i})};e.on("update",a),e.on("error",o),this.teardown.unshift(async()=>{e.off("update",a),e.off("error",o)}),this.mqttClient&&(this.mqttClient.subscribe(t.topic+"/+"),this.teardown.unshift(()=>new Promise((i,h)=>{this.mqttClient&&this.mqttClient.unsubscribe(t.topic+"/+",r=>{r?h(r):i()})})),this.mqttClient.on("message",(i,h)=>{if(t.topic+"/launch"===i){let n=h.toString();e.launchApp(n).catch(g=>{this.log({level:"error",host:t.host,message:`Unable to launch app "${n}"`,error:g})});return}let r=Object.keys(l.NodePyATVKeys).find(n=>t.topic+"/"+n===i);r&&e.pressKey(r).catch(n=>{this.log({level:"error",host:t.host,message:`Unable to press key "${r}"`,error:n})})}))}async stop(){await Promise.all(this.teardown)}};
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/lib/index.cjs.map
CHANGED
|
@@ -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, {\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"]}
|
|
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"]}
|
package/dist/lib/index.d.cts
CHANGED
package/dist/lib/index.d.ts
CHANGED
package/dist/lib/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a}from"../chunk-
|
|
1
|
+
import{a}from"../chunk-DZ7PWRQL.js";export{a as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
"url": "https://github.com/sebbo2002/pyatv-mqtt-bridge/issues"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@sebbo2002/node-pyatv": "^
|
|
12
|
-
"mqtt": "^5.
|
|
11
|
+
"@sebbo2002/node-pyatv": "^9.0.0",
|
|
12
|
+
"mqtt": "^5.13.0"
|
|
13
13
|
},
|
|
14
14
|
"description": "Bridge which allows you to control your Apple TV via MQTT",
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@eslint/js": "^9.
|
|
16
|
+
"@eslint/js": "^9.26.0",
|
|
17
17
|
"@qiwi/semantic-release-gh-pages-plugin": "^5.4.3",
|
|
18
|
-
"@sebbo2002/semantic-release-docker": "^
|
|
18
|
+
"@sebbo2002/semantic-release-docker": "^6.0.0",
|
|
19
19
|
"@semantic-release/changelog": "^6.0.3",
|
|
20
|
-
"@semantic-release/exec": "^7.0
|
|
20
|
+
"@semantic-release/exec": "^7.1.0",
|
|
21
21
|
"@semantic-release/git": "^10.0.1",
|
|
22
22
|
"@semantic-release/github": "^11.0.2",
|
|
23
23
|
"@semantic-release/npm": "^12.0.1",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@types/ws": "^8.18.1",
|
|
27
27
|
"c8": "^10.1.3",
|
|
28
28
|
"eslint": "^9.25.1",
|
|
29
|
-
"eslint-config-prettier": "^10.1.
|
|
29
|
+
"eslint-config-prettier": "^10.1.5",
|
|
30
30
|
"eslint-plugin-jsonc": "^2.20.0",
|
|
31
31
|
"eslint-plugin-perfectionist": "^4.12.3",
|
|
32
32
|
"esm": "^3.2.25",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"semantic-release-license": "^1.0.3",
|
|
38
38
|
"source-map-support": "^0.5.21",
|
|
39
39
|
"tsup": "^8.4.0",
|
|
40
|
-
"tsx": "^4.19.
|
|
41
|
-
"typedoc": "^0.28.
|
|
40
|
+
"tsx": "^4.19.4",
|
|
41
|
+
"typedoc": "^0.28.4",
|
|
42
42
|
"typescript": "^5.8.3",
|
|
43
43
|
"typescript-eslint": "^8.31.1"
|
|
44
44
|
},
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"start": "node ./dist/bin/cli.js"
|
|
71
71
|
},
|
|
72
72
|
"type": "module",
|
|
73
|
-
"version": "9.0.1-develop.
|
|
73
|
+
"version": "9.0.1-develop.4"
|
|
74
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, {\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"]}
|