orchard/src/main/base/wsapi.ts
Core 05d32089dd
fix: Bump to ESM and update all deps (#1851)
* chore: Bump various packages

* feat: Update everything to ESM

* fix: building and porting js to cjs
2024-05-18 16:29:24 +01:00

425 lines
14 KiB
TypeScript

import WebSocket, { WebSocketServer } from 'ws';
import electron from "electron";
interface standardResponse {
status?: Number;
message?: String;
data?: any;
type?: string;
}
export class wsapi {
static clients: any;
port: any = 26369;
wss: any = null;
clients: any = [];
private _win: any;
constructor(win: any) {
this._win = win;
}
createId() {
// create random guid
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
public async InitWebSockets() {
electron.ipcMain.on("wsapi-updatePlaybackState", (_event: any, arg: any) => {
this.updatePlaybackState(arg);
});
electron.ipcMain.on("wsapi-returnQueue", (_event: any, arg: any) => {
this.returnQueue(JSON.parse(arg));
});
electron.ipcMain.on("wsapi-returnSearch", (_event: any, arg: any) => {
console.log("SEARCH");
this.returnSearch(JSON.parse(arg));
});
electron.ipcMain.on("wsapi-returnSearchLibrary", (_event: any, arg: any) => {
this.returnSearchLibrary(JSON.parse(arg));
});
electron.ipcMain.on("wsapi-returnDynamic", (_event: any, arg: any, type: any) => {
this.returnDynamic(JSON.parse(arg), type);
});
electron.ipcMain.on("wsapi-returnMusicKitApi", (_event: any, arg: any, method: any) => {
this.returnMusicKitApi(JSON.parse(arg), method);
});
electron.ipcMain.on("wsapi-returnLyrics", (_event: any, arg: any) => {
this.returnLyrics(JSON.parse(arg));
});
electron.ipcMain.on("wsapi-returnvolumeMax", (_event: any, arg: any) => {
this.returnmaxVolume(JSON.parse(arg));
});
electron.ipcMain.on("wsapi-libraryStatus", (_event: any, inLibrary: boolean, rating: number) => {
this.returnLibraryStatus(inLibrary, rating);
});
electron.ipcMain.on("wsapi-rate", (_event: any, kind: string, id: string, rating: number) => {
this.returnRatingStatus(kind, id, rating);
});
electron.ipcMain.on("wsapi-change-library", (_event: any, kind: string, id: string, shouldAdd: boolean) => {
this.returnLibraryChange(kind, id, shouldAdd);
});
this.wss = new WebSocketServer({
port: this.port,
perMessageDeflate: {
zlibDeflateOptions: {
// See zlib defaults.
chunkSize: 1024,
memLevel: 7,
level: 3,
},
zlibInflateOptions: {
chunkSize: 10 * 1024,
},
// Other options settable:
clientNoContextTakeover: true, // Defaults to negotiated value.
serverNoContextTakeover: true, // Defaults to negotiated value.
serverMaxWindowBits: 10, // Defaults to negotiated value.
// Below options specified as default values.
concurrencyLimit: 10, // Limits zlib concurrency for perf.
threshold: 1024, // Size (in bytes) below which messages
// should not be compressed if context takeover is disabled.
},
});
console.log(`WebSocketServer started on port: ${this.port}`);
const defaultResponse: standardResponse = {
status: 0,
data: {},
message: "OK",
type: "generic",
};
this.wss.on("connection", (ws: any) => {
ws.id = this.createId();
console.log(`Client ${ws.id} connected`);
this.clients.push(ws);
ws.on("message", function incoming(_message: any) {});
// ws on message
ws.on("message", (message: any) => {
let data = JSON.parse(message);
let response: standardResponse = {
status: 0,
data: {},
message: "OK",
type: "generic",
};
if (data.action) {
data.action.toLowerCase();
}
switch (data.action) {
default:
response.message = "Action not found";
break;
case "identify":
response.message = "Thanks for identifying!";
response.data = {
id: ws.id,
};
ws.identity = {
name: data.name,
author: data.author,
description: data.description,
version: data.version,
};
break;
case "play-next":
this._win.webContents.executeJavaScript(`wsapi.playNext(\`${data.type}\`,\`${data.id}\`)`);
response.message = "Play Next";
break;
case "play-later":
this._win.webContents.executeJavaScript(`wsapi.playLater(\`${data.type}\`,\`${data.id}\`)`);
response.message = "Play Later";
break;
case "quick-play":
this._win.webContents.executeJavaScript(`wsapi.quickPlay(\`${data.term}\`)`);
response.message = "Quick Play";
break;
case "get-lyrics":
this._win.webContents.executeJavaScript(`wsapi.getLyrics()`);
break;
case "shuffle":
this._win.webContents.executeJavaScript(`wsapi.toggleShuffle()`);
break;
case "set-shuffle":
if (data.shuffle == true) {
this._win.webContents.executeJavaScript(`MusicKit.getInstance().shuffleMode = 1`);
} else {
this._win.webContents.executeJavaScript(`MusicKit.getInstance().shuffleMode = 0`);
}
break;
case "repeat":
this._win.webContents.executeJavaScript(`wsapi.toggleRepeat()`);
break;
case "set-repeat":
if (data.repeat === 0 || data.repeat === 1 || data.repeat === 2) {
this._win.webContents.executeJavaScript(`MusicKit.getInstance().repeatMode = ${data.repeat}`);
response.message = "Repeat " + data.repeat;
} else {
this._win.webContents.executeJavaScript(`wsapi.toggleRepeat()`);
response.message = "Invalid Repeat, toggling";
}
break;
case "seek":
this._win.webContents.executeJavaScript(`MusicKit.getInstance().seekToTime(${parseFloat(data.time)})`);
response.message = "Seek";
break;
case "pause":
this._win.webContents.executeJavaScript(`MusicKit.getInstance().pause()`);
response.message = "Paused";
break;
case "playpause":
this._win.webContents.executeJavaScript(`MusicKitInterop.playPause()`);
response.message = "Play/Pause";
break;
case "play":
this._win.webContents.executeJavaScript(`MusicKit.getInstance().play()`);
response.message = "Playing";
break;
case "stop":
this._win.webContents.executeJavaScript(`MusicKit.getInstance().stop()`);
response.message = "Stopped";
break;
case "volumeMax":
this._win.webContents.executeJavaScript(`wsapi.getmaxVolume()`);
response.message = "maxVolume";
break;
case "volume":
this._win.webContents.executeJavaScript(`MusicKit.getInstance().volume = ${parseFloat(data.volume)}`);
response.message = "Volume";
break;
case "mute":
this._win.webContents.executeJavaScript(`MusicKit.getInstance().mute()`);
response.message = "Muted";
break;
case "unmute":
this._win.webContents.executeJavaScript(`MusicKit.getInstance().unmute()`);
response.message = "Unmuted";
break;
case "next":
this._win.webContents.executeJavaScript(`MusicKitInterop.next()`);
response.message = "Next";
break;
case "previous":
this._win.webContents.executeJavaScript(`MusicKitInterop.previous()`);
response.message = "Previous";
break;
case "musickit-api":
this._win.webContents.executeJavaScript(`wsapi.musickitApi(\`${data.method}\`, \`${data.id}\`, ${JSON.stringify(data.params)} , ${data.library})`);
break;
case "musickit-library-api":
break;
case "set-autoplay":
this._win.webContents.executeJavaScript(`wsapi.setAutoplay(${data.autoplay})`);
break;
case "queue-move":
this._win.webContents.executeJavaScript(`wsapi.moveQueueItem(${data.from},${data.to})`);
break;
case "get-queue":
this._win.webContents.executeJavaScript(`wsapi.getQueue()`);
break;
case "search":
if (!data.limit) {
data.limit = 10;
}
this._win.webContents.executeJavaScript(`wsapi.search(\`${data.term}\`, \`${data.limit}\`)`);
break;
case "library-search":
if (!data.limit) {
data.limit = 10;
}
this._win.webContents.executeJavaScript(`wsapi.searchLibrary(\`${data.term}\`, \`${data.limit}\`)`);
break;
case "show-window":
this._win.show();
break;
case "hide-window":
this._win.hide();
break;
case "play-mediaitem":
this._win.webContents.executeJavaScript(`wsapi.playTrackById("${data.id}", \`${data.kind}\`)`);
response.message = "Playing track";
break;
case "get-status":
response.data = {
isAuthorized: true,
};
response.message = "Status";
break;
case "get-currentmediaitem":
this._win.webContents.executeJavaScript(`wsapi.getPlaybackState()`);
break;
case "library-status":
this._win.webContents.executeJavaScript(`wsapi.getLibraryStatus("${data.type}", "${data.id}")`);
break;
case "rating":
this._win.webContents.executeJavaScript(`wsapi.rate("${data.type}", "${data.id}", ${data.rating})`);
break;
case "change-library":
this._win.webContents.executeJavaScript(`wsapi.changeLibrary("${data.type}", "${data.id}", ${data.add})`);
break;
case "quit":
electron.app.quit();
break;
}
ws.send(JSON.stringify(response));
});
ws.on("close", () => {
// remove client from list
this.clients.splice(wsapi.clients.indexOf(ws), 1);
console.log(`Client ${ws.id} disconnected`);
});
ws.send(JSON.stringify(defaultResponse));
});
}
sendToClient(_id: any) {
// replace the clients.forEach with a filter to find the client that requested
}
updatePlaybackState(attr: any) {
const response: standardResponse = {
status: 0,
data: attr,
message: "OK",
type: "playbackStateUpdate",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnMusicKitApi(results: any, method: any) {
const response: standardResponse = {
status: 0,
data: results,
message: "OK",
type: `musickitapi.${method}`,
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnDynamic(results: any, type: any) {
const response: standardResponse = {
status: 0,
data: results,
message: "OK",
type: type,
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnLyrics(results: any) {
const response: standardResponse = {
status: 0,
data: results,
message: "OK",
type: "lyrics",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnSearch(results: any) {
const response: standardResponse = {
status: 0,
data: results,
message: "OK",
type: "searchResults",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnSearchLibrary(results: any) {
const response: standardResponse = {
status: 0,
data: results,
message: "OK",
type: "searchResultsLibrary",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnQueue(queue: any) {
const response: standardResponse = {
status: 0,
data: queue,
message: "OK",
type: "queue",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnmaxVolume(vol: any) {
const response: standardResponse = {
status: 0,
data: vol,
message: "OK",
type: "maxVolume",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnLibraryStatus(inLibrary: boolean, rating: number) {
const response: standardResponse = {
status: 0,
data: {
inLibrary,
rating,
},
message: "OK",
type: "libraryStatus",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnRatingStatus(kind: string, id: string, rating: number) {
const response: standardResponse = {
status: 0,
data: { kind, id, rating },
message: "OK",
type: "rate",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
returnLibraryChange(kind: string, id: string, shouldAdd: boolean) {
const response: standardResponse = {
status: 0,
data: { kind, id, add: shouldAdd },
message: "OK",
type: "change-library",
};
this.clients.forEach(function each(client: any) {
client.send(JSON.stringify(response));
});
}
}