Skip to content

Instantly share code, notes, and snippets.

@Miniontoby
Last active February 23, 2024 10:15
Show Gist options
  • Save Miniontoby/9a7c77538cd3d5a3cdc7324d0e23b351 to your computer and use it in GitHub Desktop.
Save Miniontoby/9a7c77538cd3d5a3cdc7324d0e23b351 to your computer and use it in GitHub Desktop.
AutoStartRichPresence.plugin.js
/**
* @name AutoStartRichPresence
* @version 2.0.10
*
* @author Miniontoby
* @authorId 849180136828960799
* @description Auto starts Rich Presence with configurable settings.
*
* @updateUrl https://raw.githubusercontent.com/Miniontoby/MinionBDStuff/main/Plugins/AutoStartRichPresence/AutoStartRichPresence.plugin.js
* @source https://raw.githubusercontent.com/Miniontoby/MinionBDStuff/main/Plugins/AutoStartRichPresence/AutoStartRichPresence.plugin.js
* @website https://raw.githubusercontent.com/Miniontoby/MinionBDStuff/main/Plugins/AutoStartRichPresence/
*/
// Updated October 26th, 2023
// Please use https://github.com/Miniontoby/MinionBDStuff/blob/main/Plugins/AutoStartRichPresence/AutoStartRichPresence.plugin.js now!
// It will be on the BD Plugins list now!
/*@cc_on
@if (@_jscript)
// Offer to self-install for clueless users that try to run this directly.
var shell = WScript.CreateObject("WScript.Shell");
var fs = new ActiveXObject("Scripting.FileSystemObject");
var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins");
var pathSelf = WScript.ScriptFullName;
// Put the user at ease by addressing them in the first person
shell.Popup("It looks like you mistakenly tried to run me directly. (don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
shell.Popup("I'm in the correct folder already.\nJust reload Discord with Ctrl+R.", 0, "I'm already installed", 0x40);
} else if (!fs.FolderExists(pathPlugins)) {
shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10);
} else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) {
fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
// Show the user where to put plugins in the future
shell.Exec("explorer " + pathPlugins);
shell.Popup("I'm installed!\nJust reload Discord with Ctrl+R.", 0, "Successfully installed", 0x40);
}
WScript.Quit();
@else @*/
const defaultSettings = {
clientID: "1012465934088405062",
disableWhenActivity: false,
enableStartTime: true,
name: "",
details: "",
state: "",
button1Label: "",
button1URL: "",
button2Label: "",
button2URL: "",
smallImageKey: "",
smallImageText: "",
largeImageKey: "",
largeImageText: "",
listeningTo: false,
};
function isURL(url) {
try {
new URL(url);
return true;
} catch (e) {
return false;
}
}
class AutoStartRichPresence {
constructor() {
this.initialized = false;
this.settings = {};
this.startPlaying = Date.now();
this.updateDataInterval = 0;
this.rpc = {};
let filter = BdApi.Webpack.Filters.byStrings("getAssetImage: size must === [number, number] for Twitch");
let assetManager = BdApi.Webpack.getModule(m => typeof m === "object" && Object.values(m).some(filter));
let getAsset;
for (const key in assetManager) {
const member = assetManager[key];
if (member.toString().includes("APPLICATION_ASSETS_FETCH")) { // find the fetchAssetIds
getAsset = member;
break;
}
}
this.getAsset = async key => {
if (getAsset) return (await getAsset(this.settings.clientID, [key, undefined]))[0];
else return "";
};
}
async start() {
this.initialize();
}
initialize() {
console.log("Starting AutoStartRichPresence");
BdApi.showToast("AutoStartRichPresence has started!");
this.updateDataInterval = setInterval(() => this.updateData(), 60*1000); // every 60 seconds
this.settings = BdApi.loadData("AutoStartRichPresence", "settings") || {};
for (const setting of Object.keys(defaultSettings)) {
if (typeof this.settings[setting] === "undefined") this.settings[setting] = defaultSettings[setting];
this.updateSettings();
}
this.getLocalPresence = BdApi.findModuleByProps("getLocalPresence").getLocalPresence;
this.rpc = BdApi.findModuleByProps("dispatch", "_subscriptions");
this.rpcClientInfo = {};
this.discordSetActivityHandler = null;
this.updateRichPresence();
this.initialized = true;
this.request = require("request");
}
async stop() {
clearInterval(this.updateDataInterval);
this.updateDataInterval = 0;
this.initialized = false;
this.setActivity({});
BdApi.showToast("AutoStartRichPresence is stopping!");
}
getSettingsPanel() {
if (!this.initialized) return;
this.settings = BdApi.loadData("AutoStartRichPresence", "settings") || {};
const panel = document.createElement("form");
panel.classList.add("form");
panel.style.setProperty("width", "100%");
this.generateSettings(panel);
return panel;
}
async updateData() {
if (!this.initialized) return;
if(this.settings.disableWhenActivity) {
const activities = this.getLocalPresence().activities;
if(activities.filter(a => a.application_id !== this.settings.ClientID).length) {
if(activities.find(a => a.application_id === this.settings.ClientID)) this.setActivity({});
return;
}
}
setTimeout(() => this.updateRichPresence(), 50);
}
createInput(label, description, type, classname, extrat='text') {
let out = `<b>${label}</b><br><span>${description}</span><br><br>`
if (type == 'onoff') out += `<select class="${classname} inputDefault-Ciwd-S input-3O04eu" style="width:80%"><option value="false">OFF</option><option value="true">ON</option></select>`
if (type == 'input') out += `<input class="${classname} inputDefault-Ciwd-S input-3O04eu" placeholder="${label}" style="width:80%" type="${extrat}">`;
return out + '<br><br>';
}
getSettingsPanel() {
this.settings = BdApi.loadData("AutoStartRichPresence", "settings") || {};
let template = document.createElement("template");
template.innerHTML = `<div style="color: var(--header-primary);font-size: 16px;font-weight: 300;line-height: 22px;max-width: 550px;margin-top: 17px;">
${this.createInput('Client ID', 'Enter your Client ID (get from developers page) [needed for image keys]', 'input', 'clientid', 'number')}
${this.createInput('Activity Name', 'Enter a name for the activity', 'input', 'activityname')}
${this.createInput('Activity Details', 'Enter a description for the activity', 'input', 'activitydetails')}
${this.createInput('Activity State', 'Enter a second description for the activity', 'input', 'activitystate')}
${this.createInput('Activity Button 1 Text', 'Enter Text for button 1', 'input', 'activitybutton1text')}
${this.createInput('Activity Button 1 URL', 'Enter URL for button 1', 'input', 'activitybutton1url')}
${this.createInput('Activity Button 2 Text', 'Enter Text for button 2', 'input', 'activitybutton2text')}
${this.createInput('Activity Button 2 URL', 'Enter URL for button 2', 'input', 'activitybutton2url')}
${this.createInput('Activity Small Image Key', 'Enter Image Key for Small Icon', 'input', 'activityiconsmallimage')}
${this.createInput('Activity Small Image Text', 'Enter Label for Small Icon', 'input', 'activityiconsmalltext')}
${this.createInput('Activity Large Image Key', 'Enter Image Key for Large Icon', 'input', 'activityiconlargeimage')}
${this.createInput('Activity Large Image Text', 'Enter Label for Large Icon', 'input', 'activityiconlargetext')}
${this.createInput('Enable Start Time', 'Enable timestamp which shows the time when started', 'onoff', 'enablestarttime')}
${this.createInput('Listening Status', 'Enable listening status', 'onoff', 'listening')}
${this.createInput('Disable When Activity', 'Disables when there is another activity', 'onoff', 'disableactivity')}
</div>`;
let clientidEl = template.content.firstElementChild.getElementsByClassName('clientid')[0];
let nameEl = template.content.firstElementChild.getElementsByClassName('activityname')[0];
let detailsEl = template.content.firstElementChild.getElementsByClassName('activitydetails')[0];
let stateEl = template.content.firstElementChild.getElementsByClassName('activitystate')[0];
let button1textEl = template.content.firstElementChild.getElementsByClassName('activitybutton1text')[0];
let button1urlEl = template.content.firstElementChild.getElementsByClassName('activitybutton1url')[0];
let button2textEl = template.content.firstElementChild.getElementsByClassName('activitybutton2text')[0];
let button2urlEl = template.content.firstElementChild.getElementsByClassName('activitybutton2url')[0];
let iconsmallkeyEl = template.content.firstElementChild.getElementsByClassName('activityiconsmallimage')[0];
let iconsmalltextEl = template.content.firstElementChild.getElementsByClassName('activityiconsmalltext')[0];
let iconlargekeyEl = template.content.firstElementChild.getElementsByClassName('activityiconlargeimage')[0];
let iconlargetextEl = template.content.firstElementChild.getElementsByClassName('activityiconlargetext')[0];
let enablestarttimeEl = template.content.firstElementChild.getElementsByClassName('enablestarttime')[0];
let listeningEl = template.content.firstElementChild.getElementsByClassName('listening')[0];
let disableEl = template.content.firstElementChild.getElementsByClassName('disableactivity')[0];
let updateSetting = (e, setting) => {
this.settings[setting] = e.target.value;
this.updateSettings();
}
const TextInputs = [["clientID", clientidEl], ["name", nameEl], ["details", detailsEl], ["state", stateEl], ["button1Label", button1textEl], ["button1URL", button1urlEl], ["button2Label", button2textEl], ["button2URL", button2urlEl], ["smallImageKey", iconsmallkeyEl], ["smallImageText", iconsmalltextEl], ["largeImageKey", iconlargekeyEl], ["largeImageText", iconlargetextEl]];
for (const [setting, el] of TextInputs) {
el.value = this.settings[setting] ?? "";
el.onchange = (e) => updateSetting(e, setting);
el.onpaste = (e) => updateSetting(e, setting);
el.onkeydown = (e) => updateSetting(e, setting);
}
const OnOffInputs = [["enableStartTime", enablestarttimeEl], ["listeningTo", listeningEl],["disableWhenActivity", disableEl]];
for (const [setting, el] of OnOffInputs) {
el.value = this.settings[setting] ? "true" : "false";
el.onchange = () => {
this.settings[setting] = el.value === "true";
this.updateSettings();
};
}
return template.content.firstElementChild;
}
setActivity(activity) {
let obj = activity && Object.assign(activity, { flags: 1, type: this.settings.listeningTo ? 2 : 0 });
console.log(obj);
this.rpc.dispatch({
type: "LOCAL_ACTIVITY_UPDATE",
activity: obj
});
}
async updateRichPresence() {
if (this.paused) {
return;
}
let button_urls = [], buttons = [];
if(this.settings.button1Label != "" && this.settings.button1URL != "" && isURL(this.settings.button1URL)) {
buttons.push(this.settings.button1Label);
button_urls.push(this.settings.button1URL);
}
if(this.settings.button2Label != "" && this.settings.button2URL != "" && isURL(this.settings.button2URL)) {
buttons.push(this.settings.button2Label);
button_urls.push(this.settings.button2URL);
}
if (this.settings.enableStartTime) {
if (this.startPlaying == null) this.startPlaying = Date.now();
} else if (this.startPlaying) this.startPlaying = null;
let obj = {
application_id: this.settings.clientID ?? "1012465934088405062",
name: this.settings.name || undefined,
details: this.settings.details || undefined,
state: this.settings.state || undefined,
timestamps: { start: this.startPlaying ? Math.floor(this.startPlaying / 1000) : undefined },
assets: (this.settings.smallImageKey && this.settings.smallImageKey != "") ? {
small_image: await this.getAsset(this.settings.smallImageKey),
small_text: this.settings.smallImageText ?? undefined,
} : {},
metadata: { button_urls }, buttons
}
if(this.settings.largeImageKey && this.settings.largeImageKey != "") {
obj.assets.large_image = await this.getAsset(this.settings.largeImageKey);
obj.assets.large_text = this.settings.largeImageText ?? undefined;
}
this.setActivity(obj);
}
updateSettings() {
BdApi.saveData("AutoStartRichPresence", "settings", this.settings);
this.updateData(); // will return when not initialized
}
}
module.exports = AutoStartRichPresence;
/*@end @*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment