diff --git a/resources/version.sh b/resources/version.sh index 2d174625..deb492ca 100755 --- a/resources/version.sh +++ b/resources/version.sh @@ -3,7 +3,6 @@ LATEST_SHA=$(curl -s https://api.github.com/repos/ciderapp/Cider/branches/stable | grep sha | cut -d '"' -f 4 | sed 's/v//' | xargs) COMMITSINCESTABLE=$(git rev-list $LATEST_SHA..HEAD --count) CURRENT_VERSION=$(node -p -e "require('./package.json').version") -CIRCLE_BRANCH="main" if [[ $CIRCLE_BRANCH == "main" && $COMMITSINCESTABLE -gt 0 ]]; then NEW_VERSION="${CURRENT_VERSION}-beta.${COMMITSINCESTABLE}" else diff --git a/src/i18n/README.md b/src/i18n/README.md index 08576423..182e730b 100644 --- a/src/i18n/README.md +++ b/src/i18n/README.md @@ -497,7 +497,21 @@ Update 14/06/2022 14:10 UTC * `term.themeManaged`: Added to `en_US` +Update 15/06/2022 20:00 UTC + +* `settings.notyf.connectivity.lastfmScrobble.connectError`: Added to `en_US` +* `settings.notyf.connectivity.lastfmScrobble.connectSuccess`: Added to `en_US` +* `settings.notyf.connectivity.lastfmScrobble.connecting`: Added to `en_US` + +Update 19/06/2022 12:00 UTC + +* `settings.option.connectivity.lastfmScrobble.filterLoop.description`: Added to `en_US` + Update 21/06/2022 20:39 UTC * `term.showSearch`: Added to `en_US` -* `term.hideSearch`: Added to `en_US` \ No newline at end of file +* `term.hideSearch`: Added to `en_US` + +Update 23/06/2022 04:00 UTC + +* `settings.option.connectivity.lastfmScrobble.filterTypes`: Added to `en_US` diff --git a/src/i18n/en_US.json b/src/i18n/en_US.json index b279e6b9..a943b39d 100644 --- a/src/i18n/en_US.json +++ b/src/i18n/en_US.json @@ -239,6 +239,7 @@ "action.delete": "Delete", "action.edit": "Edit", "action.done": "Done", + "action.submit": "Submit", "action.editTracklist": "Edit Tracklist", "action.addToLibrary": "Add to Library", "action.addToLibrary.success": "Added to Library", @@ -535,6 +536,12 @@ "settings.option.connectivity.lastfmScrobble.nowPlaying": "Enable Last.fm Now Playing", "settings.option.connectivity.lastfmScrobble.removeFeatured": "Remove featuring artists from song title (Last.fm)", "settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", + "settings.option.connectivity.lastfmScrobble.filterLoop.description": "Prevent looped tracks from being scrobbled or displayed in the Now Playing list on Last.fm.", + "settings.option.connectivity.lastfmScrobble.filterTypes": "Filter Media Types (Last.fm)", + "settings.option.connectivity.lastfmScrobble.manualToken": "Enter Last.fm Token Manually", + "settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm Connection Timed Out", + "settings.notyf.connectivity.lastfmScrobble.connectSuccess": "Last.fm Connection Successful", + "settings.notyf.connectivity.lastfmScrobble.connecting": "Connecting to Last.fm...", "settings.header.debug": "Debug", "settings.option.debug.copy_log": "Copy logs to clipboard", "settings.option.debug.openAppData": "Open Cider Folder", diff --git a/src/i18n/source/en_US.json b/src/i18n/source/en_US.json index 9218ebc2..ae09a6d3 100644 --- a/src/i18n/source/en_US.json +++ b/src/i18n/source/en_US.json @@ -234,6 +234,7 @@ "action.delete": "Delete", "action.edit": "Edit", "action.done": "Done", + "action.submit": "Submit", "action.editTracklist": "Edit Tracklist", "action.addToLibrary": "Add to Library", "action.addToLibrary.success": "Added to Library", @@ -522,6 +523,12 @@ "settings.option.connectivity.lastfmScrobble.nowPlaying": "Enable Last.fm Now Playing", "settings.option.connectivity.lastfmScrobble.removeFeatured": "Remove featuring artists from song title (Last.fm)", "settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", + "settings.option.connectivity.lastfmScrobble.filterLoop.description": "Prevent looped tracks from being scrobbled or displayed in the Now Playing list on Last.fm.", + "settings.option.connectivity.lastfmScrobble.filterTypes": "Filter Media Types (Last.fm)", + "settings.option.connectivity.lastfmScrobble.manualToken": "Enter Last.fm Token Manually", + "settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm Connection Timed Out", + "settings.notyf.connectivity.lastfmScrobble.connectSuccess": "Last.fm Connection Successful", + "settings.notyf.connectivity.lastfmScrobble.connecting": "Connecting to Last.fm...", "settings.header.debug": "Debug", "settings.option.debug.copy_log": "Copy logs to clipboard", "settings.option.debug.openAppData": "Open Cider Folder", diff --git a/src/main/base/app.ts b/src/main/base/app.ts index ea81d8f6..fe54b158 100644 --- a/src/main/base/app.ts +++ b/src/main/base/app.ts @@ -162,13 +162,10 @@ export class AppEvents { // LastFM Auth URL if (arg.includes('auth')) { - let authURI = arg.split('/auth/')[1] + const authURI = arg.split('/auth/')[1] if (authURI.startsWith('lastfm')) { // If we wanted more auth options - const authKey = authURI.split('lastfm?token=')[1]; - utils.setStoreValue('lastfm.enabled', true); - utils.setStoreValue('lastfm.auth_token', authKey); - utils.getWindow().webContents.send('LastfmAuthenticated', authKey); - this.plugin.callPlugin('lastfm', 'authenticate', authKey); + console.log('token: ', authURI.split('lastfm?token=')[1]) + utils.getWindow().webContents.executeJavaScript(`ipcRenderer.send('lastfm:auth', "${authURI.split('lastfm?token=')[1]}")`).catch(console.error) } } // Play diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index bb5ea078..7f81c72c 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -618,8 +618,7 @@ export class BrowserWindow { //region Connect Integration app.get("/connect/set-cc-user/:data", (req, res) => { //utils.getStoreValue('connectUser', JSON.parse()) // [Connect] Save user in store - utils.setStoreValue('connectUser', JSON.parse(req.params.data)) - utils.getWindow().reload() + utils.getWindow().webContents.send('setStoreValue', 'connectUser', JSON.parse(req.params.data)) res.redirect(`https://connect.cidercollective.dev/linked.html`) }); // [Connect] Set auth URL in store for `shell.openExternal` diff --git a/src/main/base/plugins.ts b/src/main/base/plugins.ts index d51e8a85..24402278 100644 --- a/src/main/base/plugins.ts +++ b/src/main/base/plugins.ts @@ -107,7 +107,8 @@ export class Plugins { try{ this.pluginsList[plugin][event](...args); }catch(e) { - console.log(`[${plugin}] Plugin error: ${e}`); + console.error(`[${plugin}] An error was encountered: ${e}`); + console.error(e) } } } diff --git a/src/main/base/store.ts b/src/main/base/store.ts index 97a3a26c..6bf6071c 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -2,6 +2,7 @@ import * as ElectronStore from 'electron-store'; import * as electron from "electron"; import {app} from "electron"; import fetch from "electron-fetch"; + export class Store { static cfg: ElectronStore; @@ -12,16 +13,6 @@ export class Store { }, "general": { "close_button_hide": false, - "discordrpc": { - "enabled": true, - "client": "Cider", - "clear_on_pause": true, - "hide_buttons": false, - "hide_timestamp": false, - "state_format": "by {artist}", - "details_format": "{title}", - }, - "refreshInterval": 120000, "language": "en_US", // electron.app.getLocale().replace('-', '_') this can be used in future "playbackNotifications": true, "resumeOnStartupBehavior": "local", @@ -67,7 +58,7 @@ export class Store { "CommandOrControl", "G" ], - "songs" : [ + "songs": [ "CommandOrControl", "J" ], @@ -90,17 +81,17 @@ export class Store { ], "audioSettings": [ "CommandOrControl", - process.platform == "darwin" ? "Option" : (process.platform == "linux" ? "Shift": "Alt"), + process.platform == "darwin" ? "Option" : (process.platform == "linux" ? "Shift" : "Alt"), "A" ], "pluginMenu": [ "CommandOrControl", - process.platform == "darwin" ? "Option" : (process.platform == "linux" ? "Shift": "Alt"), + process.platform == "darwin" ? "Option" : (process.platform == "linux" ? "Shift" : "Alt"), "P" ], "castToDevices": [ "CommandOrControl", - process.platform == "darwin" ? "Option" : (process.platform == "linux" ? "Shift": "Alt"), + process.platform == "darwin" ? "Option" : (process.platform == "linux" ? "Shift" : "Alt"), "C" ], "settings": [ @@ -127,6 +118,28 @@ export class Store { }, "showLovedTracksInline": true }, + "connectivity": { + "discord_rpc": { + "enabled": true, + "client": "Cider", + "clear_on_pause": true, + "hide_buttons": false, + "hide_timestamp": false, + "state_format": "by {artist}", + "details_format": "{title}", + }, + "lastfm": { + "enabled": false, + "scrobble_after": 50, + "filter_loop": false, + "filter_types": {}, + "secrets": { + "username": "", + "key": "" + } + + }, + }, "home": { "followedArtists": [], "favoriteItems": [] @@ -231,14 +244,6 @@ export class Store { "enable_qq": false, "enable_yt": false, }, - "lastfm": { - "enabled": false, - "scrobble_after": 30, - "auth_token": "", - "enabledRemoveFeaturingArtists": true, - "filterLoop": true, - "NowPlaying": "true" - }, "advanced": { "AudioContext": true, "experiments": [], @@ -255,15 +260,9 @@ export class Store { } }, } - private migrations: any = { - '>=1.4.3': (store: ElectronStore) => { - if (typeof store.get('general.discordrpc') == 'number' || typeof store.get('general.discordrpc') == 'string') { - store.delete('general.discordrpc'); - } - }, - } + private migrations: any = {} private schema: ElectronStore.Schema = { - "general.discordrpc": { + "connectivity.discord_rpc": { type: 'object' }, } @@ -274,57 +273,13 @@ export class Store { defaults: this.defaults, schema: this.schema, migrations: this.migrations, - clearInvalidConfig: true + clearInvalidConfig: false //disabled for now }); Store.cfg.set(this.mergeStore(this.defaults, Store.cfg.store)) this.ipcHandler(); } - /** - * Merge Configurations - * @param target The target configuration - * @param source The source configuration - */ - private mergeStore = (target: { [x: string]: any; }, source: { [x: string]: any; }) => { - // Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties - for (const key of Object.keys(source)) { - if (key.includes('migrations')) { - continue; - } - if (source[key] instanceof Array) { - continue - } - if (source[key] instanceof Object) Object.assign(source[key], this.mergeStore(target[key], source[key])) - } - // Join `target` and modified `source` - Object.assign(target || {}, source) - return target - } - - - /** - * IPC Handler - */ - private ipcHandler(): void { - electron.ipcMain.handle('getStoreValue', (_event, key, defaultValue) => { - return (defaultValue ? Store.cfg.get(key, true) : Store.cfg.get(key)); - }); - - electron.ipcMain.handle('setStoreValue', (_event, key, value) => { - Store.cfg.set(key, value); - }); - - electron.ipcMain.on('getStore', (event) => { - event.returnValue = Store.cfg.store - }) - - electron.ipcMain.on('setStore', (_event, store) => { - Store.cfg.store = store - }) - } - - static pushToCloud(): void { if (Store.cfg.get('connectUser.auth') === null) return; var syncData = Object(); @@ -338,7 +293,7 @@ export class Store { plugins: Store.cfg.store.plugins }) } - + if (Store.cfg.get('connectUser.sync.settings')) { syncData.push({ general: Store.cfg.get('general'), @@ -362,4 +317,46 @@ export class Store { body: JSON.stringify(postBody) }) } + + /** + * Merge Configurations + * @param target The target configuration + * @param source The source configuration + */ + private mergeStore = (target: { [x: string]: any; }, source: { [x: string]: any; }) => { + // Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties + for (const key of Object.keys(source)) { + if (key.includes('migrations')) { + continue; + } + if (source[key] instanceof Array) { + continue + } + if (source[key] instanceof Object) Object.assign(source[key], this.mergeStore(target[key], source[key])) + } + // Join `target` and modified `source` + Object.assign(target || {}, source) + return target + } + + /** + * IPC Handler + */ + private ipcHandler(): void { + electron.ipcMain.handle('getStoreValue', (_event, key, defaultValue) => { + return (defaultValue ? Store.cfg.get(key, true) : Store.cfg.get(key)); + }); + + electron.ipcMain.handle('setStoreValue', (_event, key, value) => { + Store.cfg.set(key, value); + }); + + electron.ipcMain.on('getStore', (event) => { + event.returnValue = Store.cfg.store + }) + + electron.ipcMain.on('setStore', (_event, store) => { + Store.cfg.store = store + }) + } } diff --git a/src/main/base/utils.ts b/src/main/base/utils.ts index b0f1b513..46b865be 100644 --- a/src/main/base/utils.ts +++ b/src/main/base/utils.ts @@ -2,18 +2,36 @@ import * as fs from "fs"; import * as path from "path"; import {Store} from "./store"; import {BrowserWindow as bw} from "./browserwindow"; -import {app, dialog, ipcMain, Notification, shell, BrowserWindow} from "electron"; +import {app, BrowserWindow, ipcMain} from "electron"; import fetch from "electron-fetch"; -import {AppImageUpdater, NsisUpdater} from "electron-updater"; -import * as log from "electron-log"; import ElectronStore from "electron-store"; export class utils { + /** + * Playback Functions + */ + static playback = { + pause: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.pause()") + }, + play: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.play()") + }, + playPause: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.playPause()") + }, + next: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.next()") + }, + previous: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.previous()") + } + } /** * Paths for the application to use */ - private static paths: any = { + static paths: any = { srcPath: path.join(__dirname, "../../src"), rendererPath: path.join(__dirname, "../../src/renderer"), mainPath: path.join(__dirname, "../../src/main"), @@ -43,6 +61,13 @@ export class utils { return app; } + /** + * Get the IPCMain + */ + static getIPCMain(): Electron.IpcMain { + return ipcMain + } + /** * Fetches the i18n locale for the given language. * @param language {string} The language to fetch the locale for. @@ -64,7 +89,7 @@ export class utils { } else { i18n = Object.assign(i18n, JSON.parse(fs.readFileSync(path.join(this.paths.i18nPath, `en_US.json`), "utf8"))); } - }) + }) } if (key) { return i18n[key] @@ -90,7 +115,6 @@ export class utils { return Store.cfg.store } - /** * Get the store instance * @returns {Store} @@ -116,10 +140,6 @@ export class utils { return Store.pushToCloud } - - - - /** * Gets the browser window */ @@ -138,25 +158,4 @@ export class utils { static loadJSFrontend(path: string): void { bw.win.webContents.executeJavaScript(fs.readFileSync(path, "utf8")); } - - /** - * Playback Functions - */ - static playback = { - pause: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.pause()") - }, - play: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.play()") - }, - playPause: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.playPause()") - }, - next: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.next()") - }, - previous: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.previous()") - } - } } diff --git a/src/main/index.ts b/src/main/index.ts index ce2d043d..4a74f0e9 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,18 +1,19 @@ -require('v8-compile-cache'); - -const {app, components, ipcMain} = require('electron'); -import {join} from 'path'; +require("v8-compile-cache"); +import {join} from "path"; +import {app} from "electron" if (!app.isPackaged) { - app.setPath('userData', join(app.getPath('appData'), 'Cider')); + app.setPath("userData", join(app.getPath("appData"), "Cider")); } import {Store} from "./base/store"; import {AppEvents} from "./base/app"; import {Plugins} from "./base/plugins"; import {BrowserWindow} from "./base/browserwindow"; -import {init as Sentry} from '@sentry/electron'; +import {init as Sentry} from "@sentry/electron"; import {RewriteFrames} from "@sentry/integrations"; +import {components, ipcMain} from "electron" + // Analytics for debugging fun yeah. Sentry({ @@ -32,13 +33,13 @@ const CiderPlug = new Plugins(); * App Event Handlers * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -app.on('ready', () => { +app.on("ready", () => { Cider.ready(CiderPlug); - console.log('[Cider] Application is Ready. Creating Window.') + console.log("[Cider] Application is Ready. Creating Window.") if (!app.isPackaged) { - console.info('[Cider] Running in development mode.') - require('vue-devtools').install() + console.info("[Cider] Running in development mode.") + require("vue-devtools").install() } components.whenReady().then(async () => { @@ -49,11 +50,11 @@ app.on('ready', () => { console.log(gpuInfo) }) - console.log('[Cider][Widevine] Status:', components.status()); + console.log("[Cider][Widevine] Status:", components.status()); Cider.bwCreated(); win.on("ready-to-show", () => { - console.debug('[Cider] Window is Ready.') - CiderPlug.callPlugins('onReady', win); + console.debug("[Cider] Window is Ready.") + CiderPlug.callPlugins("onReady", win); win.show(); }); }); @@ -68,20 +69,20 @@ ipcMain.handle("renderer-ready", (event) => { CiderPlug.callPlugins("onRendererReady", event); }) -ipcMain.on('playbackStateDidChange', (_event, attributes) => { - CiderPlug.callPlugins('onPlaybackStateDidChange', attributes); +ipcMain.on("playbackStateDidChange", (_event, attributes) => { + CiderPlug.callPlugins("onPlaybackStateDidChange", attributes); }); -ipcMain.on('nowPlayingItemDidChange', (_event, attributes) => { - CiderPlug.callPlugins('onNowPlayingItemDidChange', attributes); +ipcMain.on("nowPlayingItemDidChange", (_event, attributes) => { + CiderPlug.callPlugins("onNowPlayingItemDidChange", attributes); }); -ipcMain.on('nowPlayingItemDidChangeLastFM', (_event, attributes) => { - CiderPlug.callPlugin('lastfm.js', 'nowPlayingItemDidChangeLastFM', attributes); +ipcMain.on("nowPlayingItemDidChangeLastFM", (_event, attributes) => { + CiderPlug.callPlugin("lastfm.js", "nowPlayingItemDidChangeLastFM", attributes); }) -app.on('before-quit', () => { - CiderPlug.callPlugins('onBeforeQuit'); +app.on("before-quit", () => { + CiderPlug.callPlugins("onBeforeQuit"); console.warn(`${app.getName()} exited.`); }); @@ -90,21 +91,21 @@ app.on('before-quit', () => { * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ // @ts-ignore -app.on('widevine-ready', (version, lastVersion) => { +app.on("widevine-ready", (version, lastVersion) => { if (null !== lastVersion) { - console.log('[Cider][Widevine] Widevine ' + version + ', upgraded from ' + lastVersion + ', is ready to be used!') + console.log("[Cider][Widevine] Widevine " + version + ", upgraded from " + lastVersion + ", is ready to be used!") } else { - console.log('[Cider][Widevine] Widevine ' + version + ' is ready to be used!') + console.log("[Cider][Widevine] Widevine " + version + " is ready to be used!") } }) // @ts-ignore -app.on('widevine-update-pending', (currentVersion, pendingVersion) => { - console.log('[Cider][Widevine] Widevine ' + currentVersion + ' is ready to be upgraded to ' + pendingVersion + '!') +app.on("widevine-update-pending", (currentVersion, pendingVersion) => { + console.log("[Cider][Widevine] Widevine " + currentVersion + " is ready to be upgraded to " + pendingVersion + "!") }) // @ts-ignore -app.on('widevine-error', (error) => { - console.log('[Cider][Widevine] Widevine installation encountered an error: ' + error) +app.on("widevine-error", (error) => { + console.log("[Cider][Widevine] Widevine installation encountered an error: " + error) app.exit() }) diff --git a/src/main/plugins/discordrpc.ts b/src/main/plugins/discordrpc.ts index 9cc7baf1..cdd78144 100644 --- a/src/main/plugins/discordrpc.ts +++ b/src/main/plugins/discordrpc.ts @@ -74,7 +74,7 @@ export default class DiscordRPC { console.log(`[DiscordRPC][reload] Reloading DiscordRPC.`); this._client.destroy() - this._client.endlessLogin({clientId: this._utils.getStoreValue("general.discordrpc.client") === "Cider" ? '911790844204437504' : '886578863147192350'}) + this._client.endlessLogin({clientId: this._utils.getStoreValue("connectivity.discord_rpc.client") === "Cider" ? '911790844204437504' : '886578863147192350'}) .then(() => { this.ready = true this._utils.getWindow().webContents.send("rpcReloaded", this._client.user) @@ -125,7 +125,7 @@ export default class DiscordRPC { * @private */ private connect() { - if (!this._utils.getStoreValue("general.discordrpc.enabled")) { + if (!this._utils.getStoreValue("connectivity.discord_rpc.enabled")) { return; } @@ -143,7 +143,7 @@ export default class DiscordRPC { }) // Login to Discord - this._client.endlessLogin({clientId: this._utils.getStoreValue("general.discordrpc.client") === "Cider" ? '911790844204437504' : '886578863147192350'}) + this._client.endlessLogin({clientId: this._utils.getStoreValue("connectivity.discord_rpc.client") === "Cider" ? '911790844204437504' : '886578863147192350'}) .then(() => { this.ready = true }) @@ -161,8 +161,8 @@ export default class DiscordRPC { // Check if show buttons is (true) or (false) let activity: Object = { - details: this._utils.getStoreValue("general.discordrpc.details_format"), - state: this._utils.getStoreValue("general.discordrpc.state_format"), + details: this._utils.getStoreValue("connectivity.discord_rpc.details_format"), + state: this._utils.getStoreValue("connectivity.discord_rpc.state_format"), largeImageKey: attributes?.artwork?.url?.replace('{w}', '1024').replace('{h}', '1024'), largeImageText: attributes.albumName, instance: false // Whether the activity is in a game session @@ -177,7 +177,7 @@ export default class DiscordRPC { } // Set the activity - if (!attributes.status && this._utils.getStoreValue("general.discordrpc.clear_on_pause")) { + if (!attributes.status && this._utils.getStoreValue("connectivity.discord_rpc.clear_on_pause")) { this._client.clearActivity() } else if (activity && this._activityCache !== activity) { this._client.setActivity(activity) @@ -191,7 +191,7 @@ export default class DiscordRPC { private filterActivity(activity: any, attributes: any): Object { // Add the buttons if people want them - if (!this._utils.getStoreValue("general.discordrpc.hide_buttons")) { + if (!this._utils.getStoreValue("connectivity.discord_rpc.hide_buttons")) { activity.buttons = [ {label: 'Listen on Cider', url: attributes.url.cider}, {label: 'View on Apple Music', url: attributes.url.appleMusic} @@ -199,13 +199,13 @@ export default class DiscordRPC { } // Add the timestamp if its playing and people want them - if (!this._utils.getStoreValue("general.discordrpc.hide_timestamp") && attributes.status) { + if (!this._utils.getStoreValue("connectivity.discord_rpc.hide_timestamp") && attributes.status) { activity.startTimestamp = Date.now() - (attributes?.durationInMillis - attributes?.remainingTime) activity.endTimestamp = attributes.endTime } // If the user wants to keep the activity when paused - if (!this._utils.getStoreValue("general.discordrpc.clear_on_pause")) { + if (!this._utils.getStoreValue("connectivity.discord_rpc.clear_on_pause")) { activity.smallImageKey = attributes.status ? 'play' : 'pause'; activity.smallImageText = attributes.status ? 'Playing' : 'Paused'; } diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index 5018c01b..33796c84 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -1,278 +1,233 @@ -import * as electron from 'electron'; -import * as fs from 'fs'; -import {resolve} from 'path'; +export default class lastfm { -export default class LastFMPlugin { - private sessionPath = resolve(electron.app.getPath('userData'), 'session.json'); - private apiCredentials = { + /** + * Base Plugin Information + */ + public name: string = 'LastFM Plugin'; + public version: string = '2.0.0'; + public author: string = 'Core (Cider Collective)'; + + /** + * Private variables for interaction in plugins + */ + private _attributes: any; + private _apiCredentials = { key: "f9986d12aab5a0fe66193c559435ede3", secret: "acba3c29bd5973efa38cc2f0b63cc625" } /** - * Private variables for interaction in plugins + * Plugin Initialization */ - private _win: any; - private _app: any; - private _lastfm: any; - private _store: any; - private _timer: any; - - private authenticateFromFile() { - let sessionData = require(this.sessionPath) - console.log("[LastFM][authenticateFromFile] Logging in with Session Info.") - this._lastfm.setSessionCredentials(sessionData.username, sessionData.key) - console.log("[LastFM][authenticateFromFile] Logged in.", sessionData.username, sessionData.key) - } - - - authenticate() { - try { - if (this._store.lastfm.auth_token) { - this._store.lastfm.enabled = true; - } - - if (!this._store.lastfm.enabled || !this._store.lastfm.auth_token) { - this._store.lastfm.enabled = false; - return - } - /// dont move this require to top , app wont load - const LastfmAPI = require('lastfmapi'); - const lfmAPI = new LastfmAPI({ - 'api_key': this.apiCredentials.key, - 'secret': this.apiCredentials.secret - }); - - this._lastfm = Object.assign(lfmAPI, {cachedAttributes: false, cachedNowPlayingAttributes: false}); - - fs.stat(this.sessionPath, (err: any) => { - 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") - console.log("[LastFM][tk]", this._store.lastfm.auth_token) - this._lastfm.authenticate(this._store.lastfm.auth_token, (err: any, session: any) => { - 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(this.sessionPath, tempData, (err: any) => { - if (err) - console.log("[LastFM][fs]", err) - else { - console.log("[LastFM][fs] File was written successfully.") - this.authenticateFromFile() - new electron.Notification({ - title: electron.app.getName(), - body: "Successfully logged into LastFM using Authentication Key." - }).show() - } - }) - }); - } else { - this.authenticateFromFile() - } - }) - } catch (err) { - console.log(err) - } - } - - private scrobbleSong(attributes: any) { - if (this._timer) clearTimeout(this._timer); - var self = this; - this._timer = setTimeout(async () => { - const currentAttributes = attributes; - - if (!self._lastfm || self._lastfm.cachedAttributes === attributes) { - return - } - - if (self._lastfm.cachedAttributes) { - if (self._lastfm.cachedAttributes.playParams.id === attributes.playParams.id) return; - } - - const artist = await this.getPrimaryArtist(attributes) - const album = this.getAlbumName(attributes) - - if (currentAttributes.status && currentAttributes === attributes) { - if (fs.existsSync(this.sessionPath)) { - // Scrobble playing song. - if (attributes.status === true) { - self._lastfm.track.scrobble({ - 'artist': artist, - 'track': attributes.name, - 'album': album, - 'albumArtist': artist, - 'timestamp': new Date().getTime() / 1000 - }, function (err: any, scrobbled: any) { - if (err) { - return console.error('[LastFM] An error occurred while scrobbling', err); - } - - console.log('[LastFM] Successfully scrobbled: ', scrobbled); - }); - self._lastfm.cachedAttributes = attributes - } - } else { - self.authenticate(); - } - } else { - return console.log('[LastFM] Did not add ', attributes.name, '—', artist, 'because now playing a other song.'); - } - }, Math.round(attributes.durationInMillis * Math.min((self._store.lastfm.scrobble_after / 100), 0.8))); - } - - private async updateNowPlayingSong(attributes: any) { - if (!this._lastfm || this._lastfm.cachedNowPlayingAttributes === attributes || !this._store.lastfm.NowPlaying) { - return - } - - if (this._lastfm.cachedNowPlayingAttributes) { - if (this._lastfm.cachedNowPlayingAttributes.playParams.id === attributes.playParams.id) return; - } - - if (fs.existsSync(this.sessionPath)) { - const artist = await this.getPrimaryArtist(attributes) - const album = this.getAlbumName(attributes) - - // update Now Playing - if (attributes.status === true) { - this._lastfm.track.updateNowPlaying({ - 'artist': artist, - 'track': attributes.name, - 'album': album, - 'albumArtist': artist - }, function (err: any, nowPlaying: any) { - if (err) { - return console.error('[LastFM] An error occurred while updating nowPlayingSong', err); - } - - console.log('[LastFM] Successfully updated nowPlayingSong', nowPlaying); - }); - this._lastfm.cachedNowPlayingAttributes = attributes - } - - } else { - this.authenticate() - } - } - - private getAlbumName(attributes: any): string { - return attributes.albumName.replace(/ - Single| - EP/g, ''); - } - - private async getPrimaryArtist(attributes: any) { - const songId = attributes.playParams.catalogId || attributes.playParams.id - - if (!this._store.lastfm.enabledRemoveFeaturingArtists || !songId) return attributes.artistName; - - const res = await this._win.webContents.executeJavaScript(` - (async () => { - const subMk = await MusicKit.getInstance().api.v3.music("/v1/catalog/" + MusicKit.getInstance().storefrontId + "/songs/${songId}", { - include: { - songs: ["artists"] - } - }) - if (!subMk) console.error('[LastFM] Request failed: /v1/catalog/us/songs/${songId}') - return subMk.data - })() - `).catch(console.error) - if (!res) return attributes.artistName - - const data = res.data - if (!data.length) { - console.error(`[LastFM] Unable to locate song with id of ${songId}`) - return attributes.artistName; - } - - const artists = res.data[0].relationships.artists.data - if (!artists.length) { - console.error(`[LastFM] Unable to find artists related to the song with id of ${songId}`) - return attributes.artistName; - } - - const primaryArtist = artists[0] - return primaryArtist.attributes.name - } + private _lfm: any = null; + private _authenticated: boolean = false; + private _scrobbleDelay: any = null; + private _utils: any = null; + private _scrobbleCache: any = {}; + private _nowPlayingCache: any = {}; /** - * Base Plugin Details (Eventually implemented into a GUI in settings) + * Public Methods */ - public name: string = 'LastFMPlugin'; - public description: string = 'LastFM plugin for Cider'; - public version: string = '0.0.1'; - public author: string = 'vapormusic / Cider Collective'; - /** - * Runs on plugin load (Currently run on application start) - */ - constructor(utils: { getApp: () => any; getStore: () => any; }) { - this._app = utils.getApp(); - this._store = utils.getStore() - utils.getApp().on('second-instance', (_e: any, argv: any) => { - // Checks if first instance is authorized and if second instance has protocol args - argv.forEach((value: any) => { - if (value.includes('auth')) { - console.log('[LastFMPlugin ok]') - let authURI = String(argv).split('/auth/')[1]; - if (authURI.startsWith('lastfm')) { // If we wanted more auth options - const authKey = authURI.split('lastfm?token=')[1]; - this._store.lastfm.enabled = true; - this._store.lastfm.auth_token = authKey; - console.log(authKey); - this._win.webContents.send('LastfmAuthenticated', authKey); - this.authenticate(); - } - } - }) + constructor(utils: any) { + this._utils = utils; + this.initializeLastFM("", this._apiCredentials) + } + + onReady(_win: Electron.BrowserWindow): void { + + // Register the ipcMain handlers + this._utils.getIPCMain().handle('lastfm:url', (event: any) => { + console.debug(`${lastfm.name}:url`) + return this._lfm.getAuthenticationUrl({"cb": "cider://auth/lastfm"}) }) - electron.app.on('open-url', (event: any, arg: any) => { - console.log('[LastFMPlugin] yes') - event.preventDefault(); - if (arg.includes('auth')) { - let authURI = String(arg).split('/auth/')[1]; - if (authURI.startsWith('lastfm')) { // If we wanted more auth options - const authKey = authURI.split('lastfm?token=')[1]; - this._store.lastfm.enabled = true; - this._store.lastfm.auth_token = authKey; - this._win.webContents.send('LastfmAuthenticated', authKey); - console.log(authKey); - this.authenticate(); - } - } + + this._utils.getIPCMain().on('lastfm:auth', (event: any, token: string) => { + console.debug(`${lastfm.name}:auth`, token) + this.authenticateLastFM(token) + }) + + this._utils.getIPCMain().on('lastfm:disconnect', (_event: any) => { + this._lfm.setSessionCredentials(null, null); + this._authenticated = false; + console.debug(`${lastfm.name}:disconnect`) + }) + + this._utils.getIPCMain().on('lastfm:nowPlayingChange', (event: any, attributes: any) => { + if (this._utils.getStoreValue("connectivity.lastfm.filter_loop")) return; + this.onNowPlayingItemDidChange(attributes) }) } /** - * Runs on app ready + * Runs on playback State Change + * @param attributes Music Attributes (attributes.status = current state) */ - onReady(win: any): void { - this._win = win; - this.authenticate(); - } - - /** - * Runs on app stop - */ - onBeforeQuit(): void { - console.log('Example plugin stopped'); + onPlaybackStateDidChange(attributes: object): void { + this._attributes = attributes + // this.scrobbleTrack(attributes) } /** * Runs on song change * @param attributes Music Attributes */ - nowPlayingItemDidChangeLastFM(attributes: any): void { - if (!this._store.general.privateEnabled) { - attributes.status = true - if (!this._store.lastfm.filterLoop) { - this._lastfm.cachedNowPlayingAttributes = false; - this._lastfm.cachedAttributes = false - } - this.updateNowPlayingSong(attributes) - this.scrobbleSong(attributes) + onNowPlayingItemDidChange(attributes: any): void { + if (this._utils.getStoreValue("general.privateEnabled")) return; + this._attributes = attributes + if (!attributes?.lfmTrack || !attributes?.lfmAlbum) { + this.verifyTrack(attributes) + return + } + this.scrobbleTrack(attributes) + this.updateNowPlayingTrack(attributes) + } + + /** + * Initialize LastFM + * @param token + * @param api + * @private + */ + private initializeLastFM(token: string, api: { key: string, secret: string }): void { + const LastfmAPI = require("lastfmapi") + this._lfm = new LastfmAPI({ + 'api_key': api.key, + 'secret': api.secret, + }); + + if (this._utils.getStoreValue("connectivity.lastfm.secrets.username") && this._utils.getStoreValue("connectivity.lastfm.secrets.key")) { + this._lfm.setSessionCredentials(this._utils.getStoreValue("connectivity.lastfm.secrets.username"), this._utils.getStoreValue("connectivity.lastfm.secrets.key")); + this._authenticated = true; + } else { + this.authenticateLastFM(token) } } -} + /** + * Authenticate the user with the given token + * @param token + * @private + */ + private authenticateLastFM(token: string): void { + if (!token) return; + this._lfm.authenticate(token, (err: any, session: any) => { + if (err) { + console.error(err); + + this._utils.getWindow().webContents.executeJavaScript(`app.notyf.error("${err.message}");`) + return; + } + this._utils.getWindow().webContents.send('lastfm:authenticated', session) + this._authenticated = true; + console.debug(`[${lastfm.name}:authenticate] Authenticated as ${session.username}`) + }); + } + + /** + * Verifies the track information with lastfm + * @param attributes + * @private + */ + private verifyTrack(attributes: any): object { + if (!attributes) return attributes; + + if (!attributes.lfmAlbum) { + return this._lfm.album.getInfo({ + "artist": attributes.artistName, + "album": attributes.albumName + }, (err: any, data: any) => { + if (err) { + console.error(`[${lastfm.name}] [album.getInfo] Error: ${typeof err === "string" ? err : err.message}`) + console.error(err) + return {}; + } + if (data) { + attributes.lfmAlbum = data + } + this.onNowPlayingItemDidChange(attributes) + }) + } else { + return this._lfm.track.getCorrection(attributes.artistName, attributes.name, (err: any, data: any) => { + if (err) { + console.error(`[${lastfm.name}] [track.getCorrection] Error: ${typeof err === "string" ? err : err.message}`) + console.error(err) + return {}; + } + if (data) { + attributes.lfmTrack = data.correction.track + } + this.onNowPlayingItemDidChange(attributes) + }) + } + + + } + + /** + * Scrobbles the track to lastfm + * @param attributes + * @private + */ + private scrobbleTrack(attributes: any): void { + if (!this._authenticated || !attributes || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._scrobbleCache.track === attributes.lfmTrack.name)) return; + + if (this._scrobbleDelay) { + clearTimeout(this._scrobbleDelay); + } + + // Scrobble delay + this._scrobbleDelay = setTimeout(() => { + + // Scrobble + const scrobble = { + 'artist': attributes.lfmTrack.artist.name, + 'track': attributes.lfmTrack.name, + 'album': attributes.lfmAlbum.name, + 'albumArtist': attributes.lfmAlbum.artist, + 'timestamp': new Date().getTime() / 1000, + 'trackNumber': attributes.trackNumber, + 'duration': attributes.durationInMillis / 1000, + } + + // Easy Debugging + if (!this._utils.getApp().isPackaged) { + console.debug(scrobble) + } + + // Scrobble the track + this._lfm.track.scrobble(scrobble, (err: any, _res: any) => { + if (err) { + console.error(`[${lastfm.name}:scrobble] Scrobble failed: ${err.message}`); + } else { + console.debug(`[${lastfm.name}:scrobble] Track scrobbled: ${scrobble.artist} - ${scrobble.track}`); + this._scrobbleCache = scrobble + } + }); + }, Math.round(attributes.durationInMillis * Math.min((this._utils.getStoreValue("connectivity.lastfm.scrobble_after") / 100), 0.8))) + } + + private updateNowPlayingTrack(attributes: any): void { + if (!this._authenticated || !attributes || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._nowPlayingCache.track === attributes.lfmTrack.name)) return; + + const nowPlaying = { + 'artist': attributes.lfmTrack.artist.name, + 'track': attributes.lfmTrack.name, + 'album': attributes.lfmAlbum.name, + 'trackNumber': attributes.trackNumber, + 'duration': attributes.durationInMillis / 1000, + 'albumArtist': attributes.lfmAlbum.artist, + } + + this._lfm.track.updateNowPlaying(nowPlaying, (err: any, res: any) => { + if (err) { + console.error(`[${lastfm.name}:updateNowPlaying] Now Playing Update failed: ${err.message}`); + } else { + console.log(res) + console.debug(`[${lastfm.name}:updateNowPlaying] Now Playing Updated: ${nowPlaying.artist} - ${nowPlaying.track}`); + this._nowPlayingCache = nowPlaying + } + }); + } + +} \ No newline at end of file diff --git a/src/main/plugins/mpris.ts b/src/main/plugins/mpris.ts index 25730ee9..6b70c5c8 100644 --- a/src/main/plugins/mpris.ts +++ b/src/main/plugins/mpris.ts @@ -37,7 +37,7 @@ export default class mpris { * @private */ private static runMediaEvent(type: string) { - console.debug(`[Plugin][${this.name}] ${type}.`); + // console.debug(`[Plugin][${this.name}] ${type}.`); mpris.utils.getWindow().webContents.executeJavaScript(`MusicKitInterop.${type}()`).catch(console.error) } @@ -188,7 +188,7 @@ export default class mpris { */ @mpris.linuxOnly onPlaybackStateDidChange(attributes: object): void { - console.debug(`[Plugin][${mpris.name}] onPlaybackStateDidChange.`); + // console.debug(`[Plugin][${mpris.name}] onPlaybackStateDidChange.`); mpris.updatePlayerState(attributes) } @@ -198,7 +198,7 @@ export default class mpris { */ @mpris.linuxOnly onNowPlayingItemDidChange(attributes: object): void { - console.debug(`[Plugin][${mpris.name}] onMetadataDidChange.`); + // console.debug(`[Plugin][${mpris.name}] onMetadataDidChange.`); mpris.updatePlayer(attributes); } diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index 44ba7589..add40edf 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -11,9 +11,6 @@ const MusicKitInterop = { if (MusicKitInterop.filterTrack(attributes, true, false)) { global.ipcRenderer.send('playbackStateDidChange', attributes) global.ipcRenderer.send('wsapi-updatePlaybackState', attributes); - // if (typeof _plugins != "undefined") { - // _plugins.execute("OnPlaybackStateChanged", {Attributes: MusicKitInterop.getAttributes()}) - // } } }); @@ -24,18 +21,13 @@ const MusicKitInterop = { /** wsapi */ MusicKit.getInstance().addEventListener(MusicKit.Events.nowPlayingItemDidChange, async () => { - console.debug('nowPlayingItemDidChange') + console.debug('[cider:preload] nowPlayingItemDidChange') const attributes = MusicKitInterop.getAttributes() - const trackFilter = MusicKitInterop.filterTrack(attributes, false, true) - if (trackFilter) { + if (MusicKitInterop.filterTrack(attributes, false, true)) { global.ipcRenderer.send('nowPlayingItemDidChange', attributes); - } - - // LastFM's Custom Call - await MusicKitInterop.modifyNamesOnLocale(); - if (trackFilter || !app.cfg.lastfm.filterLoop) { - global.ipcRenderer.send('nowPlayingItemDidChangeLastFM', attributes); + } else if (attributes.name !== 'no-title-found' && attributes.playParams.id !== "no-id-found") { + global.ipcRenderer.send('lastfm:nowPlayingChange', attributes); } if (MusicKit.getInstance().nowPlayingItem) { @@ -49,38 +41,16 @@ const MusicKitInterop = { }) MusicKit.getInstance().addEventListener(MusicKit.Events.mediaPlaybackError, (e) => { - console.warn(`[mediaPlaybackError] ${e}`); + console.warn(`[cider:preload] mediaPlaybackError] ${e}`); }) }, sleep(ms) { return new Promise((resolve) => { - setTimeout(resolve, ms); + setTimeout(resolve, ms); }); }, - async modifyNamesOnLocale() { - if (app.mklang === '' || app.mklang == null) { - return; - } - const mk = MusicKit.getInstance() - const nowPlayingItem = mk.nowPlayingItem; - if ((nowPlayingItem?._songId ?? nowPlayingItem?.songId) == null){ - return; - } - const id = nowPlayingItem?._songId ?? (nowPlayingItem?.songId ?? nowPlayingItem?.id) - if (id != null && id !== -1) { - try{ - const query = await mk.api.v3.music(`/v1${(((nowPlayingItem?._songId ?? nowPlayingItem?.songId) != null) && ((nowPlayingItem?._songId ?? nowPlayingItem?.songId) !== -1)) ? `/catalog/${mk.storefrontId}/` : `/me/library/`}songs/${id}?l=${app.mklang}`); - if (query?.data?.data[0]){ - let attrs = query?.data?.data[0]?.attributes; - if (attrs?.name) { nowPlayingItem.attributes.name = attrs?.name ?? ''} - if (attrs?.albumName) { nowPlayingItem.attributes.albumName = attrs?.albumName ?? ''} - if (attrs?.artistName) { nowPlayingItem.attributes.artistName = attrs?.artistName ?? ''} - - }} catch (e) { } - } else {} - }, getAttributes: function () { const mk = MusicKit.getInstance() const nowPlayingItem = mk.nowPlayingItem; @@ -96,8 +66,8 @@ const MusicKitInterop = { attributes.playParams = attributes?.playParams ?? {id: 'no-id-found'}; attributes.playParams.id = attributes?.playParams?.id ?? 'no-id-found'; attributes.url = { - cider: `https://cider.sh/link?play/s/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ??'no-id-found')}`, - appleMusic: attributes.websiteUrl ? attributes.websiteUrl : `https://music.apple.com/${mk.storefrontId}/song/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ??'no-id-found')}` + cider: `https://cider.sh/link?play/s/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ?? 'no-id-found')}`, + appleMusic: attributes.websiteUrl ? attributes.websiteUrl : `https://music.apple.com/${mk.storefrontId}/song/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ?? 'no-id-found')}` } if (attributes.playParams.id === 'no-id-found') { attributes.playParams.id = nowPlayingItem?.id ?? 'no-id-found'; @@ -115,7 +85,7 @@ const MusicKitInterop = { attributes?.playParams?.id === cache.playParams.id ? Date.now() + attributes?.remainingTime : attributes?.startTime + attributes?.durationInMillis - ); + ); return attributes; }, @@ -156,19 +126,19 @@ const MusicKitInterop = { // } catch (e) { } // if (MusicKit.getInstance().queue.nextPlayableItemIndex != -1 && MusicKit.getInstance().queue.nextPlayableItemIndex != null) // MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex); - MusicKit.getInstance().skipToNextItem().then(r => console.debug(`[MusicKitInterop.next] Skipping to Next ${r}`)); + MusicKit.getInstance().skipToNextItem().then(r => console.debug(`[cider:preload] [next] Skipping to Next ${r}`)); }, previous: () => { // if (MusicKit.getInstance().queue.previousPlayableItemIndex != -1 && MusicKit.getInstance().queue.previousPlayableItemIndex != null) // MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.previousPlayableItemIndex); - MusicKit.getInstance().skipToPreviousItem().then(r => console.debug(`[MusicKitInterop.previous] Skipping to Previous ${r}`)); + MusicKit.getInstance().skipToPreviousItem().then(r => console.debug(`[cider:preload] [previous] Skipping to Previous ${r}`)); } } process.once('loaded', () => { - console.debug("Setting ipcRenderer") + console.debug("[cider:preload] IPC Listeners Created!") global.MusicKitInterop = MusicKitInterop; }); diff --git a/src/renderer/index.js b/src/renderer/index.js index ddfc7b2b..66cd90c9 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -68,6 +68,10 @@ Vue.component("sidebar-library-item", { required: false, default: "", }, + svgIconName: { + type: String, + required: false + }, cdClick: { type: Function, required: false, diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index a47a650f..bf4a67bd 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -832,6 +832,10 @@ const app = new Vue({ MusicKit.getInstance().videoContainerElement = document.getElementById("apple-music-video-player") + ipcRenderer.on('setStoreValue', (e, key, value) => { + app.cfg[key] = value + }) + ipcRenderer.on('theme-update', async (event, arg) => { await less.refresh(true, true, true) self.setTheme(self.cfg.visual.theme, true) @@ -4423,37 +4427,6 @@ const app = new Vue({ } app.modals.settings = true }, - 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 = ""; - app.cfg.lastfm.enabled = false; - const element = document.getElementById('lfmConnect'); - element.innerHTML = app.getLz('term.connect'); - element.onclick = app.LastFMAuthenticate; - }, - LastFMAuthenticate() { - console.log("[LastFM] Received LastFM authentication callback") - const element = document.getElementById('lfmConnect'); - // new key : f9986d12aab5a0fe66193c559435ede3 - window.open('https://www.last.fm/api/auth?api_key=f9986d12aab5a0fe66193c559435ede3&cb=cider://auth/lastfm'); - element.innerText = app.getLz('term.connecting') + '...'; - - /* Just a timeout for the button */ - setTimeout(() => { - if (element.innerText === app.getLz('term.connecting') + '...') { - element.innerText = app.getLz('term.connect'); - console.warn('[LastFM] Attempted connection timed out.'); - } - }, 20000); - - ipcRenderer.on('LastfmAuthenticated', function (_event, lfmAuthKey) { - app.cfg.lastfm.auth_token = lfmAuthKey; - app.cfg.lastfm.enabled = true; - element.innerHTML = `${app.getLz('term.disconnect')}\n

(${app.getLz('term.authed')}: ${lfmAuthKey})

`; - element.onclick = app.LastFMDeauthorize; - }); - }, fullscreen(flag) { this.fullscreenState = flag; if (flag) { diff --git a/src/renderer/views/app/chrome-top.ejs b/src/renderer/views/app/chrome-top.ejs index 03c14b97..bb7a1f48 100644 --- a/src/renderer/views/app/chrome-top.ejs +++ b/src/renderer/views/app/chrome-top.ejs @@ -198,13 +198,13 @@
- + - - + - +
diff --git a/src/renderer/views/app/sidebar.ejs b/src/renderer/views/app/sidebar.ejs index 3e43cf80..7b14d181 100644 --- a/src/renderer/views/app/sidebar.ejs +++ b/src/renderer/views/app/sidebar.ejs @@ -51,6 +51,7 @@ @@ -67,17 +68,20 @@ @@ -94,36 +98,42 @@ diff --git a/src/renderer/views/components/settings-window.ejs b/src/renderer/views/components/settings-window.ejs index 33819544..b028c6e5 100644 --- a/src/renderer/views/components/settings-window.ejs +++ b/src/renderer/views/components/settings-window.ejs @@ -994,18 +994,18 @@
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.clientName')}}
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.clearOnPause')}}
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.hideButtons')}}
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.hideTimestamp')}}
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}
{{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album}, @@ -1055,12 +1055,12 @@
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.stateFormat')}} {{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album}, @@ -1068,12 +1068,12 @@
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.reload')}}
@@ -1089,51 +1089,55 @@
{{$root.getLz('settings.option.connectivity.lastfmScrobble')}}
-
-
-
+
+
+ {{$root.getLz('settings.option.connectivity.lastfmScrobble.manualToken')}} +
+
+ +
+
+
{{$root.getLz('settings.option.connectivity.lastfmScrobble.delay')}}
-
-
- {{$root.getLz('settings.option.connectivity.lastfmScrobble.nowPlaying')}} -
-
- -
-
-
-
- {{$root.getLz('settings.option.connectivity.lastfmScrobble.removeFeatured')}} -
-
- -
-
-
+
{{$root.getLz('settings.option.connectivity.lastfmScrobble.filterLoop')}} + {{$root.getLz('settings.option.connectivity.lastfmScrobble.filterLoop.description')}}
+
+
+
+
+ {{$root.getLz('settings.option.connectivity.lastfmScrobble.filterTypes')}} +
+
+
@@ -1421,7 +1425,8 @@ app: this.$root, themes: ipcRenderer.sendSync("get-themes"), tabIndex: 0, - canChangeHash: false + canChangeHash: false, + lastfmConnecting: false } }, watch: { tabIndex: function (val) { @@ -1430,15 +1435,6 @@ } } }, - mounted: function () { - if (app.cfg.lastfm.enabled) { - const element = document.getElementById('lfmConnect'); - if (element) { - element.innerHTML = `Disconnect\n

(Authed: ${app.cfg.lastfm.auth_token})

`; - element.onclick = app.LastFMDeauthorize; - } - } - }, methods: { close() { this.$root.modals.settings = false @@ -1554,6 +1550,41 @@ }, reloadDiscordRPC() { ipcRenderer.send('reloadRPC') + }, + lfmDisconnect() { + this.$root.cfg.connectivity.lastfm.enabled = false; + this.$root.cfg.connectivity.lastfm.secrets.username = ""; + this.$root.cfg.connectivity.lastfm.secrets.key = ""; + ipcRenderer.send('lastfm:disconnect'); + }, + async lfmAuthorize() { + this.lastfmConnecting = true; + window.open(await ipcRenderer.invoke('lastfm:url')); + app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connecting')); + + /* Just a timeout for the button */ + setTimeout(() => { + if (!this.$root.cfg.connectivity.lastfm.enabled) { + app.notyf.error(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectError')); + console.warn('[lastfm:authorize] Last.fm authorization timed out.'); + this.lastfmConnecting = false; + } + }, 20000); + + ipcRenderer.once('lastfm:authenticated', (_e, session) => { + this.$root.cfg.connectivity.lastfm.secrets.username = session.username + this.$root.cfg.connectivity.lastfm.secrets.key = session.key + this.$root.cfg.connectivity.lastfm.enabled = true + this.lastfmConnecting = false; + app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectSuccess')); + }) + }, + filterChange(e) { + this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked; + }, + submitToken() { + const token = document.getElementById('lfmToken').value; + ipcRenderer.send('lastfm:auth', token); } } }) diff --git a/src/renderer/views/components/sidebar-playlist.ejs b/src/renderer/views/components/sidebar-playlist.ejs index 6d276618..8a252226 100644 --- a/src/renderer/views/components/sidebar-playlist.ejs +++ b/src/renderer/views/components/sidebar-playlist.ejs @@ -9,7 +9,7 @@ :href="item.href" @click='clickEvent()'> diff --git a/src/renderer/views/main.ejs b/src/renderer/views/main.ejs index 32bee000..34c5c9dd 100644 --- a/src/renderer/views/main.ejs +++ b/src/renderer/views/main.ejs @@ -123,7 +123,7 @@ diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index 90e2d7df..f67799af 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -954,18 +954,18 @@
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.clientName')}}
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.clearOnPause')}}
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.hideButtons')}}
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.hideTimestamp')}}
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}
{{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album}, @@ -1015,12 +1015,12 @@
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.stateFormat')}} {{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album}, @@ -1028,12 +1028,12 @@
-
+
{{$root.getLz('settings.option.connectivity.discordRPC.reload')}}
@@ -1050,50 +1050,41 @@ {{$root.getLz('settings.option.connectivity.lastfmScrobble')}}
-
-
+
{{$root.getLz('settings.option.connectivity.lastfmScrobble.delay')}}
-
-
- {{$root.getLz('settings.option.connectivity.lastfmScrobble.nowPlaying')}} -
-
- -
-
-
-
- {{$root.getLz('settings.option.connectivity.lastfmScrobble.removeFeatured')}} -
-
- -
-
-
+
{{$root.getLz('settings.option.connectivity.lastfmScrobble.filterLoop')}} + {{$root.getLz('settings.option.connectivity.lastfmScrobble.filterLoop.description')}}
+
+
+
+
+ {{$root.getLz('settings.option.connectivity.lastfmScrobble.filterTypes')}} +
+
+
@@ -1390,14 +1381,6 @@ this.canChangeHash = true } }) - - if (app.cfg.lastfm.enabled) { - const element = document.getElementById('lfmConnect'); - if (element) { - element.innerHTML = `Disconnect\n

(Authed: ${app.cfg.lastfm.auth_token})

`; - element.onclick = app.LastFMDeauthorize; - } - } }, methods: { windowBgStyleChange() { @@ -1511,6 +1494,35 @@ }, reloadDiscordRPC() { ipcRenderer.send('reloadRPC') + }, + lfmDisconnect() { + this.$root.cfg.connectivity.lastfm.enabled = false; + this.$root.cfg.connectivity.lastfm.secrets.username = ""; + this.$root.cfg.connectivity.lastfm.secrets.key = ""; + ipcRenderer.send('lastfm:disconnect'); + }, + async lfmAuthorize() { + window.open(await ipcRenderer.invoke('lastfm:url')); + app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connecting')); + + /* Just a timeout for the button */ + setTimeout(() => { + if (document.getElementById('lfmConnect').innerText === app.getLz('term.connecting') + '...') { + app.notyf.error(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectError')); + console.warn('[lastfm:authorize] Last.fm authorization timed out.'); + } + }, 20000); + + ipcRenderer.once('lastfm:authenticated', (_e, session) => { + this.$root.cfg.connectivity.lastfm.secrets.username = session.username + this.$root.cfg.connectivity.lastfm.secrets.key = session.key + this.$root.cfg.connectivity.lastfm.enabled = true + app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectSuccess')); + }) + + }, + filterChange(e) { + this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked; } } })