107 lines
3.4 KiB
TypeScript
107 lines
3.4 KiB
TypeScript
import config from "config";
|
|
import WebSocket from "ws";
|
|
import child_process from "child_process";
|
|
|
|
const metadataSeparator = '\n';
|
|
/**
|
|
* Watch My Stream (watch-my.stream) music widget
|
|
*/
|
|
export default class WMSMusicWidget {
|
|
private readonly webSocketAddress: string = config.get<string>('wms.music_widget.ws');
|
|
private readonly token: string = config.get<string>('wms.music_widget.token');
|
|
private activeSocket?: WebSocket;
|
|
private checkInterval?: NodeJS.Timeout;
|
|
private lastSentData?: string;
|
|
|
|
public constructor() {
|
|
}
|
|
|
|
|
|
public async start(): Promise<void> {
|
|
if (!this.token || this.token === 'default') {
|
|
console.warn('WMS music widget not started due to missing token.');
|
|
return;
|
|
}
|
|
|
|
this.startWebSocket();
|
|
|
|
this.checkInterval = setInterval(async () => {
|
|
try {
|
|
if (this.activeSocket) {
|
|
const metadata = (await this.getInfo()).split(metadataSeparator);
|
|
const data = JSON.stringify({
|
|
playing: metadata[0] === 'Playing',
|
|
author: metadata[1],
|
|
title: metadata[2],
|
|
album: metadata[3],
|
|
artUrl: metadata[4],
|
|
});
|
|
if (this.lastSentData !== data) {
|
|
console.log('WMS music widget out:', data);
|
|
this.activeSocket.send(data);
|
|
this.lastSentData = data;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
public async stop(): Promise<void> {
|
|
if (typeof this.checkInterval !== 'undefined') {
|
|
clearInterval(this.checkInterval);
|
|
this.checkInterval = undefined;
|
|
}
|
|
}
|
|
|
|
private startWebSocket() {
|
|
const socket = new WebSocket(this.webSocketAddress, {});
|
|
|
|
socket.on('error', (event) => {
|
|
console.error(event);
|
|
});
|
|
socket.on('close', (code, reason) => {
|
|
this.activeSocket = undefined;
|
|
console.log(`WMS music widget WS closed ${code} ${reason}. Retrying in 2s...`);
|
|
setTimeout(() => this.startWebSocket(), 2000);
|
|
});
|
|
socket.on('open', () => {
|
|
socket.send(JSON.stringify({
|
|
token: this.token,
|
|
type: 'emitter',
|
|
}));
|
|
});
|
|
|
|
socket.on('message', data => {
|
|
console.log('WMS music widget WebSocket ready!');
|
|
this.activeSocket = socket;
|
|
});
|
|
}
|
|
|
|
private async getInfo(): Promise<string> {
|
|
const format = [
|
|
'status',
|
|
'artist',
|
|
'title',
|
|
'album',
|
|
'mpris:artUrl',
|
|
].map(s => '{{' + s + '}}').join(metadataSeparator);
|
|
return await this.runCommand(`playerctl metadata -f "${format}" | sed "s/open\\.spotify\\.com/i.scdn.co/"`);
|
|
}
|
|
|
|
private async runCommand(command: string): Promise<string> {
|
|
// console.info(`> ${command}`);
|
|
return new Promise<string>((resolve, reject) => {
|
|
child_process.exec(command, {}, (err, stdout, stderr) => {
|
|
if (err) {
|
|
console.error(stderr);
|
|
reject(err);
|
|
return;
|
|
}
|
|
|
|
resolve(stdout);
|
|
});
|
|
});
|
|
}
|
|
} |