diff --git a/src/main/plugins/discordrpc.ts b/src/main/plugins/discordrpc.ts index 90b06809..0fa1540e 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 ? 'pause' : 'play'; + this._activity.smallImageText = attributes.status ? 'Paused' : 'Playing'; + } + + 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) + } }