292 lines
No EOL
12 KiB
JavaScript
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 |