diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index 755bba14..5939e870 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -1,19 +1,19 @@ -import * as path from "path"; +import {join} 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 * as yt from "youtube-search-without-api-key"; -import * as fs from "fs"; +import {search} from "youtube-search-without-api-key"; +import {existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync} from "fs"; import {Stream} from "stream"; -import * as qrcode from "qrcode-terminal"; -import * as os from "os"; +import {generate as generateQR} from "qrcode-terminal"; +import {hostname, networkInterfaces} 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 {utils} from './utils'; export class BrowserWindow { public static win: any | undefined = null; @@ -29,7 +29,7 @@ export class BrowserWindow { }, }; private options: any = { - icon: path.join( + icon: join( utils.getPath('resourcePath'), `icons/icon.` + (process.platform === "win32" ? "ico" : "png") ), @@ -57,7 +57,7 @@ export class BrowserWindow { plugins: true, nodeIntegrationInWorker: false, webSecurity: false, - preload: path.join(utils.getPath('srcPath'), "./preload/cider-preload.js"), + preload: join(utils.getPath('srcPath'), "./preload/cider-preload.js"), }, }; @@ -66,7 +66,7 @@ export class BrowserWindow { */ async createWindow(): Promise { this.clientPort = await getPort({port: 9000}); - this.verifyFiles(); + BrowserWindow.verifyFiles(); // Load the previous state with fallback to defaults const windowState = windowStateKeeper({ @@ -96,7 +96,7 @@ export class BrowserWindow { /** * Verifies the files for the renderer to use (Cache, library info, etc.) */ - private verifyFiles(): void { + private static verifyFiles(): void { const expectedDirectories = ["CiderCache"]; const expectedFiles = [ "library-songs.json", @@ -107,19 +107,19 @@ export class BrowserWindow { ]; for (let i = 0; i < expectedDirectories.length; i++) { if ( - !fs.existsSync( - path.join(app.getPath("userData"), expectedDirectories[i]) + !existsSync( + join(app.getPath("userData"), expectedDirectories[i]) ) ) { - fs.mkdirSync( - path.join(app.getPath("userData"), expectedDirectories[i]) + mkdirSync( + join(app.getPath("userData"), expectedDirectories[i]) ); } } for (let i = 0; i < expectedFiles.length; i++) { - const file = path.join(utils.getPath('ciderCache'), expectedFiles[i]); - if (!fs.existsSync(file)) { - fs.writeFileSync(file, JSON.stringify([])); + const file = join(utils.getPath('ciderCache'), expectedFiles[i]); + if (!existsSync(file)) { + writeFileSync(file, JSON.stringify([])); } } } @@ -130,8 +130,8 @@ export class BrowserWindow { private startWebServer(): void { const app = express(); - app.use(express.static(path.join(utils.getPath('srcPath'), "./renderer/"))); - app.set("views", path.join(utils.getPath('srcPath'), "./renderer/views")); + app.use(express.static(join(utils.getPath('srcPath'), "./renderer/"))); + app.set("views", join(utils.getPath('srcPath'), "./renderer/views")); app.set("view engine", "ejs"); let firstRequest = true; app.use((req, res, next) => { @@ -152,11 +152,11 @@ export class BrowserWindow { app.get("/themes/:theme", (req, res) => { const theme = req.params.theme.toLowerCase(); - const themePath = path.join(utils.getPath('srcPath'), "./renderer/themes/", theme); - const userThemePath = path.join(utils.getPath('themes'), theme); - if (fs.existsSync(userThemePath)) { + const themePath = join(utils.getPath('srcPath'), "./renderer/themes/", theme); + const userThemePath = join(utils.getPath('themes'), theme); + if (existsSync(userThemePath)) { res.sendFile(userThemePath); - } else if (fs.existsSync(themePath)) { + } else if (existsSync(themePath)) { res.sendFile(themePath); } else { res.send(`// Theme not found - ${userThemePath}`); @@ -197,8 +197,8 @@ export class BrowserWindow { * https://github.com/ciderapp/Apple-Music-Electron/blob/818ed18940ff600d76eb59d22016723a75885cd5/resources/functions/handler.js#L1173 */ const remote = express(); - remote.use(express.static(path.join(utils.getPath('srcPath'), "./web-remote/"))) - remote.set("views", path.join(utils.getPath('srcPath'), "./web-remote/views")); + remote.use(express.static(join(utils.getPath('srcPath'), "./web-remote/"))) + remote.set("views", join(utils.getPath('srcPath'), "./web-remote/views")); remote.set("view engine", "ejs"); getPort({port: 6942}).then((port) => { this.remotePort = port; @@ -208,7 +208,7 @@ export class BrowserWindow { console.log(`Cider remote port: ${this.remotePort}`); if (firstRequest) { console.log("---- Ignore Me ;) ---"); - qrcode.generate(`http://${os.hostname}:${this.remotePort}`); + generateQR(`http://${hostname}:${this.remotePort}`); console.log("---- Ignore Me ;) ---"); /* * @@ -290,9 +290,9 @@ export class BrowserWindow { event.returnValue = process.platform; }); - ipcMain.on("get-themes", (event, key) => { - if (fs.existsSync(utils.getPath("themes"))) { - event.returnValue = fs.readdirSync(utils.getPath("themes")); + ipcMain.on("get-themes", (event, _key) => { + if (existsSync(utils.getPath("themes"))) { + event.returnValue = readdirSync(utils.getPath("themes")); } else { event.returnValue = []; } @@ -303,11 +303,11 @@ export class BrowserWindow { }); ipcMain.on("get-i18n-listing", event => { - let i18nFiles = fs.readdirSync(path.join(__dirname, "../../src/i18n")).filter(file => file.endsWith(".jsonc")); + let i18nFiles = readdirSync(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(fs.readFileSync(path.join(__dirname, `../../src/i18n/${i18nFiles[i]}`), "utf8")); + const i18n: { [index: string]: Object } = jsonc.parse(readFileSync(join(__dirname, `../../src/i18n/${i18nFiles[i]}`), "utf8")); i18nListing.push({ "code": i18nFiles[i].replace(".jsonc", ""), "nameNative": i18n["i18n.languageName"] ?? i18nFiles[i].replace(".jsonc", ""), @@ -328,75 +328,75 @@ export class BrowserWindow { }); ipcMain.on("put-library-songs", (_event, arg) => { - fs.writeFileSync( - path.join(utils.getPath('ciderCache'), "library-songs.json"), + writeFileSync( + join(utils.getPath('ciderCache'), "library-songs.json"), JSON.stringify(arg) ); }); ipcMain.on("put-library-artists", (_event, arg) => { - fs.writeFileSync( - path.join(utils.getPath('ciderCache'), "library-artists.json"), + writeFileSync( + join(utils.getPath('ciderCache'), "library-artists.json"), JSON.stringify(arg) ); }); ipcMain.on("put-library-albums", (_event, arg) => { - fs.writeFileSync( - path.join(utils.getPath('ciderCache'), "library-albums.json"), + writeFileSync( + join(utils.getPath('ciderCache'), "library-albums.json"), JSON.stringify(arg) ); }); ipcMain.on("put-library-playlists", (_event, arg) => { - fs.writeFileSync( - path.join(utils.getPath('ciderCache'), "library-playlists.json"), + writeFileSync( + join(utils.getPath('ciderCache'), "library-playlists.json"), JSON.stringify(arg) ); }); ipcMain.on("put-library-recentlyAdded", (_event, arg) => { - fs.writeFileSync( - path.join(utils.getPath('ciderCache'), "library-recentlyAdded.json"), + writeFileSync( + join(utils.getPath('ciderCache'), "library-recentlyAdded.json"), JSON.stringify(arg) ); }); ipcMain.on("get-library-songs", (event) => { - let librarySongs = fs.readFileSync( - path.join(utils.getPath('ciderCache'), "library-songs.json"), + let librarySongs = readFileSync( + join(utils.getPath('ciderCache'), "library-songs.json"), "utf8" ); event.returnValue = JSON.parse(librarySongs); }); ipcMain.on("get-library-artists", (event) => { - let libraryArtists = fs.readFileSync( - path.join(utils.getPath('ciderCache'), "library-artists.json"), + let libraryArtists = readFileSync( + join(utils.getPath('ciderCache'), "library-artists.json"), "utf8" ); event.returnValue = JSON.parse(libraryArtists); }); ipcMain.on("get-library-albums", (event) => { - let libraryAlbums = fs.readFileSync( - path.join(utils.getPath('ciderCache'), "library-albums.json"), + let libraryAlbums = readFileSync( + join(utils.getPath('ciderCache'), "library-albums.json"), "utf8" ); event.returnValue = JSON.parse(libraryAlbums); }); ipcMain.on("get-library-playlists", (event) => { - let libraryPlaylists = fs.readFileSync( - path.join(utils.getPath('ciderCache'), "library-playlists.json"), + let libraryPlaylists = readFileSync( + join(utils.getPath('ciderCache'), "library-playlists.json"), "utf8" ); event.returnValue = JSON.parse(libraryPlaylists); }); ipcMain.on("get-library-recentlyAdded", (event) => { - let libraryRecentlyAdded = fs.readFileSync( - path.join(utils.getPath('ciderCache'), "library-recentlyAdded.json"), + let libraryRecentlyAdded = readFileSync( + join(utils.getPath('ciderCache'), "library-recentlyAdded.json"), "utf8" ); event.returnValue = JSON.parse(libraryRecentlyAdded); @@ -404,7 +404,7 @@ export class BrowserWindow { ipcMain.handle("getYTLyrics", async (_event, track, artist) => { const u = track + " " + artist + " official video"; - return await yt.search(u); + return await search(u); }); ipcMain.on("close", (_event, platformCheck) => { @@ -470,7 +470,7 @@ export class BrowserWindow { }) //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); }) @@ -490,7 +490,7 @@ export class BrowserWindow { }); }); - ipcMain.on('check-for-update', async (_event, url) => { + ipcMain.on('check-for-update', async (_event) => { const options: any = { provider: 'generic', url: 'https://43-429851205-gh.circle-artifacts.com/0/%7E/Cider/dist/artifacts' //Base URL @@ -570,10 +570,14 @@ export class BrowserWindow { }); } + /** + * Gets ip + * @private + */ private static getIP(): string { let ip: string = ''; let alias = 0; - const ifaces: any = os.networkInterfaces(); + const ifaces: any = networkInterfaces(); for (let dev in ifaces) { ifaces[dev].forEach((details: any) => { if (details.family === 'IPv4') { diff --git a/src/main/base/store.ts b/src/main/base/store.ts index 54ca5ba9..8156799c 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -142,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); }); @@ -154,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 }) } diff --git a/src/main/base/utils.ts b/src/main/base/utils.ts index 45794353..5197a6eb 100644 --- a/src/main/base/utils.ts +++ b/src/main/base/utils.ts @@ -13,6 +13,7 @@ export class utils { 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"), @@ -34,10 +35,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(__dirname, "../../src/i18n/en_US.jsonc"), "utf8")); + let i18n: { [index: string]: Object } = jsonc.parse(fs.readFileSync(path.join(this.paths.i18nPath, "en_US.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 (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 (key) { diff --git a/src/main/base/wsapi.ts b/src/main/base/wsapi.ts index bb82ec49..bfd62c9f 100644 --- a/src/main/base/wsapi.ts +++ b/src/main/base/wsapi.ts @@ -1,11 +1,6 @@ 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 { @@ -21,12 +16,13 @@ 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) { @@ -35,33 +31,34 @@ 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({ @@ -88,20 +85,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(); } @@ -140,9 +137,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; @@ -232,7 +229,7 @@ export class wsapi { break; case "quit": electron.app.quit(); - break; + break; } ws.send(JSON.stringify(response)); }); @@ -245,48 +242,56 @@ 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)); }); }