-
Notifications
You must be signed in to change notification settings - Fork 559
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into custom-electron-prompt
- Loading branch information
Showing
20 changed files
with
834 additions
and
229 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,151 @@ | ||
const Discord = require("discord-rpc"); | ||
const { dev } = require("electron-is"); | ||
const { dialog } = require("electron"); | ||
|
||
const registerCallback = require("../../providers/song-info"); | ||
|
||
const rpc = new Discord.Client({ | ||
transport: "ipc", | ||
}); | ||
|
||
// Application ID registered by @semvis123 | ||
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()); | ||
}; | ||
|
||
let window; | ||
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"); | ||
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' }); | ||
}); | ||
}; | ||
|
||
let clearActivity; | ||
/** | ||
* @type {import('../../providers/song-info').songInfoCallback} | ||
*/ | ||
let updateActivity; | ||
|
||
module.exports = (win, {activityTimoutEnabled, activityTimoutTime, listenAlong}) => { | ||
window = win; | ||
// We get multiple events | ||
// Next song: PAUSE(n), PAUSE(n+1), PLAY(n+1) | ||
// Skip time: PAUSE(N), PLAY(N) | ||
updateActivity = songInfo => { | ||
if (songInfo.title.length === 0 && songInfo.artist.length === 0) { | ||
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 | ||
// @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 | ||
const activityInfo = { | ||
type: 2, // Listening, addressed in https://github.com/discordjs/RPC/pull/149 | ||
details: songInfo.title, | ||
state: songInfo.artist, | ||
largeImageKey: "logo", | ||
largeImageText: [ | ||
songInfo.uploadDate, | ||
songInfo.views.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " views", | ||
].join(' || '), | ||
buttons: listenAlong ? [ | ||
{ label: "Listen Along", url: songInfo.url }, | ||
] : undefined, | ||
}; | ||
|
||
if (songInfo.isPaused) { | ||
// Add an idle icon to show that the song is paused | ||
activityInfo.smallImageKey = "idle"; | ||
activityInfo.smallImageText = "idle/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); | ||
} else { | ||
// Add the start and end time of the song | ||
const songStartTime = Date.now() - songInfo.elapsedSeconds * 1000; | ||
activityInfo.startTimestamp = songStartTime; | ||
activityInfo.endTimestamp = | ||
songStartTime + songInfo.songDuration * 1000; | ||
} | ||
|
||
info.rpc.setActivity(activityInfo).catch(console.error); | ||
}; | ||
|
||
module.exports = (win, {activityTimoutEnabled, activityTimoutTime}) => { | ||
// If the page is ready, register the callback | ||
win.once("ready-to-show", () => { | ||
rpc.once("ready", () => { | ||
// Register the callback | ||
registerCallback((songInfo) => { | ||
if (songInfo.title.length === 0 && songInfo.artist.length === 0) { | ||
return; | ||
} | ||
// Song information changed, so lets update the rich presence | ||
const activityInfo = { | ||
details: songInfo.title, | ||
state: songInfo.artist, | ||
largeImageKey: "logo", | ||
largeImageText: [ | ||
songInfo.uploadDate, | ||
songInfo.views.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " views" | ||
].join(' || '), | ||
}; | ||
|
||
if (songInfo.isPaused) { | ||
// Add an idle icon to show that the song is paused | ||
activityInfo.smallImageKey = "idle"; | ||
activityInfo.smallImageText = "idle/paused"; | ||
// Set start the timer so the activity gets cleared after a while if enabled | ||
if (activityTimoutEnabled) | ||
clearActivity = setTimeout(()=>rpc.clearActivity(), activityTimoutTime||10000); | ||
} else { | ||
// stop the clear activity timout | ||
clearTimeout(clearActivity); | ||
// Add the start and end time of the song | ||
const songStartTime = Date.now() - songInfo.elapsedSeconds * 1000; | ||
activityInfo.startTimestamp = songStartTime; | ||
activityInfo.endTimestamp = | ||
songStartTime + songInfo.songDuration * 1000; | ||
} | ||
|
||
rpc.setActivity(activityInfo); | ||
}); | ||
}); | ||
|
||
// Startup the rpc client | ||
rpc.login({ clientId }).catch(console.error); | ||
registerCallback(updateActivity); | ||
connect(); | ||
}); | ||
win.on("close", () => module.exports.clear()); | ||
}; | ||
|
||
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] } }), {})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
const { setOptions } = require("../../config/plugins"); | ||
const { edit } = require("../../config"); | ||
const { clear, info, connect, registerRefresh } = require("./back"); | ||
|
||
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", | ||
click: clear, | ||
}, | ||
{ | ||
label: "Clear activity after timeout", | ||
type: "checkbox", | ||
checked: options.activityTimoutEnabled, | ||
click: (item) => { | ||
options.activityTimoutEnabled = item.checked; | ||
setOptions('discord', options); | ||
}, | ||
}, | ||
{ | ||
label: "Listen Along", | ||
type: "checkbox", | ||
checked: options.listenAlong, | ||
click: (item) => { | ||
options.listenAlong = item.checked; | ||
setOptions('discord', options); | ||
}, | ||
}, | ||
{ | ||
label: "Set timeout time in config", | ||
// open config.json | ||
click: edit, | ||
}, | ||
]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.