orchard/resources/functions/wsapi.js
2021-11-19 17:02:28 -06:00

292 lines
No EOL
12 KiB
JavaScript

const ws = require('ws');
const http = require('http');
const WebSocketServer = ws.Server;
const WebSocket = ws.WebSocket;
const url = require('url');
const fs = require('fs');
const path = require('path');
const port = process.argv[2] || 9000;
const express = require('express');
const router = express.Router();
const {
ipcMain,
app,
BrowserWindow
} = require('electron');
const wsapi = {
standardResponse: function (status, data, message, type = "generic") {
this.status = status;
this.message = message;
this.data = data;
this.type = type;
},
port: 26369,
wss: null,
clients: [],
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);
});
},
InitWebSockets() {
ipcMain.on('wsapi-updatePlaybackState', (event, arg) => {
wsapi.updatePlaybackState(arg);
})
ipcMain.on('wsapi-returnQueue', (event, arg) => {
wsapi.returnQueue(JSON.parse(arg));
});
ipcMain.on('wsapi-returnSearch', (event, arg) => {
wsapi.returnSearch(JSON.parse(arg));
});
ipcMain.on('wsapi-returnSearchLibrary', (event, arg) => {
wsapi.returnSearchLibrary(JSON.parse(arg));
});
ipcMain.on('wsapi-returnLyrics', (event, arg) => {
wsapi.returnLyrics(JSON.parse(arg));
});
wss = new WebSocketServer({
port: 26369,
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.
}
})
const defaultResponse = new wsapi.standardResponse(0, {}, "OK");
console.log(`WebSocketServer started on port: ${this.port}`);
wss.on('connection', function connection(ws) {
ws.id = wsapi.createId();
console.log(`Client ${ws.id} connected`)
wsapi.clients.push(ws);
ws.on('message', function incoming(message) {
});
// ws on message
ws.on('message', function incoming(message) {
let data = JSON.parse(message);
let response = new wsapi.standardResponse(0, {}, "OK");;
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":
app.win.webContents.executeJavaScript(`wsapi.playNext(\`${data.type}\`,\`${data.id}\`)`);
response.message = "Play Next";
break;
case "play-later":
app.win.webContents.executeJavaScript(`wsapi.playLater(\`${data.type}\`,\`${data.id}\`)`);
response.message = "Play Later";
break;
case "quick-play":
app.win.webContents.executeJavaScript(`wsapi.quickPlay(\`${data.term}\`)`);
response.message = "Quick Play";
break;
case "get-lyrics":
app.win.webContents.executeJavaScript(`wsapi.getLyrics()`);
break;
case "shuffle":
app.win.webContents.executeJavaScript(`wsapi.toggleShuffle()`);
break;
case "repeat":
app.win.webContents.executeJavaScript(`wsapi.toggleRepeat()`);
break;
case "seek":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().seekToTime(${parseFloat(data.time)})`);
response.message = "Seek";
break;
case "pause":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().pause()`);
response.message = "Paused";
break;
case "play":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().play()`);
response.message = "Playing";
break;
case "stop":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().stop()`);
response.message = "Stopped";
break;
case "volume":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().volume = ${parseFloat(data.volume)}`);
response.message = "Volume";
break;
case "mute":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().mute()`);
response.message = "Muted";
break;
case "unmute":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().unmute()`);
response.message = "Unmuted";
break;
case "next":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().skipToNextItem()`);
response.message = "Next";
break;
case "previous":
app.win.webContents.executeJavaScript(`MusicKit.getInstance().skipToPreviousItem()`);
response.message = "Previous";
break;
case "musickit-api":
break;
case "musickit-library-api":
break;
case "set-autoplay":
app.win.webContents.executeJavaScript(`wsapi.setAutoplay(${data.autoplay})`);
break;
case "queue-move":
app.win.webContents.executeJavaScript(`wsapi.moveQueueItem(${data.from},${data.to})`);
break;
case "get-queue":
app.win.webContents.executeJavaScript(`wsapi.getQueue()`);
break;
case "search":
if (!data.limit) {
data.limit = 10;
}
app.win.webContents.executeJavaScript(`wsapi.search(\`${data.term}\`, \`${data.limit}\`)`);
break;
case "library-search":
if (!data.limit) {
data.limit = 10;
}
app.win.webContents.executeJavaScript(`wsapi.searchLibrary(\`${data.term}\`, \`${data.limit}\`)`);
break;
case "show-window":
app.win.show()
break;
case "hide-window":
app.win.hide()
break;
case "play-mediaitem":
app.win.webContents.executeJavaScript(`wsapi.playTrackById(${data.id})`);
response.message = "Playing track";
break;
case "get-status":
response.data = {
isAuthorized: true
};
response.message = "Status";
break;
case "get-currentmediaitem":
app.win.webContents.executeJavaScript(`wsapi.getPlaybackState()`);
break;
}
ws.send(JSON.stringify(response));
});
ws.on('close', function close() {
// remove client from list
wsapi.clients.splice(wsapi.clients.indexOf(ws), 1);
console.log(`Client ${ws.id} disconnected`);
});
ws.send(JSON.stringify(defaultResponse));
});
},
sendToClient(id) {
// replace the clients.forEach with a filter to find the client that requested
},
win: null,
inAppUI() {
// create a browserwindow and load "localhost:8090"
this.win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
});
this.win.loadURL(`http://localhost:${this.webRemotePort}`);
this.win.show()
this.win.on('closed', () => {
this.win = null;
});
},
updatePlaybackState(attr) {
const response = new wsapi.standardResponse(0, attr, "OK", "playbackStateUpdate");
wsapi.clients.forEach(function each(client) {
client.send(JSON.stringify(response));
});
},
returnLyrics(results) {
const response = new wsapi.standardResponse(0, results, "OK", "lyrics");
wsapi.clients.forEach(function each(client) {
client.send(JSON.stringify(response));
});
},
returnSearch(results) {
const response = new wsapi.standardResponse(0, results, "OK", "searchResults");
wsapi.clients.forEach(function each(client) {
client.send(JSON.stringify(response));
});
},
returnSearchLibrary(results) {
const response = new wsapi.standardResponse(0, results, "OK", "searchResultsLibrary");
wsapi.clients.forEach(function each(client) {
client.send(JSON.stringify(response));
});
},
returnQueue(queue) {
const response = new wsapi.standardResponse(0, queue, "OK", "queue");
wsapi.clients.forEach(function each(client) {
client.send(JSON.stringify(response));
});
},
webRemotePort: 8090,
InitWebServer() {
// Web Remote
// express server that will serve static files in the "../web-remote" folder
const webapp = express();
const webRemotePath = path.join(__dirname, '../web-remote');
webapp.use(express.static(webRemotePath));
webapp.get('/', function (req, res) {
res.sendFile(path.join(webRemotePath, 'index.html'));
});
webapp.listen(wsapi.webRemotePort, function () {
console.log(`Web Remote listening on port ${wsapi.webRemotePort}`);
});
}
}
module.exports = wsapi