Fix for latest discord update (#1217)

* Push

* Suppress Crashing
This commit is contained in:
Strencher 2022-02-16 03:23:14 +01:00 committed by GitHub
parent 67746d59ee
commit c71f9339de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 4 deletions

View File

@ -244,6 +244,36 @@ export default class WebpackModules {
return this.getModule(Filters.byString(...strings), false);
}
/**
* Finds a module that lazily loaded.
* @param {(m) => boolean} filter A function to use to filter modules.
* @returns {Promise<any>}
*/
static getLazy(filter) {
const fromCache = this.getModule(filter);
if (fromCache) return Promise.resolve(fromCache);
return new Promise((resolve) => {
const cancel = () => {this.removeListener(listener)};
const listener = function (m) {
const directMatch = filter(m);
if (directMatch) {
cancel();
return resolve(directMatch);
}
const defaultMatch = filter(m.default);
if (!defaultMatch) return;
cancel();
resolve(m.default);
};
this.addListener(listener);
});
}
/**
* Discord's __webpack_require__ function.
*/
@ -276,4 +306,75 @@ export default class WebpackModules {
return this.require.c;
}
}
// Webpack Chunk Observing
static get chunkName() {return "webpackChunkdiscord_app";}
static initialize() {
this.handlePush = this.handlePush.bind(this);
this.listeners = new Set();
this.__ORIGINAL_PUSH__ = window[this.chunkName].push;
Object.defineProperty(window[this.chunkName], "push", {
configurable: true,
get: () => this.handlePush,
set: (newPush) => {
this.__ORIGINAL_PUSH__ = newPush;
Object.defineProperty(window[this.chunkName], "push", {
value: this.handlePush,
configurable: true,
writable: true
});
}
});
}
/**
* Adds a listener for when discord loaded a chunk. Useful for subscribing to lazy loaded modules.
* @param {Function} listener - Function to subscribe for chunks
* @returns {Function} A cancelling function
*/
static addListener(listener) {
this.listeners.add(listener);
return this.removeListener.bind(this, listener);
}
/**
* Removes a listener for when discord loaded a chunk.
* @param {Function} listener
* @returns {boolean}
*/
static removeListener(listener) {return this.listeners.delete(listener);}
static handlePush(chunk) {
const [, modules] = chunk;
for (const moduleId in modules) {
const originalModule = modules[moduleId];
modules[moduleId] = (module, exports, require) => {
try {
Reflect.apply(originalModule, null, [module, exports, require]);
const listeners = [...this.listeners];
for (let i = 0; i < listeners.length; i++) {
try {listeners[i](exports);}
catch (error) {
Logger.err("WebpackModules", "Could not fire callback listener:", error);
}
}
} catch (error) {
console.error(error);
}
};
Object.assign(modules[moduleId], originalModule, {
toString: () => originalModule.toString()
});
}
return Reflect.apply(this.__ORIGINAL_PUSH__, window[this.chunkName], [chunk]);
}
}
WebpackModules.initialize();

View File

@ -4,6 +4,7 @@ import AddonList from "./settings/addonlist";
import SettingsGroup from "./settings/group";
import SettingsTitle from "./settings/title";
import Header from "./settings/sidebarheader";
import {Filters} from "../modules/webpackmodules";
export default new class SettingsRenderer {
@ -60,8 +61,9 @@ export default new class SettingsRenderer {
}, options));
}
patchSections() {
const UserSettings = WebpackModules.getByDisplayName("SettingsView");
async patchSections() {
const UserSettings = await WebpackModules.getLazy(Filters.byDisplayName("SettingsView"));
Patcher.after("SettingsManager", UserSettings.prototype, "getPredicateSections", (thisObject, args, returnValue) => {
let location = returnValue.findIndex(s => s.section.toLowerCase() == "changelog") - 1;
if (location < 0) return;
@ -91,7 +93,7 @@ export default new class SettingsRenderer {
}
forceUpdate() {
const viewClass = WebpackModules.getByProps("standardSidebarView").standardSidebarView.split(" ")[0];
const viewClass = WebpackModules.getByProps("standardSidebarView")?.standardSidebarView.split(" ")[0];
const node = document.querySelector(`.${viewClass}`);
if (!node) return;
const stateNode = Utilities.findInReactTree(Utilities.getReactInstance(node), m => m && m.getPredicateSections, {walkable: ["return", "stateNode"]});