Discord add reconnecting functionality

Clear rpc on disconnect
Add menu button to reconnect
This commit is contained in:
Constantin Piber
2021-08-27 16:32:55 +02:00
parent 36bc9c62b0
commit b5fd6b4969
3 changed files with 168 additions and 78 deletions

View File

@ -1,29 +1,97 @@
const Discord = require("discord-rpc"); const Discord = require("discord-rpc");
const { dev } = require("electron-is")
const registerCallback = require("../../providers/song-info"); const registerCallback = require("../../providers/song-info");
const rpc = new Discord.Client({
transport: "ipc",
});
// Application ID registered by @semvis123 // Application ID registered by @semvis123
const clientId = "790655993809338398"; const clientId = "790655993809338398";
/**
* @typedef {Object} Info
* @property {import('discord-rpc').Client} rpc
* @property {boolean} ready
* @property {import('../../providers/song-info').SongInfo} lastSongInfo
*/
/**
* @type {Info}
*/
const info = {
rpc: null,
ready: false,
lastSongInfo: null,
};
/**
* @type {(() => void)[]}
*/
const refreshCallbacks = [];
const resetInfo = () => {
info.rpc = null;
info.ready = false;
clearTimeout(clearActivity);
if (dev()) console.log("discord disconnected");
refreshCallbacks.forEach(cb => cb());
};
const connect = () => {
if (info.rpc) {
if (dev())
console.log('Attempted to connect with active RPC object');
return;
}
info.rpc = new Discord.Client({
transport: "ipc",
});
info.ready = false;
info.rpc.once("connected", () => {
if (dev()) console.log("discord connected");
refreshCallbacks.forEach(cb => cb());
});
info.rpc.once("ready", () => {
info.ready = true;
if (info.lastSongInfo) updateActivity(info.lastSongInfo)
});
info.rpc.once("disconnected", resetInfo);
// Startup the rpc client
info.rpc.login({ clientId }).catch(err => {
resetInfo();
if (dev()) console.error(err);
});
};
let clearActivity; let clearActivity;
/**
* @type {import('../../providers/song-info').songInfoCallback}
*/
let updateActivity;
module.exports = (win, {activityTimoutEnabled, activityTimoutTime}) => { module.exports = (win, {activityTimoutEnabled, activityTimoutTime}) => {
// If the page is ready, register the callback
win.once("ready-to-show", () => {
rpc.once("ready", () => {
// Register the callback
//
// We get multiple events // We get multiple events
// Next song: PAUSE(n), PAUSE(n+1), PLAY(n+1) // Next song: PAUSE(n), PAUSE(n+1), PLAY(n+1)
// Skip time: PAUSE(N), PLAY(N) // Skip time: PAUSE(N), PLAY(N)
registerCallback((songInfo) => { updateActivity = songInfo => {
if (songInfo.title.length === 0 && songInfo.artist.length === 0) { if (songInfo.title.length === 0 && songInfo.artist.length === 0) {
return; return;
} }
info.lastSongInfo = songInfo;
// stop the clear activity timout
clearTimeout(clearActivity);
// stop early if discord connection is not ready
// do this after clearTimeout to avoid unexpected clears
if (!info.rpc || !info.ready) {
return;
}
// clear directly if timeout is 0
if (songInfo.isPaused && activityTimoutEnabled && activityTimoutTime === 0) {
info.rpc.clearActivity().catch(console.error);
return;
}
// Song information changed, so lets update the rich presence // Song information changed, so lets update the rich presence
const activityInfo = { const activityInfo = {
details: songInfo.title, details: songInfo.title,
@ -35,22 +103,13 @@ module.exports = (win, {activityTimoutEnabled, activityTimoutTime}) => {
].join(' || '), ].join(' || '),
}; };
// stop the clear activity timout
clearTimeout(clearActivity);
// clear directly if timeout is 0
if (songInfo.isPaused && activityTimoutEnabled && activityTimoutTime === 0) {
rpc.clearActivity().catch(console.error);
return;
}
if (songInfo.isPaused) { if (songInfo.isPaused) {
// Add an idle icon to show that the song is paused // Add an idle icon to show that the song is paused
activityInfo.smallImageKey = "idle"; activityInfo.smallImageKey = "idle";
activityInfo.smallImageText = "idle/paused"; activityInfo.smallImageText = "idle/paused";
// Set start the timer so the activity gets cleared after a while if enabled // Set start the timer so the activity gets cleared after a while if enabled
if (activityTimoutEnabled) if (activityTimoutEnabled)
clearActivity = setTimeout(() => rpc.clearActivity().catch(console.error), activityTimoutTime || 10000); clearActivity = setTimeout(() => info.rpc.clearActivity().catch(console.error), activityTimoutTime || 10000);
} else { } else {
// Add the start and end time of the song // Add the start and end time of the song
const songStartTime = Date.now() - songInfo.elapsedSeconds * 1000; const songStartTime = Date.now() - songInfo.elapsedSeconds * 1000;
@ -59,13 +118,23 @@ module.exports = (win, {activityTimoutEnabled, activityTimoutTime}) => {
songStartTime + songInfo.songDuration * 1000; songStartTime + songInfo.songDuration * 1000;
} }
rpc.setActivity(activityInfo).catch(console.error); info.rpc.setActivity(activityInfo).catch(console.error);
}); };
});
// Startup the rpc client // If the page is ready, register the callback
rpc.login({ clientId }).catch(console.error); win.once("ready-to-show", () => {
registerCallback(updateActivity);
connect();
}); });
}; };
module.exports.clear = () => rpc.clearActivity(); module.exports.clear = () => {
if (info.rpc) info.rpc.clearActivity();
clearTimeout(clearActivity);
};
module.exports.connect = connect;
module.exports.registerRefresh = (cb) => refreshCallbacks.push(cb);
/**
* @type {Info}
*/
module.exports.info = Object.defineProperties({}, Object.keys(info).reduce((o, k) => ({ ...o, [k]: { enumerable: true, get: () => info[k] } }), {}));

View File

@ -1,13 +1,24 @@
const { setOptions } = require("../../config/plugins"); const { setOptions } = require("../../config/plugins");
const { edit } = require("../../config"); const { edit } = require("../../config");
const { clear } = require("./back"); const { clear, info, connect, registerRefresh } = require("./back");
module.exports = (win, options) => [ let hasRegisterred = false;
module.exports = (win, options, refreshMenu) => {
if (!hasRegisterred) {
registerRefresh(refreshMenu);
hasRegisterred = true;
}
return [
{
label: info.rpc !== null ? "Connected" : "Reconnect",
enabled: info.rpc === null,
click: connect,
},
{ {
label: "Clear activity", label: "Clear activity",
click: () => { click: clear,
clear();
},
}, },
{ {
label: "Clear activity after timeout", label: "Clear activity after timeout",
@ -20,9 +31,8 @@ module.exports = (win, options) => [
}, },
{ {
label: "Set timeout time in config", label: "Set timeout time in config",
click: () => {
// open config.json // open config.json
edit(); click: edit,
},
}, },
]; ];
};

View File

@ -40,6 +40,9 @@ const getArtist = async (win) => {
} }
// Fill songInfo with empty values // Fill songInfo with empty values
/**
* @typedef {songInfo} SongInfo
*/
const songInfo = { const songInfo = {
title: "", title: "",
artist: "", artist: "",
@ -71,6 +74,14 @@ const handleData = async (responseText, win) => {
const callbacks = []; const callbacks = [];
// This function will allow plugins to register callback that will be triggered when data changes // This function will allow plugins to register callback that will be triggered when data changes
/**
* @callback songInfoCallback
* @param {songInfo} songInfo
* @returns {void}
*/
/**
* @param {songInfoCallback} callback
*/
const registerCallback = (callback) => { const registerCallback = (callback) => {
callbacks.push(callback); callbacks.push(callback);
}; };