Swapped to discord-auto-rpc, experience should be seamless now for discordrpc.
This commit is contained in:
parent
a536e544a5
commit
a2ee309596
2 changed files with 134 additions and 184 deletions
|
@ -42,7 +42,7 @@
|
||||||
"airtunes2": "git+https://github.com/vapormusic/node_airtunes2.git#hap",
|
"airtunes2": "git+https://github.com/vapormusic/node_airtunes2.git#hap",
|
||||||
"castv2-client": "^1.2.0",
|
"castv2-client": "^1.2.0",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"discord-rpc": "^4.0.1",
|
"discord-auto-rpc": "^1.0.16",
|
||||||
"dns-js": "git+https://github.com/ciderapp/node-dns-js.git",
|
"dns-js": "git+https://github.com/ciderapp/node-dns-js.git",
|
||||||
"ejs": "^3.1.6",
|
"ejs": "^3.1.6",
|
||||||
"electron-fetch": "^1.7.4",
|
"electron-fetch": "^1.7.4",
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
"electron-builder-notarize-pkg": "^1.2.0",
|
"electron-builder-notarize-pkg": "^1.2.0",
|
||||||
"electron-webpack": "^2.8.2",
|
"electron-webpack": "^2.8.2",
|
||||||
"musickit-typescript": "^1.2.4",
|
"musickit-typescript": "^1.2.4",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.6.4",
|
||||||
"vue-devtools": "^5.1.4",
|
"vue-devtools": "^5.1.4",
|
||||||
"webpack": "~5.72.0"
|
"webpack": "~5.72.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,30 +1,29 @@
|
||||||
import * as RPC from 'discord-rpc'
|
import {AutoClient} from 'discord-auto-rpc'
|
||||||
import {ipcMain} from "electron";
|
import {ipcMain} from "electron";
|
||||||
import fetch from 'electron-fetch'
|
import fetch from 'electron-fetch'
|
||||||
|
|
||||||
export default class DiscordRPC {
|
export default class DiscordRPC {
|
||||||
|
|
||||||
/**
|
|
||||||
* Private variables for interaction in plugins
|
|
||||||
*/
|
|
||||||
private _utils: any;
|
|
||||||
private _app: any;
|
|
||||||
private _attributes: any;
|
|
||||||
private _connection: boolean = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base Plugin Details (Eventually implemented into a GUI in settings)
|
* Base Plugin Details (Eventually implemented into a GUI in settings)
|
||||||
*/
|
*/
|
||||||
public name: string = 'Discord Rich Presence';
|
public name: string = 'Discord Rich Presence';
|
||||||
public description: string = 'Discord RPC plugin for Cider';
|
public description: string = 'Discord RPC plugin for Cider';
|
||||||
public version: string = '1.0.0';
|
public version: string = '1.1.0';
|
||||||
public author: string = 'vapormusic/Core (Cider Collective)';
|
public author: string = 'vapormusic/Core (Cider Collective)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private variables for interaction in plugins
|
||||||
|
*/
|
||||||
|
private _utils: any;
|
||||||
|
private _attributes: any;
|
||||||
|
private ready: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin Initialization
|
* Plugin Initialization
|
||||||
*/
|
*/
|
||||||
private _client: any = null;
|
private _client: any = null;
|
||||||
private _activity: RPC.Presence = {
|
private _activityCache: any = {
|
||||||
details: '',
|
details: '',
|
||||||
state: '',
|
state: '',
|
||||||
largeImageKey: '',
|
largeImageKey: '',
|
||||||
|
@ -34,15 +33,72 @@ export default class DiscordRPC {
|
||||||
instance: false
|
instance: false
|
||||||
};
|
};
|
||||||
|
|
||||||
private _activityCache: RPC.Presence = {
|
/*******************************************************************************************
|
||||||
details: '',
|
* Public Methods
|
||||||
state: '',
|
* ****************************************************************************************/
|
||||||
largeImageKey: '',
|
|
||||||
largeImageText: '',
|
/**
|
||||||
smallImageKey: '',
|
* Runs on plugin load (Currently run on application start)
|
||||||
smallImageText: '',
|
*/
|
||||||
instance: false
|
constructor(utils: any) {
|
||||||
};
|
this._utils = utils;
|
||||||
|
console.debug(`[Plugin][${this.name}] Loading Complete.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs on app ready
|
||||||
|
*/
|
||||||
|
onReady(_win: any): void {
|
||||||
|
const self = this
|
||||||
|
this.connect();
|
||||||
|
console.debug(`[Plugin][${this.name}] Ready.`);
|
||||||
|
ipcMain.on('updateRPCImage', (_event, imageurl) => {
|
||||||
|
if (!this._utils.getStoreValue("general.privateEnabled")) {
|
||||||
|
fetch('https://api.cider.sh/v1/images', {
|
||||||
|
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({url: imageurl}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'User-Agent': _win.webContents.getUserAgent()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(function (json) {
|
||||||
|
self._attributes["artwork"]["url"] = json.url
|
||||||
|
self.setActivity(self._attributes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs on app stop
|
||||||
|
*/
|
||||||
|
onBeforeQuit(): void {
|
||||||
|
console.debug(`[Plugin][${this.name}] Stopped.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs on playback State Change
|
||||||
|
* @param attributes Music Attributes (attributes.status = current state)
|
||||||
|
*/
|
||||||
|
onPlaybackStateDidChange(attributes: object): void {
|
||||||
|
this._attributes = attributes
|
||||||
|
this.setActivity(attributes)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs on song change
|
||||||
|
* @param attributes Music Attributes
|
||||||
|
*/
|
||||||
|
onNowPlayingItemDidChange(attributes: object): void {
|
||||||
|
this._attributes = attributes
|
||||||
|
this.setActivity(attributes)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************************
|
/*******************************************************************************************
|
||||||
* Private Methods
|
* Private Methods
|
||||||
|
@ -58,58 +114,86 @@ export default class DiscordRPC {
|
||||||
}
|
}
|
||||||
const clientId = this._utils.getStoreValue("general.discordrpc.client") === "Cider" ? '911790844204437504' : '886578863147192350';
|
const clientId = this._utils.getStoreValue("general.discordrpc.client") === "Cider" ? '911790844204437504' : '886578863147192350';
|
||||||
|
|
||||||
// Apparently needed for ask to join, join, spectate etc.
|
|
||||||
RPC.register(clientId)
|
|
||||||
|
|
||||||
// Create the client
|
// Create the client
|
||||||
this._client = new RPC.Client({transport: "ipc"});
|
this._client = new AutoClient({transport: "ipc"});
|
||||||
|
|
||||||
// Runs on Ready
|
// Runs on Ready
|
||||||
this._client.on('ready', () => {
|
this._client.once('ready', () => {
|
||||||
console.info(`[DiscordRPC][connect] Successfully Connected to Discord. Authed for user: ${this._client.user.id}.`);
|
console.info(`[DiscordRPC][connect] Successfully Connected to Discord. Authed for user: ${this._client.user.id}.`);
|
||||||
|
|
||||||
|
if (this._activityCache && this._activityCache.details && this._activityCache.state) {
|
||||||
|
console.info(`[DiscordRPC][connect] Restoring activity cache.`);
|
||||||
|
this._client.setActivity(this._activityCache)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Handles Errors
|
|
||||||
this._client.on('error', (err: any) => {
|
|
||||||
console.error(`[DiscordRPC] ${err}`);
|
|
||||||
this.disconnect()
|
|
||||||
});
|
|
||||||
|
|
||||||
// If Discord is closed, allow reconnecting
|
|
||||||
this._client.transport.once('close', () => {
|
|
||||||
console.info(`[DiscordRPC] Connection closed`);
|
|
||||||
this.disconnect()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Login to Discord
|
// Login to Discord
|
||||||
this._client.login({clientId})
|
this._client.endlessLogin({clientId: clientId})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this._connection = true;
|
this.ready = true
|
||||||
})
|
})
|
||||||
.catch((e: any) => console.error(`[DiscordRPC][connect] ${e}`));
|
.catch((e: any) => console.error(`[DiscordRPC][connect] ${e}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects from Discord RPC
|
* Sets the activity
|
||||||
|
* @param attributes Music Attributes
|
||||||
*/
|
*/
|
||||||
private disconnect() {
|
private setActivity(attributes: any) {
|
||||||
if (!this._client) {
|
if (!this._client) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this._client.destroy().then(() => {
|
// Check if show buttons is (true) or (false)
|
||||||
this._connection = false;
|
let activity: Object = {
|
||||||
console.log('[DiscordRPC][disconnect] Disconnected from discord.')
|
details: this._utils.getStoreValue("general.discordrpc.details_format"),
|
||||||
}).catch((e: any) => console.error(`[DiscordRPC][disconnect] ${e}`));
|
state: this._utils.getStoreValue("general.discordrpc.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
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up, allow creating a new connection
|
// Filter the activity
|
||||||
this._client = null;
|
activity = this.filterActivity(activity, attributes)
|
||||||
|
|
||||||
|
if (!this.ready) {
|
||||||
|
this._activityCache = activity
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the activity
|
||||||
|
if (!attributes.status && this._utils.getStoreValue("general.discordrpc.clear_on_pause")) {
|
||||||
|
this._client.clearActivity()
|
||||||
|
} else if (activity && this._activityCache !== activity) {
|
||||||
|
this._client.setActivity(activity)
|
||||||
|
}
|
||||||
|
this._activityCache = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter the Discord activity object
|
* Filter the Discord activity object
|
||||||
*/
|
*/
|
||||||
private static filterActivity(activity: any, attributes: any): Object {
|
private filterActivity(activity: any, attributes: any): Object {
|
||||||
|
|
||||||
|
// Add the buttons if people want them
|
||||||
|
if (!this._utils.getStoreValue("general.discordrpc.hide_buttons")) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the timestamp if its playing
|
||||||
|
if (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")) {
|
||||||
|
activity.smallImageKey = attributes.status ? 'play' : 'pause';
|
||||||
|
activity.smallImageText = attributes.status ? 'Playing' : 'Paused';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Works with:
|
* Works with:
|
||||||
|
@ -173,138 +257,4 @@ export default class DiscordRPC {
|
||||||
}
|
}
|
||||||
return activity
|
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.discordrpc.clear_on_pause")) {
|
|
||||||
this._client.clearActivity()
|
|
||||||
} else if (this._activity && this._activityCache !== this._activity && this._activity.details) {
|
|
||||||
this._client.setActivity(activity)
|
|
||||||
this._activityCache = this._activity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the activity of the client
|
|
||||||
* @param {object} attributes
|
|
||||||
*/
|
|
||||||
private updateActivity(attributes: any) {
|
|
||||||
if (!this._utils.getStoreValue("general.discordrpc.enabled") || this._utils.getStoreValue("general.privateEnabled")) {
|
|
||||||
return
|
|
||||||
} else if (!this._client || !this._connection) {
|
|
||||||
this.connect()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if show buttons is (true) or (false)
|
|
||||||
this._activity = {
|
|
||||||
details: this._utils.getStoreValue("general.discordrpc.details_format"),
|
|
||||||
state: this._utils.getStoreValue("general.discordrpc.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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the buttons if people want them
|
|
||||||
if (!this._utils.getStoreValue("general.discordrpc.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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.discordrpc.clear_on_pause")) {
|
|
||||||
this._activity.smallImageKey = attributes.status ? 'play' : 'pause';
|
|
||||||
this._activity.smallImageText = attributes.status ? 'Playing' : 'Paused';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setActivity(this._activity)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************************
|
|
||||||
* Public Methods
|
|
||||||
* ****************************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on plugin load (Currently run on application start)
|
|
||||||
*/
|
|
||||||
constructor(utils: { getStore: () => any; getApp: () => any; }) {
|
|
||||||
this._utils = utils;
|
|
||||||
console.debug(`[Plugin][${this.name}] Loading Complete.`);
|
|
||||||
this._app = utils.getApp();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on app ready
|
|
||||||
*/
|
|
||||||
onReady(_win: any): void {
|
|
||||||
let self = this
|
|
||||||
this.connect();
|
|
||||||
console.debug(`[Plugin][${this.name}] Ready.`);
|
|
||||||
ipcMain.on('updateRPCImage', (_event, imageurl) => {
|
|
||||||
if (!this._utils.getStoreValue("general.privateEnabled")) {
|
|
||||||
fetch('https://api.cider.sh/v1/images', {
|
|
||||||
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({url: imageurl}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'User-Agent': _win.webContents.getUserAgent()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(function (json) {
|
|
||||||
self._attributes["artwork"]["url"] = json.url
|
|
||||||
self.updateActivity(self._attributes)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on app stop
|
|
||||||
*/
|
|
||||||
onBeforeQuit(): void {
|
|
||||||
if (this._client) {
|
|
||||||
this.disconnect()
|
|
||||||
}
|
|
||||||
console.debug(`[Plugin][${this.name}] Stopped.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on playback State Change
|
|
||||||
* @param attributes Music Attributes (attributes.status = current state)
|
|
||||||
*/
|
|
||||||
onPlaybackStateDidChange(attributes: object): void {
|
|
||||||
this._attributes = attributes
|
|
||||||
this.updateActivity(attributes)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs on song change
|
|
||||||
* @param attributes Music Attributes
|
|
||||||
*/
|
|
||||||
onNowPlayingItemDidChange(attributes: object): void {
|
|
||||||
this._attributes = attributes
|
|
||||||
this.updateActivity(attributes)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue