이 스크립트는 직접 설치하는 용도가 아닙니다. 다른 스크립트에서 메타 지시문 // @require https://update.greatest.deepsurf.us/scripts/526417/1604489/USToolkit.js
을(를) 사용하여 포함하는 라이브러리입니다.
- // ==UserScript==
- // @name USToolkit
- // @namespace https://greatest.deepsurf.us/pt-BR/users/821661
- // @version 0.0.4
- // @run-at document-start
- // @author hdyzen
- // @description simple toolkit to help me create userscripts
- // @license MIT
- // ==/UserScript==
-
- /**
- * Some functions are strongly inspired by:
- * github.com/violentmonkey/
- * github.com/gorhill/uBlock/
- *
- */
-
- (() => {
- function observer(func) {
- const observer = new MutationObserver(() => {
- const disconnect = func();
-
- if (disconnect === true) {
- observer.disconnect();
- }
- });
-
- observer.observe(document, { childList: true, subtree: true });
- }
-
- function waitElement(selector, timeoutSeconds = 10) {
- return new Promise((resolve, reject) => {
- const element = document.querySelector(selector);
- if (element) {
- resolve(element);
- }
-
- const mutationsHandler = () => {
- const target = document.querySelector(selector);
- if (target) {
- observer.disconnect();
- resolve(target);
- }
- };
-
- const observer = new MutationObserver(mutationsHandler);
-
- observer.observe(document.documentElement || document, {
- childList: true,
- subtree: true,
- });
-
- setTimeout(() => {
- observer.disconnect();
- reject(`Timeout ${timeoutSeconds} seconds!`);
- }, timeoutSeconds * 1000);
- });
- }
- const asyncQuerySelector = waitElement;
-
- function matchProp(obj, propChain) {
- if (!obj || typeof propChain !== "string") {
- return;
- }
-
- const props = propChain.split(".");
- let current = obj;
-
- for (let i = 0; i < props.length; i++) {
- const prop = props[i];
-
- if (current === undefined || current === null) {
- return;
- }
-
- if (prop === "[]" && Array.isArray(current)) {
- i++;
- current = handleArray(current, props[i]);
- continue;
- }
-
- if ((prop === "{}" || prop === "*") && isObject(current)) {
- i++;
- current = handleObject(current, props[i]);
- continue;
- }
-
- current = current[prop];
- }
-
- return current;
- }
-
- function handleArray(arr, nextProp) {
- const results = arr.map((item) => getProp(item, nextProp)).filter((val) => val !== undefined);
-
- return results.length === 1 ? results[0] : results;
- }
-
- function handleObject(obj, nextProp) {
- const keys = Object.keys(obj);
- const results = keys.map((key) => getProp(obj[key], nextProp)).filter((val) => val !== undefined);
-
- return results.length === 1 ? results[0] : results;
- }
-
- function getProp(obj, prop) {
- if (obj && Object.hasOwn(obj, prop)) {
- return obj[prop];
- }
-
- return;
- }
-
- function isObject(val) {
- return Object.prototype.toString.call(val) === "[object Object]";
- }
-
- function getValType(val) {
- return Object.prototype.toString.call(val).slice(8, -1).toLowerCase();
- }
-
- function update(func, time = 250) {
- const exec = () => {
- if (func() === true) {
- return;
- }
-
- setTimeout(() => {
- requestAnimationFrame(exec);
- }, time);
- };
-
- requestAnimationFrame(exec);
- }
-
- function patch(owner, methodName, handler) {
- const originalMethod = owner[methodName];
-
- if (typeof originalMethod !== "function") {
- throw new Error(`The method “${methodName}” was not found in the object "${owner}".`);
- }
-
- const proxy = new Proxy(originalMethod, handler);
-
- owner[methodName] = proxy;
-
- return () => {
- owner[methodName] = originalMethod;
- };
- }
-
- function onUrlChange(callback) {
- let previousUrl = location.href;
-
- const observer = new MutationObserver(() => {
- if (location.href !== previousUrl) {
- previousUrl = location.href;
- callback(location.href);
- }
- });
-
- observer.observe(document.body || document.documentElement || document, { childList: true, subtree: true });
-
- const historyHandler = {
- apply(target, thisArg, args) {
- const result = Reflect.apply(target, thisArg, args);
- setTimeout(() => {
- if (location.href !== previousUrl) {
- previousUrl = location.href;
- callback(location.href);
- }
- }, 0);
- return result;
- },
- };
-
- patch(history, "pushState", historyHandler);
- patch(history, "replaceState", historyHandler);
- }
-
- function request(options) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- ...options,
- onload: resolve,
- onerror: reject,
- ontimeout: reject,
- });
- });
- }
-
- function extractProps(element, propsArray) {
- const data = {};
-
- for (const propDefinition of propsArray) {
- const [label, valuePath] = propDefinition.split(":");
-
- if (valuePath) {
- data[label] = matchProp(element, valuePath);
- } else {
- data[label] = matchProp(element, label);
- }
- }
- return data;
- }
-
- function handleStringRule(container, rule) {
- const element = container.querySelector(rule);
- return element ? element.textContent.trim() : null;
- }
-
- function handleArrayRule(container, rule) {
- const [subSelector, ...propsToGet] = rule;
- const element = !subSelector ? container : container.querySelector(subSelector);
- return extractProps(element, propsToGet);
- }
-
- const ruleHandlers = {
- string: handleStringRule,
- array: handleArrayRule,
- };
-
- function getRuleType(rule) {
- if (typeof rule === "string") return "string";
- if (Array.isArray(rule)) return "array";
- return "unknown";
- }
-
- function processObjectSchema(container, schema) {
- const item = {};
- for (const key in schema) {
- const rule = schema[key];
- const ruleType = getRuleType(rule);
-
- const handler = ruleHandlers[ruleType];
- if (handler) {
- item[key] = handler(container, rule);
- continue;
- }
-
- console.warn(`[USToolkit.scrape] Rule for key “${key}” has an unsupported type.`);
- }
- return item;
- }
-
- function processContainer(container, schema) {
- if (Array.isArray(schema)) {
- return extractProps(container, schema);
- }
-
- if (isObject(schema)) {
- return processObjectSchema(container, schema);
- }
-
- console.warn("[USToolkit.scrape] Invalid schema format.");
- return {};
- }
-
- function scrape(containerSelector, schema, scope = document) {
- const containers = scope.querySelectorAll(containerSelector);
- const results = [];
-
- for (const container of containers) {
- const item = processContainer(container, schema);
- results.push(item);
- }
-
- return results;
- }
-
- window.UST = window.UST || {};
-
- Object.assign(window.UST, {
- observer,
- waitElement,
- asyncQuerySelector,
- matchProp,
- handleArray,
- handleObject,
- getProp,
- isObject,
- update,
- patch,
- onUrlChange,
- request,
- scrape,
- });
- })();