diff --git a/README.md b/README.md index 941ad929..dc35721e 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,14 @@

#### Links -* [Wiki](https://github.com/ciderapp/Cider/wiki) -* [Request Feature](https://github.com/ciderapp/Cider/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=%5BEnhancement%5D) -* [Report Bug](https://github.com/ciderapp/Cider/issues/new?assignees=&labels=bug&template=bug_report.md&title=%5BBUG%5D+) -* [**View The Releases**](https://github.com/ciderapp/Cider/releases/latest) + +- [Wiki](https://github.com/ciderapp/Cider/wiki) +- [Request Feature](https://github.com/ciderapp/Cider/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=%5BEnhancement%5D) +- [Report Bug](https://github.com/ciderapp/Cider/issues/new?assignees=&labels=bug&template=bug_report.md&title=%5BBUG%5D+) +- [**View The Releases**](https://github.com/ciderapp/Cider/releases/latest) ### Install Sources + [![Get it from Github](https://img.shields.io/badge/Get_It_From_GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/ciderapp/cider/releases/latest) [![Get it from the Microsoft Store](https://img.shields.io/badge/Get_It_From_The_Microsoft_Store-100000?style=for-the-badge&logo=microsoft)](https://www.microsoft.com/store/apps/9P21XJ9D9G66) @@ -34,17 +36,21 @@ [![Get it from the Snap Store](https://img.shields.io/badge/Get_It_From_The_Snap_Store-100000?style=for-the-badge&logo=snapcraft)](https://snapcraft.io/apple-music-electron) --> + [![Get it from the AUR](https://img.shields.io/badge/Get_It_From_The_AUR-100000?style=for-the-badge&logo=archlinux)](https://aur.archlinux.org/packages/cider) ### Compiling and Configuration + For more information surrounding configuration, compiling and other developer documentation, see the [compilation docs](https://cider.sh/docs/compile). ### Credits + ![Contributors](https://contrib.rocks/image?repo=ciderapp/Cider) ### Disclaimer -*This project is NOT affiliated with Apple in any way shape or form. The project is open source and free to use (with an Apple Music subscription) -for any legal concerns contact me at cryptofyre@cryptofyre.org.* + +_This project is NOT affiliated with Apple in any way shape or form. The project is open source and free to use (with an Apple Music subscription) +for any legal concerns contact me at cryptofyre@cryptofyre.org._


@@ -53,4 +59,4 @@ for any legal concerns contact me at
JetBrains MacStadium -

\ No newline at end of file +

diff --git a/src/main/cider-base.js b/src/main/cider-base.js index ed176448..801fe46d 100644 --- a/src/main/cider-base.js +++ b/src/main/cider-base.js @@ -1,9 +1,9 @@ -const { BrowserWindow, ipcMain, shell, app, screen } = require("electron") -const { join } = require("path") -const getPort = require("get-port"); -const express = require("express"); -const path = require("path"); -const windowStateKeeper = require("electron-window-state"); +const { BrowserWindow, ipcMain, shell, app, screen } = require('electron'); +const { join } = require('path'); +const getPort = require('get-port'); +const express = require('express'); +const path = require('path'); +const windowStateKeeper = require('electron-window-state'); const os = require('os'); const yt = require('youtube-search-without-api-key'); const discord = require('./discordrpc'); @@ -16,8 +16,10 @@ const fetch = require('electron-fetch').default; const { Stream } = require('stream'); // Analytics for debugging. -const ElectronSentry = require("@sentry/electron"); -ElectronSentry.init({ dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214" }); +const ElectronSentry = require('@sentry/electron'); +ElectronSentry.init({ + dsn: 'https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214' +}); const CiderBase = { win: null, @@ -25,18 +27,18 @@ const CiderBase = { audiostream: new Stream.PassThrough(), async Start() { this.clientPort = await getPort({ port: 9000 }); - this.win = this.CreateBrowserWindow() + this.win = this.CreateBrowserWindow(); }, clientPort: 0, CreateBrowserWindow() { - this.VerifyFiles() + this.VerifyFiles(); // Set default window sizes const mainWindowState = windowStateKeeper({ defaultWidth: 1024, defaultHeight: 600 }); - let win = null + let win = null; const options = { icon: join(__dirname, `../../resources/icons/icon.ico`), width: mainWindowState.width, @@ -46,7 +48,7 @@ const CiderBase = { minWidth: 844, minHeight: 410, frame: false, - title: "Cider", + title: 'Cider', vibrancy: 'dark', // transparent: true, hasShadow: false, @@ -63,135 +65,172 @@ const CiderBase = { contextIsolation: false, preload: join(__dirname, '../preload/cider-preload.js') } - } + }; - CiderBase.InitWebServer() + CiderBase.InitWebServer(); // Create the BrowserWindow - if (process.platform === "darwin" || process.platform === "linux") { - win = new BrowserWindow(options) + if (process.platform === 'darwin' || process.platform === 'linux') { + win = new BrowserWindow(options); } else { // i don't know why but we have to do this for acrylic to work properly - if (app.cfg.get("visual.window_transparency") !== "disabled") { - const { BrowserWindow } = require("electron-acrylic-window"); - win = new BrowserWindow(options) - win.setVibrancy("dark") + if (app.cfg.get('visual.window_transparency') !== 'disabled') { + const { BrowserWindow } = require('electron-acrylic-window'); + win = new BrowserWindow(options); + win.setVibrancy('dark'); } else { - win = new BrowserWindow(options) - win.setVibrancy("dark") + win = new BrowserWindow(options); + win.setVibrancy('dark'); } - } // intercept "https://js-cdn.music.apple.com/hls.js/2.141.0/hls.js/hls.js" and redirect to local file "./apple-hls.js" instead win.webContents.session.webRequest.onBeforeRequest( { - urls: ["https://*/*.js"] + urls: ['https://*/*.js'] }, (details, callback) => { - if (details.url.includes("hls.js")) { + if (details.url.includes('hls.js')) { callback({ redirectURL: `http://localhost:${CiderBase.clientPort}/apple-hls.js` - }) + }); } else { callback({ cancel: false - }) + }); } } - ) + ); - win.webContents.session.webRequest.onBeforeSendHeaders(async (details, callback) => { - if (details.url === "https://buy.itunes.apple.com/account/web/info") { - details.requestHeaders['sec-fetch-site'] = 'same-site'; - details.requestHeaders['DNT'] = '1'; - let itspod = await win.webContents.executeJavaScript(`window.localStorage.getItem("music.ampwebplay.itspod")`) - if (itspod != null) - details.requestHeaders['Cookie'] = `itspod=${itspod}` + win.webContents.session.webRequest.onBeforeSendHeaders( + async (details, callback) => { + if ( + details.url === + 'https://buy.itunes.apple.com/account/web/info' + ) { + details.requestHeaders['sec-fetch-site'] = 'same-site'; + details.requestHeaders['DNT'] = '1'; + let itspod = await win.webContents.executeJavaScript( + `window.localStorage.getItem("music.ampwebplay.itspod")` + ); + if (itspod != null) + details.requestHeaders['Cookie'] = `itspod=${itspod}`; + } + callback({ requestHeaders: details.requestHeaders }); } - callback({ requestHeaders: details.requestHeaders }) - }) + ); - let location = `http://localhost:${CiderBase.clientPort}/` - win.loadURL(location) - win.on("closed", () => { - win = null - }) + let location = `http://localhost:${CiderBase.clientPort}/`; + win.loadURL(location); + win.on('closed', () => { + win = null; + }); // Register listeners on Window to track size and position of the Window. mainWindowState.manage(win); // IPC stuff (senders) - ipcMain.on("cider-platform", (event) => { - event.returnValue = process.platform - }) + ipcMain.on('cider-platform', (event) => { + event.returnValue = process.platform; + }); - ipcMain.on("get-gpu-mode", (event) => { - event.returnValue = process.platform - }) + ipcMain.on('get-gpu-mode', (event) => { + event.returnValue = process.platform; + }); - ipcMain.on("is-dev", (event) => { - event.returnValue = !app.isPackaged - }) + ipcMain.on('is-dev', (event) => { + event.returnValue = !app.isPackaged; + }); // IPC stuff (listeners) - ipcMain.on('close', () => { // listen for close event + ipcMain.on('close', () => { + // listen for close event win.close(); - }) + }); ipcMain.on('put-library-songs', (event, arg) => { - fs.writeFileSync(join(app.paths.ciderCache, "library-songs.json"), JSON.stringify(arg)) - }) + fs.writeFileSync( + join(app.paths.ciderCache, 'library-songs.json'), + JSON.stringify(arg) + ); + }); ipcMain.on('put-library-artists', (event, arg) => { - fs.writeFileSync(join(app.paths.ciderCache, "library-artists.json"), JSON.stringify(arg)) - }) + fs.writeFileSync( + join(app.paths.ciderCache, 'library-artists.json'), + JSON.stringify(arg) + ); + }); ipcMain.on('put-library-albums', (event, arg) => { - fs.writeFileSync(join(app.paths.ciderCache, "library-albums.json"), JSON.stringify(arg)) - }) + fs.writeFileSync( + join(app.paths.ciderCache, 'library-albums.json'), + JSON.stringify(arg) + ); + }); ipcMain.on('put-library-playlists', (event, arg) => { - fs.writeFileSync(join(app.paths.ciderCache, "library-playlists.json"), JSON.stringify(arg)) - }) + fs.writeFileSync( + join(app.paths.ciderCache, 'library-playlists.json'), + JSON.stringify(arg) + ); + }); ipcMain.on('put-library-recentlyAdded', (event, arg) => { - fs.writeFileSync(join(app.paths.ciderCache, "library-recentlyAdded.json"), JSON.stringify(arg)) - }) + fs.writeFileSync( + join(app.paths.ciderCache, 'library-recentlyAdded.json'), + JSON.stringify(arg) + ); + }); ipcMain.on('get-library-songs', (event) => { - let librarySongs = fs.readFileSync(join(app.paths.ciderCache, "library-songs.json"), "utf8") - event.returnValue = JSON.parse(librarySongs) - }) + let librarySongs = fs.readFileSync( + join(app.paths.ciderCache, 'library-songs.json'), + 'utf8' + ); + event.returnValue = JSON.parse(librarySongs); + }); ipcMain.on('get-library-artists', (event) => { - let libraryArtists = fs.readFileSync(join(app.paths.ciderCache, "library-artists.json"), "utf8") - event.returnValue = JSON.parse(libraryArtists) - }) + let libraryArtists = fs.readFileSync( + join(app.paths.ciderCache, 'library-artists.json'), + 'utf8' + ); + event.returnValue = JSON.parse(libraryArtists); + }); ipcMain.on('get-library-albums', (event) => { - let libraryAlbums = fs.readFileSync(join(app.paths.ciderCache, "library-albums.json"), "utf8") - event.returnValue = JSON.parse(libraryAlbums) - }) + let libraryAlbums = fs.readFileSync( + join(app.paths.ciderCache, 'library-albums.json'), + 'utf8' + ); + event.returnValue = JSON.parse(libraryAlbums); + }); ipcMain.on('get-library-playlists', (event) => { - let libraryPlaylists = fs.readFileSync(join(app.paths.ciderCache, "library-playlists.json"), "utf8") - event.returnValue = JSON.parse(libraryPlaylists) - }) + let libraryPlaylists = fs.readFileSync( + join(app.paths.ciderCache, 'library-playlists.json'), + 'utf8' + ); + event.returnValue = JSON.parse(libraryPlaylists); + }); ipcMain.on('get-library-recentlyAdded', (event) => { - let libraryRecentlyAdded = fs.readFileSync(join(app.paths.ciderCache, "library-recentlyAdded.json"), "utf8") - event.returnValue = JSON.parse(libraryRecentlyAdded) - }) + let libraryRecentlyAdded = fs.readFileSync( + join(app.paths.ciderCache, 'library-recentlyAdded.json'), + 'utf8' + ); + event.returnValue = JSON.parse(libraryRecentlyAdded); + }); ipcMain.handle('getYTLyrics', async (event, track, artist) => { - var u = track + " " + artist + " official video"; + var u = track + ' ' + artist + ' official video'; const videos = await yt.search(u); - return videos - }) + return videos; + }); ipcMain.handle('getStoreValue', (event, key, defaultValue) => { - return (defaultValue ? app.cfg.get(key, true) : app.cfg.get(key)); + return defaultValue ? app.cfg.get(key, true) : app.cfg.get(key); }); ipcMain.handle('setStoreValue', (event, key, value) => { @@ -199,181 +238,209 @@ const CiderBase = { }); ipcMain.on('getStore', (event) => { - event.returnValue = app.cfg.store - }) - - ipcMain.on('setStore', (event, store) => { - app.cfg.store = store - }) - - ipcMain.handle('setVibrancy', (event, key, value) => { - win.setVibrancy(value) + event.returnValue = app.cfg.store; }); - ipcMain.on('maximize', () => { // listen for maximize event + ipcMain.on('setStore', (event, store) => { + app.cfg.store = store; + }); + + ipcMain.handle('setVibrancy', (event, key, value) => { + win.setVibrancy(value); + }); + + ipcMain.on('maximize', () => { + // listen for maximize event if (win.isMaximized()) { - win.unmaximize() + win.unmaximize(); } else { - win.maximize() + win.maximize(); } - }) + }); - ipcMain.on('minimize', () => { // listen for minimize event + ipcMain.on('minimize', () => { + // listen for minimize event win.minimize(); - }) + }); - if (process.platform === "win32") { + if (process.platform === 'win32') { let WND_STATE = { MINIMIZED: 0, NORMAL: 1, MAXIMIZED: 2, FULL_SCREEN: 3 - } - let wndState = WND_STATE.NORMAL + }; + let wndState = WND_STATE.NORMAL; - win.on("resize", (_event) => { - const isMaximized = win.isMaximized() - const isMinimized = win.isMinimized() - const isFullScreen = win.isFullScreen() + win.on('resize', (_event) => { + const isMaximized = win.isMaximized(); + const isMinimized = win.isMinimized(); + const isFullScreen = win.isFullScreen(); const state = wndState; if (isMinimized && state !== WND_STATE.MINIMIZED) { - wndState = WND_STATE.MINIMIZED + wndState = WND_STATE.MINIMIZED; } else if (isFullScreen && state !== WND_STATE.FULL_SCREEN) { - wndState = WND_STATE.FULL_SCREEN + wndState = WND_STATE.FULL_SCREEN; } else if (isMaximized && state !== WND_STATE.MAXIMIZED) { - wndState = WND_STATE.MAXIMIZED - win.webContents.executeJavaScript(`app.chrome.maximized = true`) + wndState = WND_STATE.MAXIMIZED; + win.webContents.executeJavaScript( + `app.chrome.maximized = true` + ); } else if (state !== WND_STATE.NORMAL) { - wndState = WND_STATE.NORMAL - win.webContents.executeJavaScript(`app.chrome.maximized = false`) + wndState = WND_STATE.NORMAL; + win.webContents.executeJavaScript( + `app.chrome.maximized = false` + ); } - }) + }); } // Set window Handler win.webContents.setWindowOpenHandler(({ url }) => { - if (url.includes("apple") || url.includes("localhost")) { - return { action: "allow" } + if (url.includes('apple') || url.includes('localhost')) { + return { action: 'allow' }; } - shell.openExternal(url).catch(() => { - }) + shell.openExternal(url).catch(() => {}); return { action: 'deny' - } - }) + }; + }); // Set scale ipcMain.on('setScreenScale', (event, scale) => { - win.webContents.setZoomFactor(parseFloat(scale)) - }) + win.webContents.setZoomFactor(parseFloat(scale)); + }); - win.webContents.setZoomFactor(screen.getPrimaryDisplay().scaleFactor) + win.webContents.setZoomFactor(screen.getPrimaryDisplay().scaleFactor); - mpris.connect(win) + mpris.connect(win); - lastfm.authenticate() + lastfm.authenticate(); // Discord - discord.connect((app.cfg.get("general.discord_rpc") == 1) ? '911790844204437504' : '886578863147192350'); + discord.connect( + app.cfg.get('general.discord_rpc') == 1 + ? '911790844204437504' + : '886578863147192350' + ); ipcMain.on('playbackStateDidChange', (_event, a) => { app.media = a; - discord.updateActivity(a) - mpris.updateState(a) - lastfm.scrobbleSong(a) - lastfm.updateNowPlayingSong(a) + discord.updateActivity(a); + mpris.updateState(a); + lastfm.scrobbleSong(a); + lastfm.updateNowPlayingSong(a); }); ipcMain.on('nowPlayingItemDidChange', (_event, a) => { app.media = a; - discord.updateActivity(a) - mpris.updateAttributes(a) - lastfm.scrobbleSong(a) - lastfm.updateNowPlayingSong(a) + discord.updateActivity(a); + mpris.updateAttributes(a); + lastfm.scrobbleSong(a); + lastfm.updateNowPlayingSong(a); }); - ipcMain.on("getPreviewURL", (_event, url) => { + ipcMain.on('getPreviewURL', (_event, url) => { fetch(url) - .then(res => res.buffer()) + .then((res) => res.buffer()) .then(async (buffer) => { try { - const metadata = await mm.parseBuffer(buffer, 'audio/x-m4a'); - SoundCheckTag = metadata.native.iTunes[1].value - win.webContents.send('SoundCheckTag', SoundCheckTag) + const metadata = await mm.parseBuffer( + buffer, + 'audio/x-m4a' + ); + SoundCheckTag = metadata.native.iTunes[1].value; + win.webContents.send('SoundCheckTag', SoundCheckTag); } catch (error) { console.error(error.message); } - }) + }); }); ipcMain.on('writeAudio', function (event, buffer) { CiderBase.audiostream.write(Buffer.from(buffer)); - }) + }); - return win + return win; }, VerifyFiles() { - const expectedDirectories = [ - "CiderCache" - ] + const expectedDirectories = ['CiderCache']; const expectedFiles = [ - "library-songs.json", - "library-artists.json", - "library-albums.json", - "library-playlists.json", - "library-recentlyAdded.json", - ] + 'library-songs.json', + 'library-artists.json', + 'library-albums.json', + 'library-playlists.json', + 'library-recentlyAdded.json' + ]; for (let i = 0; i < expectedDirectories.length; i++) { - if (!existsSync(path.join(app.getPath("userData"), expectedDirectories[i]))) { - mkdirSync(path.join(app.getPath("userData"), expectedDirectories[i])) + if ( + !existsSync( + path.join(app.getPath('userData'), expectedDirectories[i]) + ) + ) { + mkdirSync( + path.join(app.getPath('userData'), expectedDirectories[i]) + ); } } for (let i = 0; i < expectedFiles.length; i++) { - const file = path.join(app.paths.ciderCache, expectedFiles[i]) + const file = path.join(app.paths.ciderCache, expectedFiles[i]); if (!existsSync(file)) { - writeFileSync(file, JSON.stringify([])) + writeFileSync(file, JSON.stringify([])); } } }, EnvironmentVariables: { - "env": { + env: { platform: os.platform(), dev: app.isPackaged } }, LinkHandler: (startArgs) => { if (!startArgs) return; - console.log("lfmtoken", String(startArgs)) + console.log('lfmtoken', String(startArgs)); if (String(startArgs).includes('auth')) { - let authURI = String(startArgs).split('/auth/')[1] - if (authURI.startsWith('lastfm')) { // If we wanted more auth options + let authURI = String(startArgs).split('/auth/')[1]; + if (authURI.startsWith('lastfm')) { + // If we wanted more auth options const authKey = authURI.split('lastfm?token=')[1]; app.cfg.set('lastfm.enabled', true); app.cfg.set('lastfm.auth_token', authKey); CiderBase.win.webContents.send('LastfmAuthenticated', authKey); - lastfm.authenticate() + lastfm.authenticate(); } } else { - const formattedSongID = startArgs.replace('ame://', '').replace('/', ''); - console.warn(`[LinkHandler] Attempting to load song id: ${formattedSongID}`); + const formattedSongID = startArgs + .replace('ame://', '') + .replace('/', ''); + console.warn( + `[LinkHandler] Attempting to load song id: ${formattedSongID}` + ); // setQueue can be done with album, song, url, playlist id - this.win.webContents.executeJavaScript(` + this.win.webContents + .executeJavaScript( + ` MusicKit.getInstance().setQueue({ song: '${formattedSongID}'}).then(function(queue) { MusicKit.getInstance().play(); }); - `).catch((err) => console.error(err)); + ` + ) + .catch((err) => console.error(err)); } - }, async InitWebServer() { const webapp = express(); const webRemotePath = path.join(__dirname, '../renderer/'); - webapp.set("views", path.join(webRemotePath, "views")); - webapp.set("view engine", "ejs"); + webapp.set('views', path.join(webRemotePath, 'views')); + webapp.set('view engine', 'ejs'); webapp.use(function (req, res, next) { // if not localhost - if (req.url.includes("audio.webm") || (req.headers.host.includes("localhost") && req.headers["user-agent"].includes("Cider"))) { + if ( + req.url.includes('audio.webm') || + (req.headers.host.includes('localhost') && + req.headers['user-agent'].includes('Cider')) + ) { next(); } }); @@ -381,7 +448,7 @@ const CiderBase = { webapp.use(express.static(webRemotePath)); webapp.get('/', function (req, res) { //res.sendFile(path.join(webRemotePath, 'index_old.html')); - res.render("main", CiderBase.EnvironmentVariables) + res.render('main', CiderBase.EnvironmentVariables); }); webapp.get('/audio.webm', function (req, res) { try { @@ -397,16 +464,17 @@ const CiderBase = { try { res.write(data); } catch (ex) { - console.log(ex) + console.log(ex); } - }) - } catch (ex) { console.log(ex) } + }); + } catch (ex) { + console.log(ex); + } }); webapp.listen(CiderBase.clientPort, function () { console.log(`Cider client port: ${CiderBase.clientPort}`); }); - }, - -} + } +}; module.exports = CiderBase; diff --git a/src/main/discordrpc.js b/src/main/discordrpc.js index 645039ca..c0d020fe 100644 --- a/src/main/discordrpc.js +++ b/src/main/discordrpc.js @@ -1,40 +1,48 @@ -const {app} = require('electron'), - DiscordRPC = require('discord-rpc') +const { app } = require('electron'), + DiscordRPC = require('discord-rpc'); module.exports = { - /** * Connects to Discord RPC * @param {string} clientId */ connect: function (clientId) { - app.discord = {isConnected: false}; + app.discord = { isConnected: false }; if (app.cfg.get('general.discord_rpc') == 0) return; - DiscordRPC.register(clientId) // Apparently needed for ask to join, join, spectate etc. - const client = new DiscordRPC.Client({transport: "ipc"}); - app.discord = Object.assign(client, {error: false, activityCache: null, isConnected: false}); + DiscordRPC.register(clientId); // Apparently needed for ask to join, join, spectate etc. + const client = new DiscordRPC.Client({ transport: 'ipc' }); + app.discord = Object.assign(client, { + error: false, + activityCache: null, + isConnected: false + }); // Login to Discord - app.discord.login({clientId}) + app.discord + .login({ clientId }) .then(() => { app.discord.isConnected = true; }) .catch((e) => console.error(`[DiscordRPC][connect] ${e}`)); app.discord.on('ready', () => { - console.log(`[DiscordRPC][connect] Successfully Connected to Discord. Authed for user: ${client.user.username} (${client.user.id})`); + console.log( + `[DiscordRPC][connect] Successfully Connected to Discord. Authed for user: ${client.user.username} (${client.user.id})` + ); if (app.discord.activityCache) { - client.setActivity(app.discord.activityCache).catch((e) => console.error(e)); + client + .setActivity(app.discord.activityCache) + .catch((e) => console.error(e)); app.discord.activityCache = null; } - }) + }); // Handles Errors - app.discord.on('error', err => { + app.discord.on('error', (err) => { console.error(`[DiscordRPC] ${err}`); - this.disconnect() + this.disconnect(); app.discord.isConnected = false; }); }, @@ -43,15 +51,21 @@ module.exports = { * Disconnects from Discord RPC */ disconnect: function () { - if (app.cfg.get('general.discord_rpc') == 0 || !app.discord.isConnected) return; + if (app.cfg.get('general.discord_rpc') == 0 || !app.discord.isConnected) + return; try { - app.discord.destroy().then(() => { - app.discord.isConnected = false; - console.log('[DiscordRPC][disconnect] Disconnected from discord.') - }).catch((e) => console.error(`[DiscordRPC][disconnect] ${e}`)); + app.discord + .destroy() + .then(() => { + app.discord.isConnected = false; + console.log( + '[DiscordRPC][disconnect] Disconnected from discord.' + ); + }) + .catch((e) => console.error(`[DiscordRPC][disconnect] ${e}`)); } catch (err) { - console.error(err) + console.error(err); } }, @@ -63,76 +77,87 @@ module.exports = { if (app.cfg.get('general.discord_rpc') == 0) return; if (!app.discord.isConnected) { - this.connect() + this.connect(); } if (!app.discord.isConnected) return; // console.log('[DiscordRPC][updateActivity] Updating Discord Activity.') - const listenURL = `https://applemusicelectron.com/p?id=${attributes.playParams.id}` + const listenURL = `https://applemusicelectron.com/p?id=${attributes.playParams.id}`; //console.log(attributes) let ActivityObject = { details: attributes.name, state: `by ${attributes.artistName}`, startTimestamp: attributes.startTime, endTimestamp: attributes.endTime, - largeImageKey: (attributes.artwork.url.replace('{w}', '1024').replace('{h}', '1024')) ?? 'cider', + largeImageKey: + attributes.artwork.url + .replace('{w}', '1024') + .replace('{h}', '1024') ?? 'cider', largeImageText: attributes.albumName, - smallImageKey: (attributes.status ? 'play' : 'pause'), - smallImageText: (attributes.status ? 'Playing' : 'Paused'), + smallImageKey: attributes.status ? 'play' : 'pause', + smallImageText: attributes.status ? 'Playing' : 'Paused', instance: true, - buttons: [ - {label: "Listen on Cider", url: listenURL}, - ] + buttons: [{ label: 'Listen on Cider', url: listenURL }] }; - if (ActivityObject.largeImageKey == "" || ActivityObject.largeImageKey == null) { - ActivityObject.largeImageKey = (app.cfg.get("general.discord_rpc") == 1) ? "cider" : "logo" + if ( + ActivityObject.largeImageKey == '' || + ActivityObject.largeImageKey == null + ) { + ActivityObject.largeImageKey = + app.cfg.get('general.discord_rpc') == 1 ? 'cider' : 'logo'; } // console.log(`[LinkHandler] Listening URL has been set to: ${listenURL}`); - if (app.cfg.get('general.discordClearActivityOnPause') == 1) { - delete ActivityObject.smallImageKey - delete ActivityObject.smallImageText + if (app.cfg.get('general.discordClearActivityOnPause') == 1) { + delete ActivityObject.smallImageKey; + delete ActivityObject.smallImageText; } // Check all the values work - if (!((new Date(attributes.endTime)).getTime() > 0)) { - delete ActivityObject.startTimestamp - delete ActivityObject.endTimestamp + if (!(new Date(attributes.endTime).getTime() > 0)) { + delete ActivityObject.startTimestamp; + delete ActivityObject.endTimestamp; } if (!attributes.artistName) { - delete ActivityObject.state + delete ActivityObject.state; } - if (!ActivityObject.largeImageText || ActivityObject.largeImageText.length < 2) { - delete ActivityObject.largeImageText + if ( + !ActivityObject.largeImageText || + ActivityObject.largeImageText.length < 2 + ) { + delete ActivityObject.largeImageText; } if (ActivityObject.details.length > 128) { - AcitivityObject.details = ActivityObject.details.substring(0, 125) + '...' + AcitivityObject.details = + ActivityObject.details.substring(0, 125) + '...'; } // Clear if if needed if (!attributes.status) { if (app.cfg.get('general.discordClearActivityOnPause') == 1) { - app.discord.clearActivity().catch((e) => console.error(`[DiscordRPC][clearActivity] ${e}`)); - ActivityObject = null - } else - { - delete ActivityObject.startTimestamp - delete ActivityObject.endTimestamp - ActivityObject.smallImageKey = 'pause' - ActivityObject.smallImageText = 'Paused' + app.discord + .clearActivity() + .catch((e) => + console.error(`[DiscordRPC][clearActivity] ${e}`) + ); + ActivityObject = null; + } else { + delete ActivityObject.startTimestamp; + delete ActivityObject.endTimestamp; + ActivityObject.smallImageKey = 'pause'; + ActivityObject.smallImageText = 'Paused'; } } if (ActivityObject) { try { - // console.log(`[DiscordRPC][setActivity] Setting activity to ${JSON.stringify(ActivityObject)}`); - app.discord.setActivity(ActivityObject) + // console.log(`[DiscordRPC][setActivity] Setting activity to ${JSON.stringify(ActivityObject)}`); + app.discord.setActivity(ActivityObject); } catch (err) { - console.error(`[DiscordRPC][setActivity] ${err}`) + console.error(`[DiscordRPC][setActivity] ${err}`); } - } - }, -} \ No newline at end of file + } +}; diff --git a/src/main/lastfm.js b/src/main/lastfm.js index 74dfa5b2..bf661de7 100644 --- a/src/main/lastfm.js +++ b/src/main/lastfm.js @@ -1,16 +1,18 @@ -const {app, Notification} = require('electron'), +const { app, Notification } = require('electron'), fs = require('fs'), - {resolve} = require('path'), + { resolve } = require('path'), sessionPath = resolve(app.getPath('userData'), 'session.json'), apiCredentials = require('../../resources/lfmApiCredentials.json'), LastfmAPI = require('lastfmapi'); const lfm = { authenticateFromFile: function () { - let sessionData = require(sessionPath) - console.log("[LastFM][authenticateFromFile] Logging in with Session Info.") - app.lastfm.setSessionCredentials(sessionData.name, sessionData.key) - console.log("[LastFM][authenticateFromFile] Logged in.") + let sessionData = require(sessionPath); + console.log( + '[LastFM][authenticateFromFile] Logging in with Session Info.' + ); + app.lastfm.setSessionCredentials(sessionData.name, sessionData.key); + console.log('[LastFM][authenticateFromFile] Logged in.'); }, authenticate: function () { @@ -18,84 +20,125 @@ const lfm = { app.cfg.set('lastfm.enabled', true); } - if (!app.cfg.get('lastfm.enabled') || !app.cfg.get('lastfm.auth_token')) { + if ( + !app.cfg.get('lastfm.enabled') || + !app.cfg.get('lastfm.auth_token') + ) { app.cfg.set('lastfm.enabled', false); - return + return; } const lfmAPI = new LastfmAPI({ - 'api_key': apiCredentials.key, - 'secret': apiCredentials.secret + api_key: apiCredentials.key, + secret: apiCredentials.secret }); - app.lastfm = Object.assign(lfmAPI, {cachedAttributes: false, cachedNowPlayingAttributes: false}); + app.lastfm = Object.assign(lfmAPI, { + cachedAttributes: false, + cachedNowPlayingAttributes: false + }); fs.stat(sessionPath, function (err) { if (err) { - console.error("[LastFM][Session] Session file couldn't be opened or doesn't exist,", err) - console.log("[LastFM][Auth] Beginning authentication from configuration") - app.lastfm.authenticate(app.cfg.get('lastfm.auth_token'), function (err, session) { - if (err) { - throw err; - } - console.log("[LastFM] Successfully obtained LastFM session info,", session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} - console.log("[LastFM] Saving session info to disk.") - let tempData = JSON.stringify(session) - fs.writeFile(sessionPath, tempData, (err) => { - if (err) - console.log("[LastFM][fs]", err) - else { - console.log("[LastFM][fs] File was written successfully.") - lfm.authenticateFromFile() - new Notification({ - title: app.getName(), - body: "Successfully logged into LastFM using Authentication Key." - }).show() + console.error( + "[LastFM][Session] Session file couldn't be opened or doesn't exist,", + err + ); + console.log( + '[LastFM][Auth] Beginning authentication from configuration' + ); + app.lastfm.authenticate( + app.cfg.get('lastfm.auth_token'), + function (err, session) { + if (err) { + throw err; } - }) - }); + console.log( + '[LastFM] Successfully obtained LastFM session info,', + session + ); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} + console.log('[LastFM] Saving session info to disk.'); + let tempData = JSON.stringify(session); + fs.writeFile(sessionPath, tempData, (err) => { + if (err) console.log('[LastFM][fs]', err); + else { + console.log( + '[LastFM][fs] File was written successfully.' + ); + lfm.authenticateFromFile(); + new Notification({ + title: app.getName(), + body: 'Successfully logged into LastFM using Authentication Key.' + }).show(); + } + }); + } + ); } else { - lfm.authenticateFromFile() + lfm.authenticateFromFile(); } - }) + }); }, scrobbleSong: async function (attributes) { - await new Promise(resolve => setTimeout(resolve, app.cfg.get('lastfm.scrobble_after') * 1000)); + await new Promise((resolve) => + setTimeout(resolve, app.cfg.get('lastfm.scrobble_after') * 1000) + ); const currentAttributes = app.media; - - if (!app.lastfm || app.lastfm.cachedAttributes === attributes ) { - return + + if (!app.lastfm || app.lastfm.cachedAttributes === attributes) { + return; } if (app.lastfm.cachedAttributes) { - if (app.lastfm.cachedAttributes.playParams.id === attributes.playParams.id) return; + if ( + app.lastfm.cachedAttributes.playParams.id === + attributes.playParams.id + ) + return; } if (currentAttributes.status && currentAttributes === attributes) { if (fs.existsSync(sessionPath)) { // Scrobble playing song. if (attributes.status === true) { - app.lastfm.track.scrobble({ - 'artist': lfm.filterArtistName(attributes.artistName), - 'track': attributes.name, - 'album': attributes.albumName, - 'albumArtist': this.filterArtistName(attributes.artistName), - 'timestamp': new Date().getTime() / 1000 - }, function (err, scrobbled) { - if (err) { - return console.error('[LastFM] An error occurred while scrobbling', err); - } + app.lastfm.track.scrobble( + { + artist: lfm.filterArtistName(attributes.artistName), + track: attributes.name, + album: attributes.albumName, + albumArtist: this.filterArtistName( + attributes.artistName + ), + timestamp: new Date().getTime() / 1000 + }, + function (err, scrobbled) { + if (err) { + return console.error( + '[LastFM] An error occurred while scrobbling', + err + ); + } - console.log('[LastFM] Successfully scrobbled: ', scrobbled); - }); - app.lastfm.cachedAttributes = attributes + console.log( + '[LastFM] Successfully scrobbled: ', + scrobbled + ); + } + ); + app.lastfm.cachedAttributes = attributes; } } else { this.authenticate(); } } else { - return console.log('[LastFM] Did not add ', attributes.name , '-' , lfm.filterArtistName(attributes.artistName), 'because now playing a other song.'); + return console.log( + '[LastFM] Did not add ', + attributes.name, + '-', + lfm.filterArtistName(attributes.artistName), + 'because now playing a other song.' + ); } }, @@ -111,43 +154,61 @@ const lfm = { } artist = artist.join(' '); if (artist.includes(',')) { - artist = artist.split(',') - artist = artist[0] + artist = artist.split(','); + artist = artist[0]; } return artist.charAt(0).toUpperCase() + artist.slice(1); }, updateNowPlayingSong: function (attributes) { - if (!app.lastfm ||app.lastfm.cachedNowPlayingAttributes === attributes | !app.cfg.get('lastfm.NowPlaying')) { - return + if ( + !app.lastfm || + app.lastfm.cachedNowPlayingAttributes === attributes || + !app.cfg.get('lastfm.NowPlaying') + ) { + return; } if (app.lastfm.cachedNowPlayingAttributes) { - if (app.lastfm.cachedNowPlayingAttributes.playParams.id === attributes.playParams.id) return; + if ( + app.lastfm.cachedNowPlayingAttributes.playParams.id === + attributes.playParams.id + ) + return; } if (fs.existsSync(sessionPath)) { // update Now Playing if (attributes.status === true) { - app.lastfm.track.updateNowPlaying({ - 'artist': lfm.filterArtistName(attributes.artistName), - 'track': attributes.name, - 'album': attributes.albumName, - 'albumArtist': this.filterArtistName(attributes.artistName) - }, function (err, nowPlaying) { - if (err) { - return console.error('[LastFM] An error occurred while updating nowPlayingSong', err); - } + app.lastfm.track.updateNowPlaying( + { + artist: lfm.filterArtistName(attributes.artistName), + track: attributes.name, + album: attributes.albumName, + albumArtist: this.filterArtistName( + attributes.artistName + ) + }, + function (err, nowPlaying) { + if (err) { + return console.error( + '[LastFM] An error occurred while updating nowPlayingSong', + err + ); + } - console.log('[LastFM] Successfully updated nowPlayingSong', nowPlaying); - }); - app.lastfm.cachedNowPlayingAttributes = attributes + console.log( + '[LastFM] Successfully updated nowPlayingSong', + nowPlaying + ); + } + ); + app.lastfm.cachedNowPlayingAttributes = attributes; } - } else { - this.authenticate() + this.authenticate(); } } -} +}; -module.exports = lfm; \ No newline at end of file +module.exports = lfm; diff --git a/src/main/mpris.js b/src/main/mpris.js index 3c92e322..103bfb9a 100644 --- a/src/main/mpris.js +++ b/src/main/mpris.js @@ -1,13 +1,12 @@ let mediaPlayer = null; module.exports = { - /** * Connects to the MPRIS interface. * @param {Object} win - The BrowserWindow. */ connect: (win) => { - if (process.platform !== "linux") return; + if (process.platform !== 'linux') return; const Player = require('mpris-service'); @@ -18,36 +17,51 @@ module.exports = { supportedMimeTypes: [], supportedInterfaces: ['player'] }); - mediaPlayer = Object.assign(mediaPlayer, { canQuit: true, canControl: true, canPause: true, canPlay: true, canGoNext: true }) + mediaPlayer = Object.assign(mediaPlayer, { + canQuit: true, + canControl: true, + canPause: true, + canPlay: true, + canGoNext: true + }); - - let pos_atr = {durationInMillis: 0}; + let pos_atr = { durationInMillis: 0 }; mediaPlayer.getPosition = function () { const durationInMicro = pos_atr.durationInMillis * 1000; - const percentage = parseFloat("0") || 0; + const percentage = parseFloat('0') || 0; return durationInMicro * percentage; - } + }; - mediaPlayer.active = true + mediaPlayer.active = true; mediaPlayer.on('playpause', async () => { - win.webContents.executeJavaScript('MusicKitInterop.pausePlay()').catch(err => console.error(err)) + win.webContents + .executeJavaScript('MusicKitInterop.pausePlay()') + .catch((err) => console.error(err)); }); mediaPlayer.on('play', async () => { - win.webContents.executeJavaScript('MusicKitInterop.pausePlay()').catch(err => console.error(err)) + win.webContents + .executeJavaScript('MusicKitInterop.pausePlay()') + .catch((err) => console.error(err)); }); mediaPlayer.on('pause', async () => { - win.webContents.executeJavaScript('MusicKitInterop.pausePlay()').catch(err => console.error(err)) + win.webContents + .executeJavaScript('MusicKitInterop.pausePlay()') + .catch((err) => console.error(err)); }); mediaPlayer.on('next', async () => { - win.webContents.executeJavaScript('MusicKitInterop.nextTrack()').catch(err => console.error(err)) + win.webContents + .executeJavaScript('MusicKitInterop.nextTrack()') + .catch((err) => console.error(err)); }); mediaPlayer.on('previous', async () => { - win.webContents.executeJavaScript('MusicKitInterop.previousTrack()').catch(err => console.error(err)) + win.webContents + .executeJavaScript('MusicKitInterop.previousTrack()') + .catch((err) => console.error(err)); }); }, @@ -56,23 +70,29 @@ module.exports = { * @param {Object} attributes - The attributes of the track. */ updateAttributes: (attributes) => { - if (process.platform !== "linux") return; + if (process.platform !== 'linux') return; const MetaData = { - 'mpris:trackid': mediaPlayer.objectPath(`track/${attributes.playParams.id.replace(/[.]+/g, "")}`), + 'mpris:trackid': mediaPlayer.objectPath( + `track/${attributes.playParams.id.replace(/[.]+/g, '')}` + ), 'mpris:length': attributes.durationInMillis * 1000, // In microseconds - 'mpris:artUrl': (attributes.artwork.url.replace('/{w}x{h}bb', '/512x512bb')).replace('/2000x2000bb', '/35x35bb'), + 'mpris:artUrl': attributes.artwork.url + .replace('/{w}x{h}bb', '/512x512bb') + .replace('/2000x2000bb', '/35x35bb'), 'xesam:title': `${attributes.name}`, 'xesam:album': `${attributes.albumName}`, - 'xesam:artist': [`${attributes.artistName}`,], + 'xesam:artist': [`${attributes.artistName}`], 'xesam:genre': attributes.genreNames + }; + + if ( + mediaPlayer.metadata['mpris:trackid'] === MetaData['mpris:trackid'] + ) { + return; } - if (mediaPlayer.metadata["mpris:trackid"] === MetaData["mpris:trackid"]) { - return - } - - mediaPlayer.metadata = MetaData + mediaPlayer.metadata = MetaData; }, /** @@ -80,11 +100,11 @@ module.exports = { * @param {Object} attributes - The attributes of the track. */ updateState: (attributes) => { - if (process.platform !== "linux") return; + if (process.platform !== 'linux') return; function setPlaybackIfNeeded(status) { if (mediaPlayer.playbackStatus === status) { - return + return; } mediaPlayer.playbackStatus = status; } @@ -96,7 +116,8 @@ module.exports = { case false: // Paused setPlaybackIfNeeded('Paused'); break; - default: // Stopped + default: + // Stopped setPlaybackIfNeeded('Stopped'); break; } @@ -106,8 +127,10 @@ module.exports = { * Closes the MPRIS interface. */ clearActivity: () => { - if (process.platform !== "linux") return; - mediaPlayer.metadata = {'mpris:trackid': '/org/mpris/MediaPlayer2/TrackList/NoTrack'} + if (process.platform !== 'linux') return; + mediaPlayer.metadata = { + 'mpris:trackid': '/org/mpris/MediaPlayer2/TrackList/NoTrack' + }; mediaPlayer.playbackStatus = 'Stopped'; - }, -} \ No newline at end of file + } +}; diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index c0246916..3b5b2338 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -1,72 +1,135 @@ -const electron = require('electron') +const electron = require('electron'); -console.log('Loaded Preload') +console.log('Loaded Preload'); -let cache = {playParams: {id: 0}, status: null, remainingTime: 0}, - playbackCache = {status: null, time: Date.now()}; +let cache = { playParams: { id: 0 }, status: null, remainingTime: 0 }, + playbackCache = { status: null, time: Date.now() }; const MusicKitInterop = { init: function () { - MusicKit.getInstance().addEventListener(MusicKit.Events.playbackStateDidChange, () => { - if (MusicKitInterop.filterTrack(MusicKitInterop.getAttributes(), true, false)) { - console.log("ayy"); - global.ipcRenderer.send('playbackStateDidChange', MusicKitInterop.getAttributes()) - // if (typeof _plugins != "undefined") { - // _plugins.execute("OnPlaybackStateChanged", {Attributes: MusicKitInterop.getAttributes()}) - // } + MusicKit.getInstance().addEventListener( + MusicKit.Events.playbackStateDidChange, + () => { + if ( + MusicKitInterop.filterTrack( + MusicKitInterop.getAttributes(), + true, + false + ) + ) { + console.log('ayy'); + global.ipcRenderer.send( + 'playbackStateDidChange', + MusicKitInterop.getAttributes() + ); + // if (typeof _plugins != "undefined") { + // _plugins.execute("OnPlaybackStateChanged", {Attributes: MusicKitInterop.getAttributes()}) + // } + } } - }); + ); - MusicKit.getInstance().addEventListener(MusicKit.Events.nowPlayingItemDidChange, () => { - if (MusicKitInterop.filterTrack(MusicKitInterop.getAttributes(), false, true)) { - global.ipcRenderer.send('nowPlayingItemDidChange', MusicKitInterop.getAttributes()); + MusicKit.getInstance().addEventListener( + MusicKit.Events.nowPlayingItemDidChange, + () => { + if ( + MusicKitInterop.filterTrack( + MusicKitInterop.getAttributes(), + false, + true + ) + ) { + global.ipcRenderer.send( + 'nowPlayingItemDidChange', + MusicKitInterop.getAttributes() + ); + } } - }); + ); - MusicKit.getInstance().addEventListener(MusicKit.Events.authorizationStatusDidChange, () => { - global.ipcRenderer.send('authorizationStatusDidChange', MusicKit.getInstance().authorizationStatus) - }) + MusicKit.getInstance().addEventListener( + MusicKit.Events.authorizationStatusDidChange, + () => { + global.ipcRenderer.send( + 'authorizationStatusDidChange', + MusicKit.getInstance().authorizationStatus + ); + } + ); - MusicKit.getInstance().addEventListener(MusicKit.Events.mediaPlaybackError, (e) => { - console.warn(`[mediaPlaybackError] ${e}`); - }) + MusicKit.getInstance().addEventListener( + MusicKit.Events.mediaPlaybackError, + (e) => { + console.warn(`[mediaPlaybackError] ${e}`); + } + ); }, getAttributes: function () { const nowPlayingItem = MusicKit.getInstance().nowPlayingItem; const isPlayingExport = MusicKit.getInstance().isPlaying; - const remainingTimeExport = MusicKit.getInstance().currentPlaybackTimeRemaining; - const attributes = (nowPlayingItem != null ? nowPlayingItem.attributes : {}); + const remainingTimeExport = + MusicKit.getInstance().currentPlaybackTimeRemaining; + const attributes = + nowPlayingItem != null ? nowPlayingItem.attributes : {}; attributes.status = isPlayingExport ? isPlayingExport : false; attributes.name = attributes.name ? attributes.name : 'No Title Found'; - attributes.artwork = attributes.artwork ? attributes.artwork : {url: ''}; - attributes.artwork.url = attributes.artwork.url ? attributes.artwork.url : ''; - attributes.playParams = attributes.playParams ? attributes.playParams : {id: 'no-id-found'}; - attributes.playParams.id = attributes.playParams.id ? attributes.playParams.id : 'no-id-found'; + attributes.artwork = attributes.artwork + ? attributes.artwork + : { url: '' }; + attributes.artwork.url = attributes.artwork.url + ? attributes.artwork.url + : ''; + attributes.playParams = attributes.playParams + ? attributes.playParams + : { id: 'no-id-found' }; + attributes.playParams.id = attributes.playParams.id + ? attributes.playParams.id + : 'no-id-found'; attributes.albumName = attributes.albumName ? attributes.albumName : ''; - attributes.artistName = attributes.artistName ? attributes.artistName : ''; - attributes.genreNames = attributes.genreNames ? attributes.genreNames : []; - attributes.remainingTime = remainingTimeExport ? (remainingTimeExport * 1000) : 0; - attributes.durationInMillis = attributes.durationInMillis ? attributes.durationInMillis : 0; + attributes.artistName = attributes.artistName + ? attributes.artistName + : ''; + attributes.genreNames = attributes.genreNames + ? attributes.genreNames + : []; + attributes.remainingTime = remainingTimeExport + ? remainingTimeExport * 1000 + : 0; + attributes.durationInMillis = attributes.durationInMillis + ? attributes.durationInMillis + : 0; attributes.startTime = Date.now(); - attributes.endTime = Math.round((attributes.playParams.id === cache.playParams.id ? (Date.now() + attributes.remainingTime) : (attributes.startTime + attributes.durationInMillis))); - attributes.endTime = attributes.endTime ? attributes.endTime : Date.now(); - return attributes + attributes.endTime = Math.round( + attributes.playParams.id === cache.playParams.id + ? Date.now() + attributes.remainingTime + : attributes.startTime + attributes.durationInMillis + ); + attributes.endTime = attributes.endTime + ? attributes.endTime + : Date.now(); + return attributes; }, filterTrack: function (a, playbackCheck, mediaCheck) { - if (a.title === "No Title Found" || a.playParams.id === "no-id-found") { + if (a.title === 'No Title Found' || a.playParams.id === 'no-id-found') { return; } else if (mediaCheck && a.playParams.id === cache.playParams.id) { return; } else if (playbackCheck && a.status === playbackCache.status) { return; - } else if (playbackCheck && !a.status && a.remainingTime === playbackCache.time) { /* Pretty much have to do this to prevent multiple runs when a song starts playing */ + } else if ( + playbackCheck && + !a.status && + a.remainingTime === playbackCache.time + ) { + /* Pretty much have to do this to prevent multiple runs when a song starts playing */ return; } cache = a; - if (playbackCheck) playbackCache = {status: a.status, time: a.remainingTime}; + if (playbackCheck) + playbackCache = { status: a.status, time: a.remainingTime }; return true; }, @@ -74,23 +137,31 @@ const MusicKitInterop = { if (MusicKit.getInstance().isPlaying) { MusicKit.getInstance().pause(); } else if (MusicKit.getInstance().nowPlayingItem != null) { - MusicKit.getInstance().play().then(r => console.log(`[MusicKitInterop] Playing ${r}`)); + MusicKit.getInstance() + .play() + .then((r) => console.log(`[MusicKitInterop] Playing ${r}`)); } }, nextTrack: function () { - MusicKit.getInstance().skipToNextItem().then(r => console.log(`[MusicKitInterop] Skipping to Next ${r}`)); + MusicKit.getInstance() + .skipToNextItem() + .then((r) => + console.log(`[MusicKitInterop] Skipping to Next ${r}`) + ); }, previousTrack: function () { - MusicKit.getInstance().skipToPreviousItem().then(r => console.log(`[MusicKitInterop] Skipping to Previous ${r}`)); + MusicKit.getInstance() + .skipToPreviousItem() + .then((r) => + console.log(`[MusicKitInterop] Skipping to Previous ${r}`) + ); } - -} - +}; process.once('loaded', () => { - console.log("Setting ipcRenderer") + console.log('Setting ipcRenderer'); global.ipcRenderer = electron.ipcRenderer; global.MusicKitInterop = MusicKitInterop; -}); \ No newline at end of file +}); diff --git a/src/renderer/index.js b/src/renderer/index.js index 7a3f817e..2bcc0d42 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -3,41 +3,49 @@ Vue.use(VueObserveVisibility); // This is going to suck to code var CiderContextMenu = { Menu: function (event) { - this.items = [] + this.items = []; }, async Create(event, menudata) { - var menuBackground = document.createElement("div"); - var menu = document.createElement("div"); - menu.classList.add("context-menu-body"); - menu.classList.add("context-menu-open"); - menuBackground.classList.add("context-menu"); - menu.style.left = 0 + "px"; - menu.style.top = 0 + "px"; - menu.style.position = "absolute"; - menu.style.zIndex = "99909"; - menu.addEventListener("animationend", function () { - menu.classList.remove("context-menu-open"); - }, {once: true}); + var menuBackground = document.createElement('div'); + var menu = document.createElement('div'); + menu.classList.add('context-menu-body'); + menu.classList.add('context-menu-open'); + menuBackground.classList.add('context-menu'); + menu.style.left = 0 + 'px'; + menu.style.top = 0 + 'px'; + menu.style.position = 'absolute'; + menu.style.zIndex = '99909'; + menu.addEventListener( + 'animationend', + function () { + menu.classList.remove('context-menu-open'); + }, + { once: true } + ); function close() { - menuBackground.style.pointerEvents = "none"; - menu.classList.add("context-menu-close"); - menu.addEventListener("animationend", function () { - menuBackground.remove(); - menu.remove(); - }, {once: true}); + menuBackground.style.pointerEvents = 'none'; + menu.classList.add('context-menu-close'); + menu.addEventListener( + 'animationend', + function () { + menuBackground.remove(); + menu.remove(); + }, + { once: true } + ); } // when menubackground is clicked, remove it - menuBackground.addEventListener("click", close); - menuBackground.addEventListener("contextmenu", close); + menuBackground.addEventListener('click', close); + menuBackground.addEventListener('contextmenu', close); // add menu to menuBackground menuBackground.appendChild(menu); document.body.appendChild(menuBackground); - if (typeof menudata.items == "object") { + if (typeof menudata.items == 'object') { menudata.items = Object.values(menudata.items); } @@ -45,47 +53,49 @@ var CiderContextMenu = { // for each item in menudata create a menu item for (var i = 0; i < menudata.items.length; i++) { - let item = document.createElement("button") + let item = document.createElement('button'); - if (menudata.items[i]["disabled"] === true) { - continue + if (menudata.items[i]['disabled'] === true) { + continue; } - item.tabIndex = 0 - item.classList.add("context-menu-item") - if(menudata.items[i]["icon"]) { - item.innerHTML += `` + item.tabIndex = 0; + item.classList.add('context-menu-item'); + if (menudata.items[i]['icon']) { + item.innerHTML += ``; } - item.innerHTML += menudata.items[i].name - item.onclick = menudata.items[i].action - menu.appendChild(item) + item.innerHTML += menudata.items[i].name; + item.onclick = menudata.items[i].action; + menu.appendChild(item); } - menu.style.width = (menu.offsetWidth + 10) + "px"; - menu.style.left = event.clientX + "px"; - menu.style.top = event.clientY + "px"; + menu.style.width = menu.offsetWidth + 10 + 'px'; + menu.style.left = event.clientX + 'px'; + menu.style.top = event.clientY + 'px'; // if menu would be off the screen, move it into view, but preserve the width if (menu.offsetLeft + menu.offsetWidth > window.innerWidth) { - menu.style.left = (window.innerWidth - menu.offsetWidth) + "px"; + menu.style.left = window.innerWidth - menu.offsetWidth + 'px'; } if (menu.offsetTop + menu.offsetHeight > window.innerHeight) { - menu.style.top = (window.innerHeight - menu.offsetHeight) + "px"; + menu.style.top = window.innerHeight - menu.offsetHeight + 'px'; } return menuBackground; } -} +}; const MusicKitObjects = { LibraryPlaylist: function () { - this.id = "" - this.type = "library-playlist-folders" - this.href = "" + this.id = ''; + this.type = 'library-playlist-folders'; + this.href = ''; this.attributes = { - dateAdded: "", - name: "" - } - this.playlists = [] + dateAdded: '', + name: '' + }; + this.playlists = []; } -} +}; const MusicKitTools = { getHeader() { @@ -96,7 +106,7 @@ const MusicKitTools = { 'Music-User-Token': '' + MusicKit.getInstance().musicUserToken }); } -} +}; // limit an array to a certain number of items Array.prototype.limit = function (n) { @@ -106,36 +116,36 @@ Array.prototype.limit = function (n) { const store = new Vuex.Store({ state: { library: { - songs: ipcRenderer.sendSync("get-library-songs"), - albums: ipcRenderer.sendSync("get-library-albums"), - recentlyAdded: ipcRenderer.sendSync("get-library-recentlyAdded"), - playlists: ipcRenderer.sendSync("get-library-playlists") + songs: ipcRenderer.sendSync('get-library-songs'), + albums: ipcRenderer.sendSync('get-library-albums'), + recentlyAdded: ipcRenderer.sendSync('get-library-recentlyAdded'), + playlists: ipcRenderer.sendSync('get-library-playlists') }, artwork: { - playerLCD: "" + playerLCD: '' } }, mutations: { setLCDArtwork(state, artwork) { - state.artwork.playerLCD = artwork + state.artwork.playerLCD = artwork; } } -}) +}); const app = new Vue({ - el: "#app", + el: '#app', store: store, data: { - appMode: "player", + appMode: 'player', ipcRenderer: ipcRenderer, - cfg: ipcRenderer.sendSync("getStore"), - isDev: ipcRenderer.sendSync("is-dev"), + cfg: ipcRenderer.sendSync('getStore'), + isDev: ipcRenderer.sendSync('is-dev'), drawertest: false, - platform: "", + platform: '', mk: {}, - quickPlayQuery: "", + quickPlayQuery: '', search: { - term: "", + term: '', hints: [], showHints: false, results: {}, @@ -150,7 +160,7 @@ const app = new Vue({ }, drawer: { open: false, - panel: "" + panel: '' }, browsepage: [], listennow: [], @@ -159,79 +169,79 @@ const app = new Vue({ personal: [] }, webview: { - url: "", - title: "", + url: '', + title: '', loading: false }, showingPlaylist: [], appleCurator: [], artistPage: { - data: {}, + data: {} }, library: { downloadNotification: { show: false, - message: "", + message: '', total: 0, progress: 0 }, songs: { sortingOptions: { - "albumName": "Album", - "artistName": "Artist", - "name": "Name", - "genre": "Genre", - "releaseDate": "Release Date", - "durationInMillis": "Duration" + albumName: 'Album', + artistName: 'Artist', + name: 'Name', + genre: 'Genre', + releaseDate: 'Release Date', + durationInMillis: 'Duration' }, - sorting: "name", - sortOrder: "asc", + sorting: 'name', + sortOrder: 'asc', listing: [], - meta: {total: 0, progress: 0}, - search: "", + meta: { total: 0, progress: 0 }, + search: '', displayListing: [], downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library }, albums: { sortingOptions: { - "artistName": "Artist", - "name": "Name", - "genre": "Genre", - "releaseDate": "Release Date" + artistName: 'Artist', + name: 'Name', + genre: 'Genre', + releaseDate: 'Release Date' }, viewAs: 'covers', - sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page - sortOrder: ["desc", "asc"], // [0] = recentlyadded page, [1] = albums page + sorting: ['dateAdded', 'name'], // [0] = recentlyadded page, [1] = albums page + sortOrder: ['desc', 'asc'], // [0] = recentlyadded page, [1] = albums page listing: [], - meta: {total: 0, progress: 0}, - search: "", + meta: { total: 0, progress: 0 }, + search: '', displayListing: [], downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library }, artists: { sortingOptions: { - "artistName": "Artist", - "name": "Name", - "genre": "Genre", - "releaseDate": "Release Date" + artistName: 'Artist', + name: 'Name', + genre: 'Genre', + releaseDate: 'Release Date' }, viewAs: 'covers', - sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page - sortOrder: ["desc", "asc"], // [0] = recentlyadded page, [1] = albums page + sorting: ['dateAdded', 'name'], // [0] = recentlyadded page, [1] = albums page + sortOrder: ['desc', 'asc'], // [0] = recentlyadded page, [1] = albums page listing: [], - meta: {total: 0, progress: 0}, - search: "", + meta: { total: 0, progress: 0 }, + search: '', displayListing: [], downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library - }, + } }, playlists: { listing: [], details: {}, loadingState: 0, // 0 loading, 1 loaded, 2 error - id: "" + id: '' }, - mxmtoken: "", + mxmtoken: '', mkIsReady: false, playerReady: false, animateBackground: false, @@ -252,66 +262,66 @@ const app = new Vue({ tmpVar: [], notification: false, chrome: { - hideUserInfo: ipcRenderer.sendSync("is-dev"), + hideUserInfo: ipcRenderer.sendSync('is-dev'), artworkReady: false, userinfo: { - "id": "", - "attributes": { - "name": "Cider User", - "handle": "CiderUser", - "artwork": {"url": "./assets/logocut.png"} + id: '', + attributes: { + name: 'Cider User', + handle: 'CiderUser', + artwork: { url: './assets/logocut.png' } } }, menuOpened: false, maximized: false, drawerOpened: false, - drawerState: "queue", + drawerState: 'queue', topChromeVisible: true, - progresshover: false, + progresshover: false }, collectionList: { response: {}, - title: "", - type: "" + title: '', + type: '' }, prevButtonBackIndicator: false, currentSongInfo: {}, - page: "", + page: '', pageHistory: [], songstest: false, hangtimer: null, selectedMediaItems: [], - routes: ["browse", "listen_now", "radio"], - musicBaseUrl: "https://api.music.apple.com/", + routes: ['browse', 'listen_now', 'radio'], + musicBaseUrl: 'https://api.music.apple.com/', modals: { addToPlaylist: false, spatialProperties: false }, socialBadges: { badgeMap: {}, - version: "" + version: '' } }, watch: { cfg: { handler: function (val, oldVal) { console.log(`cfg changed from ${oldVal} to ${val}`); - ipcRenderer.send("setStore", val); + ipcRenderer.send('setStore', val); }, deep: true }, page: () => { - document.getElementById("app-content").scrollTo(0, 0); - app.resetState() + document.getElementById('app-content').scrollTo(0, 0); + app.resetState(); }, showingPlaylist: () => { - document.getElementById("app-content").scrollTo(0, 0); - app.resetState() + document.getElementById('app-content').scrollTo(0, 0); + app.resetState(); }, artistPage: () => { - document.getElementById("app-content").scrollTo(0, 0); - app.resetState() - }, + document.getElementById('app-content').scrollTo(0, 0); + app.resetState(); + } }, methods: { async getSvgIcon(url) { @@ -319,16 +329,15 @@ const app = new Vue({ let data = await response.text(); return data; }, - getSocialBadges(cb = () => { - }) { - let self = this + getSocialBadges(cb = () => {}) { + let self = this; try { - app.mk.api.socialBadgingMap().then(data => { - self.socialBadges.badgeMap = data.badgingMap - cb(data.badgingMap) - }) + app.mk.api.socialBadgingMap().then((data) => { + self.socialBadges.badgeMap = data.badgingMap; + cb(data.badgingMap); + }); } catch (ex) { - this.socialBadges.badgeMap = {} + this.socialBadges.badgeMap = {}; } }, addFavorite(id, type) { @@ -340,29 +349,35 @@ const app = new Vue({ modularUITest(val = false) { this.fullscreenLyrics = val; if (val) { - document.querySelector("#app-main").classList.add("modular-fs") + document.querySelector('#app-main').classList.add('modular-fs'); } else { - document.querySelector("#app-main").classList.remove("modular-fs") + document + .querySelector('#app-main') + .classList.remove('modular-fs'); } }, navigateBack() { - history.back() + history.back(); }, navigateForward() { - history.forward() + history.forward(); }, getHTMLStyle() { switch (this.cfg.visual.window_transparency) { - case "acrylic": + case 'acrylic': default: - document.querySelector("html").style.background = ""; - document.querySelector("body").style.background = ""; - document.querySelector("body").classList.remove("notransparency") + document.querySelector('html').style.background = ''; + document.querySelector('body').style.background = ''; + document + .querySelector('body') + .classList.remove('notransparency'); break; - case "disabled": - document.querySelector("html").style.background = "#222"; - document.querySelector("body").classList.add("notransparency") - + case 'disabled': + document.querySelector('html').style.background = '#222'; + document + .querySelector('body') + .classList.add('notransparency'); + // document.querySelector("body").style.background = "#222"; break; } @@ -377,291 +392,389 @@ const app = new Vue({ app.modals.addToPlaylist = true; }, async addSelectedToPlaylist(playlist_id) { - let self = this - let pl_items = [] + let self = this; + let pl_items = []; for (let i = 0; i < self.selectedMediaItems.length; i++) { - if (self.selectedMediaItems[i].kind == "song" || self.selectedMediaItems[i].kind == "songs") { - self.selectedMediaItems[i].kind = "songs" + if ( + self.selectedMediaItems[i].kind == 'song' || + self.selectedMediaItems[i].kind == 'songs' + ) { + self.selectedMediaItems[i].kind = 'songs'; pl_items.push({ id: self.selectedMediaItems[i].id, type: self.selectedMediaItems[i].kind - }) - } else if ((self.selectedMediaItems[i].kind == "album" || self.selectedMediaItems[i].kind == "albums") && self.selectedMediaItems[i].isLibrary != true ) { - self.selectedMediaItems[i].kind = "albums" - let res = await self.mk.api.albumRelationship(self.selectedMediaItems[i].id,"tracks"); - let ids = res.map(function(i) {return {id:i.id, type: i.type}}) - pl_items = pl_items.concat(ids) - } else if (self.selectedMediaItems[i].kind == "library-song" || self.selectedMediaItems[i].kind == "library-songs") { - self.selectedMediaItems[i].kind = "library-songs" + }); + } else if ( + (self.selectedMediaItems[i].kind == 'album' || + self.selectedMediaItems[i].kind == 'albums') && + self.selectedMediaItems[i].isLibrary != true + ) { + self.selectedMediaItems[i].kind = 'albums'; + let res = await self.mk.api.albumRelationship( + self.selectedMediaItems[i].id, + 'tracks' + ); + let ids = res.map(function (i) { + return { id: i.id, type: i.type }; + }); + pl_items = pl_items.concat(ids); + } else if ( + self.selectedMediaItems[i].kind == 'library-song' || + self.selectedMediaItems[i].kind == 'library-songs' + ) { + self.selectedMediaItems[i].kind = 'library-songs'; pl_items.push({ id: self.selectedMediaItems[i].id, type: self.selectedMediaItems[i].kind - }) - } else if ((self.selectedMediaItems[i].kind == "library-album" || self.selectedMediaItems[i].kind == "library-albums") || (self.selectedMediaItems[i].kind == "album" && self.selectedMediaItems[i].isLibrary == true )) { - self.selectedMediaItems[i].kind = "library-albums" - let res = await self.mk.api.library.albumRelationship(self.selectedMediaItems[i].id,"tracks"); - let ids = res.map(function(i) {return {id:i.id, type: i.type}}) - pl_items = pl_items.concat(ids) + }); + } else if ( + self.selectedMediaItems[i].kind == 'library-album' || + self.selectedMediaItems[i].kind == 'library-albums' || + (self.selectedMediaItems[i].kind == 'album' && + self.selectedMediaItems[i].isLibrary == true) + ) { + self.selectedMediaItems[i].kind = 'library-albums'; + let res = await self.mk.api.library.albumRelationship( + self.selectedMediaItems[i].id, + 'tracks' + ); + let ids = res.map(function (i) { + return { id: i.id, type: i.type }; + }); + pl_items = pl_items.concat(ids); } else { pl_items.push({ id: self.selectedMediaItems[i].id, type: self.selectedMediaItems[i].kind - }) + }); } - } - this.modals.addToPlaylist = false - this.mk.api.library.appendTracksToPlaylist(playlist_id, pl_items).then(() => { - if (this.page == 'playlist_' + this.showingPlaylist.id) { - this.getPlaylistFromID(this.showingPlaylist.id) - } - }) + this.modals.addToPlaylist = false; + this.mk.api.library + .appendTracksToPlaylist(playlist_id, pl_items) + .then(() => { + if (this.page == 'playlist_' + this.showingPlaylist.id) { + this.getPlaylistFromID(this.showingPlaylist.id); + } + }); }, async init() { - let self = this - clearTimeout(this.hangtimer) - this.mk = MusicKit.getInstance() + let self = this; + clearTimeout(this.hangtimer); + this.mk = MusicKit.getInstance(); this.mk.authorize().then(() => { - self.mkIsReady = true - }) - this.$forceUpdate() + self.mkIsReady = true; + }); + this.$forceUpdate(); if (this.isDev) { - this.mk.privateEnabled = true + this.mk.privateEnabled = true; } - if (this.cfg.visual.hw_acceleration == "disabled") { - document.body.classList.add("no-gpu") + if (this.cfg.visual.hw_acceleration == 'disabled') { + document.body.classList.add('no-gpu'); } - this.mk._services.timing.mode = 0 + this.mk._services.timing.mode = 0; this.platform = ipcRenderer.sendSync('cider-platform'); // Set profile name - this.chrome.userinfo = await this.mkapi("personalSocialProfile", false, "") + this.chrome.userinfo = await this.mkapi( + 'personalSocialProfile', + false, + '' + ); // API Fallback if (!this.chrome.userinfo) { this.chrome.userinfo = { - "id": "", - "attributes": { - "name": "Cider User", - "handle": "CiderUser", - "artwork": {"url": "./assets/logocut.png"} + id: '', + attributes: { + name: 'Cider User', + handle: 'CiderUser', + artwork: { url: './assets/logocut.png' } } - } + }; } - MusicKitInterop.init() + MusicKitInterop.init(); // Set the volume - this.mk.volume = this.cfg.general.volume + this.mk.volume = this.cfg.general.volume; // ipcRenderer.invoke('getStoreValue', 'general.volume').then((value) => { // self.mk.volume = value // }) // load cached library - if (localStorage.getItem("librarySongs") != null) { - this.library.songs.listing = JSON.parse(localStorage.getItem("librarySongs")) - this.library.songs.displayListing = this.library.songs.listing + if (localStorage.getItem('librarySongs') != null) { + this.library.songs.listing = JSON.parse( + localStorage.getItem('librarySongs') + ); + this.library.songs.displayListing = this.library.songs.listing; } - if (localStorage.getItem("libraryAlbums") != null) { - this.library.albums.listing = JSON.parse(localStorage.getItem("libraryAlbums")) - this.library.albums.displayListing = this.library.albums.listing + if (localStorage.getItem('libraryAlbums') != null) { + this.library.albums.listing = JSON.parse( + localStorage.getItem('libraryAlbums') + ); + this.library.albums.displayListing = + this.library.albums.listing; } window.onbeforeunload = function (e) { - window.localStorage.setItem("currentTrack", JSON.stringify(app.mk.nowPlayingItem)) - window.localStorage.setItem("currentTime", JSON.stringify(app.mk.currentPlaybackTime)) - window.localStorage.setItem("currentQueue", JSON.stringify(app.mk.queue.items)) + window.localStorage.setItem( + 'currentTrack', + JSON.stringify(app.mk.nowPlayingItem) + ); + window.localStorage.setItem( + 'currentTime', + JSON.stringify(app.mk.currentPlaybackTime) + ); + window.localStorage.setItem( + 'currentQueue', + JSON.stringify(app.mk.queue.items) + ); }; // Load saved quality switch (app.cfg.audio.quality) { - case "extreme": - app.mk.bitrate = app.cfg.audio.quality = 990 + case 'extreme': + app.mk.bitrate = app.cfg.audio.quality = 990; break; - case "high": - app.mk.bitrate = app.cfg.audio.quality = 256 + case 'high': + app.mk.bitrate = app.cfg.audio.quality = 256; break; - case "low": - app.mk.bitrate = app.cfg.audio.quality = 64 + case 'low': + app.mk.bitrate = app.cfg.audio.quality = 64; break; default: - app.mk.bitrate = app.cfg.audio.quality + app.mk.bitrate = app.cfg.audio.quality; } - // load last played track try { - let lastItem = window.localStorage.getItem("currentTrack") - let time = window.localStorage.getItem("currentTime") - let queue = window.localStorage.getItem("currentQueue") + let lastItem = window.localStorage.getItem('currentTrack'); + let time = window.localStorage.getItem('currentTime'); + let queue = window.localStorage.getItem('currentQueue'); if (lastItem != null) { - lastItem = JSON.parse(lastItem) + lastItem = JSON.parse(lastItem); let kind = lastItem.attributes.playParams.kind; - let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; - app.mk.setQueue({[truekind]: [lastItem.attributes.playParams.id]}) - app.mk.mute() + let truekind = !kind.endsWith('s') ? kind + 's' : kind; + app.mk.setQueue({ + [truekind]: [lastItem.attributes.playParams.id] + }); + app.mk.mute(); setTimeout(() => { app.mk.play().then(() => { app.mk.pause().then(() => { if (time != null) { - app.mk.seekToTime(time) + app.mk.seekToTime(time); } - app.mk.unmute() + app.mk.unmute(); if (queue != null) { - queue = JSON.parse(queue) + queue = JSON.parse(queue); if (queue && queue.length > 0) { - let ids = queue.map(e => (e.playParams ? e.playParams.id : (e.attributes.playParams ? e.attributes.playParams.id : ''))) + let ids = queue.map((e) => + e.playParams + ? e.playParams.id + : e.attributes.playParams + ? e.attributes.playParams.id + : '' + ); let i = 0; if (ids.length > 0) { for (id of ids) { - if (!(i == 0 && ids[0] == lastItem.attributes.playParams.id)) { + if ( + !( + i == 0 && + ids[0] == + lastItem.attributes + .playParams.id + ) + ) { try { - app.mk.playLater({songs: [id]}) - } catch (err) { - } + app.mk.playLater({ + songs: [id] + }); + } catch (err) {} } i++; } } } } - - }) - - }) - }, 1500) - + }); + }); + }, 1500); } - } catch (e) { - console.log(e) + console.log(e); } - MusicKit.getInstance().videoContainerElement = document.getElementById("apple-music-video-player") + MusicKit.getInstance().videoContainerElement = + document.getElementById('apple-music-video-player'); ipcRenderer.on('SoundCheckTag', (event, tag) => { - let replaygain = self.parseSCTagToRG(tag) + let replaygain = self.parseSCTagToRG(tag); try { - CiderAudio.audioNodes.gainNode.gain.value = (Math.min(Math.pow(10, (replaygain.gain / 20)), (1 / replaygain.peak))) - } catch (e) { + CiderAudio.audioNodes.gainNode.gain.value = Math.min( + Math.pow(10, replaygain.gain / 20), + 1 / replaygain.peak + ); + } catch (e) {} + }); + this.mk.addEventListener( + MusicKit.Events.playbackTimeDidChange, + (a) => { + self.lyriccurrenttime = self.mk.currentPlaybackTime; + this.currentSongInfo = a; + self.playerLCD.playbackDuration = + self.mk.currentPlaybackTime; } - }) + ); - this.mk.addEventListener(MusicKit.Events.playbackTimeDidChange, (a) => { - self.lyriccurrenttime = self.mk.currentPlaybackTime - this.currentSongInfo = a - self.playerLCD.playbackDuration = (self.mk.currentPlaybackTime) - }) + this.mk.addEventListener( + MusicKit.Events.nowPlayingItemDidChange, + (a) => { + if (self.$refs.queue) { + self.$refs.queue.updateQueue(); + } + this.currentSongInfo = a; - this.mk.addEventListener(MusicKit.Events.nowPlayingItemDidChange, (a) => { - if (self.$refs.queue) { - self.$refs.queue.updateQueue(); - } - this.currentSongInfo = a - - - if (app.cfg.audio.normalization) { - // get unencrypted audio previews to get SoundCheck's normalization tag - try { - let previewURL = null + if (app.cfg.audio.normalization) { + // get unencrypted audio previews to get SoundCheck's normalization tag try { - previewURL = app.mk.nowPlayingItem.previewURL - } catch (e) { - } - if (!previewURL) { - app.mk.api.song(app.mk.nowPlayingItem._songId ?? app.mk.nowPlayingItem.relationships.catalog.data[0].id).then((response) => { - previewURL = response.attributes.previews[0].url + let previewURL = null; + try { + previewURL = app.mk.nowPlayingItem.previewURL; + } catch (e) {} + if (!previewURL) { + app.mk.api + .song( + app.mk.nowPlayingItem._songId ?? + app.mk.nowPlayingItem.relationships + .catalog.data[0].id + ) + .then((response) => { + previewURL = + response.attributes.previews[0].url; + if (previewURL) + ipcRenderer.send( + 'getPreviewURL', + previewURL + ); + }); + } else { if (previewURL) - ipcRenderer.send('getPreviewURL', previewURL) - }) - } else { - if (previewURL) - ipcRenderer.send('getPreviewURL', previewURL) + ipcRenderer.send( + 'getPreviewURL', + previewURL + ); + } + } catch (e) {} + } + + try { + a = a.item.attributes; + } catch (_) {} + let type = + self.mk.nowPlayingItem != null + ? self.mk.nowPlayingItem['type'] ?? '' + : ''; + + if ( + type.includes('musicVideo') || + type.includes('uploadedVideo') || + type.includes('music-movie') + ) { + document.getElementById( + 'apple-music-video-container' + ).style.display = 'block'; + // app.chrome.topChromeVisible = false + } else { + document.getElementById( + 'apple-music-video-container' + ).style.display = 'none'; + // app.chrome.topChromeVisible = true + } + self.chrome.artworkReady = false; + self.lyrics = []; + self.richlyrics = []; + app.getCurrentArtURL(); + // app.getNowPlayingArtwork(42); + app.getNowPlayingArtworkBG(32); + app.loadLyrics(); + + // Playback Notifications + if ( + (app.platform === 'darwin' || + app.platform === 'linux') && + !document.hasFocus() && + a.artistName && + a.artwork && + a.name + ) { + if (this.notification) { + this.notification.close(); } - - } catch (e) { + this.notification = new Notification(a.name, { + body: a.artistName, + icon: a.artwork.url + .replace('/{w}x{h}bb', '/512x512bb') + .replace('/2000x2000bb', '/35x35bb'), + silent: true + }); } } + ); - try { - a = a.item.attributes; - } catch (_) { + this.mk.addEventListener( + MusicKit.Events.playbackVolumeDidChange, + (_a) => { + this.cfg.general.volume = this.mk.volume; } - let type = (self.mk.nowPlayingItem != null) ? self.mk.nowPlayingItem["type"] ?? '' : ''; + ); - if (type.includes("musicVideo") || type.includes("uploadedVideo") || type.includes("music-movie")) { - document.getElementById("apple-music-video-container").style.display = "block"; - // app.chrome.topChromeVisible = false - } else { - document.getElementById("apple-music-video-container").style.display = "none"; - // app.chrome.topChromeVisible = true - } - self.chrome.artworkReady = false - self.lyrics = [] - self.richlyrics = [] - app.getCurrentArtURL(); - // app.getNowPlayingArtwork(42); - app.getNowPlayingArtworkBG(32); - app.loadLyrics(); - - // Playback Notifications - if ((app.platform === "darwin" || app.platform === "linux") && !document.hasFocus() && a.artistName && a.artwork && a.name) { - if (this.notification) { - this.notification.close() - } - this.notification = new Notification(a.name, { - body: a.artistName, - icon: a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb'), - silent: true, - }); - } - - }) - - - this.mk.addEventListener(MusicKit.Events.playbackVolumeDidChange, (_a) => { - this.cfg.general.volume = this.mk.volume - }) - - this.refreshPlaylists() - document.body.removeAttribute("loading") - if (window.location.hash != "") { - this.appRoute(window.location.hash) + this.refreshPlaylists(); + document.body.removeAttribute('loading'); + if (window.location.hash != '') { + this.appRoute(window.location.hash); } else { - this.page = "home" + this.page = 'home'; } setTimeout(() => { - this.getSocialBadges() + this.getSocialBadges(); this.getBrowsePage(); - this.$forceUpdate() - }, 500) + this.$forceUpdate(); + }, 500); }, invokeDrawer(panel) { if (this.drawer.panel == panel && this.drawer.open) { - if (panel == "lyrics") { - this.lyricon = false + if (panel == 'lyrics') { + this.lyricon = false; } - this.drawer.panel = "" - this.drawer.open = false + this.drawer.panel = ''; + this.drawer.open = false; } else { - if (panel == "lyrics") { - this.lyricon = true + if (panel == 'lyrics') { + this.lyricon = true; } else { - this.lyricon = false + this.lyricon = false; } - this.drawer.open = true - this.drawer.panel = panel + this.drawer.open = true; + this.drawer.panel = panel; } }, select_removeMediaItem(id) { - this.selectedMediaItems.filter(item => item.guid == id).forEach(item => { - this.selectedMediaItems.splice(this.selectedMediaItems.indexOf(item), 1) - }) + this.selectedMediaItems + .filter((item) => item.guid == id) + .forEach((item) => { + this.selectedMediaItems.splice( + this.selectedMediaItems.indexOf(item), + 1 + ); + }); }, select_hasMediaItem(id) { - let found = this.selectedMediaItems.find(item => item.guid == id) + let found = this.selectedMediaItems.find((item) => item.guid == id); if (found) { - return true + return true; } else { - return false + return false; } }, select_selectMediaItem(id, kind, index, guid, library) { @@ -672,1177 +785,1537 @@ const app = new Vue({ index: index, guid: guid, isLibrary: library - }) + }); } }, getPlaylistFolderChildren(id) { - return this.playlists.listing.filter(playlist => { + return this.playlists.listing.filter((playlist) => { if (playlist.parent == id) { - return playlist + return playlist; } - }) + }); }, async refreshPlaylists() { - let self = this - this.apiCall('https://api.music.apple.com/v1/me/library/playlist-folders/p.playlistsroot/children/', res => { - self.playlists.listing = res.data - self.playlists.listing.forEach(playlist => { - playlist.parent = "p.playlistsroot" - }) - self.sortPlaylists() - }) + let self = this; + this.apiCall( + 'https://api.music.apple.com/v1/me/library/playlist-folders/p.playlistsroot/children/', + (res) => { + self.playlists.listing = res.data; + self.playlists.listing.forEach((playlist) => { + playlist.parent = 'p.playlistsroot'; + }); + self.sortPlaylists(); + } + ); }, sortPlaylists() { this.playlists.listing.sort((a, b) => { - if (a.type === "library-playlist-folders" && b.type !== "library-playlist-folders") { - return -1 - } else if (a.type !== "library-playlist-folders" && b.type === "library-playlist-folders") { - return 1 + if ( + a.type === 'library-playlist-folders' && + b.type !== 'library-playlist-folders' + ) { + return -1; + } else if ( + a.type !== 'library-playlist-folders' && + b.type === 'library-playlist-folders' + ) { + return 1; } else { - return 0 + return 0; } - }) + }); }, playlistHeaderContextMenu(event) { let menu = { items: [ { - name: "New Playlist", + name: 'New Playlist', action: () => { - this.newPlaylist() + this.newPlaylist(); } }, { - name: "New Playlist Folder", + name: 'New Playlist Folder', action: () => { - this.newPlaylistFolder() + this.newPlaylistFolder(); } } ] - } - CiderContextMenu.Create(event, menu) + }; + CiderContextMenu.Create(event, menu); }, - async editPlaylistFolder(id, name = "New Playlist") { - let self = this - this.mk.api.v3.music( - `/v1/me/library/playlist-folders/${id}`, - {}, - { - fetchOptions: { - method: "PATCH", - body: JSON.stringify({ - attributes: {name: name} - }) + async editPlaylistFolder(id, name = 'New Playlist') { + let self = this; + this.mk.api.v3 + .music( + `/v1/me/library/playlist-folders/${id}`, + {}, + { + fetchOptions: { + method: 'PATCH', + body: JSON.stringify({ + attributes: { name: name } + }) + } } - } - ).then(res => { - self.refreshPlaylists() - }) + ) + .then((res) => { + self.refreshPlaylists(); + }); }, - async editPlaylist(id, name = "New Playlist") { - let self = this - this.mk.api.v3.music( - `/v1/me/library/playlists/${id}`, - {}, - { - fetchOptions: { - method: "PATCH", - body: JSON.stringify({ - attributes: {name: name} - }) + async editPlaylist(id, name = 'New Playlist') { + let self = this; + this.mk.api.v3 + .music( + `/v1/me/library/playlists/${id}`, + {}, + { + fetchOptions: { + method: 'PATCH', + body: JSON.stringify({ + attributes: { name: name } + }) + } } - } - ).then(res => { - self.refreshPlaylists() - }) + ) + .then((res) => { + self.refreshPlaylists(); + }); }, copyToClipboard(str) { - navigator.clipboard.writeText(str) + navigator.clipboard.writeText(str); }, - newPlaylist(name = "New Playlist", tracks = []) { - let self = this + newPlaylist(name = 'New Playlist', tracks = []) { + let self = this; let request = { name: name - } + }; if (tracks.length > 0) { - request.tracks = tracks + request.tracks = tracks; } - app.mk.api.library.createPlaylist(request).then(res => { - console.log(res) + app.mk.api.library.createPlaylist(request).then((res) => { + console.log(res); self.appRoute(`playlist_` + res.id); self.showingPlaylist = []; - self.getPlaylistFromID(app.page.substring(9)) + self.getPlaylistFromID(app.page.substring(9)); self.playlists.listing.push({ id: res.id, attributes: { name: name }, - parent: "p.playlistsroot" - }) - self.sortPlaylists() + parent: 'p.playlistsroot' + }); + self.sortPlaylists(); setTimeout(() => { - app.refreshPlaylists() - }, 8000) - }) + app.refreshPlaylists(); + }, 8000); + }); }, deletePlaylist(id) { - let self = this + let self = this; if (confirm(`Are you sure you want to delete this playlist?`)) { - app.mk.api.library.deletePlaylist(id).then(res => { + app.mk.api.library.deletePlaylist(id).then((res) => { // remove this playlist from playlists.listing if it exists - let found = self.playlists.listing.find(item => item.id == id) + let found = self.playlists.listing.find( + (item) => item.id == id + ); if (found) { - self.playlists.listing.splice(self.playlists.listing.indexOf(found), 1) + self.playlists.listing.splice( + self.playlists.listing.indexOf(found), + 1 + ); } - }) + }); } }, async showCollection(response, title, type) { - let self = this - this.collectionList.response = response - this.collectionList.title = title - this.collectionList.type = type - app.appRoute("collection-list") + let self = this; + this.collectionList.response = response; + this.collectionList.title = title; + this.collectionList.type = type; + app.appRoute('collection-list'); }, async showArtistView(artist, title, view) { - let response = await this.mk.api.artistView(artist, view, {}, {view: view, includeResponseMeta: !0}) - await this.showCollection(response, title, "artists") + let response = await this.mk.api.artistView( + artist, + view, + {}, + { view: view, includeResponseMeta: !0 } + ); + await this.showCollection(response, title, 'artists'); }, async showRecordLabelView(label, title, view) { - let response = await this.mk.api.recordLabelView(label, view, {}, {view: view, includeResponseMeta: !0}) - await this.showCollection(response, title, "record-labels") + let response = await this.mk.api.recordLabelView( + label, + view, + {}, + { view: view, includeResponseMeta: !0 } + ); + await this.showCollection(response, title, 'record-labels'); }, async showSearchView(term, group, title) { - let response = await this.mk.api.search(term, { - platform: "web", - groups: group, - types: "activities,albums,apple-curators,artists,curators,editorial-items,music-movies,music-videos,playlists,songs,stations,tv-episodes,uploaded-videos,record-labels", - limit: 25, - relate: { - editorialItems: ["contents"] + let response = await this.mk.api.search( + term, + { + platform: 'web', + groups: group, + types: 'activities,albums,apple-curators,artists,curators,editorial-items,music-movies,music-videos,playlists,songs,stations,tv-episodes,uploaded-videos,record-labels', + limit: 25, + relate: { + editorialItems: ['contents'] + }, + include: { + albums: ['artists'], + songs: ['artists'], + 'music-videos': ['artists'] + }, + extend: 'artistUrl', + fields: { + artists: 'url,name,artwork,hero', + albums: 'artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url' + }, + with: 'serverBubbles,lyricHighlights', + art: { + url: 'cf' + }, + omit: { + resource: ['autos'] + } }, - include: { - albums: ["artists"], - songs: ["artists"], - "music-videos": ["artists"] - }, - extend: "artistUrl", - fields: { - artists: "url,name,artwork,hero", - albums: "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url" - }, - with: "serverBubbles,lyricHighlights", - art: { - "url": "cf" - }, - omit: { - resource: ["autos"] - } - }, {groups: group, includeResponseMeta: !0}) - console.log(response) + { groups: group, includeResponseMeta: !0 } + ); + console.log(response); let responseFormat = { data: response[group].data.data, next: response[group].next, groups: group - } - await this.showCollection(responseFormat, title, "search") + }; + await this.showCollection(responseFormat, title, 'search'); }, async getPlaylistContinuous(response, transient = false) { - let self = this - let playlistId = response.id - if (!transient) this.playlists.loadingState = 0 - this.showingPlaylist = response + let self = this; + let playlistId = response.id; + if (!transient) this.playlists.loadingState = 0; + this.showingPlaylist = response; if (!response.relationships.tracks.next) { - this.playlists.loadingState = 1 - return + this.playlists.loadingState = 1; + return; } function getPlaylistTracks(next) { - app.apiCall(app.musicBaseUrl + next, res => { + app.apiCall(app.musicBaseUrl + next, (res) => { if (self.showingPlaylist.id != playlistId) { - return + return; } - self.showingPlaylist.relationships.tracks.data = self.showingPlaylist.relationships.tracks.data.concat(res.data) + self.showingPlaylist.relationships.tracks.data = + self.showingPlaylist.relationships.tracks.data.concat( + res.data + ); if (res.next) { - getPlaylistTracks(res.next) + getPlaylistTracks(res.next); } else { - self.playlists.loadingState = 1 + self.playlists.loadingState = 1; } - }) + }); } - getPlaylistTracks(response.relationships.tracks.next) - + getPlaylistTracks(response.relationships.tracks.next); }, async getPlaylistFromID(id, transient = false) { - let self = this + let self = this; const params = { - include: "tracks", - platform: "web", - "include[library-playlists]": "catalog,tracks", - "fields[playlists]": "curatorName,playlistType,name,artwork,url", - "include[library-songs]": "catalog,artists,albums", - "fields[catalog]": "artistUrl,albumUrl", - "fields[songs]": "artistUrl,albumUrl" + include: 'tracks', + platform: 'web', + 'include[library-playlists]': 'catalog,tracks', + 'fields[playlists]': + 'curatorName,playlistType,name,artwork,url', + 'include[library-songs]': 'catalog,artists,albums', + 'fields[catalog]': 'artistUrl,albumUrl', + 'fields[songs]': 'artistUrl,albumUrl' + }; + if (!transient) { + this.playlists.loadingState = 0; } - if (!transient) {this.playlists.loadingState = 0;} - let playlistId = '' + let playlistId = ''; try { - app.mk.api.library.playlist(id, params).then(res => { - self.getPlaylistContinuous(res, transient) - }) + app.mk.api.library.playlist(id, params).then((res) => { + self.getPlaylistContinuous(res, transient); + }); } catch (e) { console.log(e); try { - app.mk.api.library.playlist(id, params).then(res => { - self.getPlaylistContinuous(res, transient) - }) + app.mk.api.library.playlist(id, params).then((res) => { + self.getPlaylistContinuous(res, transient); + }); } catch (err) { - console.log(err) + console.log(err); } } - }, async getArtistFromID(id) { - const artistData = await this.mkapi("artists", false, id, { - "views": "featured-release,full-albums,appears-on-albums,featured-albums,featured-on-albums,singles,compilation-albums,live-albums,latest-release,top-music-videos,similar-artists,top-songs,playlists,more-to-hear,more-to-see", - "extend": "artistBio,bornOrFormed,editorialArtwork,editorialVideo,isGroup,origin,hero", - "extend[playlists]": "trackCount", - "include[songs]": "albums", - "fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount", - "limit[artists:top-songs]": 20, - "art[url]": "f" - }, {includeResponseMeta: !0}) - console.log(artistData) - this.artistPage.data = artistData.data[0] - this.page = "artist-page" + const artistData = await this.mkapi( + 'artists', + false, + id, + { + views: 'featured-release,full-albums,appears-on-albums,featured-albums,featured-on-albums,singles,compilation-albums,live-albums,latest-release,top-music-videos,similar-artists,top-songs,playlists,more-to-hear,more-to-see', + extend: 'artistBio,bornOrFormed,editorialArtwork,editorialVideo,isGroup,origin,hero', + 'extend[playlists]': 'trackCount', + 'include[songs]': 'albums', + 'fields[albums]': + 'artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount', + 'limit[artists:top-songs]': 20, + 'art[url]': 'f' + }, + { includeResponseMeta: !0 } + ); + console.log(artistData); + this.artistPage.data = artistData.data[0]; + this.page = 'artist-page'; }, progressBarStyle() { - let val = this.playerLCD.playbackDuration + let val = this.playerLCD.playbackDuration; if (this.playerLCD.desiredDuration > 0) { - val = this.playerLCD.desiredDuration + val = this.playerLCD.desiredDuration; } - let min = 0 - let max = this.mk.currentPlaybackDuration - let value = (val - min) / (max - min) * 100 + let min = 0; + let max = this.mk.currentPlaybackDuration; + let value = ((val - min) / (max - min)) * 100; return { - 'background': ('linear-gradient(to right, var(--keyColor) 0%, var(--keyColor) ' + value + '%, #333 ' + value + '%, #333 100%)') - } + background: + 'linear-gradient(to right, var(--keyColor) 0%, var(--keyColor) ' + + value + + '%, #333 ' + + value + + '%, #333 100%)' + }; }, async getRecursive(response) { // if response has a .next() property run it and keep running until .next is null or undefined // and then return the response concatenated with the results of the next() call function executeRequest() { if (response.next) { - return response.next().then(executeRequest) + return response.next().then(executeRequest); } else { - return response + return response; } } - return executeRequest() + return executeRequest(); }, async getRecursive2(response, sendTo) { let returnData = { - "data": [], - "meta": {} - } + data: [], + meta: {} + }; if (response.next) { - console.log("has next") - returnData.data.concat(response.data) - returnData.meta = response.meta - return await this.getRecursive(await response.next()) + console.log('has next'); + returnData.data.concat(response.data); + returnData.meta = response.meta; + return await this.getRecursive(await response.next()); } else { - console.log("no next") - returnData.data.concat(response.data) - return returnData + console.log('no next'); + returnData.data.concat(response.data); + return returnData; } }, async getSearchHints() { - if (this.search.term == "") { - this.search.hints = [] - return + if (this.search.term == '') { + this.search.hints = []; + return; } - let hints = await app.mkapi("searchHints", false, this.search.term) - this.search.hints = hints ? hints.terms : [] + let hints = await app.mkapi('searchHints', false, this.search.term); + this.search.hints = hints ? hints.terms : []; }, getSongProgress() { if (this.playerLCD.userInteraction) { - return this.playerLCD.desiredDuration + return this.playerLCD.desiredDuration; } else { - return this.playerLCD.playbackDuration + return this.playerLCD.playbackDuration; } }, convertToMins(time) { - let mins = Math.floor(time / 60) - let seconds = (Math.floor(time % 60) / 100).toFixed(2) - return `${mins}:${seconds.replace("0.", "")}` + let mins = Math.floor(time / 60); + let seconds = (Math.floor(time % 60) / 100).toFixed(2); + return `${mins}:${seconds.replace('0.', '')}`; }, hashCode(str) { - let hash = 0, i, chr; + let hash = 0, + i, + chr; if (str.length === 0) return hash; for (i = 0; i < str.length; i++) { chr = str.charCodeAt(i); - hash = ((hash << 5) - hash) + chr; + hash = (hash << 5) - hash + chr; hash |= 0; // Convert to 32bit integer } return hash; }, appRoute(route) { - if (route == "" || route == "#" || route == "/") { + if (route == '' || route == '#' || route == '/') { return; } - route = route.replace(/#/g, "") + route = route.replace(/#/g, ''); // if the route contains does not include a / then route to the page directly - if (route.indexOf("/") == -1) { - this.page = route - window.location.hash = this.page - return + if (route.indexOf('/') == -1) { + this.page = route; + window.location.hash = this.page; + return; } - let hash = route.split("/") - let page = hash[0] - let id = hash[1] - console.log(`page: ${page} id: ${id}`) + let hash = route.split('/'); + let page = hash[0]; + let id = hash[1]; + console.log(`page: ${page} id: ${id}`); this.routeView({ kind: page, id: id, attributes: { - playParams: {kind: page, id: id} + playParams: { kind: page, id: id } } - }) + }); }, routeView(item) { - let kind = (item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')) : (item.type ?? '')); - let id = (item.attributes.playParams ? (item.attributes.playParams.id ?? (item.id ?? '')) : (item.id ?? '')); - ; - let isLibrary = item.attributes.playParams ? (item.attributes.playParams.isLibrary ?? false) : false; - console.log(kind, id, isLibrary) + let kind = item.attributes.playParams + ? item.attributes.playParams.kind ?? item.type ?? '' + : item.type ?? ''; + let id = item.attributes.playParams + ? item.attributes.playParams.id ?? item.id ?? '' + : item.id ?? ''; + let isLibrary = item.attributes.playParams + ? item.attributes.playParams.isLibrary ?? false + : false; + console.log(kind, id, isLibrary); if (true) { - if (kind.includes("playlist") || kind.includes("album")) { + if (kind.includes('playlist') || kind.includes('album')) { app.showingPlaylist = []; } - if (kind.toString().includes("apple-curator")) { - kind = "appleCurator" - app.getTypeFromID("appleCurator", (id), false, { - platform: "web", - include: "grouping,playlists", - extend: "editorialArtwork", - "art[url]": "f" + if (kind.toString().includes('apple-curator')) { + kind = 'appleCurator'; + app.getTypeFromID('appleCurator', id, false, { + platform: 'web', + include: 'grouping,playlists', + extend: 'editorialArtwork', + 'art[url]': 'f' }); - window.location.hash = `${kind}/${id}` - document.querySelector("#app-content").scrollTop = 0 - } else if (kind.toString().includes("artist")) { - app.getArtistInfo(id, isLibrary) - window.location.hash = `${kind}/${id}` - document.querySelector("#app-content").scrollTop = 0 - - } else if (kind.toString().includes("record-label") || kind.toString().includes("curator")) { - if (kind.toString().includes("record-label")) { - kind = "recordLabel" + window.location.hash = `${kind}/${id}`; + document.querySelector('#app-content').scrollTop = 0; + } else if (kind.toString().includes('artist')) { + app.getArtistInfo(id, isLibrary); + window.location.hash = `${kind}/${id}`; + document.querySelector('#app-content').scrollTop = 0; + } else if ( + kind.toString().includes('record-label') || + kind.toString().includes('curator') + ) { + if (kind.toString().includes('record-label')) { + kind = 'recordLabel'; } else { - kind = "curator" + kind = 'curator'; } - app.page = (kind) + "_" + (id); - app.getTypeFromID((kind), (id), (isLibrary), { - extend: "editorialVideo", + app.page = kind + '_' + id; + app.getTypeFromID(kind, id, isLibrary, { + extend: 'editorialVideo', include: 'grouping,playlists', views: 'top-releases,latest-releases,top-artists' }); - window.location.hash = `${kind}/${id}` - document.querySelector("#app-content").scrollTop = 0 - } else if (!kind.toString().includes("radioStation") && !kind.toString().includes("song") && !kind.toString().includes("musicVideo") && !kind.toString().includes("uploadedVideo") && !kind.toString().includes("music-movie")) { - let params = {extend: "editorialVideo"} - app.page = (kind) + "_" + (id); - app.getTypeFromID((kind), (id), (isLibrary), params); - window.location.hash = `${kind}/${id}` - document.querySelector("#app-content").scrollTop = 0 + window.location.hash = `${kind}/${id}`; + document.querySelector('#app-content').scrollTop = 0; + } else if ( + !kind.toString().includes('radioStation') && + !kind.toString().includes('song') && + !kind.toString().includes('musicVideo') && + !kind.toString().includes('uploadedVideo') && + !kind.toString().includes('music-movie') + ) { + let params = { extend: 'editorialVideo' }; + app.page = kind + '_' + id; + app.getTypeFromID(kind, id, isLibrary, params); + window.location.hash = `${kind}/${id}`; + document.querySelector('#app-content').scrollTop = 0; } else { - app.playMediaItemById((id), (kind), (isLibrary), item.attributes.url ?? '') + app.playMediaItemById( + id, + kind, + isLibrary, + item.attributes.url ?? '' + ); } - } - }, prevButton() { - if (!app.prevButtonBackIndicator && app.mk.nowPlayingItem && app.mk.currentPlaybackTime > 2) { + if ( + !app.prevButtonBackIndicator && + app.mk.nowPlayingItem && + app.mk.currentPlaybackTime > 2 + ) { app.prevButtonBackIndicator = true; app.mk.seekToTime(0); } else { app.prevButtonBackIndicator = false; - app.mk.skipToPreviousItem() + app.mk.skipToPreviousItem(); } }, async getNowPlayingItemDetailed(target) { - let u = await app.mkapi(app.mk.nowPlayingItem.playParams.kind, (app.mk.nowPlayingItem.songId == -1), (app.mk.nowPlayingItem.songId != -1) ? app.mk.nowPlayingItem.songId : app.mk.nowPlayingItem["id"], {"include[songs]": "albums,artists"}); - app.searchAndNavigate(u, target) + let u = await app.mkapi( + app.mk.nowPlayingItem.playParams.kind, + app.mk.nowPlayingItem.songId == -1, + app.mk.nowPlayingItem.songId != -1 + ? app.mk.nowPlayingItem.songId + : app.mk.nowPlayingItem['id'], + { 'include[songs]': 'albums,artists' } + ); + app.searchAndNavigate(u, target); }, async searchAndNavigate(item, target) { - let self = this + let self = this; app.tmpVar = item; switch (target) { - case "artist": + case 'artist': let artistId = ''; try { - if (item.relationships.artists && item.relationships.artists.data.length > 0 && !item.relationships.artists.data[0].type.includes("library")) { - if (item.relationships.artists.data[0].type === "artist" || item.relationships.artists.data[0].type === "artists") { - artistId = item.relationships.artists.data[0].id + if ( + item.relationships.artists && + item.relationships.artists.data.length > 0 && + !item.relationships.artists.data[0].type.includes( + 'library' + ) + ) { + if ( + item.relationships.artists.data[0].type === + 'artist' || + item.relationships.artists.data[0].type === + 'artists' + ) { + artistId = + item.relationships.artists.data[0].id; } } if (artistId == '') { - const url = (item.relationships.catalog.data[0].attributes.artistUrl); - artistId = (url).substring(url.lastIndexOf('/') + 1) + const url = + item.relationships.catalog.data[0].attributes + .artistUrl; + artistId = url.substring(url.lastIndexOf('/') + 1); if (artistId.includes('viewCollaboration')) { - artistId = artistId.substring(artistId.lastIndexOf('ids=') + 4, artistId.lastIndexOf('-')) + artistId = artistId.substring( + artistId.lastIndexOf('ids=') + 4, + artistId.lastIndexOf('-') + ); } } - } catch (_) { - } + } catch (_) {} - if (artistId == "") { - let artistQuery = await app.mk.api.search(item.attributes.artistName, { - limit: 1, - types: 'artists' - }) + if (artistId == '') { + let artistQuery = await app.mk.api.search( + item.attributes.artistName, + { + limit: 1, + types: 'artists' + } + ); try { if (artistQuery.artists.data.length > 0) { artistId = artistQuery.artists.data[0].id; - console.log(artistId) + console.log(artistId); } - } catch (e) { - } + } catch (e) {} } console.log(artistId); - if (artistId != "") - self.appRoute(`artist/${artistId}`) + if (artistId != '') self.appRoute(`artist/${artistId}`); break; - case "album": + case 'album': let albumId = ''; try { - if (item.relationships.albums && item.relationships.albums.data.length > 0 && !item.relationships.albums.data[0].type.includes("library")) { - if (item.relationships.albums.data[0].type === "album" || item.relationships.albums.data[0].type === "albums") { - albumId = item.relationships.albums.data[0].id + if ( + item.relationships.albums && + item.relationships.albums.data.length > 0 && + !item.relationships.albums.data[0].type.includes( + 'library' + ) + ) { + if ( + item.relationships.albums.data[0].type === + 'album' || + item.relationships.albums.data[0].type === + 'albums' + ) { + albumId = item.relationships.albums.data[0].id; } } if (albumId == '') { - const url = (item.relationships.catalog.data[0].attributes.url); - albumId = (url).substring(url.lastIndexOf('/') + 1) - if (albumId.includes("?i=")) { - albumId = albumId.substring(0, albumId.indexOf("?i=")) + const url = + item.relationships.catalog.data[0].attributes + .url; + albumId = url.substring(url.lastIndexOf('/') + 1); + if (albumId.includes('?i=')) { + albumId = albumId.substring( + 0, + albumId.indexOf('?i=') + ); } } - } catch (_) { - } + } catch (_) {} - if (albumId == "") { + if (albumId == '') { try { - let albumQuery = await app.mk.api.search(item.attributes.albumName + " " + (item.attributes.artistName ?? ""), { - limit: 1, - types: 'albums' - }) + let albumQuery = await app.mk.api.search( + item.attributes.albumName + + ' ' + + (item.attributes.artistName ?? ''), + { + limit: 1, + types: 'albums' + } + ); if (albumQuery.albums.data.length > 0) { albumId = albumQuery.albums.data[0].id; - console.log(albumId) + console.log(albumId); } - } catch (e) { - } + } catch (e) {} } - if (albumId != "") { - self.appRoute(`album/${albumId}`) + if (albumId != '') { + self.appRoute(`album/${albumId}`); } break; - case "recordLabel": + case 'recordLabel': let labelId = ''; try { - labelId = item.relationships['record-labels'].data[0].id - } catch (_) { - } + labelId = + item.relationships['record-labels'].data[0].id; + } catch (_) {} - if (labelId == "") { + if (labelId == '') { try { - let labelQuery = await app.mk.api.search(item.attributes.recordLabel, { - limit: 1, - types: 'record-labels' - }) - if (labelQuery["record-labels"].data.length > 0) { - labelId = labelQuery["record-labels"].data[0].id; - console.log(labelId) + let labelQuery = await app.mk.api.search( + item.attributes.recordLabel, + { + limit: 1, + types: 'record-labels' + } + ); + if (labelQuery['record-labels'].data.length > 0) { + labelId = + labelQuery['record-labels'].data[0].id; + console.log(labelId); } - } catch (e) { - } + } catch (e) {} } - if (labelId != "") { - app.showingPlaylist = [] - await app.getTypeFromID("recordLabel", labelId, false, {views: 'top-releases,latest-releases,top-artists'}); - app.page = "recordLabel_" + labelId; + if (labelId != '') { + app.showingPlaylist = []; + await app.getTypeFromID('recordLabel', labelId, false, { + views: 'top-releases,latest-releases,top-artists' + }); + app.page = 'recordLabel_' + labelId; } break; } }, exitMV() { - MusicKit.getInstance().stop() - document.getElementById("apple-music-video-container").style.display = "none"; + MusicKit.getInstance().stop(); + document.getElementById( + 'apple-music-video-container' + ).style.display = 'none'; }, getArtistInfo(id, isLibrary) { - this.getArtistFromID(id) + this.getArtistFromID(id); //this.getTypeFromID("artist",id,isLibrary,query) }, playMediaItem(item) { - let kind = (item.attributes.playParams ? (item.attributes.playParams.kind ?? (item.type ?? '')) : (item.type ?? '')); - let id = (item.attributes.playParams ? (item.attributes.playParams.id ?? (item.id ?? '')) : (item.id ?? '')); - ; - let isLibrary = item.attributes.playParams ? (item.attributes.playParams.isLibrary ?? false) : false; - console.log(kind, id, isLibrary) - if (kind.includes("artist")) { - app.mk.setStationQueue({artist: 'a-' + id}).then(() => { - app.mk.play() - }) + let kind = item.attributes.playParams + ? item.attributes.playParams.kind ?? item.type ?? '' + : item.type ?? ''; + let id = item.attributes.playParams + ? item.attributes.playParams.id ?? item.id ?? '' + : item.id ?? ''; + let isLibrary = item.attributes.playParams + ? item.attributes.playParams.isLibrary ?? false + : false; + console.log(kind, id, isLibrary); + if (kind.includes('artist')) { + app.mk.setStationQueue({ artist: 'a-' + id }).then(() => { + app.mk.play(); + }); } else { - app.playMediaItemById((id), (kind), (isLibrary), item.attributes.url ?? '') + app.playMediaItemById( + id, + kind, + isLibrary, + item.attributes.url ?? '' + ); } }, - async getTypeFromID(kind, id, isLibrary = false, params = {}, params2 = {}) { + async getTypeFromID( + kind, + id, + isLibrary = false, + params = {}, + params2 = {} + ) { let a; - if (kind == "album" | kind == "albums") { - params["include"] = "tracks,artists,record-labels"; + if ((kind == 'album') | (kind == 'albums')) { + params['include'] = 'tracks,artists,record-labels'; } try { - a = await this.mkapi(kind.toString(), isLibrary, id.toString(), params, params2); + a = await this.mkapi( + kind.toString(), + isLibrary, + id.toString(), + params, + params2 + ); } catch (e) { console.log(e); try { - a = await this.mkapi(kind.toString(), !isLibrary, id.toString(), params, params2); + a = await this.mkapi( + kind.toString(), + !isLibrary, + id.toString(), + params, + params2 + ); } catch (err) { console.log(err); - a = [] + a = []; } finally { - if (kind == "appleCurator") { - app.appleCurator = a + if (kind == 'appleCurator') { + app.appleCurator = a; } else { - this.getPlaylistContinuous(a) + this.getPlaylistContinuous(a); } } } finally { - if (kind == "appleCurator") { - app.appleCurator = a + if (kind == 'appleCurator') { + app.appleCurator = a; } else { - this.getPlaylistContinuous(a) + this.getPlaylistContinuous(a); } } - ; }, searchLibrarySongs() { - let self = this + let self = this; function sortSongs() { // sort this.library.songs.displayListing by song.attributes[self.library.songs.sorting] in descending or ascending order based on alphabetical order and numeric order // check if song.attributes[self.library.songs.sorting] is a number and if so, sort by number if not, sort by alphabetical order ignoring case self.library.songs.displayListing.sort((a, b) => { - let aa = a.attributes[self.library.songs.sorting] - let bb = b.attributes[self.library.songs.sorting] - if (self.library.songs.sorting == "genre") { - aa = a.attributes.genreNames[0] - bb = b.attributes.genreNames[0] + let aa = a.attributes[self.library.songs.sorting]; + let bb = b.attributes[self.library.songs.sorting]; + if (self.library.songs.sorting == 'genre') { + aa = a.attributes.genreNames[0]; + bb = b.attributes.genreNames[0]; } if (aa == null) { - aa = "" + aa = ''; } if (bb == null) { - bb = "" + bb = ''; } - if (self.library.songs.sortOrder == "asc") { - if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { - return aa - bb + if (self.library.songs.sortOrder == 'asc') { + if ( + aa.toString().match(/^\d+$/) && + bb.toString().match(/^\d+$/) + ) { + return aa - bb; } else { - return aa.toString().toLowerCase().localeCompare(bb.toString().toLowerCase()) + return aa + .toString() + .toLowerCase() + .localeCompare(bb.toString().toLowerCase()); } - } else if (self.library.songs.sortOrder == "desc") { - if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { - return bb - aa + } else if (self.library.songs.sortOrder == 'desc') { + if ( + aa.toString().match(/^\d+$/) && + bb.toString().match(/^\d+$/) + ) { + return bb - aa; } else { - return bb.toString().toLowerCase().localeCompare(aa.toString().toLowerCase()) + return bb + .toString() + .toLowerCase() + .localeCompare(aa.toString().toLowerCase()); } } - }) + }); } - if (this.library.songs.search == "") { - this.library.songs.displayListing = this.library.songs.listing - sortSongs() + if (this.library.songs.search == '') { + this.library.songs.displayListing = this.library.songs.listing; + sortSongs(); } else { - this.library.songs.displayListing = this.library.songs.listing.filter(item => { - let itemName = item.attributes.name.toLowerCase() - let searchTerm = this.library.songs.search.toLowerCase() - let artistName = "" - let albumName = "" - if (item.attributes.artistName != null) { - artistName = item.attributes.artistName.toLowerCase() - } - if (item.attributes.albumName != null) { - albumName = item.attributes.albumName.toLowerCase() - } + this.library.songs.displayListing = + this.library.songs.listing.filter((item) => { + let itemName = item.attributes.name.toLowerCase(); + let searchTerm = + this.library.songs.search.toLowerCase(); + let artistName = ''; + let albumName = ''; + if (item.attributes.artistName != null) { + artistName = + item.attributes.artistName.toLowerCase(); + } + if (item.attributes.albumName != null) { + albumName = item.attributes.albumName.toLowerCase(); + } - // remove any non-alphanumeric characters and spaces from search term and item name - searchTerm = searchTerm.replace(/[^a-z0-9 ]/gi, "") - itemName = itemName.replace(/[^a-z0-9 ]/gi, "") - artistName = artistName.replace(/[^a-z0-9 ]/gi, "") - albumName = albumName.replace(/[^a-z0-9 ]/gi, "") + // remove any non-alphanumeric characters and spaces from search term and item name + searchTerm = searchTerm.replace(/[^a-z0-9 ]/gi, ''); + itemName = itemName.replace(/[^a-z0-9 ]/gi, ''); + artistName = artistName.replace(/[^a-z0-9 ]/gi, ''); + albumName = albumName.replace(/[^a-z0-9 ]/gi, ''); - if (itemName.includes(searchTerm) || artistName.includes(searchTerm) || albumName.includes(searchTerm)) { - return item - } - }) - sortSongs() + if ( + itemName.includes(searchTerm) || + artistName.includes(searchTerm) || + albumName.includes(searchTerm) + ) { + return item; + } + }); + sortSongs(); } }, // make a copy of searchLibrarySongs except use Albums instead of Songs searchLibraryAlbums(index) { - let self = this + let self = this; function sortAlbums() { // sort this.library.albums.displayListing by album.attributes[self.library.albums.sorting[index]] in descending or ascending order based on alphabetical order and numeric order // check if album.attributes[self.library.albums.sorting[index]] is a number and if so, sort by number if not, sort by alphabetical order ignoring case self.library.albums.displayListing.sort((a, b) => { - let aa = a.attributes[self.library.albums.sorting[index]] - let bb = b.attributes[self.library.albums.sorting[index]] - if (self.library.albums.sorting[index] == "genre") { - aa = a.attributes.genreNames[0] - bb = b.attributes.genreNames[0] + let aa = a.attributes[self.library.albums.sorting[index]]; + let bb = b.attributes[self.library.albums.sorting[index]]; + if (self.library.albums.sorting[index] == 'genre') { + aa = a.attributes.genreNames[0]; + bb = b.attributes.genreNames[0]; } if (aa == null) { - aa = "" + aa = ''; } if (bb == null) { - bb = "" + bb = ''; } - if (self.library.albums.sortOrder[index] == "asc") { - if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { - return aa - bb + if (self.library.albums.sortOrder[index] == 'asc') { + if ( + aa.toString().match(/^\d+$/) && + bb.toString().match(/^\d+$/) + ) { + return aa - bb; } else { - return aa.toString().toLowerCase().localeCompare(bb.toString().toLowerCase()) + return aa + .toString() + .toLowerCase() + .localeCompare(bb.toString().toLowerCase()); } - } else if (self.library.albums.sortOrder[index] == "desc") { - if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { - return bb - aa + } else if (self.library.albums.sortOrder[index] == 'desc') { + if ( + aa.toString().match(/^\d+$/) && + bb.toString().match(/^\d+$/) + ) { + return bb - aa; } else { - return bb.toString().toLowerCase().localeCompare(aa.toString().toLowerCase()) + return bb + .toString() + .toLowerCase() + .localeCompare(aa.toString().toLowerCase()); } } - }) + }); } - if (this.library.albums.search == "") { - this.library.albums.displayListing = this.library.albums.listing - sortAlbums() + if (this.library.albums.search == '') { + this.library.albums.displayListing = + this.library.albums.listing; + sortAlbums(); } else { - this.library.albums.displayListing = this.library.albums.listing.filter(item => { - let itemName = item.attributes.name.toLowerCase() - let searchTerm = this.library.albums.search.toLowerCase() - let artistName = "" - let albumName = "" - if (item.attributes.artistName != null) { - artistName = item.attributes.artistName.toLowerCase() - } - if (item.attributes.albumName != null) { - albumName = item.attributes.albumName.toLowerCase() - } + this.library.albums.displayListing = + this.library.albums.listing.filter((item) => { + let itemName = item.attributes.name.toLowerCase(); + let searchTerm = + this.library.albums.search.toLowerCase(); + let artistName = ''; + let albumName = ''; + if (item.attributes.artistName != null) { + artistName = + item.attributes.artistName.toLowerCase(); + } + if (item.attributes.albumName != null) { + albumName = item.attributes.albumName.toLowerCase(); + } - // remove any non-alphanumeric characters and spaces from search term and item name - searchTerm = searchTerm.replace(/[^a-z0-9 ]/gi, "") - itemName = itemName.replace(/[^a-z0-9 ]/gi, "") - artistName = artistName.replace(/[^a-z0-9 ]/gi, "") - albumName = albumName.replace(/[^a-z0-9 ]/gi, "") + // remove any non-alphanumeric characters and spaces from search term and item name + searchTerm = searchTerm.replace(/[^a-z0-9 ]/gi, ''); + itemName = itemName.replace(/[^a-z0-9 ]/gi, ''); + artistName = artistName.replace(/[^a-z0-9 ]/gi, ''); + albumName = albumName.replace(/[^a-z0-9 ]/gi, ''); - if (itemName.includes(searchTerm) || artistName.includes(searchTerm) || albumName.includes(searchTerm)) { - return item - } - }) - sortAlbums() + if ( + itemName.includes(searchTerm) || + artistName.includes(searchTerm) || + albumName.includes(searchTerm) + ) { + return item; + } + }); + sortAlbums(); } }, // make a copy of searchLibrarySongs except use Albums instead of Songs searchLibraryArtists(index) { - let self = this + let self = this; function sortArtists() { // sort this.library.albums.displayListing by album.attributes[self.library.albums.sorting[index]] in descending or ascending order based on alphabetical order and numeric order // check if album.attributes[self.library.albums.sorting[index]] is a number and if so, sort by number if not, sort by alphabetical order ignoring case self.library.artists.displayListing.sort((a, b) => { - let aa = a.attributes[self.library.artists.sorting[index]] - let bb = b.attributes[self.library.artists.sorting[index]] - if (self.library.artists.sorting[index] == "genre") { - aa = a.attributes.genreNames[0] - bb = b.attributes.genreNames[0] + let aa = a.attributes[self.library.artists.sorting[index]]; + let bb = b.attributes[self.library.artists.sorting[index]]; + if (self.library.artists.sorting[index] == 'genre') { + aa = a.attributes.genreNames[0]; + bb = b.attributes.genreNames[0]; } if (aa == null) { - aa = "" + aa = ''; } if (bb == null) { - bb = "" + bb = ''; } - if (self.library.artists.sortOrder[index] == "asc") { - if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { - return aa - bb + if (self.library.artists.sortOrder[index] == 'asc') { + if ( + aa.toString().match(/^\d+$/) && + bb.toString().match(/^\d+$/) + ) { + return aa - bb; } else { - return aa.toString().toLowerCase().localeCompare(bb.toString().toLowerCase()) + return aa + .toString() + .toLowerCase() + .localeCompare(bb.toString().toLowerCase()); } - } else if (self.library.artists.sortOrder[index] == "desc") { - if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { - return bb - aa + } else if ( + self.library.artists.sortOrder[index] == 'desc' + ) { + if ( + aa.toString().match(/^\d+$/) && + bb.toString().match(/^\d+$/) + ) { + return bb - aa; } else { - return bb.toString().toLowerCase().localeCompare(aa.toString().toLowerCase()) + return bb + .toString() + .toLowerCase() + .localeCompare(aa.toString().toLowerCase()); } } - }) + }); } - if (this.library.artists.search == "") { - this.library.artists.displayListing = this.library.artists.listing - sortArtists() + if (this.library.artists.search == '') { + this.library.artists.displayListing = + this.library.artists.listing; + sortArtists(); } else { - this.library.artists.displayListing = this.library.artists.listing.filter(item => { - let itemName = item.attributes.name.toLowerCase() - let searchTerm = this.library.artists.search.toLowerCase() - let artistName = "" - let albumName = "" - // if (item.attributes.artistName != null) { - // artistName = item.attributes.artistName.toLowerCase() - // } - // if (item.attributes.albumName != null) { - // albumName = item.attributes.albumName.toLowerCase() - // } + this.library.artists.displayListing = + this.library.artists.listing.filter((item) => { + let itemName = item.attributes.name.toLowerCase(); + let searchTerm = + this.library.artists.search.toLowerCase(); + let artistName = ''; + let albumName = ''; + // if (item.attributes.artistName != null) { + // artistName = item.attributes.artistName.toLowerCase() + // } + // if (item.attributes.albumName != null) { + // albumName = item.attributes.albumName.toLowerCase() + // } - // remove any non-alphanumeric characters and spaces from search term and item name - searchTerm = searchTerm.replace(/[^a-z0-9 ]/gi, "") - itemName = itemName.replace(/[^a-z0-9 ]/gi, "") + // remove any non-alphanumeric characters and spaces from search term and item name + searchTerm = searchTerm.replace(/[^a-z0-9 ]/gi, ''); + itemName = itemName.replace(/[^a-z0-9 ]/gi, ''); - - if (itemName.includes(searchTerm) || artistName.includes(searchTerm) || albumName.includes(searchTerm)) { - return item - } - }) - sortArtists() + if ( + itemName.includes(searchTerm) || + artistName.includes(searchTerm) || + albumName.includes(searchTerm) + ) { + return item; + } + }); + sortArtists(); } }, getSidebarItemClass(page) { if (this.page == page) { - return ["active"] + return ['active']; } else { - return [] + return []; } }, - async mkapi(method, library = false, term, params = {}, params2 = {}, attempts = 0) { + async mkapi( + method, + library = false, + term, + params = {}, + params2 = {}, + attempts = 0 + ) { if (attempts > 3) { - return + return; } try { if (library) { - return await this.mk.api.library[method](term, params, params2) + return await this.mk.api.library[method]( + term, + params, + params2 + ); } else { - return await this.mk.api[method](term, params, params2) + return await this.mk.api[method](term, params, params2); } } catch (e) { - console.log(e) - return await this.mkapi(method, library, term, params, params2, attempts + 1) + console.log(e); + return await this.mkapi( + method, + library, + term, + params, + params2, + attempts + 1 + ); } }, getLibraryGenres() { - let genres = [] - genres = [] + let genres = []; + genres = []; this.library.songs.listing.forEach((item) => { item.attributes.genreNames.forEach((genre) => { if (!genres.includes(genre)) { - genres.push(genre) + genres.push(genre); } - }) - }) - return genres + }); + }); + return genres; }, async getLibrarySongsFull(force = false) { - let self = this - let library = [] + let self = this; + let library = []; let downloaded = null; - if ((this.library.songs.downloadState == 2) && !force) { - return + if (this.library.songs.downloadState == 2 && !force) { + return; } if (this.library.songs.downloadState == 1) { - return + return; } - if (localStorage.getItem("librarySongs") != null) { - this.library.songs.listing = JSON.parse(localStorage.getItem("librarySongs")) - this.searchLibrarySongs() + if (localStorage.getItem('librarySongs') != null) { + this.library.songs.listing = JSON.parse( + localStorage.getItem('librarySongs') + ); + this.searchLibrarySongs(); } if (this.songstest) { - return + return; } - this.library.songs.downloadState = 1 - this.library.downloadNotification.show = true - this.library.downloadNotification.message = "Updating library songs..." + this.library.songs.downloadState = 1; + this.library.downloadNotification.show = true; + this.library.downloadNotification.message = + 'Updating library songs...'; function downloadChunk() { const params = { - "include[library-songs]": "catalog,artists,albums", - "fields[artists]": "name,url,id", - "fields[albums]": "name,url,id", - platform: "web", - "fields[catalog]": "artistUrl,albumUrl", - "fields[songs]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url", - limit: 100, - } - self.library.songs.downloadState = 1 + 'include[library-songs]': 'catalog,artists,albums', + 'fields[artists]': 'name,url,id', + 'fields[albums]': 'name,url,id', + platform: 'web', + 'fields[catalog]': 'artistUrl,albumUrl', + 'fields[songs]': + 'artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url', + limit: 100 + }; + self.library.songs.downloadState = 1; if (downloaded == null) { - app.mk.api.library.songs("", params, {includeResponseMeta: !0}).then((response) => { - processChunk(response) - }) + app.mk.api.library + .songs('', params, { includeResponseMeta: !0 }) + .then((response) => { + processChunk(response); + }); } else { - downloaded.next("", params, {includeResponseMeta: !0}).then((response) => { - processChunk(response) - }) + downloaded + .next('', params, { includeResponseMeta: !0 }) + .then((response) => { + processChunk(response); + }); } } function processChunk(response) { - downloaded = response - library = library.concat(downloaded.data) - self.library.downloadNotification.show = true - self.library.downloadNotification.message = "Updating library songs..." - self.library.downloadNotification.total = downloaded.meta.total - self.library.downloadNotification.progress = library.length + downloaded = response; + library = library.concat(downloaded.data); + self.library.downloadNotification.show = true; + self.library.downloadNotification.message = + 'Updating library songs...'; + self.library.downloadNotification.total = downloaded.meta.total; + self.library.downloadNotification.progress = library.length; if (downloaded.meta.total == 0) { - self.library.songs.downloadState = 3 - return + self.library.songs.downloadState = 3; + return; } - if (typeof downloaded.next == "undefined") { - console.log("downloaded.next is undefined") - self.library.songs.listing = library - self.library.songs.downloadState = 2 - self.library.downloadNotification.show = false - self.searchLibrarySongs() - localStorage.setItem("librarySongs", JSON.stringify(library)) + if (typeof downloaded.next == 'undefined') { + console.log('downloaded.next is undefined'); + self.library.songs.listing = library; + self.library.songs.downloadState = 2; + self.library.downloadNotification.show = false; + self.searchLibrarySongs(); + localStorage.setItem( + 'librarySongs', + JSON.stringify(library) + ); } - if (downloaded.meta.total > library.length || typeof downloaded.meta.next != "undefined") { - console.log(`downloading next chunk - ${library.length} songs so far`) - downloadChunk() + if ( + downloaded.meta.total > library.length || + typeof downloaded.meta.next != 'undefined' + ) { + console.log( + `downloading next chunk - ${library.length} songs so far` + ); + downloadChunk(); } else { - self.library.songs.listing = library - self.library.songs.downloadState = 2 - self.library.downloadNotification.show = false - self.searchLibrarySongs() - localStorage.setItem("librarySongs", JSON.stringify(library)) - console.log(library) + self.library.songs.listing = library; + self.library.songs.downloadState = 2; + self.library.downloadNotification.show = false; + self.searchLibrarySongs(); + localStorage.setItem( + 'librarySongs', + JSON.stringify(library) + ); + console.log(library); } } - downloadChunk() + downloadChunk(); }, // copy the getLibrarySongsFull function except change Songs to Albums async getLibraryAlbumsFull(force = false, index) { - let self = this - let library = [] + let self = this; + let library = []; let downloaded = null; - if ((this.library.albums.downloadState == 2 || this.library.albums.downloadState == 1) && !force) { - return + if ( + (this.library.albums.downloadState == 2 || + this.library.albums.downloadState == 1) && + !force + ) { + return; } - if (localStorage.getItem("libraryAlbums") != null) { - this.library.albums.listing = JSON.parse(localStorage.getItem("libraryAlbums")) - this.searchLibraryAlbums(index) + if (localStorage.getItem('libraryAlbums') != null) { + this.library.albums.listing = JSON.parse( + localStorage.getItem('libraryAlbums') + ); + this.searchLibraryAlbums(index); } if (this.songstest) { - return + return; } - this.library.albums.downloadState = 1 - this.library.downloadNotification.show = true - this.library.downloadNotification.message = "Updating library albums..." + this.library.albums.downloadState = 1; + this.library.downloadNotification.show = true; + this.library.downloadNotification.message = + 'Updating library albums...'; function downloadChunk() { - self.library.albums.downloadState = 1 + self.library.albums.downloadState = 1; const params = { - "include[library-albums]": "catalog,artists,albums", - "fields[artists]": "name,url,id", - "fields[albums]": "name,url,id", - platform: "web", - "fields[catalog]": "artistUrl,albumUrl", - "fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url", - limit: 100, - } + 'include[library-albums]': 'catalog,artists,albums', + 'fields[artists]': 'name,url,id', + 'fields[albums]': 'name,url,id', + platform: 'web', + 'fields[catalog]': 'artistUrl,albumUrl', + 'fields[albums]': + 'artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url', + limit: 100 + }; if (downloaded == null) { - app.mk.api.library.albums("", params, {includeResponseMeta: !0}).then((response) => { - processChunk(response) - }) + app.mk.api.library + .albums('', params, { includeResponseMeta: !0 }) + .then((response) => { + processChunk(response); + }); } else { - downloaded.next("", params, {includeResponseMeta: !0}).then((response) => { - processChunk(response) - }) + downloaded + .next('', params, { includeResponseMeta: !0 }) + .then((response) => { + processChunk(response); + }); } } function processChunk(response) { - downloaded = response - library = library.concat(downloaded.data) - self.library.downloadNotification.show = true - self.library.downloadNotification.message = "Updating library albums..." - self.library.downloadNotification.total = downloaded.meta.total - self.library.downloadNotification.progress = library.length + downloaded = response; + library = library.concat(downloaded.data); + self.library.downloadNotification.show = true; + self.library.downloadNotification.message = + 'Updating library albums...'; + self.library.downloadNotification.total = downloaded.meta.total; + self.library.downloadNotification.progress = library.length; if (downloaded.meta.total == 0) { - self.library.albums.downloadState = 3 - return + self.library.albums.downloadState = 3; + return; } - if (typeof downloaded.next == "undefined") { - console.log("downloaded.next is undefined") - self.library.albums.listing = library - self.library.albums.downloadState = 2 - self.library.downloadNotification.show = false - localStorage.setItem("libraryAlbums", JSON.stringify(library)) - self.searchLibraryAlbums(index) + if (typeof downloaded.next == 'undefined') { + console.log('downloaded.next is undefined'); + self.library.albums.listing = library; + self.library.albums.downloadState = 2; + self.library.downloadNotification.show = false; + localStorage.setItem( + 'libraryAlbums', + JSON.stringify(library) + ); + self.searchLibraryAlbums(index); } - if (downloaded.meta.total > library.length || typeof downloaded.meta.next != "undefined") { - console.log(`downloading next chunk - ${library.length - } albums so far`) - downloadChunk() + if ( + downloaded.meta.total > library.length || + typeof downloaded.meta.next != 'undefined' + ) { + console.log( + `downloading next chunk - ${library.length} albums so far` + ); + downloadChunk(); } else { - self.library.albums.listing = library - self.library.albums.downloadState = 2 - self.library.downloadNotification.show = false - localStorage.setItem("libraryAlbums", JSON.stringify(library)) - self.searchLibraryAlbums(index) - console.log(library) + self.library.albums.listing = library; + self.library.albums.downloadState = 2; + self.library.downloadNotification.show = false; + localStorage.setItem( + 'libraryAlbums', + JSON.stringify(library) + ); + self.searchLibraryAlbums(index); + console.log(library); } } - downloadChunk() + downloadChunk(); }, // copy the getLibrarySongsFull function except change Songs to Albums async getLibraryArtistsFull(force = false, index) { - let self = this - let library = [] + let self = this; + let library = []; let downloaded = null; - if ((this.library.artists.downloadState == 2 || this.library.artists.downloadState == 1) && !force) { - return + if ( + (this.library.artists.downloadState == 2 || + this.library.artists.downloadState == 1) && + !force + ) { + return; } - if (localStorage.getItem("libraryArtists") != null) { - this.library.artists.listing = JSON.parse(localStorage.getItem("libraryArtists")) - this.searchLibraryArtists(index) + if (localStorage.getItem('libraryArtists') != null) { + this.library.artists.listing = JSON.parse( + localStorage.getItem('libraryArtists') + ); + this.searchLibraryArtists(index); } if (this.songstest) { - return + return; } - this.library.artists.downloadState = 1 - this.library.downloadNotification.show = true - this.library.downloadNotification.message = "Updating library artists..." + this.library.artists.downloadState = 1; + this.library.downloadNotification.show = true; + this.library.downloadNotification.message = + 'Updating library artists...'; function downloadChunk() { - self.library.artists.downloadState = 1 + self.library.artists.downloadState = 1; const params = { - include: "catalog", + include: 'catalog', // "include[library-artists]": "catalog,artists,albums", // "fields[artists]": "name,url,id", // "fields[albums]": "name,url,id", - platform: "web", + platform: 'web', // "fields[catalog]": "artistUrl,albumUrl", // "fields[artists]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url", - limit: 100, - } + limit: 100 + }; if (downloaded == null) { - app.mk.api.library.artists("", params, {includeResponseMeta: !0}).then((response) => { - processChunk(response) - }) + app.mk.api.library + .artists('', params, { includeResponseMeta: !0 }) + .then((response) => { + processChunk(response); + }); } else { - downloaded.next("", "artists", {includeResponseMeta: !0}).then((response) => { - processChunk(response) - }) + downloaded + .next('', 'artists', { includeResponseMeta: !0 }) + .then((response) => { + processChunk(response); + }); } } function processChunk(response) { - downloaded = response - library = library.concat(downloaded.data) - self.library.downloadNotification.show = true - self.library.downloadNotification.message = "Updating library artists..." - self.library.downloadNotification.total = downloaded.meta.total - self.library.downloadNotification.progress = library.length + downloaded = response; + library = library.concat(downloaded.data); + self.library.downloadNotification.show = true; + self.library.downloadNotification.message = + 'Updating library artists...'; + self.library.downloadNotification.total = downloaded.meta.total; + self.library.downloadNotification.progress = library.length; if (downloaded.meta.total == 0) { - self.library.albums.downloadState = 3 - return + self.library.albums.downloadState = 3; + return; } - if (typeof downloaded.next == "undefined") { - console.log("downloaded.next is undefined") - self.library.artists.listing = library - self.library.artists.downloadState = 2 - self.library.artists.show = false - localStorage.setItem("libraryArtists", JSON.stringify(library)) - self.searchLibraryArtists(index) + if (typeof downloaded.next == 'undefined') { + console.log('downloaded.next is undefined'); + self.library.artists.listing = library; + self.library.artists.downloadState = 2; + self.library.artists.show = false; + localStorage.setItem( + 'libraryArtists', + JSON.stringify(library) + ); + self.searchLibraryArtists(index); } - if (downloaded.meta.total > library.length || typeof downloaded.meta.next != "undefined") { - console.log(`downloading next chunk - ${library.length - } artists so far`) - downloadChunk() + if ( + downloaded.meta.total > library.length || + typeof downloaded.meta.next != 'undefined' + ) { + console.log( + `downloading next chunk - ${library.length} artists so far` + ); + downloadChunk(); } else { - self.library.artists.listing = library - self.library.artists.downloadState = 2 - self.library.downloadNotification.show = false - localStorage.setItem("libraryArtists", JSON.stringify(library)) - self.searchLibraryArtists(index) - console.log(library) + self.library.artists.listing = library; + self.library.artists.downloadState = 2; + self.library.downloadNotification.show = false; + localStorage.setItem( + 'libraryArtists', + JSON.stringify(library) + ); + self.searchLibraryArtists(index); + console.log(library); } } - downloadChunk() + downloadChunk(); }, getTotalTime() { try { if (app.showingPlaylist.relationships.tracks.data.length > 0) { - let time = Math.round([].concat(...app.showingPlaylist.relationships.tracks.data).reduce((a, {attributes: {durationInMillis}}) => a + durationInMillis, 0) / 1000); - let hours = Math.floor(time / 3600) - let mins = Math.floor(time / 60) % 60 - let secs = time % 60 - return app.showingPlaylist.relationships.tracks.data.length + " tracks, " + ((hours > 0) ? (hours + (" hour" + ((hours > 1) ? "s, " : ", "))) : "") + ((mins > 0) ? (mins + (" minute" + ((mins > 1) ? "s, " : ", "))) : "") + secs + (" second" + ((secs > 1) ? "s." : ".")); - } else return "" + let time = Math.round( + [] + .concat( + ...app.showingPlaylist.relationships.tracks.data + ) + .reduce( + (a, { attributes: { durationInMillis } }) => + a + durationInMillis, + 0 + ) / 1000 + ); + let hours = Math.floor(time / 3600); + let mins = Math.floor(time / 60) % 60; + let secs = time % 60; + return ( + app.showingPlaylist.relationships.tracks.data.length + + ' tracks, ' + + (hours > 0 + ? hours + (' hour' + (hours > 1 ? 's, ' : ', ')) + : '') + + (mins > 0 + ? mins + (' minute' + (mins > 1 ? 's, ' : ', ')) + : '') + + secs + + (' second' + (secs > 1 ? 's.' : '.')) + ); + } else return ''; } catch (err) { - return "" + return ''; } }, async getLibrarySongs() { - let response = await this.mkapi("songs", true, "", {limit: 100}, {includeResponseMeta: !0}) - this.library.songs.listing = response.data - this.library.songs.meta = response.meta + let response = await this.mkapi( + 'songs', + true, + '', + { limit: 100 }, + { includeResponseMeta: !0 } + ); + this.library.songs.listing = response.data; + this.library.songs.meta = response.meta; }, async getLibraryAlbums() { - let response = await this.mkapi("albums", true, "", {limit: 100}, {includeResponseMeta: !0}) - this.library.albums.listing = response.data - this.library.albums.meta = response.meta + let response = await this.mkapi( + 'albums', + true, + '', + { limit: 100 }, + { includeResponseMeta: !0 } + ); + this.library.albums.listing = response.data; + this.library.albums.meta = response.meta; }, async getListenNow(attempt = 0) { if (attempt > 3) { - return + return; } try { - this.listennow = await this.mk.api.personalRecommendations("", + this.listennow = await this.mk.api.personalRecommendations( + '', { - name: "listen-now", - with: "friendsMix,library,social", - "art[social-profiles:url]": "c", - "art[url]": "c,f", - "omit[resource]": "autos", - "relate[editorial-items]": "contents", - extend: ["editorialCard", "editorialVideo"], - "extend[albums]": ["artistUrl"], - "extend[library-albums]": ["artistUrl", "editorialVideo"], - "extend[playlists]": ["artistNames", "editorialArtwork", "editorialVideo"], - "extend[library-playlists]": ["artistNames", "editorialArtwork", "editorialVideo"], - "extend[social-profiles]": "topGenreNames", - "include[albums]": "artists", - "include[songs]": "artists", - "include[music-videos]": "artists", - "fields[albums]": ["artistName", "artistUrl", "artwork", "contentRating", "editorialArtwork", "editorialVideo", "name", "playParams", "releaseDate", "url"], - "fields[artists]": ["name", "url"], - "extend[stations]": ["airDate", "supportsAirTimeUpdates"], - "meta[stations]": "inflectionPoints", - types: "artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells", - platform: "web" + name: 'listen-now', + with: 'friendsMix,library,social', + 'art[social-profiles:url]': 'c', + 'art[url]': 'c,f', + 'omit[resource]': 'autos', + 'relate[editorial-items]': 'contents', + extend: ['editorialCard', 'editorialVideo'], + 'extend[albums]': ['artistUrl'], + 'extend[library-albums]': [ + 'artistUrl', + 'editorialVideo' + ], + 'extend[playlists]': [ + 'artistNames', + 'editorialArtwork', + 'editorialVideo' + ], + 'extend[library-playlists]': [ + 'artistNames', + 'editorialArtwork', + 'editorialVideo' + ], + 'extend[social-profiles]': 'topGenreNames', + 'include[albums]': 'artists', + 'include[songs]': 'artists', + 'include[music-videos]': 'artists', + 'fields[albums]': [ + 'artistName', + 'artistUrl', + 'artwork', + 'contentRating', + 'editorialArtwork', + 'editorialVideo', + 'name', + 'playParams', + 'releaseDate', + 'url' + ], + 'fields[artists]': ['name', 'url'], + 'extend[stations]': [ + 'airDate', + 'supportsAirTimeUpdates' + ], + 'meta[stations]': 'inflectionPoints', + types: 'artists,albums,editorial-items,library-albums,library-playlists,music-movies,music-videos,playlists,stations,uploaded-audios,uploaded-videos,activities,apple-curators,curators,tv-shows,social-upsells', + platform: 'web' }, { includeResponseMeta: !0, reload: !0 - }); - console.log(this.listennow) + } + ); + console.log(this.listennow); } catch (e) { - console.log(e) - this.getListenNow(attempt + 1) + console.log(e); + this.getListenNow(attempt + 1); } }, async getBrowsePage(attempt = 0) { if (attempt > 3) { - return + return; } try { - let browse = await this.mk.api.groupings("", - { - platform: "web", - name: "music", - "omit[resource:artists]": "relationships", - "include[albums]": "artists", - "include[songs]": "artists", - "include[music-videos]": "artists", - extend: "editorialArtwork,artistUrl", - "fields[artists]": "name,url,artwork,editorialArtwork,genreNames,editorialNotes", - "art[url]": "f" - }); + let browse = await this.mk.api.groupings('', { + platform: 'web', + name: 'music', + 'omit[resource:artists]': 'relationships', + 'include[albums]': 'artists', + 'include[songs]': 'artists', + 'include[music-videos]': 'artists', + extend: 'editorialArtwork,artistUrl', + 'fields[artists]': + 'name,url,artwork,editorialArtwork,genreNames,editorialNotes', + 'art[url]': 'f' + }); this.browsepage = browse[0]; - console.log(this.browsepage) + console.log(this.browsepage); } catch (e) { - console.log(e) - this.getBrowsePage(attempt + 1) + console.log(e); + this.getBrowsePage(attempt + 1); } }, async getRadioStations(attempt = 0) { if (attempt > 3) { - return + return; } try { - this.radio.personal = await this.mkapi("recentRadioStations", false, "", + this.radio.personal = await this.mkapi( + 'recentRadioStations', + false, + '', { - "platform": "web", - "art[url]": "f" - }); + platform: 'web', + 'art[url]': 'f' + } + ); } catch (e) { - console.log(e) - this.getRadioStations(attempt + 1) + console.log(e); + this.getRadioStations(attempt + 1); } }, async getMadeForYou(attempt = 0) { if (attempt > 3) { - return + return; } try { - mfu = await app.mk.api.v3.music("/v1/me/library/playlists?platform=web&extend=editorialVideo&fields%5Bplaylists%5D=lastModifiedDate&filter%5Bfeatured%5D=made-for-you&include%5Blibrary-playlists%5D=catalog&fields%5Blibrary-playlists%5D=artwork%2Cname%2CplayParams%2CdateAdded") - this.madeforyou = mfu.data + mfu = await app.mk.api.v3.music( + '/v1/me/library/playlists?platform=web&extend=editorialVideo&fields%5Bplaylists%5D=lastModifiedDate&filter%5Bfeatured%5D=made-for-you&include%5Blibrary-playlists%5D=catalog&fields%5Blibrary-playlists%5D=artwork%2Cname%2CplayParams%2CdateAdded' + ); + this.madeforyou = mfu.data; } catch (e) { - console.log(e) - this.getMadeForYou(attempt + 1) + console.log(e); + this.getMadeForYou(attempt + 1); } }, - newPlaylistFolder(name = "New Folder") { - let self = this - this.mk.api.v3.music( - "/v1/me/library/playlist-folders/", - {}, - { - fetchOptions: { - method: "POST", - body: JSON.stringify({ - attributes: {name: name} - }) + newPlaylistFolder(name = 'New Folder') { + let self = this; + this.mk.api.v3 + .music( + '/v1/me/library/playlist-folders/', + {}, + { + fetchOptions: { + method: 'POST', + body: JSON.stringify({ + attributes: { name: name } + }) + } } - } - ).then((res) => { - let playlist = (res.data.data[0]) - self.playlists.listing.push({ - id: playlist.id, - attributes: { - name: playlist.attributes.name - }, - type: "library-playlist-folders", - parent: "p.playlistsroot" - }) - self.sortPlaylists() - setTimeout(() => { - app.refreshPlaylists() - }, 13000) - }) + ) + .then((res) => { + let playlist = res.data.data[0]; + self.playlists.listing.push({ + id: playlist.id, + attributes: { + name: playlist.attributes.name + }, + type: 'library-playlist-folders', + parent: 'p.playlistsroot' + }); + self.sortPlaylists(); + setTimeout(() => { + app.refreshPlaylists(); + }, 13000); + }); }, unauthorize() { - this.mk.unauthorize() + this.mk.unauthorize(); }, showSearch() { - this.page = "search" + this.page = 'search'; }, loadLyrics() { - const musicType = (MusicKit.getInstance().nowPlayingItem != null) ? MusicKit.getInstance().nowPlayingItem["type"] ?? '' : ''; - console.log("mt", musicType) - if (musicType === "musicVideo") { + const musicType = + MusicKit.getInstance().nowPlayingItem != null + ? MusicKit.getInstance().nowPlayingItem['type'] ?? '' + : ''; + console.log('mt', musicType); + if (musicType === 'musicVideo') { this.loadYTLyrics(); } else { if (app.cfg.lyrics.enable_mxm) { @@ -1853,43 +2326,60 @@ const app = new Vue({ } }, loadAMLyrics() { - const songID = (this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem["_songId"] ?? -1 : -1; + const songID = + this.mk.nowPlayingItem != null + ? this.mk.nowPlayingItem['_songId'] ?? -1 + : -1; // this.getMXM( trackName, artistName, 'en', duration); if (songID != -1) { - MusicKit.getInstance().api.lyric(songID) + MusicKit.getInstance() + .api.lyric(songID) .then((response) => { - this.lyricsMediaItem = response.attributes["ttml"] - this.parseTTML() - }) + this.lyricsMediaItem = response.attributes['ttml']; + this.parseTTML(); + }); } }, addToLibrary(id) { - let self = this + let self = this; this.mk.addToLibrary(id).then((data) => { - self.getLibrarySongsFull(true) - }) + self.getLibrarySongsFull(true); + }); }, removeFromLibrary(kind, id) { - let self = this - let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; - this.mk.api.library.remove({[truekind]: id}).then((data) => { - self.getLibrarySongsFull(true) - }) + let self = this; + let truekind = !kind.endsWith('s') ? kind + 's' : kind; + this.mk.api.library.remove({ [truekind]: id }).then((data) => { + self.getLibrarySongsFull(true); + }); }, async loadYTLyrics() { - const track = (this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.title ?? '' : ''; - const artist = (this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.artistName ?? '' : ''; - const time = (this.mk.nowPlayingItem != null) ? (Math.round((this.mk.nowPlayingItem.attributes["durationInMillis"] ?? -1000) / 1000) ?? -1) : -1; + const track = + this.mk.nowPlayingItem != null + ? this.mk.nowPlayingItem.title ?? '' + : ''; + const artist = + this.mk.nowPlayingItem != null + ? this.mk.nowPlayingItem.artistName ?? '' + : ''; + const time = + this.mk.nowPlayingItem != null + ? Math.round( + (this.mk.nowPlayingItem.attributes[ + 'durationInMillis' + ] ?? -1000) / 1000 + ) ?? -1 + : -1; ipcRenderer.invoke('getYTLyrics', track, artist).then((result) => { if (result.length > 0) { let ytid = result[0]['id']['videoId']; if (app.cfg.lyrics.enable_yt) { - loadYT(ytid, app.cfg.lyrics.mxm_language ?? "en") + loadYT(ytid, app.cfg.lyrics.mxm_language ?? 'en'); } else { - app.loadMXM() + app.loadMXM(); } } else { - app.loadMXM() + app.loadMXM(); } function loadYT(id, lang) { @@ -1898,57 +2388,78 @@ const app = new Vue({ req.open('GET', url, true); req.onerror = function (e) { this.loadMXM(); - } + }; req.onload = function () { // console.log(this.responseText); res = this.responseText; - let captionurl1 = res.substring(res.indexOf(`{"playerCaptionsRenderer":{"baseUrl":"`) + (`{"playerCaptionsRenderer":{"baseUrl":"`).length); - let captionurl = captionurl1.substring(0, captionurl1.indexOf(`"`)); - if (captionurl.includes("timedtext")) { + let captionurl1 = res.substring( + res.indexOf( + `{"playerCaptionsRenderer":{"baseUrl":"` + ) + `{"playerCaptionsRenderer":{"baseUrl":"`.length + ); + let captionurl = captionurl1.substring( + 0, + captionurl1.indexOf(`"`) + ); + if (captionurl.includes('timedtext')) { let json = JSON.parse(`{"url": "${captionurl}"}`); - let newurl = json.url + `&lang=${lang}&format=ttml` + let newurl = json.url + `&lang=${lang}&format=ttml`; let req2 = new XMLHttpRequest(); req2.open('GET', newurl, true); req2.onerror = function (e) { app.loadMXM(); - } + }; req2.onload = function () { try { const ttmlLyrics = this.responseText; if (ttmlLyrics) { - this.lyricsMediaItem = ttmlLyrics - this.parseTTML() + this.lyricsMediaItem = ttmlLyrics; + this.parseTTML(); } } catch (e) { app.loadMXM(); } - - } + }; req2.send(); } else { - app.loadMXM(); - } - } + }; req.send(); } - - }) - + }); }, loadMXM() { let attempt = 0; - const track = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.title ?? '' : ''); - const artist = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.artistName ?? '' : ''); - const time = encodeURIComponent((this.mk.nowPlayingItem != null) ? (Math.round((this.mk.nowPlayingItem.attributes["durationInMillis"] ?? -1000) / 1000) ?? -1) : -1); - let lrcfile = ""; + const track = encodeURIComponent( + this.mk.nowPlayingItem != null + ? this.mk.nowPlayingItem.title ?? '' + : '' + ); + const artist = encodeURIComponent( + this.mk.nowPlayingItem != null + ? this.mk.nowPlayingItem.artistName ?? '' + : '' + ); + const time = encodeURIComponent( + this.mk.nowPlayingItem != null + ? Math.round( + (this.mk.nowPlayingItem.attributes[ + 'durationInMillis' + ] ?? -1000) / 1000 + ) ?? -1 + : -1 + ); + let lrcfile = ''; let richsync = []; - const lang = app.cfg.lyrics.mxm_language // translation language + const lang = app.cfg.lyrics.mxm_language; // translation language function revisedRandId() { - return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10); + return Math.random() + .toString(36) + .replace(/[^a-z]+/g, '') + .substr(2, 10); } /* get token */ @@ -1957,35 +2468,59 @@ const app = new Vue({ app.loadAMLyrics(); } else { attempt = attempt + 1; - let url = "https://apic-desktop.musixmatch.com/ws/1.1/token.get?app_id=web-desktop-app-v1.0&t=" + revisedRandId(); + let url = + 'https://apic-desktop.musixmatch.com/ws/1.1/token.get?app_id=web-desktop-app-v1.0&t=' + + revisedRandId(); let req = new XMLHttpRequest(); - req.overrideMimeType("application/json"); + req.overrideMimeType('application/json'); req.open('GET', url, true); - req.setRequestHeader("authority", "apic-desktop.musixmatch.com"); + req.setRequestHeader( + 'authority', + 'apic-desktop.musixmatch.com' + ); req.onload = function () { let jsonResponse = JSON.parse(this.responseText); - let status2 = jsonResponse["message"]["header"]["status_code"]; + let status2 = + jsonResponse['message']['header']['status_code']; if (status2 == 200) { - let token = jsonResponse["message"]["body"]["user_token"] ?? ''; - if (token != "" && token != "UpgradeOnlyUpgradeOnlyUpgradeOnlyUpgradeOnly") { + let token = + jsonResponse['message']['body']['user_token'] ?? + ''; + if ( + token != '' && + token != + 'UpgradeOnlyUpgradeOnlyUpgradeOnlyUpgradeOnly' + ) { console.log('200 token', mode); // token good app.mxmtoken = token; if (mode == 1) { - getMXMSubs(track, artist, app.mxmtoken, lang, time); + getMXMSubs( + track, + artist, + app.mxmtoken, + lang, + time + ); } else { getMXMTrans(songid, lang, app.mxmtoken); } } else { console.log('fake 200 token'); - getToken(mode, track, artist, songid, lang, time) + getToken( + mode, + track, + artist, + songid, + lang, + time + ); } } else { console.log('token 4xx'); - getToken(mode, track, artist, songid, lang, time) + getToken(mode, track, artist, songid, lang, time); } - }; req.onerror = function () { console.log('error'); @@ -1997,57 +2532,113 @@ const app = new Vue({ function getMXMSubs(track, artist, token, lang, time) { let usertoken = encodeURIComponent(token); - let richsyncQuery = (app.cfg.lyrics.mxm_karaoke) ? "&optional_calls=track.richsync" : "" - let timecustom = (!time || (time && time < 0)) ? '' : `&f_subtitle_length=${time}&q_duration=${time}&f_subtitle_length_max_deviation=40`; - let url = "https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get?format=json&namespace=lyrics_richsynched" + richsyncQuery + "&subtitle_format=lrc&q_artist=" + artist + "&q_track=" + track + "&usertoken=" + usertoken + timecustom + "&app_id=web-desktop-app-v1.0&t=" + revisedRandId(); + let richsyncQuery = app.cfg.lyrics.mxm_karaoke + ? '&optional_calls=track.richsync' + : ''; + let timecustom = + !time || (time && time < 0) + ? '' + : `&f_subtitle_length=${time}&q_duration=${time}&f_subtitle_length_max_deviation=40`; + let url = + 'https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get?format=json&namespace=lyrics_richsynched' + + richsyncQuery + + '&subtitle_format=lrc&q_artist=' + + artist + + '&q_track=' + + track + + '&usertoken=' + + usertoken + + timecustom + + '&app_id=web-desktop-app-v1.0&t=' + + revisedRandId(); let req = new XMLHttpRequest(); - req.overrideMimeType("application/json"); + req.overrideMimeType('application/json'); req.open('GET', url, true); - req.setRequestHeader("authority", "apic-desktop.musixmatch.com"); + req.setRequestHeader( + 'authority', + 'apic-desktop.musixmatch.com' + ); req.onload = function () { let jsonResponse = JSON.parse(this.responseText); console.log(jsonResponse); - let status1 = jsonResponse["message"]["header"]["status_code"]; + let status1 = + jsonResponse['message']['header']['status_code']; if (status1 == 200) { let id = ''; try { - if (jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["header"]["status_code"] == 200 && jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["header"]["status_code"] == 200) { - id = jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["body"]["track"]["track_id"] ?? ''; - lrcfile = jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["body"]["subtitle_list"][0]["subtitle"]["subtitle_body"]; + if ( + jsonResponse['message']['body']['macro_calls'][ + 'matcher.track.get' + ]['message']['header']['status_code'] == 200 && + jsonResponse['message']['body']['macro_calls'][ + 'track.subtitles.get' + ]['message']['header']['status_code'] == 200 + ) { + id = + jsonResponse['message']['body'][ + 'macro_calls' + ]['matcher.track.get']['message']['body'][ + 'track' + ]['track_id'] ?? ''; + lrcfile = + jsonResponse['message']['body'][ + 'macro_calls' + ]['track.subtitles.get']['message']['body'][ + 'subtitle_list' + ][0]['subtitle']['subtitle_body']; try { - lrcrich = jsonResponse["message"]["body"]["macro_calls"]["track.richsync.get"]["message"]["body"]["richsync"]["richsync_body"]; + lrcrich = + jsonResponse['message']['body'][ + 'macro_calls' + ]['track.richsync.get']['message'][ + 'body' + ]['richsync']['richsync_body']; richsync = JSON.parse(lrcrich); app.richlyrics = richsync; - } catch (_) { - } + } catch (_) {} } - if (lrcfile == "") { - app.loadAMLyrics() + if (lrcfile == '') { + app.loadAMLyrics(); } else { if (richsync == [] || richsync.length == 0) { - console.log("ok"); + console.log('ok'); // process lrcfile to json here - app.lyricsMediaItem = lrcfile + app.lyricsMediaItem = lrcfile; let u = app.lyricsMediaItem.split(/[\r\n]/); - let preLrc = [] + let preLrc = []; for (var i = u.length - 1; i >= 0; i--) { - let xline = (/(\[[0-9.:\[\]]*\])+(.*)/).exec(u[i]) - let end = (preLrc.length > 0) ? ((preLrc[preLrc.length - 1].startTime) ?? 99999) : 99999 + let xline = + /(\[[0-9.:\[\]]*\])+(.*)/.exec( + u[i] + ); + let end = + preLrc.length > 0 + ? preLrc[preLrc.length - 1] + .startTime ?? 99999 + : 99999; preLrc.push({ - startTime: app.toMS(xline[1].substring(1, xline[1].length - 2)) ?? 0, + startTime: + app.toMS( + xline[1].substring( + 1, + xline[1].length - 2 + ) + ) ?? 0, endTime: end, line: xline[2], translation: '' - }) + }); } if (preLrc.length > 0) preLrc.push({ startTime: 0, - endTime: preLrc[preLrc.length - 1].startTime, - line: "lrcInstrumental", + endTime: + preLrc[preLrc.length - 1] + .startTime, + line: 'lrcInstrumental', translation: '' }); app.lyrics = preLrc.reverse(); @@ -2058,58 +2649,91 @@ const app = new Vue({ endTime: item.te, line: item.x, translation: '' - } - }) + }; + }); if (preLrc.length > 0) preLrc.unshift({ startTime: 0, endTime: preLrc[0].startTime, - line: "lrcInstrumental", + line: 'lrcInstrumental', translation: '' }); app.lyrics = preLrc; } - if (lrcfile != null && lrcfile != '' && lang != "disabled") { + if ( + lrcfile != null && + lrcfile != '' && + lang != 'disabled' + ) { // load translation getMXMTrans(id, lang, token); } else { - app.loadAMLyrics() + app.loadAMLyrics(); } } } catch (e) { console.log(e); - app.loadAMLyrics() + app.loadAMLyrics(); } - } else { //4xx rejected + } else { + //4xx rejected getToken(1, track, artist, '', lang, time); } - } + }; req.send(); } function getMXMTrans(id, lang, token) { - if (lang != "disabled" && id != '') { + if (lang != 'disabled' && id != '') { let usertoken = encodeURIComponent(token); - let url2 = "https://apic-desktop.musixmatch.com/ws/1.1/crowd.track.translations.get?translation_fields_set=minimal&selected_language=" + lang + "&track_id=" + id + "&comment_format=text&part=user&format=json&usertoken=" + usertoken + "&app_id=web-desktop-app-v1.0&t=" + revisedRandId(); + let url2 = + 'https://apic-desktop.musixmatch.com/ws/1.1/crowd.track.translations.get?translation_fields_set=minimal&selected_language=' + + lang + + '&track_id=' + + id + + '&comment_format=text&part=user&format=json&usertoken=' + + usertoken + + '&app_id=web-desktop-app-v1.0&t=' + + revisedRandId(); let req2 = new XMLHttpRequest(); - req2.overrideMimeType("application/json"); + req2.overrideMimeType('application/json'); req2.open('GET', url2, true); - req2.setRequestHeader("authority", "apic-desktop.musixmatch.com"); + req2.setRequestHeader( + 'authority', + 'apic-desktop.musixmatch.com' + ); req2.onload = function () { let jsonResponse2 = JSON.parse(this.responseText); console.log(jsonResponse2); - let status2 = jsonResponse2["message"]["header"]["status_code"]; + let status2 = + jsonResponse2['message']['header']['status_code']; if (status2 == 200) { try { - let preTrans = [] + let preTrans = []; let u = app.lyrics; - let translation_list = jsonResponse2["message"]["body"]["translations_list"]; + let translation_list = + jsonResponse2['message']['body'][ + 'translations_list' + ]; if (translation_list.length > 0) { for (var i = 0; i < u.length - 1; i++) { - preTrans[i] = "" + preTrans[i] = ''; for (var trans_line of translation_list) { - if (u[i].line == " " + trans_line["translation"]["matched_line"] || u[i].line == trans_line["translation"]["matched_line"]) { - u[i].translation = trans_line["translation"]["description"]; + if ( + u[i].line == + ' ' + + trans_line[ + 'translation' + ]['matched_line'] || + u[i].line == + trans_line['translation'][ + 'matched_line' + ] + ) { + u[i].translation = + trans_line['translation'][ + 'description' + ]; break; } } @@ -2117,20 +2741,20 @@ const app = new Vue({ app.lyrics = u; } } catch (e) { - /// not found trans -> ignore + /// not found trans -> ignore } - } else { //4xx rejected + } else { + //4xx rejected getToken(2, '', '', id, lang, ''); } - } + }; req2.send(); } - } - if (track != "" & track != "No Title Found") { + if ((track != '') & (track != 'No Title Found')) { if (app.mxmtoken != null && app.mxmtoken != '') { - getMXMSubs(track, artist, app.mxmtoken, lang, time) + getMXMSubs(track, artist, app.mxmtoken, lang, time); } else { getToken(1, track, artist, '', lang, time); } @@ -2138,11 +2762,19 @@ const app = new Vue({ }, toMS(str) { let rawTime = str.match(/(\d+:)?(\d+:)?(\d+)(\.\d+)?/); - let hours = (rawTime[2] != null) ? (rawTime[1].replace(":", "")) : 0; - let minutes = (rawTime[2] != null) ? (hours * 60 + rawTime[2].replace(":", "") * 1) : ((rawTime[1] != null) ? rawTime[1].replace(":", "") : 0); - let seconds = (rawTime[3] != null) ? (rawTime[3]) : 0; - let milliseconds = (rawTime[4] != null) ? (rawTime[4].replace(".", "")) : 0 - return parseFloat(`${minutes * 60 + seconds * 1}.${milliseconds * 1}`); + let hours = rawTime[2] != null ? rawTime[1].replace(':', '') : 0; + let minutes = + rawTime[2] != null + ? hours * 60 + rawTime[2].replace(':', '') * 1 + : rawTime[1] != null + ? rawTime[1].replace(':', '') + : 0; + let seconds = rawTime[3] != null ? rawTime[3] : 0; + let milliseconds = + rawTime[4] != null ? rawTime[4].replace('.', '') : 0; + return parseFloat( + `${minutes * 60 + seconds * 1}.${milliseconds * 1}` + ); }, parseTTML() { this.lyrics = []; @@ -2151,48 +2783,72 @@ const app = new Vue({ let lyricsLines = xml.getElementsByTagName('p'); let synced = true; let endTimes = []; - if (xml.getElementsByTagName('tt')[0].getAttribute("itunes:timing") === "None") { + if ( + xml + .getElementsByTagName('tt')[0] + .getAttribute('itunes:timing') === 'None' + ) { synced = false; } endTimes.push(0); if (synced) { for (element of lyricsLines) { - start = this.toMS(element.getAttribute('begin')) - end = this.toMS(element.getAttribute('end')) - if (start - endTimes[endTimes.length - 1] > 5 && endTimes[endTimes.length - 1] != 0) { + start = this.toMS(element.getAttribute('begin')); + end = this.toMS(element.getAttribute('end')); + if ( + start - endTimes[endTimes.length - 1] > 5 && + endTimes[endTimes.length - 1] != 0 + ) { preLrc.push({ startTime: endTimes[endTimes.length - 1], endTime: start, - line: "lrcInstrumental" + line: 'lrcInstrumental' }); } - preLrc.push({startTime: start, endTime: end, line: element.textContent}); + preLrc.push({ + startTime: start, + endTime: end, + line: element.textContent + }); endTimes.push(end); } // first line dot if (preLrc.length > 0) - preLrc.unshift({startTime: 0, endTime: preLrc[0].startTime, line: "lrcInstrumental"}); + preLrc.unshift({ + startTime: 0, + endTime: preLrc[0].startTime, + line: 'lrcInstrumental' + }); } else { for (element of lyricsLines) { - preLrc.push({startTime: 9999999, endTime: 9999999, line: element.textContent}); + preLrc.push({ + startTime: 9999999, + endTime: 9999999, + line: element.textContent + }); } } this.lyrics = preLrc; - }, parseLyrics() { - let xml = this.stringToXml(this.lyricsMediaItem) + let xml = this.stringToXml(this.lyricsMediaItem); let json = xmlToJson(xml); - this.lyrics = json + this.lyrics = json; }, stringToXml(st) { // string to xml - let xml = (new DOMParser()).parseFromString(st, "text/xml"); + let xml = new DOMParser().parseFromString(st, 'text/xml'); return xml; - }, getCurrentTime() { - return parseFloat(this.hmsToSecondsOnly(this.parseTime(this.mk.nowPlayingItem.attributes.durationInMillis - app.mk.currentPlaybackTimeRemaining * 1000))); + return parseFloat( + this.hmsToSecondsOnly( + this.parseTime( + this.mk.nowPlayingItem.attributes.durationInMillis - + app.mk.currentPlaybackTimeRemaining * 1000 + ) + ) + ); }, seekTo(time) { this.mk.seekToTime(time); @@ -2200,12 +2856,12 @@ const app = new Vue({ parseTime(value) { let minutes = Math.floor(value / 60000); let seconds = ((value % 60000) / 1000).toFixed(0); - return minutes + ":" + (seconds < 10 ? '0' : '') + seconds; + return minutes + ':' + (seconds < 10 ? '0' : '') + seconds; }, parseTimeDecimal(value) { let minutes = Math.floor(value / 60000); let seconds = ((value % 60000) / 1000).toFixed(0); - return minutes + "." + (seconds < 10 ? '0' : '') + seconds; + return minutes + '.' + (seconds < 10 ? '0' : '') + seconds; }, hmsToSecondsOnly(str) { let p = str.split(':'), @@ -2222,299 +2878,406 @@ const app = new Vue({ getLyricBGStyle(start, end) { let currentTime = this.getCurrentTime(); // let duration = this.mk.nowPlayingItem.attributes.durationInMillis - let start2 = this.hmsToSecondsOnly(start) - let end2 = this.hmsToSecondsOnly(end) + let start2 = this.hmsToSecondsOnly(start); + let end2 = this.hmsToSecondsOnly(end); // let currentProgress = ((100 * (currentTime)) / (end2)) // check if currenttime is between start and end - this.player.lyricsDebug.start = start2 - this.player.lyricsDebug.end = end2 - this.player.lyricsDebug.current = currentTime + this.player.lyricsDebug.start = start2; + this.player.lyricsDebug.end = end2; + this.player.lyricsDebug.current = currentTime; if (currentTime >= start2 && currentTime <= end2) { return { - "--bgSpeed": `${(end2 - start2)}s` - } + '--bgSpeed': `${end2 - start2}s` + }; } else { - return {} + return {}; } }, - playMediaItemById(id, kind, isLibrary, raurl = "") { - let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; - console.log(id, truekind, isLibrary) + playMediaItemById(id, kind, isLibrary, raurl = '') { + let truekind = !kind.endsWith('s') ? kind + 's' : kind; + console.log(id, truekind, isLibrary); try { - if (truekind.includes("artist")) { - app.mk.setStationQueue({artist: 'a-' + id}).then(() => { - app.mk.play() - }) - } else if (truekind == "radioStations") { - this.mk.setStationQueue({url: raurl}).then(function (queue) { - MusicKit.getInstance().play() + if (truekind.includes('artist')) { + app.mk.setStationQueue({ artist: 'a-' + id }).then(() => { + app.mk.play(); }); + } else if (truekind == 'radioStations') { + this.mk + .setStationQueue({ url: raurl }) + .then(function (queue) { + MusicKit.getInstance().play(); + }); } else { - this.mk.setQueue({[truekind]: [id]}).then(function (queue) { - MusicKit.getInstance().play() - }) + this.mk + .setQueue({ [truekind]: [id] }) + .then(function (queue) { + MusicKit.getInstance().play(); + }); } } catch (err) { - console.log(err) - this.playMediaItemById(id, kind, isLibrary, raurl) + console.log(err); + this.playMediaItemById(id, kind, isLibrary, raurl); } }, queueParentandplayChild(parent, childIndex, item) { - let kind = parent.substring(0, parent.indexOf(":")) - let id = parent.substring(parent.indexOf(":") + 1, parent.length) - let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; - console.log(truekind, id) + let kind = parent.substring(0, parent.indexOf(':')); + let id = parent.substring(parent.indexOf(':') + 1, parent.length); + let truekind = !kind.endsWith('s') ? kind + 's' : kind; + console.log(truekind, id); try { - if (app.library.songs.listing.length > childIndex && parent == "librarysongs") { - console.log(item) - if (item && ((app.library.songs.listing[childIndex].id != item.id))) { - childIndex = app.library.songs.listing.indexOf(item) + if ( + app.library.songs.listing.length > childIndex && + parent == 'librarysongs' + ) { + console.log(item); + if ( + item && + app.library.songs.listing[childIndex].id != item.id + ) { + childIndex = app.library.songs.listing.indexOf(item); } - let query = app.library.songs.listing.map(item => new MusicKit.MediaItem(item)); + let query = app.library.songs.listing.map( + (item) => new MusicKit.MediaItem(item) + ); try { - app.mk.stop() - } catch (e) { - } + app.mk.stop(); + } catch (e) {} this.mk.clearQueue().then(function (_) { - app.mk.queue.append(query) + app.mk.queue.append(query); if (childIndex != -1) { - app.mk.changeToMediaAtIndex(childIndex) + app.mk.changeToMediaAtIndex(childIndex); } else if (item) { - app.mk.playNext({[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id}).then(function () { - app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1) - app.mk.play() - }) + app.mk + .playNext({ + [item.attributes.playParams.kind ?? + item.type]: + item.attributes.playParams.id ?? item.id + }) + .then(function () { + app.mk.changeToMediaAtIndex( + app.mk.queue._itemIDs.indexOf( + item.id + ) ?? 1 + ); + app.mk.play(); + }); } else { - app.mk.play() + app.mk.play(); } - }) + }); } else { try { - app.mk.stop() - } catch (e) { - } - if (truekind == "playlists" && (id.startsWith("p.") || id.startsWith("pl.u"))){ - app.mk.playNext({[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id}).then(function () { - app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1) - app.mk.play().then(function(){ - app.mk.clearQueue().then(function () { - if ((app.showingPlaylist && app.showingPlaylist.id == id)) { - let query = app.showingPlaylist.relationships.tracks.data.map(item => new MusicKit.MediaItem(item)); - app.mk.queue.append(query) - } else { - app.getPlaylistFromID(id, true).then(function () { - let query = app.showingPlaylist.relationships.tracks.data.map(item => new MusicKit.MediaItem(item)); - app.mk.queue.append(query) + app.mk.stop(); + } catch (e) {} + if ( + truekind == 'playlists' && + (id.startsWith('p.') || id.startsWith('pl.u')) + ) { + app.mk + .playNext({ + [item.attributes.playParams.kind ?? item.type]: + item.attributes.playParams.id ?? item.id + }) + .then(function () { + app.mk.changeToMediaAtIndex( + app.mk.queue._itemIDs.indexOf(item.id) ?? 1 + ); + app.mk.play().then(function () { + app.mk.clearQueue().then(function () { + if ( + app.showingPlaylist && + app.showingPlaylist.id == id + ) { + let query = + app.showingPlaylist.relationships.tracks.data.map( + (item) => + new MusicKit.MediaItem( + item + ) + ); + app.mk.queue.append(query); + } else { + app.getPlaylistFromID( + id, + true + ).then(function () { + let query = + app.showingPlaylist.relationships.tracks.data.map( + (item) => + new MusicKit.MediaItem( + item + ) + ); + app.mk.queue.append(query); + }); + } + }); + }); + }); + } else { + this.mk + .setQueue({ [truekind]: [id] }) + .then(function (queue) { + if ( + item && + queue._itemIDs[childIndex] != item.id + ) { + childIndex = queue._itemIDs.indexOf( + item.id + ); + } + if (childIndex != -1) { + app.mk.changeToMediaAtIndex(childIndex); + } else if (item) { + app.mk + .playNext({ + [item.attributes.playParams.kind ?? + item.type]: + item.attributes.playParams.id ?? + item.id }) - } - }) - }) - - }) + .then(function () { + app.mk.changeToMediaAtIndex( + app.mk.queue._itemIDs.indexOf( + item.id + ) ?? 1 + ); + app.mk.play(); + }); + } else { + app.mk.play(); + } + }); } - else{ - this.mk.setQueue({[truekind]: [id]}).then(function (queue) { - if (item && ((queue._itemIDs[childIndex] != item.id))) { - childIndex = queue._itemIDs.indexOf(item.id) - } - if (childIndex != -1) { - app.mk.changeToMediaAtIndex(childIndex) - } else if (item) { - app.mk.playNext({[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id}).then(function () { - app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1) - app.mk.play() - }) - } else { - app.mk.play() - } - })} } } catch (err) { - console.log(err) + console.log(err); try { - app.mk.stop() - } catch (e) { - } - this.playMediaItemById(item.attributes.playParams.id ?? item.id, item.attributes.playParams.kind ?? item.type, item.attributes.playParams.isLibrary ?? false, item.attributes.url) + app.mk.stop(); + } catch (e) {} + this.playMediaItemById( + item.attributes.playParams.id ?? item.id, + item.attributes.playParams.kind ?? item.type, + item.attributes.playParams.isLibrary ?? false, + item.attributes.url + ); } - }, friendlyTypes(type) { // use switch statement to return friendly name for media types "songs,artists,albums,playlists,music-videos,stations,apple-curators,curators" switch (type) { - case "song": - return "Songs" + case 'song': + return 'Songs'; break; - case "artist": - return "Artists" + case 'artist': + return 'Artists'; break; - case "album": - return "Albums" + case 'album': + return 'Albums'; break; - case "playlist": - return "Playlists" + case 'playlist': + return 'Playlists'; break; - case "music_video": - return "Music Videos" + case 'music_video': + return 'Music Videos'; break; - case "station": - return "Stations" + case 'station': + return 'Stations'; break; - case "apple-curator": - return "Apple Curators" + case 'apple-curator': + return 'Apple Curators'; break; - case "radio_show": - return "Radio Shows" + case 'radio_show': + return 'Radio Shows'; break; - case "record_label": - return "Record Labels" + case 'record_label': + return 'Record Labels'; break; - case "radio_episode": - return "Episodes" + case 'radio_episode': + return 'Episodes'; break; - case "video_extra": - return "Video Extras" + case 'video_extra': + return 'Video Extras'; break; - case "curator": - return "Curators" + case 'curator': + return 'Curators'; break; - case "top": - return "Top" + case 'top': + return 'Top'; break; default: - return type + return type; break; } }, async searchQuery(term = this.search.term) { - let self = this - if (term == "") { - return + let self = this; + if (term == '') { + return; } - this.mk.api.search(this.search.term, - { - types: "activities,albums,apple-curators,artists,curators,editorial-items,music-movies,music-videos,playlists,songs,stations,tv-episodes,uploaded-videos,record-labels", - "relate[editorial-items]": "contents", - "include[editorial-items]": "contents", - "include[albums]": "artists", - "include[artists]": "artists", - "include[songs]": "artists,albums", - "include[music-videos]": "artists", - "extend": "artistUrl", - "fields[artists]": "url,name,artwork,hero", - "fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url", - "with": "serverBubbles,lyricHighlights", - "art[url]": "c,f", - "omit[resource]": "autos", - "platform": "web", + this.mk.api + .search(this.search.term, { + types: 'activities,albums,apple-curators,artists,curators,editorial-items,music-movies,music-videos,playlists,songs,stations,tv-episodes,uploaded-videos,record-labels', + 'relate[editorial-items]': 'contents', + 'include[editorial-items]': 'contents', + 'include[albums]': 'artists', + 'include[artists]': 'artists', + 'include[songs]': 'artists,albums', + 'include[music-videos]': 'artists', + extend: 'artistUrl', + 'fields[artists]': 'url,name,artwork,hero', + 'fields[albums]': + 'artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url', + with: 'serverBubbles,lyricHighlights', + 'art[url]': 'c,f', + 'omit[resource]': 'autos', + platform: 'web', limit: 25 - }).then(function (results) { - self.search.results = results - }) - await this.mk.api.socialSearch(this.search.term, { - types: ["playlists", "social-profiles"], - limit: 25, - with: ["serverBubbles", "lyricSnippet"], - "art[url]": "f", - "art[social-profiles:url]": "c" - }, {includeResponseMeta: !0}).then(function (results) { - self.search.resultsSocial = results - }) + }) + .then(function (results) { + self.search.results = results; + }); + await this.mk.api + .socialSearch( + this.search.term, + { + types: ['playlists', 'social-profiles'], + limit: 25, + with: ['serverBubbles', 'lyricSnippet'], + 'art[url]': 'f', + 'art[social-profiles:url]': 'c' + }, + { includeResponseMeta: !0 } + ) + .then(function (results) { + self.search.resultsSocial = results; + }); }, async inLibrary(items = []) { - let types = [] + let types = []; for (let item of items) { - let type = item.type - if (type.slice(-1) != "s") { - type += "s" + let type = item.type; + if (type.slice(-1) != 's') { + type += 's'; } - let id = item.playParams.catalogId ? item.playParams.catalogId : item.id + let id = item.playParams.catalogId + ? item.playParams.catalogId + : item.id; let index = types.findIndex(function (type) { - return type.type == this - }, type) + return type.type == this; + }, type); if (index == -1) { - types.push({type: type, id: [id]}) + types.push({ type: type, id: [id] }); } else { - types[index].id.push(id) + types[index].id.push(id); } } - return await this.mk.api.catalogResources(types, {"omit[resource]": "autos", relate: "library", fields: "inLibrary"}) + return await this.mk.api.catalogResources(types, { + 'omit[resource]': 'autos', + relate: 'library', + fields: 'inLibrary' + }); }, isInLibrary(playParams) { - let self = this - let id = "" + let self = this; + let id = ''; // ugly code to check if current playback item is in library - if (typeof playParams == "undefined") { - return true + if (typeof playParams == 'undefined') { + return true; } - if (playParams["isLibrary"]) { - return true - } else if (playParams["catalogId"]) { - id = playParams["catalogId"] - } else if (playParams["id"]) { - id = playParams["id"] + if (playParams['isLibrary']) { + return true; + } else if (playParams['catalogId']) { + id = playParams['catalogId']; + } else if (playParams['id']) { + id = playParams['id']; } let found = this.library.songs.listing.filter((item) => { - if (item["attributes"]) { - if (item["attributes"]["playParams"] && (item["attributes"]["playParams"]["catalogId"] == id)) { + if (item['attributes']) { + if ( + item['attributes']['playParams'] && + item['attributes']['playParams']['catalogId'] == id + ) { return item; } } - }) + }); if (found.length != 0) { - return true + return true; } else { - return false + return false; } }, mkReady() { - if (this.mk["nowPlayingItem"]) { - return true + if (this.mk['nowPlayingItem']) { + return true; } else { - return false + return false; } }, getMediaItemArtwork(url, height = 64, width) { - if(typeof url == "undefined" || url == "") { - return "https://beta.music.apple.com/assets/product/MissingArtworkMusic.svg" + if (typeof url == 'undefined' || url == '') { + return 'https://beta.music.apple.com/assets/product/MissingArtworkMusic.svg'; } - let newurl = `${url.replace('{w}', width ?? height).replace('{h}', height).replace('{f}', "webp").replace('{c}', ((width === 900) ? "sr" : "cc"))}`; + let newurl = `${url + .replace('{w}', width ?? height) + .replace('{h}', height) + .replace('{f}', 'webp') + .replace('{c}', width === 900 ? 'sr' : 'cc')}`; - if (newurl.includes("900x516")) { - newurl = newurl.replace("900x516cc", "900x516sr").replace("900x516bb", "900x516sr"); + if (newurl.includes('900x516')) { + newurl = newurl + .replace('900x516cc', '900x516sr') + .replace('900x516bb', '900x516sr'); } - return newurl + return newurl; }, - _rgbToRgb(rgb = [0,0,0]) { + _rgbToRgb(rgb = [0, 0, 0]) { // if rgb - return `rgb(${rgb[0]},${rgb[1]},${rgb[2]})` + return `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`; }, getNowPlayingArtworkBG(size = 600) { - let self = this - if (typeof this.mk.nowPlayingItem === "undefined") return; + let self = this; + if (typeof this.mk.nowPlayingItem === 'undefined') return; let bginterval = setInterval(() => { if (!this.mkReady()) { - return "" + return ''; } try { - if (this.mk.nowPlayingItem && this.mk.nowPlayingItem["id"] != this.currentTrackID && document.querySelector('.bg-artwork')) { + if ( + this.mk.nowPlayingItem && + this.mk.nowPlayingItem['id'] != this.currentTrackID && + document.querySelector('.bg-artwork') + ) { if (document.querySelector('.bg-artwork')) { clearInterval(bginterval); } - this.currentTrackID = this.mk.nowPlayingItem["id"]; - document.querySelector('.bg-artwork').src = ""; - if (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"]) { - getBase64FromUrl(this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"].replace('{w}', size).replace('{h}', size)).then(img =>{ - document.querySelectorAll('.bg-artwork').forEach(artwork => { - artwork.src = img; - }) - self.$store.commit("setLCDArtwork", img) - }) + this.currentTrackID = this.mk.nowPlayingItem['id']; + document.querySelector('.bg-artwork').src = ''; + if ( + this.mk['nowPlayingItem']['attributes']['artwork'][ + 'url' + ] + ) { + getBase64FromUrl( + this.mk['nowPlayingItem']['attributes'][ + 'artwork' + ]['url'] + .replace('{w}', size) + .replace('{h}', size) + ).then((img) => { + document + .querySelectorAll('.bg-artwork') + .forEach((artwork) => { + artwork.src = img; + }); + self.$store.commit('setLCDArtwork', img); + }); // Vibrant.from(this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"].replace('{w}', size).replace('{h}', size)).getPalette().then(palette=>{ // let angle = "140deg" @@ -2534,27 +3297,30 @@ const app = new Vue({ try { clearInterval(bginterval); - } catch (err) { - } + } catch (err) {} } else { - this.setLibraryArtBG() + this.setLibraryArtBG(); } - } else if (this.mk.nowPlayingItem["id"] == this.currentTrackID) { + } else if ( + this.mk.nowPlayingItem['id'] == this.currentTrackID + ) { try { clearInterval(bginterval); - } catch (err) { - } + } catch (err) {} } } catch (e) { - if (this.mk.nowPlayingItem && this.mk.nowPlayingItem["id"] && document.querySelector('.bg-artwork')) { - this.setLibraryArtBG() + if ( + this.mk.nowPlayingItem && + this.mk.nowPlayingItem['id'] && + document.querySelector('.bg-artwork') + ) { + this.setLibraryArtBG(); try { clearInterval(bginterval); - } catch (err) { - } + } catch (err) {} } } - }, 200) + }, 200); }, // getNowPlayingArtwork(size = 600) { @@ -2595,170 +3361,256 @@ const app = new Vue({ // } // }, 200) - // }, - async getCurrentArtURL(){ - try{ + async getCurrentArtURL() { + try { this.currentArtUrl = ''; - if (app.mk.nowPlayingItem != null && app.mk.nowPlayingItem.attributes != null && app.mk.nowPlayingItem.attributes.artwork != null && app.mk.nowPlayingItem.attributes.artwork.url != null && app.mk.nowPlayingItem.attributes.artwork.url!= '' ) - { - this.currentArtUrl = (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"] ?? '').replace('{w}', 50).replace('{h}', 50); - try{ - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);} - catch (e) {} + if ( + app.mk.nowPlayingItem != null && + app.mk.nowPlayingItem.attributes != null && + app.mk.nowPlayingItem.attributes.artwork != null && + app.mk.nowPlayingItem.attributes.artwork.url != null && + app.mk.nowPlayingItem.attributes.artwork.url != '' + ) { + this.currentArtUrl = ( + this.mk['nowPlayingItem']['attributes']['artwork'][ + 'url' + ] ?? '' + ) + .replace('{w}', 50) + .replace('{h}', 50); + try { + document + .querySelector('.app-playback-controls .artwork') + .style.setProperty( + '--artwork', + `url("${this.currentArtUrl}")` + ); + } catch (e) {} } else { - let data = await this.mk.api.library.song(this.mk.nowPlayingItem.id); - if (data != null && data !== "" && data.attributes != null && data.attributes.artwork != null) { - this.currentArtUrl = (data["attributes"]["artwork"]["url"] ?? '').replace('{w}', 50).replace('{h}', 50); - try{ - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);} - catch (e) {} - } else {this.currentArtUrl = ''; - try{ - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);} - catch (e) {} + let data = await this.mk.api.library.song( + this.mk.nowPlayingItem.id + ); + if ( + data != null && + data !== '' && + data.attributes != null && + data.attributes.artwork != null + ) { + this.currentArtUrl = ( + data['attributes']['artwork']['url'] ?? '' + ) + .replace('{w}', 50) + .replace('{h}', 50); + try { + document + .querySelector( + '.app-playback-controls .artwork' + ) + .style.setProperty( + '--artwork', + `url("${this.currentArtUrl}")` + ); + } catch (e) {} + } else { + this.currentArtUrl = ''; + try { + document + .querySelector( + '.app-playback-controls .artwork' + ) + .style.setProperty( + '--artwork', + `url("${this.currentArtUrl}")` + ); + } catch (e) {} + } } - } - }catch(e){ - - } + } catch (e) {} }, async setLibraryArt() { - if (typeof this.mk.nowPlayingItem === "undefined") return; - const data = await this.mk.api.library.song(this.mk.nowPlayingItem["id"]) + if (typeof this.mk.nowPlayingItem === 'undefined') return; + const data = await this.mk.api.library.song( + this.mk.nowPlayingItem['id'] + ); try { - const data = await this.mk.api.library.song(this.mk.nowPlayingItem.id) + const data = await this.mk.api.library.song( + this.mk.nowPlayingItem.id + ); - if (data != null && data !== "") { - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', 'url("' + (data["attributes"]["artwork"]["url"]).toString() + '")'); + if (data != null && data !== '') { + document + .querySelector('.app-playback-controls .artwork') + .style.setProperty( + '--artwork', + 'url("' + + data['attributes']['artwork'][ + 'url' + ].toString() + + '")' + ); } else { - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("")`); + document + .querySelector('.app-playback-controls .artwork') + .style.setProperty('--artwork', `url("")`); } - } catch (e) { - } + } catch (e) {} }, async setLibraryArtBG() { - if (typeof this.mk.nowPlayingItem === "undefined") return; - const data = await this.mk.api.library.song(this.mk.nowPlayingItem["id"]) + if (typeof this.mk.nowPlayingItem === 'undefined') return; + const data = await this.mk.api.library.song( + this.mk.nowPlayingItem['id'] + ); try { - const data = await this.mk.api.library.song(this.mk.nowPlayingItem.id) + const data = await this.mk.api.library.song( + this.mk.nowPlayingItem.id + ); - if (data != null && data !== "") { - getBase64FromUrl((data["attributes"]["artwork"]["url"]).toString()).then(img =>{ - document.querySelector('.bg-artwork').forEach(artwork => { - artwork.src = img; - }) - self.$store.commit("setLCDArtwork", img) - }) + if (data != null && data !== '') { + getBase64FromUrl( + data['attributes']['artwork']['url'].toString() + ).then((img) => { + document + .querySelector('.bg-artwork') + .forEach((artwork) => { + artwork.src = img; + }); + self.$store.commit('setLCDArtwork', img); + }); } - } catch (e) { - } - + } catch (e) {} }, quickPlay(query) { - let self = this - MusicKit.getInstance().api.search(query, {limit: 2, types: 'songs'}).then(function (data) { - MusicKit.getInstance().setQueue({song: data["songs"]['data'][0]["id"]}).then(function (queue) { - MusicKit.getInstance().play() - setTimeout(() => { - self.$forceUpdate() - }, 1000) - }) - }) + let self = this; + MusicKit.getInstance() + .api.search(query, { limit: 2, types: 'songs' }) + .then(function (data) { + MusicKit.getInstance() + .setQueue({ song: data['songs']['data'][0]['id'] }) + .then(function (queue) { + MusicKit.getInstance().play(); + setTimeout(() => { + self.$forceUpdate(); + }, 1000); + }); + }); }, async getRating(item) { - let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" - let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id - if (item.id.startsWith("i.")) { - if(!type.startsWith("library-")) { - type = "library-" + type + let type = + item.type.slice(-1) === 's' ? item.type : item.type + 's'; + let id = item.attributes.playParams.catalogId + ? item.attributes.playParams.catalogId + : item.id; + if (item.id.startsWith('i.')) { + if (!type.startsWith('library-')) { + type = 'library-' + type; } - id = item.id + id = item.id; } - let response = await this.mk.api.v3.music(`/v1/me/ratings/${type}?platform=web&ids=${id}`) - if(response.data.data.length != 0) { - let value = response.data.data[0].attributes.value - return value - }else{ - return 0 + let response = await this.mk.api.v3.music( + `/v1/me/ratings/${type}?platform=web&ids=${id}` + ); + if (response.data.data.length != 0) { + let value = response.data.data[0].attributes.value; + return value; + } else { + return 0; } }, love(item) { - let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" - let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id - if (item.id.startsWith("i.")) { - if(!type.startsWith("library-")) { - type = "library-" + type + let type = + item.type.slice(-1) === 's' ? item.type : item.type + 's'; + let id = item.attributes.playParams.catalogId + ? item.attributes.playParams.catalogId + : item.id; + if (item.id.startsWith('i.')) { + if (!type.startsWith('library-')) { + type = 'library-' + type; } - id = item.id + id = item.id; } - this.mk.api.v3.music(`/v1/me/ratings/${type}/${id}`, {}, { - fetchOptions: - { - method: "PUT", - body: JSON.stringify( - { - "type": "rating", - "attributes": { - "value": 1 - } + this.mk.api.v3.music( + `/v1/me/ratings/${type}/${id}`, + {}, + { + fetchOptions: { + method: 'PUT', + body: JSON.stringify({ + type: 'rating', + attributes: { + value: 1 } - ) + }) } - }) + } + ); }, dislike(item) { - let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" - let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id - if (item.id.startsWith("i.")) { - if(!type.startsWith("library-")) { - type = "library-" + type + let type = + item.type.slice(-1) === 's' ? item.type : item.type + 's'; + let id = item.attributes.playParams.catalogId + ? item.attributes.playParams.catalogId + : item.id; + if (item.id.startsWith('i.')) { + if (!type.startsWith('library-')) { + type = 'library-' + type; } - id = item.id + id = item.id; } - this.mk.api.v3.music(`/v1/me/ratings/${type}/${id}`, {}, { - fetchOptions: - { - method: "PUT", - body: JSON.stringify( - { - "type": "rating", - "attributes": { - "value": -1 - } + this.mk.api.v3.music( + `/v1/me/ratings/${type}/${id}`, + {}, + { + fetchOptions: { + method: 'PUT', + body: JSON.stringify({ + type: 'rating', + attributes: { + value: -1 } - ) + }) } - }) + } + ); }, unlove(item) { - let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" - let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id - if (item.id.startsWith("i.")) { - if(!type.startsWith("library-")) { - type = "library-" + type + let type = + item.type.slice(-1) === 's' ? item.type : item.type + 's'; + let id = item.attributes.playParams.catalogId + ? item.attributes.playParams.catalogId + : item.id; + if (item.id.startsWith('i.')) { + if (!type.startsWith('library-')) { + type = 'library-' + type; } - id = item.id + id = item.id; } - this.mk.api.v3.music(`/v1/me/ratings/${type}/${id}`, {}, { - fetchOptions: - { - method: "DELETE", + this.mk.api.v3.music( + `/v1/me/ratings/${type}/${id}`, + {}, + { + fetchOptions: { + method: 'DELETE' } - }) + } + ); }, volumeWheel(event) { if (event.deltaY < 0) { - if(this.mk.volume < 1){ + if (this.mk.volume < 1) { if (this.mk.volume <= 0.9) { - this.mk.volume += 0.1 - } else { this.mk.volume = 1 } + this.mk.volume += 0.1; + } else { + this.mk.volume = 1; + } } } else if (event.deltaY > 0) { - if(this.mk.volume > 0){ - if (this.mk.volume >= 0.1){ - this.mk.volume -= 0.1 - } else {this.mk.volume = 0} + if (this.mk.volume > 0) { + if (this.mk.volume >= 0.1) { + this.mk.volume -= 0.1; + } else { + this.mk.volume = 0; + } } } }, @@ -2778,51 +3630,75 @@ const app = new Vue({ } }; - xmlHttp.open("GET", url); - xmlHttp.setRequestHeader("Authorization", "Bearer " + MusicKit.getInstance().developerToken); - xmlHttp.setRequestHeader("Music-User-Token", "" + MusicKit.getInstance().musicUserToken); - xmlHttp.setRequestHeader("Accept", "application/json"); - xmlHttp.setRequestHeader("Content-Type", "application/json"); - xmlHttp.responseType = "text"; + xmlHttp.open('GET', url); + xmlHttp.setRequestHeader( + 'Authorization', + 'Bearer ' + MusicKit.getInstance().developerToken + ); + xmlHttp.setRequestHeader( + 'Music-User-Token', + '' + MusicKit.getInstance().musicUserToken + ); + xmlHttp.setRequestHeader('Accept', 'application/json'); + xmlHttp.setRequestHeader('Content-Type', 'application/json'); + xmlHttp.responseType = 'text'; xmlHttp.send(); }, fetchPlaylist(id, callback) { // id can be found in playlist.attributes.playParams.globalId - this.mk.api.playlist(id).then(res => { - callback(res) - }) + this.mk.api.playlist(id).then((res) => { + callback(res); + }); // tracks are found in relationship.data }, windowFocus(val) { if (val) { - document.querySelectorAll(".animated-artwork-video").forEach(el => { - el.play() - }) - this.animateBackground = true + document + .querySelectorAll('.animated-artwork-video') + .forEach((el) => { + el.play(); + }); + this.animateBackground = true; } else { - document.querySelectorAll(".animated-artwork-video").forEach(el => { - el.pause() - }) - this.animateBackground = false + document + .querySelectorAll('.animated-artwork-video') + .forEach((el) => { + el.pause(); + }); + this.animateBackground = false; } }, async nowPlayingContextMenu(event) { // function revisedRandId() { // return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10); // } - let self = this - let data_type = this.mk.nowPlayingItem.playParams.kind - let item_id = this.mk.nowPlayingItem.attributes.playParams.id ?? this.mk.nowPlayingItem.id - let isLibrary = this.mk.nowPlayingItem.attributes.playParams.isLibrary ?? false - let params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library", "t": "1"} + let self = this; + let data_type = this.mk.nowPlayingItem.playParams.kind; + let item_id = + this.mk.nowPlayingItem.attributes.playParams.id ?? + this.mk.nowPlayingItem.id; + let isLibrary = + this.mk.nowPlayingItem.attributes.playParams.isLibrary ?? false; + let params = { + 'fields[songs]': 'inLibrary', + 'fields[albums]': 'inLibrary', + relate: 'library', + t: '1' + }; // let res = await app.mkapi(data_type, isLibrary , item_id, params); // if (res && res.relationships && res.relationships.library && res.relationships.library.data && res.relationships.library.data.length > 0) { // item_id = res.relationships.library.data[0].id // } - app.selectedMediaItems = [] - app.select_selectMediaItem(item_id, data_type, 0, '12344', isLibrary) - let useMenu = "normal" + app.selectedMediaItems = []; + app.select_selectMediaItem( + item_id, + data_type, + 0, + '12344', + isLibrary + ); + let useMenu = 'normal'; let menus = { multiple: { items: [] @@ -2830,75 +3706,79 @@ const app = new Vue({ normal: { items: [ { - "icon": "./assets/feather/list.svg", - "name": "Add to Playlist...", - "action": function () { - app.promptAddToPlaylist() + icon: './assets/feather/list.svg', + name: 'Add to Playlist...', + action: function () { + app.promptAddToPlaylist(); } }, { - "icon": "./assets/feather/plus.svg", - "id": "addToLibrary", - "name": "Add to Library...", - "disabled": false, - "action": function () { + icon: './assets/feather/plus.svg', + id: 'addToLibrary', + name: 'Add to Library...', + disabled: false, + action: function () { app.addToLibrary(item_id); // if (!isLibrary) {app.addToLibrary(item_id); this.mk.nowPlayingItem.attributes.playParams["isLibrary"] = true} else { app.removeFromLibrary(data_type,item_id); this.mk.nowPlayingItem.attributes.playParams["isLibrary"] = false}; } }, { - "icon": "./assets/feather/heart.svg", - "id": "love", - "name": "Love", - "disabled": true, - "action": function () { - app.love(app.mk.nowPlayingItem) + icon: './assets/feather/heart.svg', + id: 'love', + name: 'Love', + disabled: true, + action: function () { + app.love(app.mk.nowPlayingItem); } }, { - "icon": "./assets/feather/x-circle.svg", - "id": "unlove", - "name": "Unlove", - "disabled": true, - "action": function () { - app.unlove(app.mk.nowPlayingItem) + icon: './assets/feather/x-circle.svg', + id: 'unlove', + name: 'Unlove', + disabled: true, + action: function () { + app.unlove(app.mk.nowPlayingItem); } }, { - "icon": "./assets/feather/thumbs-down.svg", - "id": "dislike", - "name": "Dislike", - "disabled": true, - "action": function () { - app.dislike(app.mk.nowPlayingItem) + icon: './assets/feather/thumbs-down.svg', + id: 'dislike', + name: 'Dislike', + disabled: true, + action: function () { + app.dislike(app.mk.nowPlayingItem); } }, { - "icon": "./assets/feather/x-circle.svg", - "id": "undo_dislike", - "name": "Undo dislike", - "disabled": true, - "action": function () { - app.unlove(app.mk.nowPlayingItem) + icon: './assets/feather/x-circle.svg', + id: 'undo_dislike', + name: 'Undo dislike', + disabled: true, + action: function () { + app.unlove(app.mk.nowPlayingItem); } }, { - "icon": "./assets/feather/radio.svg", - "name": "Start Radio", - "action": function () { - app.mk.setStationQueue({song: item_id}).then(() => { - app.mk.play() - app.selectedMediaItems = [] - }) + icon: './assets/feather/radio.svg', + name: 'Start Radio', + action: function () { + app.mk + .setStationQueue({ song: item_id }) + .then(() => { + app.mk.play(); + app.selectedMediaItems = []; + }); } - }, + } ] } - } + }; if (this.contextExt) { // if this.context-ext.normal is true append all options to the 'normal' menu which is a kvp of arrays if (this.contextExt.normal) { - menus.normal.items = menus.normal.items.concat(this.contextExt.normal) + menus.normal.items = menus.normal.items.concat( + this.contextExt.normal + ); } } @@ -2912,30 +3792,42 @@ const app = new Vue({ // menus.normal.items.find(x => x.id == "addToLibrary").disabled = true // } - let rating = await app.getRating(app.mk.nowPlayingItem) - if(rating == 0) { - menus.normal.items.find(x => x.id == 'love').disabled = false - menus.normal.items.find(x => x.id == 'dislike').disabled = false - }else if(rating == 1) { - menus.normal.items.find(x => x.id == 'unlove').disabled = false - }else if(rating == -1) { - menus.normal.items.find(x => x.id == 'undo_dislike').disabled = false + let rating = await app.getRating(app.mk.nowPlayingItem); + if (rating == 0) { + menus.normal.items.find((x) => x.id == 'love').disabled = false; + menus.normal.items.find( + (x) => x.id == 'dislike' + ).disabled = false; + } else if (rating == 1) { + menus.normal.items.find( + (x) => x.id == 'unlove' + ).disabled = false; + } else if (rating == -1) { + menus.normal.items.find( + (x) => x.id == 'undo_dislike' + ).disabled = false; } - CiderContextMenu.Create(event, menus[useMenu]) + CiderContextMenu.Create(event, menus[useMenu]); }, LastFMDeauthorize() { - ipcRenderer.invoke('setStoreValue', 'lastfm.enabled', false).catch((e) => console.error(e)); - ipcRenderer.invoke('setStoreValue', 'lastfm.auth_token', '').catch((e) => console.error(e)); - app.cfg.lastfm.auth_token = ""; + ipcRenderer + .invoke('setStoreValue', 'lastfm.enabled', false) + .catch((e) => console.error(e)); + ipcRenderer + .invoke('setStoreValue', 'lastfm.auth_token', '') + .catch((e) => console.error(e)); + app.cfg.lastfm.auth_token = ''; app.cfg.lastfm.enabled = false; const element = document.getElementById('lfmConnect'); element.innerHTML = 'Connect'; element.onclick = app.LastFMAuthenticate; }, LastFMAuthenticate() { - console.log("wag") + console.log('wag'); const element = document.getElementById('lfmConnect'); - window.open('https://www.last.fm/api/auth?api_key=174905d201451602407b428a86e8344d&cb=ame://auth/lastfm'); + window.open( + 'https://www.last.fm/api/auth?api_key=174905d201451602407b428a86e8344d&cb=ame://auth/lastfm' + ); element.innerText = 'Connecting...'; /* Just a timeout for the button */ @@ -2946,31 +3838,35 @@ const app = new Vue({ } }, 20000); - ipcRenderer.on('LastfmAuthenticated', function (_event, lfmAuthKey) { - app.cfg.lastfm.auth_token = lfmAuthKey; - app.cfg.lastfm.enabled = true; - element.innerHTML = `Disconnect\n

(Authed: ${lfmAuthKey})

`; - element.onclick = app.LastFMDeauthorize; - }); + ipcRenderer.on( + 'LastfmAuthenticated', + function (_event, lfmAuthKey) { + app.cfg.lastfm.auth_token = lfmAuthKey; + app.cfg.lastfm.enabled = true; + element.innerHTML = `Disconnect\n

(Authed: ${lfmAuthKey})

`; + element.onclick = app.LastFMDeauthorize; + } + ); }, parseSCTagToRG: function (tag) { - let soundcheck = tag.split(" ") - let numbers = [] + let soundcheck = tag.split(' '); + let numbers = []; for (item of soundcheck) { - numbers.push(parseInt(item, 16)) - + numbers.push(parseInt(item, 16)); } - numbers.shift() - let gain = Math.log10((Math.max(numbers[0], numbers[1]) ?? 1000) / 1000.0) * -10 - let peak = Math.max(numbers[6], numbers[7]) / 32768.0 + numbers.shift(); + let gain = + Math.log10( + (Math.max(numbers[0], numbers[1]) ?? 1000) / 1000.0 + ) * -10; + let peak = Math.max(numbers[6], numbers[7]) / 32768.0; return { gain: gain, peak: peak - } + }; } - } -}) +}); Vue.component('sidebar-library-item', { template: '#sidebar-library-item', @@ -2996,12 +3892,12 @@ Vue.component('sidebar-library-item', { data: function () { return { app: app, - svgIconData: "" - } + svgIconData: '' + }; }, async mounted() { if (this.svgIcon) { - this.svgIconData = await this.app.getSvgIcon(this.svgIcon) + this.svgIconData = await this.app.getSvgIcon(this.svgIcon); } }, methods: {} @@ -3010,86 +3906,88 @@ Vue.component('sidebar-library-item', { // Key binds document.addEventListener('keydown', function (e) { if (e.keyCode === 70 && e.ctrlKey) { - app.$refs.searchInput.focus() - app.$refs.searchInput.select() + app.$refs.searchInput.focus(); + app.$refs.searchInput.select(); } }); // Hang Timer app.hangtimer = setTimeout(() => { - if (confirm("Cider is not responding. Reload the app?")) { - window.location.reload() + if (confirm('Cider is not responding. Reload the app?')) { + window.location.reload(); } -}, 10000) +}, 10000); // add event listener for when window.location.hash changes -window.addEventListener("hashchange", function () { - app.appRoute(window.location.hash) +window.addEventListener('hashchange', function () { + app.appRoute(window.location.hash); }); document.addEventListener('musickitloaded', function () { // MusicKit global is now defined function initMusicKit() { - let parsedJson = JSON.parse(this.responseText) + let parsedJson = JSON.parse(this.responseText); MusicKit.configure({ developerToken: parsedJson.Key, app: { name: 'Apple Music', build: '1978.4.1', - version: "1.0" + version: '1.0' }, sourceType: 24, suppressErrorDialog: true }); setTimeout(() => { - app.init() - }, 1000) + app.init(); + }, 1000); } function fallbackinitMusicKit() { const request = new XMLHttpRequest(); function loadAlternateKey() { - let parsedJson = JSON.parse(this.responseText) + let parsedJson = JSON.parse(this.responseText); MusicKit.configure({ developerToken: parsedJson.developerToken, app: { name: 'Apple Music', build: '1978.4.1', - version: "1.0" + version: '1.0' }, sourceType: 24, suppressErrorDialog: true }); setTimeout(() => { - app.init() - }, 1000) + app.init(); + }, 1000); } - request.addEventListener("load", loadAlternateKey); - request.open("GET", "https://raw.githubusercontent.com/lujjjh/LitoMusic/main/token.json"); + request.addEventListener('load', loadAlternateKey); + request.open( + 'GET', + 'https://raw.githubusercontent.com/lujjjh/LitoMusic/main/token.json' + ); request.send(); } const request = new XMLHttpRequest(); request.timeout = 5000; - request.addEventListener("load", initMusicKit); + request.addEventListener('load', initMusicKit); request.onreadystatechange = function (aEvt) { if (request.readyState == 4) { - if (request.status != 200) - fallbackinitMusicKit() + if (request.status != 200) fallbackinitMusicKit(); } }; - request.open("GET", "https://api.cider.sh/"); + request.open('GET', 'https://api.cider.sh/'); request.send(); }); if ('serviceWorker' in navigator) { // Use the window load event to keep the page load performant window.addEventListener('load', () => { - navigator.serviceWorker.register('sw.js?v=1'); + navigator.serviceWorker.register('sw.js?v=1'); }); - } +} const getBase64FromUrl = async (url) => { const data = await fetch(url); @@ -3100,44 +3998,48 @@ const getBase64FromUrl = async (url) => { reader.onloadend = () => { const base64data = reader.result; resolve(base64data); - } + }; }); -} +}; function uuidv4() { - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => - (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => + ( + c ^ + (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4))) + ).toString(16) ); } function refreshFocus() { if (document.hasFocus() == false) { - app.windowFocus(false) + app.windowFocus(false); } else { - app.windowFocus(true) + app.windowFocus(true); } setTimeout(refreshFocus, 200); } -app.getHTMLStyle() +app.getHTMLStyle(); refreshFocus(); function xmlToJson(xml) { - // Create the return object let obj = {}; - if (xml.nodeType == 1) { // element + if (xml.nodeType == 1) { + // element // do attributes if (xml.attributes.length > 0) { - obj["@attributes"] = {}; + obj['@attributes'] = {}; for (var j = 0; j < xml.attributes.length; j++) { let attribute = xml.attributes.item(j); - obj["@attributes"][attribute.nodeName] = attribute.nodeValue; + obj['@attributes'][attribute.nodeName] = attribute.nodeValue; } } - } else if (xml.nodeType == 3) { // text + } else if (xml.nodeType == 3) { + // text obj = xml.nodeValue; } @@ -3146,10 +4048,10 @@ function xmlToJson(xml) { for (var i = 0; i < xml.childNodes.length; i++) { var item = xml.childNodes.item(i); var nodeName = item.nodeName; - if (typeof (obj[nodeName]) == "undefined") { + if (typeof obj[nodeName] == 'undefined') { obj[nodeName] = xmlToJson(item); } else { - if (typeof (obj[nodeName].push) == "undefined") { + if (typeof obj[nodeName].push == 'undefined') { var old = obj[nodeName]; obj[nodeName] = []; obj[nodeName].push(old); @@ -3160,33 +4062,37 @@ function xmlToJson(xml) { } console.log(obj); return obj; -}; +} var checkIfScrollIsStatic = setInterval(() => { try { - if (position === document.getElementsByClassName('lyric-body')[0].scrollTop) { - clearInterval(checkIfScrollIsStatic) + if ( + position === + document.getElementsByClassName('lyric-body')[0].scrollTop + ) { + clearInterval(checkIfScrollIsStatic); // do something } - position = document.getElementsByClassName('lyric-body')[0].scrollTop - } catch (e) { - } - + position = document.getElementsByClassName('lyric-body')[0].scrollTop; + } catch (e) {} }, 50); // WebGPU Console Notification async function webGPU() { try { - const currentGPU = await navigator.gpu.requestAdapter() - console.log("WebGPU enabled on", currentGPU.name, "with feature ID", currentGPU.features.size) + const currentGPU = await navigator.gpu.requestAdapter(); + console.log( + 'WebGPU enabled on', + currentGPU.name, + 'with feature ID', + currentGPU.features.size + ); } catch (e) { - console.log("WebGPU disabled / WebGPU initialization failed") + console.log('WebGPU disabled / WebGPU initialization failed'); } } -webGPU().then() +webGPU().then(); let screenWidth = screen.width; let screenHeight = screen.height; - - diff --git a/src/renderer/index_old.html b/src/renderer/index_old.html index 7d8da566..353abb90 100644 --- a/src/renderer/index_old.html +++ b/src/renderer/index_old.html @@ -2,15 +2,15 @@ - - - - - - - - - + + + + + + + + + @@ -23,332 +23,321 @@ -
-
-
-
-
-
-
-
- - -
-
- -
-
- - -
-
- -
-
- +
+
+ +
+
+ + +
+
+ +
+
+ - - +
-
-
-
- \ No newline at end of file diff --git a/src/renderer/views/pages/zoo.ejs b/src/renderer/views/pages/zoo.ejs index 6b065883..85dac661 100644 --- a/src/renderer/views/pages/zoo.ejs +++ b/src/renderer/views/pages/zoo.ejs @@ -6,4 +6,4 @@
- + \ No newline at end of file diff --git a/workbox-config.js b/workbox-config.js index 1483a0e7..c0c06892 100644 --- a/workbox-config.js +++ b/workbox-config.js @@ -2,39 +2,40 @@ module.exports = { globDirectory: 'src/renderer/', swDest: 'src/renderer/sw.js', // Define runtime caching rules. - runtimeCaching: [{ - // Match any request that ends with .png, .jpg, .jpeg or .svg. - urlPattern: /\.(?:png|jpg|jpeg|svg|webp)$/, + runtimeCaching: [ + { + // Match any request that ends with .png, .jpg, .jpeg or .svg. + urlPattern: /\.(?:png|jpg|jpeg|svg|webp)$/, - // Apply a cache-first strategy. - handler: 'CacheFirst', + // Apply a cache-first strategy. + handler: 'CacheFirst', - options: { - // Use a custom cache name. - cacheName: 'imageinternet', - - // Only cache 10 images. + options: { + // Use a custom cache name. + cacheName: 'imageinternet' + // Only cache 10 images. + } }, - }, { urlPattern: /https:\/\/amp-api.music.apple.com\/v1\//, handler: 'StaleWhileRevalidate', options: { cacheName: 'amp-api', cacheableResponse: { - statuses: [0, 200], - }, - }, + statuses: [0, 200] + } + } }, { urlPattern: /https:\/\/is[0-9]-ssl\.mzstatic\.com\/image+/, - handler: "CacheFirst", + handler: 'CacheFirst' }, { - urlPattern: /^https:\/\/store-\d{3}\.blobstore\.apple\.com\/.{65}\/image+/, - handler: "CacheFirst", - }, + urlPattern: + /^https:\/\/store-\d{3}\.blobstore\.apple\.com\/.{65}\/image+/, + handler: 'CacheFirst' + } ], ignoreURLParametersMatching: [ /^utm_/, @@ -44,6 +45,6 @@ module.exports = { /^X-Amz-SignedHeaders/, /^X-Amz-Expires/, /^X-Amz-Credential/, - /^X-Amz-Signature/, + /^X-Amz-Signature/ ] };