librespot-to-mqtt/index.mjs
2022-05-09 20:42:29 +02:00

68 lines
1.8 KiB
JavaScript

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));
});