Revert "Develop > main"

This commit is contained in:
Core 2022-02-05 09:34:33 +00:00 committed by GitHub
parent d7d90fbc36
commit f843fe0ba7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
86 changed files with 6687 additions and 25151 deletions

View file

@ -1,8 +1,6 @@
import {app, Menu, nativeImage, Tray, ipcMain, clipboard, shell} from 'electron';
import {readFileSync} from "fs";
import {app, Menu, nativeImage, Tray} from 'electron';
import * as path from 'path';
import * as log from 'electron-log';
import {utils} from './utils';
import {utils} from './utils'
export class AppEvents {
private protocols: string[] = [
@ -26,7 +24,6 @@ export class AppEvents {
* @returns {void}
*/
private start(): void {
AppEvents.initLogging()
console.info('[AppEvents] App started');
/**********************************************************************************************************************
@ -172,8 +169,6 @@ export class AppEvents {
let url = arg.split('//')[1]
console.warn(`[LinkHandler] Attempting to load url: ${url}`);
utils.getWindow().webContents.send('play', 'url', url)
} else if (arg.includes('/debug/appdata')) {
shell.openPath(app.getPath('userData'))
}
}
@ -289,18 +284,4 @@ export class AppEvents {
])
this.tray.setContextMenu(menu)
}
/**
* Initializes logging in the application
* @private
*/
private static initLogging() {
log.transports.console.format = '[{h}:{i}:{s}.{ms}] [{level}] {text}';
Object.assign(console, log.functions);
ipcMain.on('fetch-log', (_event) => {
const data = readFileSync(log.transports.file.getFile().path, {encoding: 'utf8', flag: 'r'});
clipboard.writeText(data)
})
}
}

View file

@ -1,27 +1,31 @@
import {join} from "path";
import {app, BrowserWindow as bw, ipcMain, shell, ShareMenu, Menu, nativeImage} from "electron";
import * as path from "path";
import {app, BrowserWindow as bw, ipcMain, shell} from "electron";
import * as windowStateKeeper from "electron-window-state";
import * as express from "express";
import * as getPort from "get-port";
import {search} from "youtube-search-without-api-key";
import {existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync} from "fs";
import * as yt from "youtube-search-without-api-key";
import * as fs from "fs";
import {Stream} from "stream";
import {generate as generateQR} from "qrcode-terminal";
import {hostname, networkInterfaces} from "os";
import * as qrcode from "qrcode-terminal";
import * as os from "os";
import * as mm from 'music-metadata';
import fetch from 'electron-fetch'
import {wsapi} from "./wsapi";
import {jsonc} from "jsonc";
import {AppImageUpdater, NsisUpdater} from "electron-updater";
import {utils} from './utils';
import * as path from "path";
import {NsisUpdater} from "electron-updater";
import {utils} from './utils'
export class BrowserWindow {
public static win: any | undefined = null;
private devMode: boolean = !app.isPackaged;
private paths: any = {
srcPath: path.join(__dirname, "../../src"),
resourcePath: path.join(__dirname, "../../resources"),
ciderCache: path.resolve(app.getPath("userData"), "CiderCache"),
themes: path.resolve(app.getPath("userData"), "Themes"),
plugins: path.resolve(app.getPath("userData"), "Plugins"),
};
private audioStream: any = new Stream.PassThrough();
private clientPort: number = 0;
private remotePort: number = 6942;
@ -29,57 +33,11 @@ export class BrowserWindow {
env: {
platform: process.platform,
dev: app.isPackaged,
components: [
"pages/podcasts",
"pages/apple-account-settings",
"pages/library-songs",
"pages/browse",
"pages/settings",
"pages/listen_now",
"pages/home",
"pages/artist-feed",
"pages/cider-playlist",
"pages/playlist-inline",
"pages/recordLabel",
"pages/collection-list",
"pages/apple-curator",
"pages/artist",
"pages/search",
"pages/about",
"pages/library-videos",
"components/mediaitem-artwork",
"components/artwork-material",
"components/menu-panel",
"components/sidebar-playlist",
"components/spatial-properties",
"components/audio-settings",
"components/qrcode-modal",
"components/equalizer",
"components/add-to-playlist",
"components/queue",
"components/queue-item",
"components/mediaitem-scroller-horizontal",
"components/mediaitem-scroller-horizontal-large",
"components/mediaitem-scroller-horizontal-sp",
"components/mediaitem-scroller-horizontal-mvview",
"components/mediaitem-list-item",
"components/mediaitem-hrect",
"components/mediaitem-square",
"components/mediaitem-square-sp",
"components/mediaitem-mvview",
"components/libraryartist-item",
"components/listennow-child",
"components/mediaitem-mvview-sp",
"components/animatedartwork-view",
"components/lyrics-view",
"components/fullscreen",
"components/miniplayer",
]
},
};
private options: any = {
icon: join(
utils.getPath('resourcePath'),
icon: path.join(
this.paths.resourcePath,
`icons/icon.` + (process.platform === "win32" ? "ico" : "png")
),
width: 1024,
@ -90,13 +48,11 @@ export class BrowserWindow {
minHeight: 390,
frame: false,
title: "Cider",
vibrancy: "fullscreen-ui",
vibrancy: "dark",
transparent: process.platform === "darwin",
hasShadow: false,
show: false,
backgroundColor: "#1E1E1E",
titleBarStyle: 'hidden',
trafficLightPosition: {x: 15, y: 20},
webPreferences: {
nodeIntegration: true,
sandbox: true,
@ -106,7 +62,7 @@ export class BrowserWindow {
plugins: true,
nodeIntegrationInWorker: false,
webSecurity: false,
preload: join(utils.getPath('srcPath'), "./preload/cider-preload.js"),
preload: path.join(this.paths.srcPath, "./preload/cider-preload.js"),
},
};
@ -115,7 +71,7 @@ export class BrowserWindow {
*/
async createWindow(): Promise<Electron.BrowserWindow> {
this.clientPort = await getPort({port: 9000});
BrowserWindow.verifyFiles();
this.verifyFiles();
// Load the previous state with fallback to defaults
const windowState = windowStateKeeper({
@ -145,7 +101,7 @@ export class BrowserWindow {
/**
* Verifies the files for the renderer to use (Cache, library info, etc.)
*/
private static verifyFiles(): void {
private verifyFiles(): void {
const expectedDirectories = ["CiderCache"];
const expectedFiles = [
"library-songs.json",
@ -156,19 +112,19 @@ export class BrowserWindow {
];
for (let i = 0; i < expectedDirectories.length; i++) {
if (
!existsSync(
join(app.getPath("userData"), expectedDirectories[i])
!fs.existsSync(
path.join(app.getPath("userData"), expectedDirectories[i])
)
) {
mkdirSync(
join(app.getPath("userData"), expectedDirectories[i])
fs.mkdirSync(
path.join(app.getPath("userData"), expectedDirectories[i])
);
}
}
for (let i = 0; i < expectedFiles.length; i++) {
const file = join(utils.getPath('ciderCache'), expectedFiles[i]);
if (!existsSync(file)) {
writeFileSync(file, JSON.stringify([]));
const file = path.join(this.paths.ciderCache, expectedFiles[i]);
if (!fs.existsSync(file)) {
fs.writeFileSync(file, JSON.stringify([]));
}
}
}
@ -179,8 +135,8 @@ export class BrowserWindow {
private startWebServer(): void {
const app = express();
app.use(express.static(join(utils.getPath('srcPath'), "./renderer/")));
app.set("views", join(utils.getPath('srcPath'), "./renderer/views"));
app.use(express.static(path.join(this.paths.srcPath, "./renderer/")));
app.set("views", path.join(this.paths.srcPath, "./renderer/views"));
app.set("view engine", "ejs");
let firstRequest = true;
app.use((req, res, next) => {
@ -199,53 +155,6 @@ export class BrowserWindow {
res.render("main", this.EnvironmentVariables);
});
app.get("/api/playback/:action", (req, res)=>{
const action = req.params.action;
switch(action) {
case "playpause":
BrowserWindow.win.webContents.executeJavaScript("wsapi.togglePlayPause()")
res.send("Play/Pause toggle")
break;
case "play":
BrowserWindow.win.webContents.executeJavaScript("MusicKit.getInstance().play()")
res.send("Playing")
break;
case "pause":
BrowserWindow.win.webContents.executeJavaScript("MusicKit.getInstance().pause()")
res.send("Paused")
break;
case "stop":
BrowserWindow.win.webContents.executeJavaScript("MusicKit.getInstance().stop()")
res.send("Stopped")
break;
case "next":
BrowserWindow.win.webContents.executeJavaScript("MusicKit.getInstance().skipToNextItem()")
res.send("Next")
break;
case "previous":
BrowserWindow.win.webContents.executeJavaScript("MusicKit.getInstance().skipToPreviousItem()")
res.send("Previous")
break;
default: {
res.send("Invalid action")
}
}
})
app.get("/themes/:theme", (req, res) => {
const theme = req.params.theme.toLowerCase();
const themePath = join(utils.getPath('srcPath'), "./renderer/themes/", theme);
const userThemePath = join(utils.getPath('themes'), theme);
if (existsSync(userThemePath)) {
res.sendFile(userThemePath);
} else if (existsSync(themePath)) {
res.sendFile(themePath);
} else {
res.send(`// Theme not found - ${userThemePath}`);
}
});
app.get("/audio.webm", (req, res) => {
try {
req.socket.setTimeout(Number.MAX_SAFE_INTEGER);
@ -274,12 +183,13 @@ export class BrowserWindow {
});
/*
* Remote Client -@quacksire
* https://github.com/ciderapp/Apple-Music-Electron/blob/818189ed40ff600d76eb59d22016723a75885cd5/resources/functions/handler.js#L1173
* Remote Client (I had no idea how to add it to our existing express server, so I just made another one) -@quacksire
* TODO: Broadcast the remote so that /web-remote/ can connect
* https://github.com/ciderapp/Apple-Music-Electron/blob/818ed18940ff600d76eb59d22016723a75885cd5/resources/functions/handler.js#L1173
*/
const remote = express();
remote.use(express.static(join(utils.getPath('srcPath'), "./web-remote/")))
remote.set("views", join(utils.getPath('srcPath'), "./web-remote/views"));
remote.use(express.static(path.join(this.paths.srcPath, "./web-remote/")))
remote.set("views", path.join(this.paths.srcPath, "./web-remote/views"));
remote.set("view engine", "ejs");
getPort({port: 6942}).then((port) => {
this.remotePort = port;
@ -288,7 +198,15 @@ export class BrowserWindow {
remote.listen(this.remotePort, () => {
console.log(`Cider remote port: ${this.remotePort}`);
if (firstRequest) {
generateQR(`http://${hostname}:${this.remotePort}`);
console.log("---- Ignore Me ;) ---");
qrcode.generate(`http://${os.hostname}:${this.remotePort}`);
console.log("---- Ignore Me ;) ---");
/*
*
* USING https://www.npmjs.com/package/qrcode-terminal for terminal
* WE SHOULD USE https://www.npmjs.com/package/qrcode for the remote (or others) for showing to user via an in-app dialog
* -@quacksire
*/
}
firstRequest = false;
})
@ -363,24 +281,16 @@ export class BrowserWindow {
event.returnValue = process.platform;
});
ipcMain.on("get-themes", (event, _key) => {
if (existsSync(utils.getPath("themes"))) {
event.returnValue = readdirSync(utils.getPath("themes"));
} else {
event.returnValue = [];
}
});
ipcMain.on("get-i18n", (event, key) => {
event.returnValue = utils.getLocale(key);
});
ipcMain.on("get-i18n-listing", event => {
let i18nFiles = readdirSync(join(__dirname, "../../src/i18n")).filter(file => file.endsWith(".jsonc"));
let i18nFiles = fs.readdirSync(path.join(__dirname, "../../src/i18n")).filter(file => file.endsWith(".jsonc"));
// read all the files and parse them
let i18nListing = []
for (let i = 0; i < i18nFiles.length; i++) {
const i18n: { [index: string]: Object } = jsonc.parse(readFileSync(join(__dirname, `../../src/i18n/${i18nFiles[i]}`), "utf8"));
const i18n: { [index: string]: Object } = jsonc.parse(fs.readFileSync(path.join(__dirname, `../../src/i18n/${i18nFiles[i]}`), "utf8"));
i18nListing.push({
"code": i18nFiles[i].replace(".jsonc", ""),
"nameNative": i18n["i18n.languageName"] ?? i18nFiles[i].replace(".jsonc", ""),
@ -401,75 +311,75 @@ export class BrowserWindow {
});
ipcMain.on("put-library-songs", (_event, arg) => {
writeFileSync(
join(utils.getPath('ciderCache'), "library-songs.json"),
fs.writeFileSync(
path.join(this.paths.ciderCache, "library-songs.json"),
JSON.stringify(arg)
);
});
ipcMain.on("put-library-artists", (_event, arg) => {
writeFileSync(
join(utils.getPath('ciderCache'), "library-artists.json"),
fs.writeFileSync(
path.join(this.paths.ciderCache, "library-artists.json"),
JSON.stringify(arg)
);
});
ipcMain.on("put-library-albums", (_event, arg) => {
writeFileSync(
join(utils.getPath('ciderCache'), "library-albums.json"),
fs.writeFileSync(
path.join(this.paths.ciderCache, "library-albums.json"),
JSON.stringify(arg)
);
});
ipcMain.on("put-library-playlists", (_event, arg) => {
writeFileSync(
join(utils.getPath('ciderCache'), "library-playlists.json"),
fs.writeFileSync(
path.join(this.paths.ciderCache, "library-playlists.json"),
JSON.stringify(arg)
);
});
ipcMain.on("put-library-recentlyAdded", (_event, arg) => {
writeFileSync(
join(utils.getPath('ciderCache'), "library-recentlyAdded.json"),
fs.writeFileSync(
path.join(this.paths.ciderCache, "library-recentlyAdded.json"),
JSON.stringify(arg)
);
});
ipcMain.on("get-library-songs", (event) => {
let librarySongs = readFileSync(
join(utils.getPath('ciderCache'), "library-songs.json"),
let librarySongs = fs.readFileSync(
path.join(this.paths.ciderCache, "library-songs.json"),
"utf8"
);
event.returnValue = JSON.parse(librarySongs);
});
ipcMain.on("get-library-artists", (event) => {
let libraryArtists = readFileSync(
join(utils.getPath('ciderCache'), "library-artists.json"),
let libraryArtists = fs.readFileSync(
path.join(this.paths.ciderCache, "library-artists.json"),
"utf8"
);
event.returnValue = JSON.parse(libraryArtists);
});
ipcMain.on("get-library-albums", (event) => {
let libraryAlbums = readFileSync(
join(utils.getPath('ciderCache'), "library-albums.json"),
let libraryAlbums = fs.readFileSync(
path.join(this.paths.ciderCache, "library-albums.json"),
"utf8"
);
event.returnValue = JSON.parse(libraryAlbums);
});
ipcMain.on("get-library-playlists", (event) => {
let libraryPlaylists = readFileSync(
join(utils.getPath('ciderCache'), "library-playlists.json"),
let libraryPlaylists = fs.readFileSync(
path.join(this.paths.ciderCache, "library-playlists.json"),
"utf8"
);
event.returnValue = JSON.parse(libraryPlaylists);
});
ipcMain.on("get-library-recentlyAdded", (event) => {
let libraryRecentlyAdded = readFileSync(
join(utils.getPath('ciderCache'), "library-recentlyAdded.json"),
let libraryRecentlyAdded = fs.readFileSync(
path.join(this.paths.ciderCache, "library-recentlyAdded.json"),
"utf8"
);
event.returnValue = JSON.parse(libraryRecentlyAdded);
@ -477,14 +387,14 @@ export class BrowserWindow {
ipcMain.handle("getYTLyrics", async (_event, track, artist) => {
const u = track + " " + artist + " official video";
return await search(u);
return await yt.search(u);
});
ipcMain.on("close", (_event) => {
ipcMain.on("close", () => {
BrowserWindow.win.close();
});
ipcMain.on("maximize", (_event) => {
ipcMain.on("maximize", () => {
// listen for maximize event
if (BrowserWindow.win.isMaximized()) {
BrowserWindow.win.unmaximize();
@ -533,23 +443,18 @@ export class BrowserWindow {
ipcMain.on('play', (_event, type, id) => {
BrowserWindow.win.webContents.executeJavaScript(`
MusicKit.getInstance().setQueue({ ${type}: '${id}'}).then(function(queue) {
MusicKit.getInstance().play();
});
`)
MusicKit.getInstance().setQueue({ ${type}: '${id}'}).then(function(queue) {
MusicKit.getInstance().play();
});
`)
})
//QR Code
ipcMain.handle('showQR', async (_event, _) => {
ipcMain.handle('showQR', async (event, _) => {
let url = `http://${BrowserWindow.getIP()}:${this.remotePort}`;
shell.openExternal(`https://cider.sh/pair-remote?url=${Buffer.from(encodeURI(url)).toString('base64')}`).catch(console.error);
})
ipcMain.on('get-remote-pair-url', (_event, _) => {
let url = `http://${BrowserWindow.getIP()}:${this.remotePort}`;
BrowserWindow.win.webContents.send('send-remote-pair-url', url);
})
// Get previews for normalization
ipcMain.on("getPreviewURL", (_event, url) => {
@ -565,39 +470,15 @@ export class BrowserWindow {
});
});
ipcMain.on('check-for-update', async (_event) => {
ipcMain.on('check-for-update', async (_event, url) => {
const options: any = {
provider: 'generic',
url: 'https://43-429851205-gh.circle-artifacts.com/0/%7E/Cider/dist/artifacts' //Base URL
}
/*
* Have to handle the auto updaters seperatly until we can support macOS. electron-builder limitation -q
*/
const win_autoUpdater = new NsisUpdater(options) //Windows
const linux_autoUpdater = new AppImageUpdater(options) //Linux
await win_autoUpdater.checkForUpdatesAndNotify()
await linux_autoUpdater.checkForUpdatesAndNotify()
const autoUpdater = new NsisUpdater(options) //Windows Only (for now) -q
await autoUpdater.checkForUpdatesAndNotify()
})
ipcMain.on('share-menu', async (_event, url) => {
if ( process.platform != 'darwin') return;
//https://www.electronjs.org/docs/latest/api/share-menu
console.log('[Share Sheet - App.ts]', url)
const options = {
title: 'Share',
urls: [url]
};
// @ts-ignore
const shareMenu = new ShareMenu(options);
shareMenu.popup();
})
/* *********************************************************************************************
* Window Events
* **********************************************************************************************/
@ -662,128 +543,12 @@ export class BrowserWindow {
shell.openExternal(x.url).catch(console.error);
return {action: "deny"};
});
/* *********************************************************************************************
* Menu
* **********************************************************************************************/
//@ts-ignore
console.log(path.join(__dirname, '../../src/renderer/views/svg/smartphone.svg'))
const isMac = process.platform === 'darwin';
//TODO: Figure out the icons
const remoteIcon = nativeImage.createFromPath(path.join(__dirname, '../../src/renderer/views/svg/smartphone.svg')).toPNG()
const soundIcon = nativeImage.createFromPath(path.join(__dirname, '../../src/renderer/views/svg/headphones.svg')).toPNG()
const aboutIcon = nativeImage.createFromPath(path.join(__dirname, '../../src/renderer/views/svg/info.svg')).toPNG()
const settingsIcon = nativeImage.createFromPath(path.join(__dirname, '../../src/renderer/views/svg/settings.svg')).toPNG()
const logoutIcon = nativeImage.createFromPath(path.join(__dirname, '../../src/renderer/views/svg/log-out.svg')).toPNG()
const ciderIcon = nativeImage.createFromPath(path.join(__dirname, '../../src/renderer/assets/logocute.png'))
const template = [
// { role: 'appMenu' }
...(isMac ? [{
label: app.name,
submenu: [
{ label: 'Web Remote', accelerator: 'CommandOrControl+W', sublabel: 'Opens in external window', click: () => BrowserWindow.win.webContents.executeJavaScript(`ipcRenderer.invoke('showQR')`)}, //accelerator
{ label: 'Audio Settings', accelerator: 'CommandOrControl+Shift+A', click: () => BrowserWindow.win.webContents.executeJavaScript(`app.modals.audioSettings = true`)},
{ label: 'About', accelerator: 'CommandOrControl+Shift+B', click: () => BrowserWindow.win.webContents.executeJavaScript(`app.appRoute('about'`)},
{ label: 'Settings', accelerator: 'CommandOrControl+,', click: () => BrowserWindow.win.webContents.executeJavaScript(`app.appRoute('settings')`)},
{ label: 'Logout', accelerator: 'CommandOrControl+Shift+O', click: () => BrowserWindow.win.webContents.executeJavaScript(`app.unauthorize(); document.location.reload()`)},
{ type: 'separator' },
{ role: 'quit' }
]
}] : []),
// { role: 'viewMenu' }
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forceReload' },
{ role: 'toggleDevTools' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
// { role: 'windowMenu' }
{
label: 'Window',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
...(isMac ? [
{ type: 'separator' },
{ role: 'front' },
{ type: 'separator' },
{ role: 'window' }
] : [
{ role: 'close' }
])
]
},
{
role: 'help',
submenu: [
{
label: 'Discord',
accelerator: 'CommandOrControl+Shift+D',
click: async () => {
const { shell } = require('electron')
await shell.openExternal('https://discord.gg/applemusic')
}
},
{
label: 'Donate',
accelerator: 'CommandOrControl+D',
icon: ciderIcon,
click: async () => {
const { shell } = require('electron')
await shell.openExternal('https://opencollective.com/ciderapp/')
}
},
{
label: 'Report a...',
submenu: [
{
label: 'Bug',
click: async () => {
const {shell} = require('electron')
await shell.openExternal("https://github.com/ciderapp/Cider/issues/new?assignees=&labels=bug%2Ctriage&template=bug_report.yaml&title=%5BBug%5D%3A+")
}
},
{
label: 'Feature Request',
click: async () => {
const {shell} = require('electron')
await shell.openExternal("https://github.com/ciderapp/Cider/issues/new?assignees=&labels=enhancement%2Ctriage&template=feature_request.yaml&title=%5BEnhancement%5D%3A+")
}
},
{
label: 'Translation Report/Request',
click: async () => {
const {shell} = require('electron')
await shell.openExternal("https://github.com/ciderapp/Cider/issues/new?assignees=&labels=%F0%9F%8C%90+Translations&template=translation.yaml&title=%5BTranslation%5D%3A+")
}
},
]
},
]
}
]
//@ts-ignore
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
}
/**
* Gets ip
* @private
*/
private static getIP(): string {
let ip: string = '';
let alias = 0;
const ifaces: any = networkInterfaces();
const ifaces: any = os.networkInterfaces();
for (let dev in ifaces) {
ifaces[dev].forEach((details: any) => {
if (details.family === 'IPv4') {

View file

@ -31,7 +31,6 @@ export class Store {
"quality": "256",
"seamless_audio": true,
"normalization": false,
"decryptLLPW": false,
"spatial": false,
"maxVolume": 1,
"volumePrecision": 0.1,
@ -143,11 +142,11 @@ export class Store {
* IPC Handler
*/
private ipcHandler(): void {
electron.ipcMain.handle('getStoreValue', (_event, key, defaultValue) => {
electron.ipcMain.handle('getStoreValue', (event, key, defaultValue) => {
return (defaultValue ? Store.cfg.get(key, true) : Store.cfg.get(key));
});
electron.ipcMain.handle('setStoreValue', (_event, key, value) => {
electron.ipcMain.handle('setStoreValue', (event, key, value) => {
Store.cfg.set(key, value);
});
@ -155,7 +154,7 @@ export class Store {
event.returnValue = Store.cfg.store
})
electron.ipcMain.on('setStore', (_event, store) => {
electron.ipcMain.on('setStore', (event, store) => {
Store.cfg.store = store
})
}

View file

@ -3,31 +3,9 @@ import * as path from "path";
import {jsonc} from "jsonc";
import {Store} from "./store";
import {BrowserWindow as bw} from "./browserwindow";
import {app} from "electron";
export class utils {
/**
* Paths for the application to use
*/
private static paths: any = {
srcPath: path.join(__dirname, "../../src"),
resourcePath: path.join(__dirname, "../../resources"),
i18nPath: path.join(__dirname, "../../src/i18n"),
ciderCache: path.resolve(app.getPath("userData"), "CiderCache"),
themes: path.resolve(app.getPath("userData"), "Themes"),
plugins: path.resolve(app.getPath("userData"), "Plugins"),
};
/**
* Get the path
* @returns {string}
* @param name
*/
static getPath(name: string): string {
return this.paths[name];
}
/**
* Fetches the i18n locale for the given language.
* @param language {string} The language to fetch the locale for.
@ -35,10 +13,10 @@ export class utils {
* @returns {string | Object} The locale value.
*/
static getLocale(language: string, key?: string): string | object {
let i18n: { [index: string]: Object } = jsonc.parse(fs.readFileSync(path.join(this.paths.i18nPath, "en_US.jsonc"), "utf8"));
let i18n: { [index: string]: Object } = jsonc.parse(fs.readFileSync(path.join(__dirname, "../../src/i18n/en_US.jsonc"), "utf8"));
if (language !== "en_US" && fs.existsSync(path.join(this.paths.i18nPath, `${language}.jsonc`))) {
i18n = Object.assign(i18n, jsonc.parse(fs.readFileSync(path.join(this.paths.i18nPath, `${language}.jsonc`), "utf8")));
if (language !== "en_US" && fs.existsSync(path.join(__dirname, `../../src/i18n/${language}.jsonc`))) {
i18n = Object.assign(i18n, jsonc.parse(fs.readFileSync(path.join(__dirname, `../../src/i18n/${language}.jsonc`), "utf8")));
}
if (key) {
@ -80,25 +58,4 @@ export class utils {
static getWindow(): Electron.BrowserWindow {
return bw.win
}
/**
* Playback Functions
*/
static playback = {
pause: () => {
bw.win.webContents.executeJavaScript("MusicKitInterop.pause()")
},
play: () => {
bw.win.webContents.executeJavaScript("MusicKitInterop.play()")
},
playPause: () => {
bw.win.webContents.executeJavaScript("MusicKitInterop.playPause()")
},
next: () => {
bw.win.webContents.executeJavaScript("MusicKitInterop.next()")
},
previous: () => {
bw.win.webContents.executeJavaScript("MusicKitInterop.previous()")
}
}
}

View file

@ -1,6 +1,11 @@
import * as ws from "ws";
import * as http from "http";
import * as https from "https";
import * as url from "url";
import * as fs from "fs";
import * as path from "path";
import * as electron from "electron";
const WebSocket = ws;
const WebSocketServer = ws.Server;
interface standardResponse {
@ -16,13 +21,12 @@ export class wsapi {
port: any = 26369
wss: any = null
clients: any = []
private _win: any;
constructor(win: 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) {
@ -31,34 +35,33 @@ export class wsapi {
return v.toString(16);
});
}
public async InitWebSockets() {
electron.ipcMain.on('wsapi-updatePlaybackState', (_event: any, arg: any) => {
public async InitWebSockets () {
electron.ipcMain.on('wsapi-updatePlaybackState', (event :any, arg :any) => {
this.updatePlaybackState(arg);
})
electron.ipcMain.on('wsapi-returnQueue', (_event: any, arg: any) => {
electron.ipcMain.on('wsapi-returnQueue', (event :any, arg :any) => {
this.returnQueue(JSON.parse(arg));
});
electron.ipcMain.on('wsapi-returnSearch', (_event: any, arg: any) => {
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) => {
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) => {
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) => {
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) => {
electron.ipcMain.on('wsapi-returnLyrics', (event :any, arg :any) => {
this.returnLyrics(JSON.parse(arg));
});
this.wss = new WebSocketServer({
@ -85,20 +88,20 @@ export class wsapi {
})
console.log(`WebSocketServer started on port: ${this.port}`);
const defaultResponse: standardResponse = {status: 0, data: {}, message: "OK", type: "generic"};
const defaultResponse :standardResponse = {status :0, data:{}, message:"OK", type:"generic"};
this.wss.on('connection', (ws: any) => {
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', function incoming(message : any) {
});
// ws on message
ws.on('message', (message: any) => {
ws.on('message', (message : any) => {
let data = JSON.parse(message);
let response: standardResponse = {status: 0, data: {}, message: "OK", type: "generic"};
let response :standardResponse = {status :0, data:{}, message:"OK", type:"generic"};
if (data.action) {
data.action.toLowerCase();
}
@ -137,9 +140,9 @@ export class wsapi {
this._win.webContents.executeJavaScript(`wsapi.toggleShuffle()`);
break;
case "set-shuffle":
if (data.shuffle == true) {
if(data.shuffle == true) {
this._win.webContents.executeJavaScript(`MusicKit.getInstance().shuffleMode = 1`);
} else {
}else{
this._win.webContents.executeJavaScript(`MusicKit.getInstance().shuffleMode = 0`);
}
break;
@ -229,7 +232,7 @@ export class wsapi {
break;
case "quit":
electron.app.quit();
break;
break;
}
ws.send(JSON.stringify(response));
});
@ -242,56 +245,48 @@ export class wsapi {
ws.send(JSON.stringify(defaultResponse));
});
}
sendToClient(_id: any) {
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"};
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) {
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) {
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) {
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) {
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) {
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) {
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));
});
}