Library to modify static and dynamic components of osu web pages
Tính đến
Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta
// @require https://update.greasyfork.org/scripts/473977/1241412/osu-web.js
// ==UserScript==
// @name osu-web
// @namespace osu
// @version 1.0.0
// @description Library to modify static and dynamic components of osu web pages
// @author Magnus Cosmos
// ==/UserScript==
function loaded(selector, parent, callback, options = { childList: true }) {
const el = parent.querySelector(selector);
if (el) {
callback(el);
} else {
new MutationObserver(function (_mutations, observer) {
const el = parent.querySelector(selector);
if (el) {
callback(el);
observer = observer ? observer : this;
observer.disconnect();
}
}).observe(parent, options);
}
}
class Module {
constructor() {
if (this.constructor == Module) {
throw new Error("Module class cannot be instantiated.");
}
this.loaded = false;
this.static = [];
this.dynamic = [];
this.before = {};
this.after = {};
this.keys = [];
}
init() {
this.webpack = new Webpack();
this.#getTurboLinks();
this.#getReactModules();
}
#getTurboLinks() {
for (const id in this.webpack.modules) {
const exports = this.webpack.modules[id];
if ("controller" in exports) {
this.turbolinks = exports;
return;
}
}
}
#getReactModules() {
const reactModules = new Set();
for (const id in this.webpack.modules) {
const exports = this.webpack.modules[id];
if ("__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED" in exports) {
reactModules.add(exports);
}
}
[this.React, this.ReactDOM] = reactModules;
}
modifyFn(obj, fn, key, _before, _after) {
if (!(key in this.keys)) {
this.keys.push(key);
this.before[key] = [];
this.after[key] = [];
this.#modify(obj, fn, key);
}
if (_before) {
this.before[key].push(_before);
}
if (_after) {
this.after[key].push(_after);
}
}
#modify(obj, fn, key) {
const self = this;
const oldFn = obj[fn];
obj[fn] = function () {
self.#beforeFn(key, arguments);
const r = oldFn.apply(this, arguments);
self.#afterFn(key, arguments, r);
return r;
};
}
#beforeFn(key, args) {
const arr = this.before[key] || [];
for (const fn of arr) {
fn(args);
}
}
#afterFn(key, args, r) {
const arr = this.after[key] || [];
for (const fn of arr) {
fn(args, r);
}
}
}
class OsuWeb extends Module {
constructor(staticFn, dynamicFn) {
super();
this.static = staticFn || (() => {});
this.dynamic = dynamicFn || (() => {});
loaded("html", document, (html) => {
loaded("body", html, () => {
this.init();
this.start();
});
});
}
start() {
this.static(document.body);
const controller = this.turbolinks.controller;
this.modifyFn(controller, "render", "turbolinks.render", null, (args, r) => {
this.static(r.newBody);
});
this.dynamic();
}
}