Add a few small features

- Fixes colored text
- Fixes detach window not showing saved css (closes #635)
- Adds option to prevent Discord from hijacking the media keys (closes #410)
- Adds command line flag to launch a vanilla version of Discord `--vanilla` (closes #337)
- Adds option for app-wide ctrl+shift+c shortcut for inspect element (closes #349)
- Adds emote blocklist to BdApi via `BdApi.Emotes.blocklist` (closes #408)
This commit is contained in:
Zack Rauen 2021-04-02 23:16:23 -04:00
parent 59d9ec3dea
commit a223806060
18 changed files with 136 additions and 70 deletions

View File

@ -8,4 +8,5 @@ export const RUN_SCRIPT = "bd-run-script";
export const NAVIGATE = "bd-did-navigate-in-page";
export const OPEN_DEVTOOLS = "bd-open-devtools";
export const CLOSE_DEVTOOLS = "bd-close-devtools";
export const OPEN_WINDOW = "bd-open-window";
export const OPEN_WINDOW = "bd-open-window";
export const INSPECT_ELEMENT = "bd-inspect-element";

View File

@ -1,34 +1,35 @@
const path = require("path");
const electron = require("electron");
const Module = require("module");
import path from "path";
import {app} from "electron";
import Module from "module";
import ipc from "./modules/ipc";
import BrowserWindow from "./modules/browserwindow";
import CSP from "./modules/csp";
process.env.NODE_OPTIONS = "--no-force-async-hooks-checks";
electron.app.commandLine.appendSwitch("no-force-async-hooks-checks");
process.electronBinding("command_line").appendSwitch("no-force-async-hooks-checks");
if (!process.argv.includes("--vanilla")) {
process.env.NODE_OPTIONS = "--no-force-async-hooks-checks";
app.commandLine.appendSwitch("no-force-async-hooks-checks");
process.electronBinding("command_line").appendSwitch("no-force-async-hooks-checks");
// Patch and replace the built-in BrowserWindow
BrowserWindow.patchBrowserWindow();
// Patch and replace the built-in BrowserWindow
BrowserWindow.patchBrowserWindow();
// Register all IPC events
ipc.registerEvents();
// Register all IPC events
ipc.registerEvents();
// Remove CSP immediately on linux since they install to discord_desktop_core still
if (process.platform == "win32" || process.platform == "darwin") electron.app.once("ready", CSP.remove);
else CSP.remove();
// Remove CSP immediately on linux since they install to discord_desktop_core still
if (process.platform == "win32" || process.platform == "darwin") app.once("ready", CSP.remove);
else CSP.remove();
}
// Use Discord's info to run the app
if (process.platform == "win32" || process.platform == "darwin") {
const basePath = path.join(electron.app.getAppPath(), "..", "app.asar");
const basePath = path.join(app.getAppPath(), "..", "app.asar");
const pkg = __non_webpack_require__(path.join(basePath, "package.json"));
electron.app.setAppPath(basePath);
electron.app.name = pkg.name;
app.setAppPath(basePath);
app.name = pkg.name;
Module._load(path.join(basePath, pkg.main), null, true);
}

View File

@ -1,6 +1,6 @@
const fs = require("fs");
const path = require("path");
const electron = require("electron");
import fs from "fs";
import path from "path";
import electron from "electron";
import ReactDevTools from "./reactdevtools";
import * as IPCEvents from "common/constants/ipcevents";
@ -21,8 +21,12 @@ electron.app.once("ready", async () => {
await ReactDevTools.install();
});
let hasCrashed = false;
if (BetterDiscord.getSetting("general", "mediaKeys")) {
electron.app.commandLine.appendSwitch("disable-features", "HardwareMediaKeyHandling,MediaSessionService");
}
let hasCrashed = false;
export default class BetterDiscord {
static getWindowPrefs() {
if (!fs.existsSync(buildInfoFile)) return {};
@ -37,7 +41,7 @@ export default class BetterDiscord {
try {
const buildInfo = __non_webpack_require__(buildInfoFile);
const settingsFile = path.resolve(dataPath, "data", buildInfo.releaseChannel, "settings.json");
const settingsFile = path.resolve(dataPath, "data", buildInfo.releaseChannel, "settings.json");
this._settings = __non_webpack_require__(settingsFile) ?? {};
return this._settings[category]?.[key];
}

View File

@ -1,5 +1,5 @@
const electron = require("electron");
const path = require("path");
import electron from "electron";
import path from "path";
import BetterDiscord from "./betterdiscord";

View File

@ -1,4 +1,4 @@
const electron = require("electron");
import electron from "electron";
export default class {
static remove() {

View File

@ -8,20 +8,20 @@ const getPath = (event, pathReq) => {
case "appPath":
returnPath = app.getAppPath();
break;
case "appData":
case "userData":
case "home":
case "cache":
case "temp":
case "exe":
case "module":
case "desktop":
case "documents":
case "downloads":
case "music":
case "pictures":
case "videos":
case "recent":
case "appData":
case "userData":
case "home":
case "cache":
case "temp":
case "exe":
case "module":
case "desktop":
case "documents":
case "downloads":
case "music":
case "pictures":
case "videos":
case "recent":
case "logs":
returnPath = app.getPath(pathReq);
break;
@ -62,12 +62,21 @@ const createBrowserWindow = async (event, url, {windowOptions, closeOnUrl} = {})
});
};
const inspectElement = async event => {
if (!event.sender.isDevToolsOpened()) {
event.sender.openDevTools();
while (!event.sender.isDevToolsOpened()) await new Promise(r => setTimeout(r, 100));
}
event.sender.devToolsWebContents.executeJavaScript("DevToolsAPI.enterInspectElementMode();");
};
export default class IPCMain {
static registerEvents() {
ipc.on(IPCEvents.GET_PATH, getPath);
ipc.on(IPCEvents.RELAUNCH, relaunch);
ipc.on(IPCEvents.OPEN_DEVTOOLS, openDevTools);
ipc.on(IPCEvents.CLOSE_DEVTOOLS, closeDevTools);
ipc.on(IPCEvents.INSPECT_ELEMENT, inspectElement);
ipc.handle(IPCEvents.RUN_SCRIPT, runScript);
ipc.handle(IPCEvents.OPEN_WINDOW, createBrowserWindow);
}

View File

@ -6174,9 +6174,9 @@
}
},
"y18n": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.4.tgz",
"integrity": "sha512-deLOfD+RvFgrpAmSZgfGdWYE+OKyHcVHaRQ7NphG/63scpRvTHHeQMAxGGvaLVGJ+HYVcCXlzcTK0ZehFf+eHQ==",
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz",
"integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==",
"dev": true
},
"yargs": {
@ -8812,8 +8812,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"optional": true
"dev": true
},
"readdirp": {
"version": "3.4.0",

View File

@ -18,24 +18,10 @@ export default new class ColoredText extends Builtin {
}
injectColoredText() {
const MessageContent = WebpackModules.getModule(m => m.default && m.default.displayName && m.default.displayName == "Message");
this.before(MessageContent, "default", (thisObject, [props]) => {
if (!props || !props.childrenMessageContent) return;
const messageContent = props.childrenMessageContent;
if (!messageContent.type || !messageContent.type.type || messageContent.type.type.displayName != "MessageContent") return;
const originalType = messageContent.type.type;
if (originalType.__originalMethod) return; // Don't patch again
const self = this;
messageContent.type.type = function (childProps) {
const returnValue = originalType(childProps);
const roleColor = self.getRoleColor(childProps.message.channel_id, childProps.message.author.id) || "";
returnValue.props.style = {color: roleColor};
return returnValue;
};
messageContent.type.type.__originalMethod = originalType;
Object.assign(messageContent.type.type, originalType);
const MessageContent = WebpackModules.getModule(m => m.type && m.type.displayName === "MessageContent");
this.after(MessageContent, "type", (thisObject, [props], returnValue) => {
const roleColor = this.getRoleColor(props.message.channel_id, props.message.author.id) || "";
returnValue.props.style = {color: roleColor};
});
}

View File

@ -6,6 +6,7 @@ export {default as WindowPrefs} from "./windowprefs";
export {default as ClassNormalizer} from "./general/classnormalizer";
export {default as PublicServers} from "./general/publicservers";
export {default as VoiceDisconnect} from "./general/voicedisconnect";
export {default as MediaKeys} from "./general/mediakeys";
export {default as TwentyFourHour} from "./appearance/24hour";
export {default as ColoredText} from "./appearance/coloredtext";
@ -18,4 +19,5 @@ export {default as EmoteMenu} from "./emotes/emotemenu";
// export {default as EmoteAutocaps} from "./emotes/emoteautocaps";
export {default as Debugger} from "./developer/debugger";
export {default as ReactDevTools} from "./developer/reactdevtools";
export {default as ReactDevTools} from "./developer/reactdevtools";
export {default as InspectElement} from "./developer/inspectelement";

View File

@ -71,7 +71,7 @@ export default new class CustomCSS extends Builtin {
onClick: (thisObject) => {
if (this.isDetached) return;
if (this.nativeOpen) return this.openNative();
else if (this.startDetached) return this.openDetached();
else if (this.startDetached) return this.openDetached(this.savedCss);
const settingsView = Utilities.findInRenderTree(thisObject._reactInternalFiber, m => m && m.onSetSection, {walkable: ["child", "memoizedProps", "props", "children"]});
if (settingsView && settingsView.onSetSection) settingsView.onSetSection(this.id);
}

View File

@ -0,0 +1,22 @@
import Builtin from "../../structs/builtin";
import IPC from "../../modules/ipc";
export default new class InspectElement extends Builtin {
get name() {return "InspectElementHotkey";}
get category() {return "developer";}
get id() {return "inspectElement";}
enabled() {
document.addEventListener("keydown", this.inspectElement);
}
disabled() {
document.removeEventListener("keydown", this.inspectElement);
}
inspectElement(e) {
if (e.ctrlKey && e.shiftKey && e.which === 67) { // Ctrl + Shift + C
IPC.inspectElement();
}
}
};

View File

@ -37,7 +37,7 @@ export default new class EmoteModule extends Builtin {
get(id) {return super.get("emotes", "general", id);}
get MessageComponent() {return WebpackModules.find(m => m.default && m.default.displayName && m.default.displayName == "Message");}
get MessageComponent() {return WebpackModules.find(m => m.default && m.default.toString().search("childrenRepliedMessage") > -1);}
get Emotes() {return Emotes;}
get TwitchGlobal() {return Emotes.TwitchGlobal;}

View File

@ -0,0 +1,27 @@
import Builtin from "../../structs/builtin";
import Modals from "../../ui/modals";
import {Strings, IPC} from "modules";
export default new class MediaKeys extends Builtin {
get name() {return "DisableMediaKeys";}
get category() {return "general";}
get id() {return "mediaKeys";}
enabled() {
this.showModal();
}
disabled() {
this.showModal();
}
showModal() {
if (!this.initialized) return;
Modals.showConfirmationModal(Strings.Modals.additionalInfo, Strings.Modals.restartPrompt, {
confirmText: Strings.Modals.restartNow,
cancelText: Strings.Modals.restartLater,
danger: true,
onConfirm: () => IPC.relaunch()
});
}
};

View File

@ -1,6 +1,6 @@
import Builtin from "../structs/builtin";
import Modals from "../ui/modals";
import {DataStore, Strings, IPC} from "modules";
import {Strings, IPC} from "modules";
export default new class WindowPrefs extends Builtin {
get name() {return "WindowPrefs";}

View File

@ -8,7 +8,8 @@ export default [
{type: "switch", id: "publicServers", value: true},
{type: "switch", id: "voiceDisconnect", value: false},
{type: "switch", id: "classNormalizer", value: false},
{type: "switch", id: "showToasts", value: true}
{type: "switch", id: "showToasts", value: true},
{type: "switch", id: "mediaKeys", value: false}
]
},
{
@ -52,7 +53,8 @@ export default [
shown: false,
settings: [
{type: "switch", id: "debuggerHotkey", value: false},
{type: "switch", id: "reactDevTools", value: false}
{type: "switch", id: "reactDevTools", value: false},
{type: "switch", id: "inspectElement", value: false}
]
},
{

View File

@ -109,6 +109,10 @@ export default {
reactDevTools: {
name: "React Developer Tools",
note: "Injects your local installation of React Developer Tools into Discord"
},
inspectElement: {
name: "Inspect Element Hotkey",
note: "Enables the inspect element hotkey (ctrl + shift + c) that is common in most browsers"
}
},
window: {
@ -150,6 +154,10 @@ export default {
animateOnHover: {
name: "Animate On Hover",
note: "Only animate the emote modifiers on hover"
},
mediaKeys: {
name: "Disable Media Keys",
note: "Prevents Discord from hijacking your media keys after playing a video."
}
},
categories: {
@ -269,7 +277,7 @@ export default {
},
ReactDevTools: {
notFound: "Extension Not Found",
notFoundDetails: "Unable to find the React Developer Tools extension on your PC. Please install the extension on your local Chrome installation."
notFoundDetails: "Unable to find the React Developer Tools extension on your PC. Please install the extension on your local Chrome installation."
},
Sorting: {
sortBy: "Sort By",

View File

@ -31,4 +31,8 @@ export default new class IPCRenderer {
openWindow(url, options) {
return ipc.invoke(IPCEvents.OPEN_WINDOW, url, options);
}
inspectElement() {
ipc.send(IPCEvents.INSPECT_ELEMENT);
}
};

View File

@ -21,6 +21,7 @@ const BdApi = {
get emotes() {
return new Proxy(Emotes.Emotes, {
get(category) {
if (category === "blocklist") return Emotes.blocklist;
const group = Emotes.Emotes[category];
if (!group) return undefined;
return new Proxy(group, {