This commit is contained in:
Jiiks 2018-03-12 17:36:11 +02:00
parent 5083a80ba2
commit 6a854ab070
6 changed files with 289 additions and 4 deletions

View File

@ -16,6 +16,9 @@ export default new class extends Module {
constructor(args) {
super(args);
}
initg() {
this.first();
}

View File

@ -0,0 +1,83 @@
import WebpackModules from './webpackmodules';
export default class Patcher {
static get patches() { return this._patches || (this._patches = {}) }
static resolveModule(mn) {
if (mn instanceof Function || (mn instanceof Object && !(mn instanceof Array))) return mn;
if ('string' === typeof mn) return WebpackModules.getModuleByName(mn);
if (mn instanceof Array) return WebpackModules.getModuleByProps(mn);
return null;
}
static overrideFn(patch) {
return function () {
for (const s of patch.supers) {
try {
s.fn.apply(this, arguments);
} catch (err) { }
}
const retVal = patch.ofn.apply(this, arguments);
for (const s of patch.slaves) {
try {
s.fn.apply(this, [arguments, { patch, retVal }]);
} catch (err) { }
}
return retVal;
}
}
static rePatch(po) {
po.patch = po.module[po.fnn] = this.overrideFn(po);
}
static pushPatch(id, module, fnn) {
const patch = {
module,
fnn,
ofn: module[fnn],
revert: () => {
patch.module[patch.fnn] = patch.ofn;
patch.patch = null;
patch.slaves = patch.supers = [];
},
supers: [],
slaves: [],
patch: null
};
patch.patch = module[fnn] = this.overrideFn(patch);
return this.patches[id] = patch;
}
static superpatch(mn, fnn, cb, dn) {
const module = this.resolveModule(mn);
if (!module || !module[fnn] || !(module[fnn] instanceof Function)) return null;
const displayName = 'string' === typeof mn ? mn : dn || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${fnn}`;
const patchObject = this.patches[patchId] || this.pushPatch(patchId, module, fnn);
if (!patchObject.patch) this.rePatch(patchObject);
const id = patchObject.supers.length + 1;
const patch = {
id,
fn: cb,
unpatch: () => patchObject.supers.splice(patchObject.supers.findIndex(slave => slave.id === id), 1)
};
patchObject.supers.push(patch);
return patch;
}
static slavepatch(mn, fnn, cb, dn) {
const module = this.resolveModule(mn);
if (!module || !module[fnn] || !(module[fnn] instanceof Function)) return null;
const displayName = 'string' === typeof mn ? mn : dn || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${fnn}`;
const patchObject = this.patches[patchId] || this.pushPatch(patchId, module, fnn);
if (!patchObject.patch) this.rePatch(patchObject);
const id = patchObject.slaves.length + 1;
const patch = {
id,
fn: cb,
unpatch: () => patchObject.slaves.splice(patchObject.slaves.findIndex(slave => slave.id === id), 1)
};
patchObject.slaves.push(patch);
return patch;
}
}

View File

@ -0,0 +1,192 @@
import Patcher from './patcher';
class Helpers {
static get plannedActions() {
return this._plannedActions || (this._plannedActions = new Map());
}
static recursiveArray(parent, key, count = 1) {
let index = 0;
function* innerCall(parent, key) {
const item = parent[key];
if (item instanceof Array) {
for (const subKey of item.keys()) {
yield* innerCall(item, subKey)
}
return;
}
yield { item, parent, key, index: index++, count };
}
return innerCall(parent, key);
}
static recursiveArrayCount(parent, key) {
let count = 0;
for (let { } of this.recursiveArray(parent, key))
++count;
return this.recursiveArray(parent, key, count);
}
static get recursiveChildren() {
return function*(parent, key, index = 0, count = 1) {
const item = parent[key];
yield { item, parent, key, index, count };
if (item && item.props && item.props.children) {
for (let { parent, key, index, count } of this.recursiveArrayCount(item.props, 'children')) {
yield* this.recursiveChildren(parent, key, index, count);
}
}
}
}
static returnFirst(iterator, process) {
for (let child of iterator) {
const retVal = process(child);
if (retVal !== undefined) return retVal;
}
}
static getFirstChild(rootParent, rootKey, selector) {
const getDirectChild = (item, selector) => {
if (item && item.props && item.props.children) {
return this.returnFirst(this.recursiveArrayCount(item.props, 'children'), checkFilter.bind(null, selector));
}
};
const checkFilter = (selector, { item, parent, key, count, index }) => {
let match = true;
if (match && selector.type)
match = item && selector.type === item.type;
if (match && selector.tag)
match = item && typeof item.type === 'string' && selector.tag === item.type;
if (match && selector.className) {
match = item && item.props && typeof item.props.className === 'string';
if (match) {
const classes = item.props.className.split(' ');
if (selector.className === true)
match = !!classes[0];
else if (typeof selector.className === 'string')
match = classes.includes(selector.className);
else if (selector.className instanceof RegExp)
match = !!classes.find(cls => selector.className.test(cls));
else match = false;
}
}
if (match && selector.text) {
if (selector.text === true)
match = typeof item === 'string';
else if (typeof selector.text === 'string')
match = item === selector.text;
else if (selector.text instanceof RegExp)
match = typeof item === 'string' && selector.text.test(item);
else match = false;
}
if (match && selector.nthChild)
match = index === (selector.nthChild < 0 ? count + selector.nthChild : selector.nthChild);
if (match && selector.hasChild)
match = getDirectChild(item, selector.hasChild);
if (match && selector.hasSuccessor)
match = item && !!this.getFirstChild(parent, key, selector.hasSuccessor).item;
if (match && selector.eq) {
--selector.eq;
return;
}
if (match) {
if (selector.child) {
return getDirectChild(item, selector.child);
}
else if (selector.successor) {
return this.getFirstChild(parent, key, selector.successor);
}
else {
return { item, parent, key };
}
}
};
return this.returnFirst(this.recursiveChildren(rootParent, rootKey), checkFilter.bind(null, selector)) || {};
}
static parseSelector(selector) {
if (selector.startsWith('.')) return { className: selector.substr(1) }
if (selector.startsWith('#')) return { id: selector.substr(1) }
return {}
}
}
class ReactComponent {
constructor(id, component, retVal) {
this._id = id;
this._component = component;
this._retVal = retVal;
}
get id() {
return this._id;
}
get component() {
return this._component;
}
get retVal() {
return this._retVal;
}
unpatchRender() {
}
patchRender(actions, updateOthers) {
const self = this;
if (!(actions instanceof Array)) actions = [actions];
Patcher.slavepatch(this.component.prototype, 'render', function(args, obj) {
for (const action of actions) {
let { selector, method, fn } = action;
if ('string' === typeof selector) selector = Helpers.parseSelector(selector);
const { item, parent, key } = Helpers.getFirstChild(obj, 'retVal', selector);
if (!item) continue;
const content = fn.apply(this, [item]);
switch (method) {
case 'replace':
parent[key] = content;
break;
}
}
if (updateOthers) self.forceUpdateOthers();
});
}
forceUpdateOthers() {
}
}
export default class ReactComponents {
static get components() { return this._components || (this._components = []) }
static get listeners() { return this._listeners || (this._listeners = []) }
static push(component, retVal) {
if (!(component instanceof Function)) return null;
const { displayName } = component;
if (!displayName) return null;
const have = this.components.find(comp => comp.id === displayName);
if (have) return component;
const c = new ReactComponent(displayName, component, retVal);
this.components.push(c);
const listener = this.listeners.find(listener => listener.id === displayName);
if (!listener) return c;
for (const l of listener.listeners) {
l(c);
}
this.listeners.splice(this.listeners.findIndex(listener => listener.id === displayName), 1);
return c;
}
static async getComponent(name) {
const have = this.components.find(c => c.id === name);
if (have) return have;
const listener = this.listeners.find(l => l.id === name);
if (!listener) this.listeners.push({
id: name,
listeners: []
});
return new Promise(resolve => {
this.listeners.find(l => l.id === name).listeners.push(c => resolve(c));
});
}
}

View File

@ -8,7 +8,7 @@
* LICENSE file in the root directory of this source tree.
*/
import { Events, WebpackModules, EventListener } from 'modules';
import { Events, WebpackModules, EventListener, ReactComponents, Renderer } from 'modules';
import Reflection from './reflection';
import DOM from './dom';
import VueInjector from './vueinjector';
@ -41,6 +41,10 @@ class TempApi {
export default class extends EventListener {
constructor(args) {
super(args);
}
bindings() {
this.manipAll = this.manipAll.bind(this);
this.markupInjector = this.markupInjector.bind(this);
@ -50,6 +54,8 @@ export default class extends EventListener {
}
get eventBindings() {
return [{ id: 'gkh:keyup', callback: this.injectAutocomplete }];
/*
return [
{ id: 'server-switch', callback: this.manipAll },
{ id: 'channel-switch', callback: this.manipAll },
@ -57,6 +63,7 @@ export default class extends EventListener {
{ id: 'discord:MESSAGE_UPDATE', callback: this.markupInjector },
{ id: 'gkh:keyup', callback: this.injectAutocomplete }
];
*/
}
manipAll() {

View File

@ -57,10 +57,10 @@ export default class {
if (!this.profilePopupModule) return;
clearInterval(defer);
Utils.monkeyPatch(this.profilePopupModule, 'open', 'after', (data, userid) => Events.emit('ui-event', {
/*Utils.monkeyPatch(this.profilePopupModule, 'open', 'after', (data, userid) => Events.emit('ui-event', {
event: 'profile-popup-open',
data: { userid }
}));
}));*/
}, 100);
const ehookInterval = setInterval(() => {

View File

@ -150,7 +150,7 @@ class BetterDiscord {
//this.windowUtils.webContents.on('did-finish-load', e => this.injectScripts(true));
this.windowUtils.events('did-get-response-details', () => this.ignite(this.windowUtils.window));
this.windowUtils.events('did-finish-load', e => this.injectScripts(true));
this.windowUtils.events('did-get-response-details', e => this.injectScripts(true));
this.windowUtils.events('did-navigate-in-page', (event, url, isMainFrame) => {
this.windowUtils.send('did-navigate-in-page', { event, url, isMainFrame });