Skip to content

Commit

Permalink
Merge pull request #961 from xhayper/patch-1
Browse files Browse the repository at this point in the history
feat: auto reconnect rpc and CSP fix
  • Loading branch information
th-ch authored Feb 12, 2023
2 parents 6577bcd + 7282a22 commit 0e68344
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 40 deletions.
3 changes: 2 additions & 1 deletion config/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const defaultConfig = {
},
discord: {
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
activityTimoutTime: 10 * 60 * 1000, // 10 minutes
listenAlong: true, // add a "listen along" button to rich presence
Expand All @@ -54,7 +55,7 @@ const defaultConfig = {
notifications: {
enabled: false,
unpauseNotification: false,
urgency: "normal", //has effect only on Linux
urgency: "normal", //has effect only on Linux
interactive: false //has effect only on Windows
},
"precise-volume": {
Expand Down
9 changes: 4 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,13 +486,12 @@ function removeContentSecurityPolicy(

// Custom listener to tweak the content security policy
session.webRequest.onHeadersReceived(function (details, callback) {
if (
!details.responseHeaders["content-security-policy-report-only"] &&
!details.responseHeaders["content-security-policy"]
)
return callback({ cancel: false });
details.responseHeaders ??= {}

// Remove the content security policy
delete details.responseHeaders["content-security-policy-report-only"];
delete details.responseHeaders["content-security-policy"];

callback({ cancel: false, responseHeaders: details.responseHeaders });
});

Expand Down
9 changes: 2 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,21 @@
},
"engines": {
"node": ">=16.0.0",
"npm": "Please use yarn and not npm"
"npm": "Please use yarn instead"
},
"dependencies": {
"@cliqz/adblocker-electron": "^1.25.2",
"@ffmpeg/core": "^0.11.0",
"@ffmpeg/ffmpeg": "^0.11.6",
"@foobar404/wave": "^2.0.4",
"@xhayper/discord-rpc": "^1.0.15",
"async-mutex": "^0.4.0",
"browser-id3-writer": "^4.4.0",
"butterchurn": "^2.6.7",
"butterchurn-presets": "^2.4.7",
"chokidar": "^3.5.3",
"custom-electron-prompt": "^1.5.1",
"custom-electron-titlebar": "^4.1.5",
"discord-rpc": "^4.0.1",
"electron-better-web-request": "^1.0.1",
"electron-debug": "^3.2.0",
"electron-is": "^3.0.0",
Expand Down Expand Up @@ -140,11 +140,6 @@
"playwright": "^1.29.2",
"xo": "^0.53.1"
},
"resolutions": {
"glob-parent": "5.1.2",
"minimist": "1.2.7",
"yargs-parser": "21.1.1"
},
"auto-changelog": {
"hideCredit": true,
"package": true,
Expand Down
2 changes: 1 addition & 1 deletion plugins/adblocker/preload.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = () => {
// Preload adblocker to inject scripts/styles
require("@cliqz/adblocker-electron-preload/dist/preload.cjs");
require("@cliqz/adblocker-electron-preload");
};
78 changes: 52 additions & 26 deletions plugins/discord/back.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const Discord = require("discord-rpc");
"use strict";
const Discord = require("@xhayper/discord-rpc");
const { dev } = require("electron-is");
const { dialog, app } = require("electron");

Expand All @@ -9,58 +10,81 @@ const clientId = "1043858434585526382";

/**
* @typedef {Object} Info
* @property {import('discord-rpc').Client} rpc
* @property {import('@xhayper/discord-rpc').Client} rpc
* @property {boolean} ready
* @property {boolean} autoReconnect
* @property {import('../../providers/song-info').SongInfo} lastSongInfo
*/
/**
* @type {Info}
*/
const info = {
rpc: null,
rpc: new Discord.Client({
clientId
}),
ready: false,
autoReconnect: true,
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());
};

info.rpc.on("connected", () => {
if (dev()) console.log("discord connected");
refreshCallbacks.forEach(cb => cb());
});

info.rpc.on("ready", () => {
info.ready = true;
if (info.lastSongInfo) updateActivity(info.lastSongInfo)
});

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) {
if (info.rpc.isConnected) {
if (dev())
console.log('Attempted to connect with active RPC object');
console.log('Attempted to connect with active connection');
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);
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' });
});
};

Expand All @@ -70,7 +94,9 @@ let clearActivity;
*/
let updateActivity;

module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong, hideDurationLeft }) => {
module.exports = (win, { autoReconnect, activityTimoutEnabled, activityTimoutTime, listenAlong, hideDurationLeft }) => {
info.autoReconnect = autoReconnect;

window = win;
// We get multiple events
// Next song: PAUSE(n), PAUSE(n+1), PLAY(n+1)
Expand All @@ -92,15 +118,14 @@ module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong,

// clear directly if timeout is 0
if (songInfo.isPaused && activityTimoutEnabled && activityTimoutTime === 0) {
info.rpc.clearActivity().catch(console.error);
info.rpc.user?.clearActivity().catch(console.error);
return;
}

// Song information changed, so lets update the rich presence
// @see https://discord.com/developers/docs/topics/gateway#activity-object
// not all options are transfered through https:/discordjs/RPC/blob/6f83d8d812c87cb7ae22064acd132600407d7d05/src/client.js#L518-530
const activityInfo = {
type: 2, // Listening, addressed in https:/discordjs/RPC/pull/149
details: songInfo.title,
state: songInfo.artist,
largeImageKey: songInfo.imageSrc,
Expand All @@ -116,7 +141,7 @@ module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong,
activityInfo.smallImageText = "Paused";
// Set start the timer so the activity gets cleared after a while if enabled
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) {
// Add the start and end time of the song
const songStartTime = Date.now() - songInfo.elapsedSeconds * 1000;
Expand All @@ -125,7 +150,7 @@ module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong,
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
Expand All @@ -137,9 +162,10 @@ module.exports = (win, { activityTimoutEnabled, activityTimoutTime, listenAlong,
};

module.exports.clear = () => {
if (info.rpc) info.rpc.clearActivity();
if (info.rpc) info.rpc.user?.clearActivity();
clearTimeout(clearActivity);
};

module.exports.connect = connect;
module.exports.registerRefresh = (cb) => refreshCallbacks.push(cb);
module.exports.isConnected = () => info.rpc !== null;
9 changes: 9 additions & 0 deletions plugins/discord/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ module.exports = (win, options, refreshMenu) => {
enabled: !isConnected(),
click: connect,
},
{
label: "Auto reconnect",
type: "checkbox",
checked: options.autoReconnect,
click: (item) => {
options.autoReconnect = item.checked;
setMenuOptions('discord', options);
},
},
{
label: "Clear activity",
click: clear,
Expand Down

0 comments on commit 0e68344

Please sign in to comment.