diff --git a/package.json b/package.json index 2f43ab69..edd5b3af 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "cider", "applicationId": "Cider", "productName": "Cider", - "version": "1.4.2", + "version": "1.4.3", "description": "A new cross-platform Apple Music experience based on Electron and Vue.js written from scratch with performance in mind.", "license": "AGPL-3.0", "main": "./build/index.js", diff --git a/src/i18n/README.md b/src/i18n/README.md index d1a57fdb..c4220aa0 100644 --- a/src/i18n/README.md +++ b/src/i18n/README.md @@ -246,3 +246,15 @@ Update 09/04/2022 13:45 UTC * `action.tray.show`: Changed for `en_US` (Deleted for all language files) +Update 14/04/2022 14:30 UTC +* `term.variables`: Added for `en_US` +* `settings.option.connectivity.discordRPC.clientName`: Added for `en_US` +* `settings.option.connectivity.discordRPC.detailsFormat`: Added for `en_US` +* `settings.option.connectivity.discordRPC.stateFormat`: Added for `en_US` +* `settings.header.connectivity.discordRPC.cider`: Removed from `en_US` +* `settings.header.connectivity.discordRPC.appleMusic`: Removed from `en_US` + +Update 16/04/2022 9:30 UTC + +* `settings.header.connect`: Added for `en_US` + diff --git a/src/i18n/en_OWO.json b/src/i18n/en_OWO.json index c7ecf483..9b7efd65 100644 --- a/src/i18n/en_OWO.json +++ b/src/i18n/en_OWO.json @@ -10,6 +10,7 @@ "notification.updatingLibrarySongs": "Updating wibwawy songs...", "notification.updatingLibraryAlbums": "Updating wibwawy awbums...", "notification.updatingLibraryArtists": "Updating wibwawy awtists...", + "term.variables": "Vawiabwes", "term.appleInc": "Appwe Inc.", "term.appleMusic": "Appwe Music", "term.applePodcasts": "Appwe Podcasts", @@ -23,6 +24,7 @@ "term.cast": "Cast", "term.about": "About", "term.privateSession": "Pwivate Session", + "term.disablePrivateSession": "Disabwe Pwivate Session", "term.queue": "Queue", "term.lyrics": "Wywics", "term.miniplayer": "MinyiPwayew", @@ -256,6 +258,8 @@ "action.cast.airplay.underdevelopment": "AiwPway is stiww undew devewopment", "action.cast.scan": "Scan", "action.cast.scanning": "Scannying...", + "action.createNew": "Cweate Nyew...", + "action.openArtworkInBrowser": "Open awtwowk in bwowsew", "settings.header.general": "Genyewaw", "settings.header.general.description": "Adjust the genyewaw settings fow Cidew.", "settings.option.general.language": "Wanguage", @@ -298,6 +302,7 @@ "settings.warn.audio.enableAdvancedFunctionality.lowcores": "Cidew thinks youw PC can't handwe these featuwes. Awe you suwe you want to continyue?", "settings.option.audio.audioLab": "Cidew Audio Wab", "settings.option.audio.audioLab.description": "An assowtment of in-house devewoped audio effects fow Cidew.", + "settings.option.audio.audioLab.subheader": "Designyed by Cidew Acoustic Technyowogies in Cawifownyia", "settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionyawity) is wequiwed to enyabwe Cidew Audio Wabowatowy.", "settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Anyawog Wawmth", "settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simuwates the anyawog wawmth modewwed aftew the Kowg Nyutube 6P1", @@ -305,6 +310,13 @@ "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description": "Changes the intensity of the Anyawog Wawmth Moduwe pwocessing.", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.smooth": "Smooth", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.warm": "Wawm", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer": "Cidew Atmosphewe Weawizew™️", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description": "Weawizes a diffewent musicaw atmosphewe modewwed aftew the state of the awt audio setups.", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode": "Cidew Atmosphewe Weawizew™️ Mode", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description": "Changes the mode of opewation of the Atmosphewe Weawizew moduwe.", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural1": "Nyatuwaw (Standawd)", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural2": "Nyatuwaw (High)", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural3": "Nyatuwaw (Pwus)", "settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cidew Adwenyawinye Pwocessow™️", "settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "Enhances the pewceived audio quawity of 256 kbps AAC audio by using a weaw-time awgowithm that takes advantage of both psychoacoustic modews of human heawing and AAC encoding chawactewistics.", "settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility": "CAP is nyot compatibwe with Spatiawization. Pwease disabwe Spatiawization to continyue.", @@ -320,7 +332,7 @@ "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization": "Cidew Tunyed Spatiawization", "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.description": "Pwe-tunyed Spatiawizing Effect, disabwes the customizabwe settings of Audio Spatiawization. Spatiawization must be enyabwed as a pwewequisite.", "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile": "Cidew Spatiawization Pwofiwe", - "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.description": "Changes the Tunying Pwofiwe of the Spatiawization. (Wequiwes App Westawt)", + "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.description": "Changes the Tunying Pwofiwe of the Spatiawization.", "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.standard": "Standawd", "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.audiophile": "Audiophiwe", "settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "Spatiawization is nyot compatibwe with CAP. Pwease disabwe CAP to continyue.", @@ -346,6 +358,7 @@ "settings.option.visual.hardwareAcceleration.description": "Wequiwes wewaunch", "settings.header.visual.hardwareAcceleration.default": "Defauwt", "settings.header.visual.hardwareAcceleration.webGPU": "WebGPU", + "settings.option.visual.uiscale": "UI Scawe", "settings.header.visual.theme": "Theme", "settings.option.visual.theme.github.download": "Instaww fwom GitHub UWW", "settings.option.visual.theme.github.explore": "Expwowe GitHub Themes", @@ -382,12 +395,13 @@ "settings.option.lyrics.enableYoutubeLyrics": "Enyabwe Youtube Wywics fow Music Videos", "settings.header.connectivity": "Connyectivity", "settings.header.connectivity.description": "Adjust the connyectivity settings fow Cidew.", - "settings.option.connectivity.discordRPC": "Discowd Wich Pwesence", "settings.option.connectivity.playbackNotifications": "Pwayback Nyotifications", - "settings.header.connectivity.discordRPC.cider": "Dispway as 'Cidew'", - "settings.header.connectivity.discordRPC.appleMusic": "Dispway as 'Appwe Music'", + "settings.option.connectivity.discordRPC": "Discowd Wich Pwesence", + "settings.option.connectivity.discordRPC.clientName": "Cwient Nyame", "settings.option.connectivity.discordRPC.clearOnPause": "Cweaw Discowd Wich Pwesence on Pause", "settings.option.connectivity.discordRPC.hideButtons": "Hide buttons on Discowd Wich Pwesence", + "settings.option.connectivity.discordRPC.detailsFormat": "Detaiws Fowmat", + "settings.option.connectivity.discordRPC.stateFormat": "State Fowmat", "settings.option.connectivity.lastfmScrobble": "Wast.fm Scwobbwing", "settings.option.connectivity.lastfmScrobble.delay": "Wast.fm Scwobbwe Deway (%)", "settings.option.connectivity.lastfmScrobble.nowPlaying": "Enyabwe Wast.fm Nyow Pwaying", @@ -410,6 +424,7 @@ "settings.option.visual.transparent": "Twanspawent fwame", "settings.option.visual.transparent.description": "Twanspawent fwame (nyeeds Theme Suppowt , wequiwes wewaunch)", "settings.header.advanced": "Advanced", + "settings.header.connect": "Connyect", "spatial.notTurnedOn": "Audio Spatiawization is disabwed. To use, pwease enyabwe it fiwst.", "spatial.spatialProperties": "Spatiaw Pwopewties", "spatial.width": "Width", diff --git a/src/i18n/en_US.json b/src/i18n/en_US.json index 8b9f8cc8..3b92951b 100644 --- a/src/i18n/en_US.json +++ b/src/i18n/en_US.json @@ -10,6 +10,7 @@ "notification.updatingLibrarySongs": "Updating library songs...", "notification.updatingLibraryAlbums": "Updating library albums...", "notification.updatingLibraryArtists": "Updating library artists...", + "term.variables": "Variables", "term.appleInc": "Apple Inc.", "term.appleMusic": "Apple Music", "term.applePodcasts": "Apple Podcasts", @@ -301,6 +302,7 @@ "settings.warn.audio.enableAdvancedFunctionality.lowcores": "Cider thinks your PC can't handle these features. Are you sure you want to continue?", "settings.option.audio.audioLab": "Cider Audio Lab", "settings.option.audio.audioLab.description": "An assortment of in-house developed audio effects for Cider.", + "settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California", "settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionality) is required to enable Cider Audio Laboratory.", "settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Analog Warmth", "settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simulates the analog warmth modelled after the Korg Nutube 6P1", @@ -308,6 +310,13 @@ "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description": "Changes the intensity of the Analog Warmth Module processing.", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.smooth": "Smooth", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.warm": "Warm", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer": "Cider Atmosphere Realizer™️", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description": "Realizes a different musical atmosphere modelled after the state of the art audio setups.", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode": "Cider Atmosphere Realizer™️ Mode", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description": "Changes the mode of operation of the Atmosphere Realizer module.", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural1": "Natural (Standard)", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural2": "Natural (High)", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural3": "Natural (Plus)", "settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider Adrenaline Processor™️", "settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "Enhances the perceived audio quality of 256 kbps AAC audio by using a real-time algorithm that takes advantage of both psychoacoustic models of human hearing and AAC encoding characteristics.", "settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility": "CAP is not compatible with Spatialization. Please disable Spatialization to continue.", @@ -386,12 +395,13 @@ "settings.option.lyrics.enableYoutubeLyrics": "Enable Youtube Lyrics for Music Videos", "settings.header.connectivity": "Connectivity", "settings.header.connectivity.description": "Adjust the connectivity settings for Cider.", - "settings.option.connectivity.discordRPC": "Discord Rich Presence", "settings.option.connectivity.playbackNotifications": "Playback Notifications", - "settings.header.connectivity.discordRPC.cider": "Display as 'Cider'", - "settings.header.connectivity.discordRPC.appleMusic": "Display as 'Apple Music'", + "settings.option.connectivity.discordRPC": "Discord Rich Presence", + "settings.option.connectivity.discordRPC.clientName": "Client Name", "settings.option.connectivity.discordRPC.clearOnPause": "Clear Discord Rich Presence on Pause", "settings.option.connectivity.discordRPC.hideButtons": "Hide buttons on Discord Rich Presence", + "settings.option.connectivity.discordRPC.detailsFormat": "Details Format", + "settings.option.connectivity.discordRPC.stateFormat": "State Format", "settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling", "settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble Delay (%)", "settings.option.connectivity.lastfmScrobble.nowPlaying": "Enable Last.fm Now Playing", @@ -414,6 +424,9 @@ "settings.option.visual.transparent": "Transparent frame", "settings.option.visual.transparent.description": "Transparent frame (needs Theme Support , requires relaunch)", "settings.header.advanced": "Advanced", + "settings.header.connect": "Sync", + "settings.option.connect.link_account": "Enable Sync with Cider Connect", + "settings.option.connect.link_account.description": "Linking your Discord account with Cider Connect allows you to store userdata including Settings, EQ's, and eventually more once finished. (Work In Progress)", "spatial.notTurnedOn": "Audio Spatialization is disabled. To use, please enable it first.", "spatial.spatialProperties": "Spatial Properties", "spatial.width": "Width", diff --git a/src/i18n/source/en_US.json b/src/i18n/source/en_US.json index 8b9f8cc8..2d5f4bf5 100644 --- a/src/i18n/source/en_US.json +++ b/src/i18n/source/en_US.json @@ -10,6 +10,7 @@ "notification.updatingLibrarySongs": "Updating library songs...", "notification.updatingLibraryAlbums": "Updating library albums...", "notification.updatingLibraryArtists": "Updating library artists...", + "term.variables": "Variables", "term.appleInc": "Apple Inc.", "term.appleMusic": "Apple Music", "term.applePodcasts": "Apple Podcasts", @@ -301,6 +302,7 @@ "settings.warn.audio.enableAdvancedFunctionality.lowcores": "Cider thinks your PC can't handle these features. Are you sure you want to continue?", "settings.option.audio.audioLab": "Cider Audio Lab", "settings.option.audio.audioLab.description": "An assortment of in-house developed audio effects for Cider.", + "settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California", "settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionality) is required to enable Cider Audio Laboratory.", "settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Analog Warmth", "settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simulates the analog warmth modelled after the Korg Nutube 6P1", @@ -308,6 +310,13 @@ "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description": "Changes the intensity of the Analog Warmth Module processing.", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.smooth": "Smooth", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.warm": "Warm", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer": "Cider Atmosphere Realizer™️", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description": "Realizes a different musical atmosphere modelled after the state of the art audio setups.", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode": "Cider Atmosphere Realizer™️ Mode", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description": "Changes the mode of operation of the Atmosphere Realizer module.", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural1": "Natural (Standard)", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural2": "Natural (High)", + "settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural3": "Natural (Plus)", "settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider Adrenaline Processor™️", "settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "Enhances the perceived audio quality of 256 kbps AAC audio by using a real-time algorithm that takes advantage of both psychoacoustic models of human hearing and AAC encoding characteristics.", "settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility": "CAP is not compatible with Spatialization. Please disable Spatialization to continue.", @@ -386,12 +395,13 @@ "settings.option.lyrics.enableYoutubeLyrics": "Enable Youtube Lyrics for Music Videos", "settings.header.connectivity": "Connectivity", "settings.header.connectivity.description": "Adjust the connectivity settings for Cider.", - "settings.option.connectivity.discordRPC": "Discord Rich Presence", "settings.option.connectivity.playbackNotifications": "Playback Notifications", - "settings.header.connectivity.discordRPC.cider": "Display as 'Cider'", - "settings.header.connectivity.discordRPC.appleMusic": "Display as 'Apple Music'", + "settings.option.connectivity.discordRPC": "Discord Rich Presence", + "settings.option.connectivity.discordRPC.clientName": "Client Name", "settings.option.connectivity.discordRPC.clearOnPause": "Clear Discord Rich Presence on Pause", "settings.option.connectivity.discordRPC.hideButtons": "Hide buttons on Discord Rich Presence", + "settings.option.connectivity.discordRPC.detailsFormat": "Details Format", + "settings.option.connectivity.discordRPC.stateFormat": "State Format", "settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling", "settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble Delay (%)", "settings.option.connectivity.lastfmScrobble.nowPlaying": "Enable Last.fm Now Playing", @@ -414,6 +424,7 @@ "settings.option.visual.transparent": "Transparent frame", "settings.option.visual.transparent.description": "Transparent frame (needs Theme Support , requires relaunch)", "settings.header.advanced": "Advanced", + "settings.header.connect": "Connect", "spatial.notTurnedOn": "Audio Spatialization is disabled. To use, please enable it first.", "spatial.spatialProperties": "Spatial Properties", "spatial.width": "Width", diff --git a/src/main/base/app.ts b/src/main/base/app.ts index c24ed6e5..3ab49a66 100644 --- a/src/main/base/app.ts +++ b/src/main/base/app.ts @@ -203,6 +203,8 @@ export class AppEvents { shell.openExternal('https://opencollective.com/ciderapp') } else if (arg.includes('/beep')) { shell.beep() + } else { + utils.getWindow().webContents.executeJavaScript(`app.appRoute('${arg.split('//')[1]}')`) } } diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index cc04aa15..082d1677 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -18,6 +18,7 @@ const wallpaper = require('wallpaper'); // @ts-ignore import * as AdmZip from "adm-zip"; +import * as util from "util"; /** * @file Creates the BrowserWindow @@ -413,7 +414,7 @@ export class BrowserWindow { console.error('Req not defined') return } - if (req.url.includes("api") || req.url.includes("audio.wav") || (req.headers.host.includes("localhost") && (this.devMode || req.headers["user-agent"].includes("Electron")))) { + if (req.url.includes("api") || req.url.includes("audio.wav") || (req.headers.host.includes("localhost") && (this.devMode || req.headers["user-agent"].includes("Electron")) || req.url.includes("/connect"))) { next(); } else { res.redirect("https://discord.gg/applemusic"); @@ -526,12 +527,23 @@ export class BrowserWindow { console.log(ex); } }); - //app.use(express.static()) + //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)) + res.redirect(`https://connect.cidercollective.dev/linked.html`) + }); + // [Connect] Set auth URL in store for `shell.openExternal` + utils.setStoreValue('cc_authURL', `https://connect.cidercollective.dev/callback/discord?app=cider&appPort=${this.clientPort}`) + console.log(`[Connect] Auth URL: ${utils.getStoreValue('cc_authURL')}`) + //endregion + app.listen(this.clientPort, () => { console.log(`Cider client port: ${this.clientPort}`); }); + /* * Remote Client -@quacksire * https://github.com/ciderapp/Apple-Music-Electron/blob/818189ed40ff600d76eb59d22016723a75885cd5/resources/functions/handler.js#L1173 @@ -1088,12 +1100,13 @@ export class BrowserWindow { }); //QR Code - ipcMain.handle('showQR', async (_event, _) => { + ipcMain.handle('showQR', async (_event, _) => { //macOS let url = `http://${BrowserWindow.getIP()}:${this.remotePort}`; - shell.openExternal(`https://cider.sh/remote/pair?url=${Buffer.from(encodeURI(url)).toString('base64')}`).catch(console.error); + BrowserWindow.win.webContents.send('send-remote-pair-url', (`https://cider.sh/remote/pair?url=${Buffer.from(encodeURI(url)).toString('base64')}`).toString()); + }); - ipcMain.on('get-remote-pair-url', (_event, _) => { + ipcMain.on('get-remote-pair-url', (_event, _) => { // Linux and Windows let url = `http://${BrowserWindow.getIP()}:${this.remotePort}`; //if (app.isPackaged) { BrowserWindow.win.webContents.send('send-remote-pair-url', (`https://cider.sh/remote/pair?url=${Buffer.from(encodeURI(url)).toString('base64')}`).toString()); @@ -1102,7 +1115,9 @@ export class BrowserWindow { //} }); - if (process.platform === "darwin") { + + + if (process.platform === "darwin") { //macOS app.setUserActivity('com.CiderCollective.remote.pair', { ip: `${BrowserWindow.getIP()}` }, `http://${BrowserWindow.getIP()}:${this.remotePort}`); @@ -1156,6 +1171,10 @@ export class BrowserWindow { ipcMain.on('open-appdata', (_event) => { shell.openPath(app.getPath('userData')); }); + + ipcMain.on('cc-auth', (_event) => { + shell.openExternal(String(utils.getStoreValue('cc_authURL'))); + }); /* ********************************************************************************************* * Window Events * **********************************************************************************************/ diff --git a/src/main/base/plugins.ts b/src/main/base/plugins.ts index 1f501cd2..a09ee3e9 100644 --- a/src/main/base/plugins.ts +++ b/src/main/base/plugins.ts @@ -4,7 +4,7 @@ import * as electron from 'electron' import {utils} from './utils'; // -// Hello, this our loader for the various plugins that the Cider Development Team built for our +// Hello, this is our loader for the various plugins that the Cider Development Team built for our // numerous plugins internally and ones made by the community // // To learn how to make your own, visit https://github.com/ciderapp/Cider/wiki/Plugins diff --git a/src/main/base/store.ts b/src/main/base/store.ts index da524ae9..cbd474d2 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -12,9 +12,14 @@ export class Store { }, "general": { "close_button_hide": false, - "discord_rpc": 1, // 0 = disabled, 1 = enabled as Cider, 2 = enabled as Apple Music - "discord_rpc_clear_on_pause": true, - "discord_rpc_hide_buttons": false, + "discord_rpc": { + "enabled": false, + "client": "Cider", + "clear_on_pause": true, + "hide_buttons": false, + "state_format": "by {artist}", + "details_format": "{title}", + }, "language": "en_US", // electron.app.getLocale().replace('-', '_') this can be used in future "playbackNotifications": true, "update_branch": "main", @@ -152,13 +157,21 @@ export class Store { "playlistTrackMapping": true } } - private migrations: any = {} + private migrations: any = { + '>=1.4.3': (store: ElectronStore) => { + if (typeof(store.get('general.discord_rpc')) == 'number' || typeof(store.get('general.discord_rpc')) == 'string') { + store.delete('general.discord_rpc'); + store.set('general.discord_rpc', this.defaults.general.discord_rpc) + } + }, + } constructor() { Store.cfg = new ElectronStore({ name: 'cider-config', defaults: this.defaults, migrations: this.migrations, + clearInvalidConfig: true }); Store.cfg.set(this.mergeStore(this.defaults, Store.cfg.store)) diff --git a/src/main/plugins/discordrpc.ts b/src/main/plugins/discordrpc.ts index 90b06809..33593c0c 100644 --- a/src/main/plugins/discordrpc.ts +++ b/src/main/plugins/discordrpc.ts @@ -2,15 +2,15 @@ import * as RPC from 'discord-rpc' import {ipcMain} from "electron"; import fetch from 'electron-fetch' -export default class DiscordRichPresence { +export default class DiscordRPC { /** * Private variables for interaction in plugins */ - private static _store: any; + private _utils: any; private _app: any; private _attributes: any; - private static _connection: boolean = false; + private _connection: boolean = false; /** * Base Plugin Details (Eventually implemented into a GUI in settings) @@ -33,7 +33,6 @@ export default class DiscordRichPresence { smallImageText: '', instance: false }; - private _clientId: number = 0; private _activityCache: RPC.Presence = { details: '', @@ -50,21 +49,21 @@ export default class DiscordRichPresence { * ****************************************************************************************/ /** - * Connect to Discord - * @param clientId + * Connect to Discord RPC * @private */ - private connect(clientId: any) { - this._clientId = clientId; - if (DiscordRichPresence._store.general.discord_rpc == 0) { - return + private connect() { + if (!this._utils.getStoreValue("general.discord_rpc.enabled")) { + return; } + const clientId = this._utils.getStoreValue("general.discord_rpc.client") === "Cider" ? '911790844204437504' : '886578863147192350'; // Apparently needed for ask to join, join, spectate etc. RPC.register(clientId) // Create the client this._client = new RPC.Client({transport: "ipc"}); + // Runs on Ready this._client.on('ready', () => { console.info(`[DiscordRPC][connect] Successfully Connected to Discord. Authed for user: ${this._client.user.id}.`); @@ -72,22 +71,22 @@ export default class DiscordRichPresence { // Handles Errors this._client.on('error', (err: any) => { - console.error(`[DiscordRichPresence] ${err}`); + console.error(`[DiscordRPC] ${err}`); this.disconnect() }); // If Discord is closed, allow reconnecting this._client.transport.once('close', () => { - console.info(`[DiscordRichPresence] Connection closed`); + console.info(`[DiscordRPC] Connection closed`); this.disconnect() }); // Login to Discord this._client.login({clientId}) .then(() => { - DiscordRichPresence._connection = true; + this._connection = true; }) - .catch((e: any) => console.error(`[DiscordRichPresence][connect] ${e}`)); + .catch((e: any) => console.error(`[DiscordRPC][connect] ${e}`)); } /** @@ -99,7 +98,7 @@ export default class DiscordRichPresence { } this._client.destroy().then(() => { - DiscordRichPresence._connection = false; + this._connection = false; console.log('[DiscordRPC][disconnect] Disconnected from discord.') }).catch((e: any) => console.error(`[DiscordRPC][disconnect] ${e}`)); @@ -112,6 +111,32 @@ export default class DiscordRichPresence { */ private static filterActivity(activity: any, attributes: any): Object { + /** + * Works with: + * {artist} + * {composer} + * {title} + * {album} + * {trackNumber} + */ + const rpcVars: any = { + "artist": attributes.artistName, + "composer": attributes.composerName, + "title": attributes.name, + "album": attributes.albumName, + "trackNumber": attributes.trackNumber + } + + // Replace the variables + Object.keys(rpcVars).forEach((key) => { + if (activity.details.includes(`{${key}}`)) { + activity.details = activity.details.replace(`{${key}}`, rpcVars[key]) + } + if (activity.state.includes(`{${key}}`)) { + activity.state = activity.state.replace(`{${key}}`, rpcVars[key]) + } + }) + // Checks if the name is greater than 128 because some songs can be that long if (activity.details && activity.details.length > 128) { activity.details = activity.details.substring(0, 125) + '...' @@ -139,67 +164,68 @@ export default class DiscordRichPresence { return activity } + /** + * Sets the activity + * @param {activity} activity + */ + private setActivity(activity: any) { + if (!this._connection || !this._client || !activity) { + return + } + + // Filter the activity + activity = DiscordRPC.filterActivity(activity, this._attributes) + + // Set the activity + if (!this._attributes.status && this._utils.getStoreValue("general.discord_rpc.clear_on_pause")) { + this._client.clearActivity() + } else { + this._client.setActivity(activity) + this._activityCache = this._activity; + } + } + /** * Sets the activity of the client * @param {object} attributes */ private updateActivity(attributes: any) { - if (DiscordRichPresence._store.general.discord_rpc == 0) { + if (!this._utils.getStoreValue("general.discord_rpc.enabled") || this._utils.getStoreValue("general.privateEnabled")) { return - } else if (!DiscordRichPresence._connection || !this._client) { - this.connect(this._clientId) - } - - if (!DiscordRichPresence._connection) { - this._client.clearActivity().catch((e: any) => console.error(`[DiscordRichPresence][clearActivity] ${e}`)); - return; + } else if (!this._client || !this._connection) { + this.connect() } // Check if show buttons is (true) or (false) this._activity = { - details: attributes.name, - state: `${attributes.artistName ? `by ${attributes.artistName}` : ''}`, - startTimestamp: Date.now() - (attributes?.durationInMillis - attributes?.remainingTime), - endTimestamp: attributes.endTime, + details: this._utils.getStoreValue("general.discord_rpc.details_format"), + state: this._utils.getStoreValue("general.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 } - if (!DiscordRichPresence._store.general.discord_rpc_hide_buttons) { + // Add the buttons if people want them + if (!this._utils.getStoreValue("general.discord_rpc.hide_buttons")) { this._activity.buttons = [ {label: 'Listen on Cider', url: attributes.url.cider}, {label: 'View on Apple Music', url: attributes.url.appleMusic} ] //To change attributes.url => preload/cider-preload.js } - - this._activity = DiscordRichPresence.filterActivity(this._activity, attributes) - - // Check if its pausing (false) or playing (true) - if (!attributes.status) { - if (DiscordRichPresence._store.general.discord_rpc_clear_on_pause) { - this._client.clearActivity() - .catch((e: any) => console.error(`[DiscordRichPresence][clearActivity] ${e}`)); - } else { - this._activity.smallImageKey = 'pause'; - this._activity.smallImageText = 'Paused'; - delete this._activity.endTimestamp; - delete this._activity.startTimestamp; - this._client.setActivity(this._activity) - .catch((e: any) => console.error(`[DiscordRichPresence][setActivity] ${e}`)); - } - } else if (this._activity && this._activityCache !== this._activity && this._activity.details) { - if (!DiscordRichPresence._store.general.discord_rpc_clear_on_pause) { - this._activity.smallImageKey = 'play'; - this._activity.smallImageText = 'Playing'; - } - - this._client.setActivity(this._activity) - .catch((e: any) => console.error(`[DiscordRichPresence][updateActivity] ${e}`)); - this._activityCache = this._activity; + // Add the timestamp if its playing + if (attributes.status) { + this._activity.startTimestamp = Date.now() - (attributes?.durationInMillis - attributes?.remainingTime) + this._activity.endTimestamp = attributes.endTime } + // If the user wants to keep the activity when paused + if (!this._utils.getStoreValue("general.discord_rpc.clear_on_pause")) { + this._activity.smallImageKey = attributes.status ? 'play' : 'pause'; + this._activity.smallImageText = attributes.status ? 'Playing' : 'Paused'; + } + + this.setActivity(this._activity) } /******************************************************************************************* @@ -210,7 +236,7 @@ export default class DiscordRichPresence { * Runs on plugin load (Currently run on application start) */ constructor(utils: { getStore: () => any; getApp: () => any; }) { - DiscordRichPresence._store = utils.getStore(); + this._utils = utils; console.debug(`[Plugin][${this.name}] Loading Complete.`); this._app = utils.getApp(); } @@ -220,10 +246,10 @@ export default class DiscordRichPresence { */ onReady(_win: any): void { let self = this - this.connect((DiscordRichPresence._store.general.discord_rpc == 1) ? '911790844204437504' : '886578863147192350'); + this.connect(); console.debug(`[Plugin][${this.name}] Ready.`); ipcMain.on('updateRPCImage', (_event, imageurl) => { - if (!DiscordRichPresence._store.general.privateEnabled) { + if (!this._utils.getStoreValue("general.privateEnabled")) { fetch('https://api.cider.sh/v1/images', { method: 'POST', @@ -246,6 +272,9 @@ export default class DiscordRichPresence { * Runs on app stop */ onBeforeQuit(): void { + if (this._client) { + this.disconnect() + } console.debug(`[Plugin][${this.name}] Stopped.`); } @@ -254,10 +283,9 @@ export default class DiscordRichPresence { * @param attributes Music Attributes (attributes.status = current state) */ onPlaybackStateDidChange(attributes: object): void { - if (!DiscordRichPresence._store.general.privateEnabled) { - this._attributes = attributes - this.updateActivity(attributes) - } + this._attributes = attributes + this.updateActivity(attributes) + } /** @@ -265,9 +293,8 @@ export default class DiscordRichPresence { * @param attributes Music Attributes */ onNowPlayingItemDidChange(attributes: object): void { - if (!DiscordRichPresence._store.general.privateEnabled) { - this._attributes = attributes - this.updateActivity(attributes) - } + this._attributes = attributes + this.updateActivity(attributes) + } } diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index d988dcd3..4dcade4b 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -82,10 +82,10 @@ const app = new Vue({ }, albums: { sortingOptions: { - "albumName": "0", "artistName": "0", "name": "0", - "genre": "0" + "genre": "0", + "releaseDate": "0" }, viewAs: 'covers', sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page @@ -349,10 +349,10 @@ const app = new Vue({ } app.$data.library.albums.sortingOptions = { - "albumName": app.getLz('term.sortBy.album'), "artistName": app.getLz('term.sortBy.artist'), "name": app.getLz('term.sortBy.name'), - "genre": app.getLz('term.sortBy.genre') + "genre": app.getLz('term.sortBy.genre'), + "releaseDate": app.getLz('term.sortBy.releaseDate') } app.$data.library.artists.sortingOptions = { @@ -1507,10 +1507,9 @@ const app = new Vue({ */ convertTime(seconds, format = "short") { - if (isNaN(seconds) || seconds == Infinity) { + if (isNaN(seconds) || seconds === Infinity) { seconds = 0 } - seconds = parseInt(seconds); const datetime = new Date(seconds * 1000) @@ -1520,12 +1519,11 @@ const app = new Vue({ const m = Math.floor(seconds % 3600 / 60); const s = Math.floor(seconds % 60); - const dDisplay = d > 0 ? `${d} ${app.getLz("term.time.day", { "count": d })}, ` : ""; - const hDisplay = h > 0 ? `${h} ${app.getLz("term.time.hour", { "count": h })}, ` : ""; - const mDisplay = m > 0 ? `${m} ${app.getLz("term.time.minute", { "count": m })}, ` : ""; - const sDisplay = s > 0 ? `${s} ${app.getLz("term.time.second", { "count": s })}` : ""; + const dDisplay = d > 0 ? `${d} ${app.getLz("term.time.day", { "count": d })}` : ""; + const hDisplay = h > 0 ? `${h} ${app.getLz("term.time.hour", { "count": h })}` : ""; + const mDisplay = m > 0 ? `${m} ${app.getLz("term.time.minute", { "count": m })}` : ""; - return dDisplay + hDisplay + mDisplay + sDisplay; + return dDisplay + (dDisplay && hDisplay ? ", " : "") + hDisplay + (hDisplay && mDisplay ? ", " : "") + mDisplay; } else { let returnTime = datetime.toISOString().substring(11, 19); @@ -4258,6 +4256,9 @@ const app = new Vue({ document.getElementById('settings.option.general.updateCider.check').innerHTML = app.getLz('term.check') }) }, + authCC(){ + ipcRenderer.send('cc-auth') + } } }) diff --git a/src/renderer/style.css b/src/renderer/style.css index e8001474..42702b6e 100644 --- a/src/renderer/style.css +++ b/src/renderer/style.css @@ -11626,7 +11626,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { filter: none !important; } .lyricWaiting { - margin-top: 8px; + margin-bottom: 10px; display: none; } .lyric-line.active .lyricWaiting { diff --git a/src/renderer/style.less b/src/renderer/style.less index 84875bca..80934d6f 100644 --- a/src/renderer/style.less +++ b/src/renderer/style.less @@ -1261,7 +1261,7 @@ body[platform="darwin"] .app-chrome .app-chrome-item > .window-controls > div.cl .marquee { - animation: marquee 15s linear infinite; + animation: marquee 15s linear 2s infinite; &.song-artist { overflow: unset; @@ -1630,7 +1630,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { } .lyricWaiting { - margin-top: 8px; + margin-bottom:10px; display: none; } diff --git a/src/renderer/views/components/queue.ejs b/src/renderer/views/components/queue.ejs index b08bdebf..fc675bd5 100644 --- a/src/renderer/views/components/queue.ejs +++ b/src/renderer/views/components/queue.ejs @@ -122,7 +122,7 @@ }, multiple: { items: [{ - "name": app.getLz('action.removeTracks'), + "name": app.getLz('action.removeTracks').replace('${self.selectedItems.length}', self.selectedItems.length.toString()), "action": function () { // add property to items to be removed self.selectedItems.forEach(function (item) { diff --git a/src/renderer/views/pages/audiolabs.ejs b/src/renderer/views/pages/audiolabs.ejs index 4a8aa644..e0ad0908 100644 --- a/src/renderer/views/pages/audiolabs.ejs +++ b/src/renderer/views/pages/audiolabs.ejs @@ -5,7 +5,7 @@
+ lead="$root.getLz('settings.option.audio.audioLab.subheader')">
@@ -79,9 +79,9 @@
- Cider Atmosphere Realizer™️ + {{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer')}}
- Realizes a different musical atmosphere modelled after the state of the art audio setups. + {{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description')}}
- Cider Atmosphere Realizer™️ Mode + {{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode')}}
- Changes the mode of operation of the Atmosphere Realizer module. + {{$root.getLz('settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description')}}
diff --git a/src/renderer/views/pages/connect-linked.ejs b/src/renderer/views/pages/connect-linked.ejs new file mode 100644 index 00000000..1d83dff1 --- /dev/null +++ b/src/renderer/views/pages/connect-linked.ejs @@ -0,0 +1,21 @@ + + \ No newline at end of file diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index 7a45c317..e72a036a 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -204,7 +204,7 @@ {{app.cfg.audio.equalizer.vibrantBass != 0 || app.cfg.audio.maikiwiAudio.spatial === true || app.cfg.audio.maikiwiAudio.ciderPPE === true ? `${$root.getLz('settings.option.audio.enableAdvancedFunctionality.audioNormalization.description')}\n${$root.getLz('settings.option.audio.enableAdvancedFunctionality.audioNormalization.disabled')}` : $root.getLz('settings.option.audio.enableAdvancedFunctionality.audioNormalization.description')}}
-
@@ -394,7 +394,7 @@
- +
@@ -710,36 +710,68 @@ +
{{$root.getLz('settings.option.connectivity.discordRPC')}}
- +
+
+ +
+
+ {{$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.visual.hardwareAcceleration.description')}}) + {{$root.getLz('settings.option.connectivity.discordRPC.hideButtons')}}
- +
+ +
+
+ {{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}
+ {{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album}, {trackNumber} +
+
+ +
+
+ +
+
+ {{$root.getLz('settings.option.connectivity.discordRPC.stateFormat')}} + {{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album}, {trackNumber} +
+
+ +
+
+ +
{{$root.getLz('settings.option.connectivity.lastfmScrobble')}} @@ -944,6 +976,30 @@
+ +
+ +
+ {{$root.getLz('settings.header.connect')}} +
+
+
+
+ {{$root.getLz('settings.option.connect.link_account')}} + {{$root.getLz('settings.option.connect.link_account.description')}} +
+ Debug Status: {{ app.cfg.connectUser }} +
+
+ +
+
+
+
+
+
@@ -1010,7 +1066,7 @@ }, getThemeName(filename) { try { - return this.themes.find(theme => theme.file === filename).name; + return this.themes.find(theme => theme.file === filename).name; }catch(e) { return filename; } @@ -1180,7 +1236,10 @@ ipcRenderer.send('relaunchApp', ''); } }); - } + }, + authCC() { + ipcRenderer.send('cc-auth') + }, } }) \ No newline at end of file diff --git a/src/renderer/views/pages/webview.ejs b/src/renderer/views/pages/webview.ejs index 8c96062f..36682716 100644 --- a/src/renderer/views/pages/webview.ejs +++ b/src/renderer/views/pages/webview.ejs @@ -1,6 +1,5 @@