diff --git a/index.mjs b/index.mjs new file mode 100644 index 0000000..5a20937 --- /dev/null +++ b/index.mjs @@ -0,0 +1,68 @@ +import WebSocket from "ws"; +import { connect } from "mqtt"; +import secrets from "./secrets.mjs"; + +let ws; +const wsConnect = () => { + ws = new WebSocket(secrets.wsUrl); + ws.on("close", () => { + ws = undefined; + setTimeout(wsConnect, 10000); // Retry after 10 seconds + }); + ws.on("error", () => { + ws = undefined; + setTimeout(wsConnect, 10000); // Retry after 10 seconds + }); +} +do { + wsConnect(); +} while(!ws); + +const client = connect(secrets.mqttUrl, { + username: secrets.mqttUser, + password: secrets.mqttPass, + protocol: "ws", + reconnectPeriod: 10000, // Retry after 10 seconds +}); + +function metaFromMetadata(metadata) { + const meta = { + title: metadata.name, + album: metadata.album.name, + artist: metadata.artist.map(artist => artist.name) + }; + const cover = metadata.album.coverGroup.image.find(image => image.size.toLowerCase() === "default"); + if (cover) { + meta.cover = `https://i.scdn.co/image/${cover.fileId.toLowerCase()}`; + } + + return meta; +} + +ws.on("message", (data) => { + if (!client.connected) return; + + const parsed = JSON.parse(data); + let message = {}; + + switch (parsed.event) { + case "trackChanged": + case "playbackResumed": + message.playbackState = "PLAYING"; + case "metadataAvailable": + if (parsed.track) message = {...message, ...metaFromMetadata(parsed.track)}; + break; + case "playbackPaused": + message.playbackState = "PAUSED"; + break; + case "sessionCleared": + case "playbackEnded": + case "inactiveSession": + case "connectionDropped": + default: + message.playbackState = "STOPPED"; + break; + } + + client.publish(secrets.mqttTopic, JSON.stringify(message)); +}); \ No newline at end of file