feat: auto reconnect rpc and CSP fix

This commit is contained in:
xhayper
2023-01-12 01:41:50 +07:00
parent 3a822f611a
commit dbfddebbc2
4 changed files with 71 additions and 27 deletions

View File

@ -46,6 +46,7 @@ const defaultConfig = {
}, },
discord: { discord: {
enabled: false, enabled: false,
autoReconnect: true, // if enabled, will try to reconnect to discord every 5 seconds after disconnecting or failing to connect
activityTimoutEnabled: true, // if enabled, the discord rich presence gets cleared when music paused after the time specified below activityTimoutEnabled: true, // if enabled, the discord rich presence gets cleared when music paused after the time specified below
activityTimoutTime: 10 * 60 * 1000, // 10 minutes activityTimoutTime: 10 * 60 * 1000, // 10 minutes
listenAlong: true, // add a "listen along" button to rich presence listenAlong: true, // add a "listen along" button to rich presence

View File

@ -258,6 +258,15 @@ function createMainWindow() {
} }
app.once("browser-window-created", (event, win) => { app.once("browser-window-created", (event, win) => {
electron.session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
"Content-Security-Policy": ["default-src 'self' music.youtube.com youtube.com accounts.google.com google.com"]
}
})
})
if (config.get("options.overrideUserAgent")) { if (config.get("options.overrideUserAgent")) {
// User agents are from https://developers.whatismybrowser.com/useragents/explore/ // User agents are from https://developers.whatismybrowser.com/useragents/explore/
const originalUserAgent = win.webContents.userAgent; const originalUserAgent = win.webContents.userAgent;

View File

@ -1,4 +1,4 @@
const Discord = require("discord-rpc"); const Discord = require("@xhayper/discord-rpc");
const { dev } = require("electron-is"); const { dev } = require("electron-is");
const { dialog, app } = require("electron"); const { dialog, app } = require("electron");
@ -9,58 +9,81 @@ const clientId = "1043858434585526382";
/** /**
* @typedef {Object} Info * @typedef {Object} Info
* @property {import('discord-rpc').Client} rpc * @property {import('@xhayper/discord-rpc').Client} rpc
* @property {boolean} ready * @property {boolean} ready
* @property {boolean} autoReconnect
* @property {import('../../providers/song-info').SongInfo} lastSongInfo * @property {import('../../providers/song-info').SongInfo} lastSongInfo
*/ */
/** /**
* @type {Info} * @type {Info}
*/ */
const info = { const info = {
rpc: null, rpc: new Discord.Client({
clientId
}),
ready: false, ready: false,
autoReconnect: true,
lastSongInfo: null, lastSongInfo: null,
}; };
/** /**
* @type {(() => void)[]} * @type {(() => void)[]}
*/ */
const refreshCallbacks = []; const refreshCallbacks = [];
const resetInfo = () => { const resetInfo = () => {
info.rpc = null;
info.ready = false; info.ready = false;
clearTimeout(clearActivity); clearTimeout(clearActivity);
if (dev()) console.log("discord disconnected"); if (dev()) console.log("discord disconnected");
refreshCallbacks.forEach(cb => cb()); refreshCallbacks.forEach(cb => cb());
}; };
let window; info.rpc.on("connected", () => {
const connect = (showErr = false) => {
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"); if (dev()) console.log("discord connected");
refreshCallbacks.forEach(cb => cb()); refreshCallbacks.forEach(cb => cb());
}); });
info.rpc.once("ready", () => {
info.rpc.on("ready", () => {
info.ready = true; info.ready = true;
if (info.lastSongInfo) updateActivity(info.lastSongInfo) if (info.lastSongInfo) updateActivity(info.lastSongInfo)
}); });
info.rpc.once("disconnected", resetInfo);
info.rpc.on("disconnected", () => {
resetInfo();
if (info.autoReconnect) {
connectTimeout();
}
});
const connectTimeout = () => new Promise((resolve, reject) => setTimeout(() => {
if (!info.autoReconnect || info.rpc.isConnected) return;
info.rpc.login().then(resolve).catch(reject);
}, 5000));
const connectRecursive = () => {
if (!info.autoReconnect || info.rpc.isConnected) return;
connectTimeout().catch(connectRecursive);
}
let window;
const connect = (showErr = false) => {
if (info.rpc.isConnected) {
if (dev())
console.log('Attempted to connect with active connection');
return;
}
info.ready = false;
// Startup the rpc client // Startup the rpc client
info.rpc.login({ clientId }).catch(err => { info.rpc.login({ clientId }).catch(err => {
resetInfo(); resetInfo();
if (dev()) console.error(err); if (dev()) console.error(err);
if (showErr) dialog.showMessageBox(window, { title: 'Connection failed', message: err.message || String(err), type: 'error' }); if (info.autoReconnect) {
connectRecursive();
}
else if (showErr) dialog.showMessageBox(window, { title: 'Connection failed', message: err.message || String(err), type: 'error' });
}); });
}; };
@ -70,7 +93,9 @@ let clearActivity;
*/ */
let updateActivity; let updateActivity;
module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong, hideDurationLeft }) => { module.exports = (win, { autoReconnect, activityTimoutEnabled, activityTimoutTime, listenAlong, hideDurationLeft }) => {
info.autoReconnect = autoReconnect;
window = win; window = win;
// 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)
@ -92,7 +117,7 @@ module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong,
// clear directly if timeout is 0 // clear directly if timeout is 0
if (songInfo.isPaused && activityTimoutEnabled && activityTimoutTime === 0) { if (songInfo.isPaused && activityTimoutEnabled && activityTimoutTime === 0) {
info.rpc.clearActivity().catch(console.error); info.rpc.user?.clearActivity().catch(console.error);
return; return;
} }
@ -100,7 +125,6 @@ module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong,
// @see https://discord.com/developers/docs/topics/gateway#activity-object // @see https://discord.com/developers/docs/topics/gateway#activity-object
// not all options are transfered through https://github.com/discordjs/RPC/blob/6f83d8d812c87cb7ae22064acd132600407d7d05/src/client.js#L518-530 // not all options are transfered through https://github.com/discordjs/RPC/blob/6f83d8d812c87cb7ae22064acd132600407d7d05/src/client.js#L518-530
const activityInfo = { const activityInfo = {
type: 2, // Listening, addressed in https://github.com/discordjs/RPC/pull/149
details: songInfo.title, details: songInfo.title,
state: songInfo.artist, state: songInfo.artist,
largeImageKey: songInfo.imageSrc, largeImageKey: songInfo.imageSrc,
@ -116,7 +140,7 @@ module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong,
activityInfo.smallImageText = "Paused"; activityInfo.smallImageText = "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(() => info.rpc.clearActivity().catch(console.error), activityTimoutTime ?? 10000); clearActivity = setTimeout(() => info.rpc.user?.clearActivity().catch(console.error), activityTimoutTime ?? 10000);
} else if (!hideDurationLeft) { } else if (!hideDurationLeft) {
// 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;
@ -125,7 +149,7 @@ module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong,
songStartTime + songInfo.songDuration * 1000; songStartTime + songInfo.songDuration * 1000;
} }
info.rpc.setActivity(activityInfo).catch(console.error); info.rpc.user?.setActivity(activityInfo).catch(console.error);
}; };
// If the page is ready, register the callback // If the page is ready, register the callback
@ -140,6 +164,7 @@ module.exports.clear = () => {
if (info.rpc) info.rpc.clearActivity(); if (info.rpc) info.rpc.clearActivity();
clearTimeout(clearActivity); clearTimeout(clearActivity);
}; };
module.exports.connect = connect; module.exports.connect = connect;
module.exports.registerRefresh = (cb) => refreshCallbacks.push(cb); module.exports.registerRefresh = (cb) => refreshCallbacks.push(cb);
module.exports.isConnected = () => info.rpc !== null; module.exports.isConnected = () => info.rpc !== null;

View File

@ -18,6 +18,15 @@ module.exports = (win, options, refreshMenu) => {
enabled: !isConnected(), enabled: !isConnected(),
click: connect, click: connect,
}, },
{
label: "Auto reconnect",
type: "checkbox",
checked: options.autoReconnect,
click: (item) => {
options.autoReconnect = item.checked;
setMenuOptions('discord', options);
},
},
{ {
label: "Clear activity", label: "Clear activity",
click: clear, click: clear,