Last active
March 4, 2026 06:10
-
-
Save evensandbox/198e58075d4b3415c2f0f5e394204c6a to your computer and use it in GitHub Desktop.
auto-run-script-for-task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Task | |
| // @namespace https://x181.cn/ | |
| // @version 0.50.0 | |
| // @author TT | |
| // @description Hello world! | |
| // @icon https://img.artproglobal.com/c/21736720685ad57d4fb8362b70f62f8d?width=512&height=512&hTag=d7a495871ba01409369e6c2231ad49f0 | |
| // @homepage https://x181.cn | |
| // @downloadURL https://gist.github.com/evensandbox/198e58075d4b3415c2f0f5e394204c6a/raw/task.user.js | |
| // @updateURL https://gist.github.com/evensandbox/198e58075d4b3415c2f0f5e394204c6a/raw/task.user.js | |
| // @match *://*/* | |
| // @connect localhost | |
| // @connect x181.cn | |
| // @connect api.telegram.org | |
| // @connect * | |
| // @grant GM.xmlHttpRequest | |
| // @grant GM_getValue | |
| // @grant GM_info | |
| // @grant GM_openInTab | |
| // @grant GM_registerMenuCommand | |
| // @grant GM_setClipboard | |
| // @grant GM_setValue | |
| // @grant GM_xmlhttpRequest | |
| // @grant unsafeWindow | |
| // @run-at document-idle | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| const Log = (flag = false) => { | |
| return function log2(...rest) { | |
| if (flag === false) return; | |
| let list2 = rest; | |
| if (typeof window !== "undefined" && typeof top !== "undefined") { | |
| list2 = [ | |
| `%cisTop: ${top === window}. url = ${location.href}.`, | |
| "color: gray; font-size: 1.2em;", | |
| ...rest | |
| ]; | |
| } | |
| console.log(...list2); | |
| }; | |
| }; | |
| function hashRule(rule) { | |
| switch (rule.type) { | |
| case "atom": { | |
| const { op, value } = rule; | |
| return `atom:${op}:${JSON.stringify(value)}`; | |
| } | |
| case "not": | |
| return `not(${hashRule(rule.rule)})`; | |
| case "and": | |
| case "or": { | |
| const hashes = rule.rules.map(hashRule).join(","); | |
| return `${rule.type}(${hashes})`; | |
| } | |
| } | |
| } | |
| function isConstantAtom$1(rule, value) { | |
| return rule.type === "atom" && rule.op === "const" && (value === void 0 || rule.value === value); | |
| } | |
| function constAtom(value) { | |
| return { | |
| type: "atom", | |
| op: "const", | |
| value | |
| }; | |
| } | |
| function flattenRule(rule) { | |
| if (rule.type === "and" || rule.type === "or") { | |
| const rules = rule.rules.flatMap((r) => { | |
| const child = flattenRule(r); | |
| return child.type === rule.type ? child.rules : [child]; | |
| }); | |
| return { ...rule, rules }; | |
| } | |
| if (rule.type === "not") { | |
| return { type: "not", rule: flattenRule(rule.rule) }; | |
| } | |
| return rule; | |
| } | |
| function applyDeMorgans(rule) { | |
| if (rule.type === "not") { | |
| const r = rule.rule; | |
| if (r.type === "not") { | |
| return applyDeMorgans(r.rule); | |
| } | |
| if (r.type === "and") { | |
| return { | |
| type: "or", | |
| rules: r.rules.map( | |
| (x) => applyDeMorgans({ type: "not", rule: x }) | |
| ) | |
| }; | |
| } | |
| if (r.type === "or") { | |
| return { | |
| type: "and", | |
| rules: r.rules.map( | |
| (x) => applyDeMorgans({ type: "not", rule: x }) | |
| ) | |
| }; | |
| } | |
| return rule; | |
| } | |
| if (rule.type === "and" || rule.type === "or") { | |
| return { | |
| ...rule, | |
| rules: rule.rules.map(applyDeMorgans) | |
| }; | |
| } | |
| return rule; | |
| } | |
| function elimConstantAtoms(rule) { | |
| if (rule.type === "and") { | |
| const rules = rule.rules.filter((r) => !isConstantAtom$1(r, true)); | |
| if (rules.some((r) => isConstantAtom$1(r, false))) { | |
| return constAtom(false); | |
| } | |
| if (rules.length === 0) { | |
| return constAtom(true); | |
| } | |
| if (rules.length === 1) { | |
| return rules[0]; | |
| } | |
| return { ...rule, rules }; | |
| } | |
| if (rule.type === "or") { | |
| const rules = rule.rules.filter((r) => !isConstantAtom$1(r, false)); | |
| if (rules.some((r) => isConstantAtom$1(r, true))) { | |
| return constAtom(true); | |
| } | |
| if (rules.length === 0) { | |
| return constAtom(false); | |
| } | |
| if (rules.length === 1) { | |
| return rules[0]; | |
| } | |
| return { ...rule, rules }; | |
| } | |
| return rule; | |
| } | |
| function deduplicateRules(rule) { | |
| if (rule.type === "and" || rule.type === "or") { | |
| const seen = new Set(); | |
| const rules = rule.rules.filter((r) => { | |
| const h = hashRule(r); | |
| if (seen.has(h)) { | |
| return false; | |
| } | |
| seen.add(h); | |
| return true; | |
| }); | |
| return { ...rule, rules }; | |
| } | |
| return rule; | |
| } | |
| function detectContradictions(rule) { | |
| if (rule.type !== "and") { | |
| return rule; | |
| } | |
| const positives = new Set(); | |
| const negatives = new Set(); | |
| for (const r of rule.rules) { | |
| if (r.type === "atom") { | |
| positives.add(hashRule(r)); | |
| } else if (r.type === "not" && r.rule.type === "atom") { | |
| negatives.add(hashRule(r.rule)); | |
| } | |
| } | |
| for (const p of positives) { | |
| if (negatives.has(p)) { | |
| return constAtom(false); | |
| } | |
| } | |
| return rule; | |
| } | |
| function sortRulesDeterministically(rule) { | |
| if (rule.type === "and" || rule.type === "or") { | |
| return { | |
| ...rule, | |
| rules: [...rule.rules].map(sortRulesDeterministically).sort((a, b) => hashRule(a).localeCompare(hashRule(b))) | |
| }; | |
| } | |
| if (rule.type === "not") { | |
| return { type: "not", rule: sortRulesDeterministically(rule.rule) }; | |
| } | |
| return rule; | |
| } | |
| function normalize(rule) { | |
| return sortRulesDeterministically( | |
| detectContradictions( | |
| elimConstantAtoms( | |
| deduplicateRules( | |
| elimConstantAtoms( | |
| applyDeMorgans( | |
| flattenRule(rule) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ); | |
| } | |
| function isConstantAtom(rule, value) { | |
| return rule.type === "atom" && rule.op === "const" && (value === void 0 || rule.value === value); | |
| } | |
| function isLiteral(rule) { | |
| return rule.type === "atom" || rule.type === "not"; | |
| } | |
| function foldConstants(rule) { | |
| if (rule.type === "and" || rule.type === "or") { | |
| const rules = rule.rules.map(foldConstants); | |
| if (rule.type === "and") { | |
| if (rules.some((r) => isConstantAtom(r, false))) return constAtom(false); | |
| const filtered2 = rules.filter((r) => !isConstantAtom(r, true)); | |
| if (filtered2.length === 0) return constAtom(true); | |
| if (filtered2.length === 1) return filtered2[0]; | |
| return { type: "and", rules: filtered2 }; | |
| } | |
| if (rules.some((r) => isConstantAtom(r, true))) return constAtom(true); | |
| const filtered = rules.filter((r) => !isConstantAtom(r, false)); | |
| if (filtered.length === 0) return constAtom(false); | |
| if (filtered.length === 1) return filtered[0]; | |
| return { type: "or", rules: filtered }; | |
| } | |
| if (rule.type === "not") { | |
| return { type: "not", rule: foldConstants(rule.rule) }; | |
| } | |
| return rule; | |
| } | |
| function absorbOrRules(rule) { | |
| if (rule.type !== "or") return rule; | |
| const literalHashes = new Set( | |
| rule.rules.filter(isLiteral).map(hashRule) | |
| ); | |
| const kept = []; | |
| for (const r of rule.rules) { | |
| if (r.type === "and") { | |
| const andSet = new Set(r.rules.map(hashRule)); | |
| let absorbed = false; | |
| for (const h of literalHashes) { | |
| if (andSet.has(h)) { | |
| absorbed = true; | |
| break; | |
| } | |
| } | |
| if (!absorbed) kept.push(r); | |
| } else { | |
| kept.push(r); | |
| } | |
| } | |
| if (kept.length === 1) return kept[0]; | |
| return { type: "or", rules: kept }; | |
| } | |
| function absorbAndRules(rule) { | |
| if (rule.type !== "and") return rule; | |
| const literalHashes = new Set( | |
| rule.rules.filter(isLiteral).map(hashRule) | |
| ); | |
| const kept = []; | |
| for (const r of rule.rules) { | |
| if (r.type === "or") { | |
| const orSet = new Set(r.rules.map(hashRule)); | |
| let absorbed = false; | |
| for (const h of literalHashes) { | |
| if (orSet.has(h)) { | |
| absorbed = true; | |
| break; | |
| } | |
| } | |
| if (!absorbed) kept.push(r); | |
| } else { | |
| kept.push(r); | |
| } | |
| } | |
| if (kept.length === 1) return kept[0]; | |
| return { type: "and", rules: kept }; | |
| } | |
| const implicationRegistry = new Map(); | |
| function impliesByHash(fromHash, toHash) { | |
| if (fromHash === toHash) return true; | |
| return implicationRegistry.get(fromHash)?.has(toHash) ?? false; | |
| } | |
| function domainShortCircuitByImplications(rule) { | |
| if (rule.type !== "and" && rule.type !== "or") return rule; | |
| if (implicationRegistry.size === 0) return rule; | |
| if (rule.rules.length <= 1) return rule; | |
| const hashes = rule.rules.map(hashRule); | |
| const kept = []; | |
| for (let i = 0; i < rule.rules.length; i++) { | |
| const current = rule.rules[i]; | |
| let drop = false; | |
| for (let j = 0; j < rule.rules.length; j++) { | |
| if (i === j) continue; | |
| if (hashes[i] === hashes[j]) continue; | |
| if (rule.type === "and" && impliesByHash(hashes[j], hashes[i])) { | |
| drop = true; | |
| break; | |
| } | |
| if (rule.type === "or" && impliesByHash(hashes[i], hashes[j])) { | |
| drop = true; | |
| break; | |
| } | |
| } | |
| if (!drop) kept.push(current); | |
| } | |
| if (kept.length === 1) return kept[0]; | |
| return { ...rule, rules: kept }; | |
| } | |
| function simplifyNormalized(rule) { | |
| let simplified = foldConstants(rule); | |
| simplified = absorbOrRules(simplified); | |
| simplified = absorbAndRules(simplified); | |
| simplified = domainShortCircuitByImplications(simplified); | |
| return simplified; | |
| } | |
| function compileRule(rule) { | |
| if (typeof rule === "boolean") { | |
| return constAtom(rule); | |
| } | |
| if (typeof rule === "string") { | |
| return { type: "atom", op: "includes", value: rule }; | |
| } | |
| if (typeof rule === "function") { | |
| return { type: "atom", op: "function", value: rule }; | |
| } | |
| if (rule instanceof RegExp) { | |
| return { type: "atom", op: "regexp", value: rule }; | |
| } | |
| if (rule instanceof URLPattern) { | |
| return { type: "atom", op: "urlPattern", value: rule }; | |
| } | |
| if (rule && typeof rule === "object" && "test" in rule && typeof rule.test === "function") { | |
| return { type: "atom", op: "test", value: rule }; | |
| } | |
| if (Array.isArray(rule)) { | |
| return { type: "or", rules: rule.map(compileRule) }; | |
| } | |
| if (rule && typeof rule === "object") { | |
| if (rule.and) return { type: "and", rules: rule.and.map(compileRule) }; | |
| if (rule.or) return { type: "or", rules: rule.or.map(compileRule) }; | |
| if (rule.not) return { type: "not", rule: compileRule(rule.not) }; | |
| } | |
| throw new Error("Unsupported rule"); | |
| } | |
| class PredicateRegistry { | |
| map = new Map(); | |
| register(op, fn) { | |
| this.map.set(op, fn); | |
| } | |
| get(op) { | |
| const fn = this.map.get(op); | |
| if (!fn) throw new Error(`Unknown predicate: ${op}`); | |
| return fn; | |
| } | |
| has(op) { | |
| return this.map.has(op); | |
| } | |
| unregister(op) { | |
| return this.map.delete(op); | |
| } | |
| } | |
| function createDefaultRegistry() { | |
| const registry = new PredicateRegistry(); | |
| registry.register("const", (_ctx, value) => value); | |
| registry.register( | |
| "includes", | |
| (ctx, value) => ctx.value.includes(value) | |
| ); | |
| registry.register( | |
| "regexp", | |
| (ctx, re) => re.test(ctx.value) | |
| ); | |
| registry.register( | |
| "urlPattern", | |
| (ctx, pattern) => pattern.test(ctx.value) | |
| ); | |
| registry.register( | |
| "function", | |
| async (ctx, fn) => await fn(ctx.value) | |
| ); | |
| registry.register( | |
| "test", | |
| async (ctx, testable) => await testable.test(ctx.value) | |
| ); | |
| return registry; | |
| } | |
| const defaultRegistry = createDefaultRegistry(); | |
| function proofFromAtom(trace) { | |
| return { | |
| type: "atom", | |
| op: trace.op, | |
| value: trace.value, | |
| result: trace.result, | |
| meta: trace.meta | |
| }; | |
| } | |
| function proofFromAndSuccess(trace) { | |
| return { | |
| type: "and", | |
| result: true, | |
| children: trace.children.map(toProof) | |
| }; | |
| } | |
| function proofFromAndFailure(trace) { | |
| const failing = trace.children.find((c) => c.result === false); | |
| return { | |
| type: "and", | |
| result: false, | |
| children: [toProof(failing)] | |
| }; | |
| } | |
| function proofFromOrSuccess(trace) { | |
| const success = trace.children.find((c) => c.result === true); | |
| return { | |
| type: "or", | |
| result: true, | |
| children: [toProof(success)] | |
| }; | |
| } | |
| function proofFromOrFailure(trace) { | |
| return { | |
| type: "or", | |
| result: false, | |
| children: trace.children.map(toProof) | |
| }; | |
| } | |
| function proofFromNot(trace) { | |
| return { | |
| type: "not", | |
| result: trace.result, | |
| children: trace.children.map(toProof) | |
| }; | |
| } | |
| function toProof(trace) { | |
| switch (trace.type) { | |
| case "atom": | |
| return proofFromAtom(trace); | |
| case "and": | |
| return trace.result ? proofFromAndSuccess(trace) : proofFromAndFailure(trace); | |
| case "or": | |
| return trace.result ? proofFromOrSuccess(trace) : proofFromOrFailure(trace); | |
| case "not": | |
| return proofFromNot(trace); | |
| } | |
| } | |
| class RuleEvaluator { | |
| constructor(registry) { | |
| this.registry = registry; | |
| } | |
| register(op, fn) { | |
| this.registry.register(op, fn); | |
| } | |
| async evaluate(rule, ctx) { | |
| const simplified = simplifyNormalized(normalize(rule)); | |
| return this.evaluateNormalized(simplified, ctx); | |
| } | |
| async evaluateWithProof(rule, ctx) { | |
| const result = await this.evaluate(rule, ctx); | |
| return { | |
| ...result, | |
| proof: toProof(result.trace) | |
| }; | |
| } | |
| async evaluateNormalized(rule, ctx) { | |
| switch (rule.type) { | |
| case "atom": | |
| return this.evalAtom(rule, ctx); | |
| case "and": | |
| return this.evalAnd(rule, ctx); | |
| case "or": | |
| return this.evalOr(rule, ctx); | |
| case "not": | |
| return this.evalNot(rule, ctx); | |
| } | |
| } | |
| async evalAnd(rule, ctx) { | |
| const children = []; | |
| for (const r of rule.rules) { | |
| const res = await this.evaluateNormalized(r, ctx); | |
| children.push(res.trace); | |
| if (!res.result) { | |
| return { | |
| result: false, | |
| trace: { | |
| type: "and", | |
| result: false, | |
| shortCircuited: true, | |
| children | |
| } | |
| }; | |
| } | |
| } | |
| return { | |
| result: true, | |
| trace: { | |
| type: "and", | |
| result: true, | |
| children | |
| } | |
| }; | |
| } | |
| async evalOr(rule, ctx) { | |
| const children = []; | |
| for (const r of rule.rules) { | |
| const res = await this.evaluateNormalized(r, ctx); | |
| children.push(res.trace); | |
| if (res.result) { | |
| return { | |
| result: true, | |
| trace: { | |
| type: "or", | |
| result: true, | |
| shortCircuited: true, | |
| children | |
| } | |
| }; | |
| } | |
| } | |
| return { | |
| result: false, | |
| trace: { | |
| type: "or", | |
| result: false, | |
| children | |
| } | |
| }; | |
| } | |
| async evalNot(rule, ctx) { | |
| const res = await this.evaluateNormalized(rule.rule, ctx); | |
| return { | |
| result: !res.result, | |
| trace: { | |
| type: "not", | |
| result: !res.result, | |
| children: [res.trace] | |
| } | |
| }; | |
| } | |
| async evalAtom(rule, ctx) { | |
| const predicate = this.registry.get(rule.op); | |
| const start = performance.now(); | |
| try { | |
| const raw = await predicate(ctx, rule.value); | |
| const result = typeof raw === "boolean" ? raw : raw.ok; | |
| const reason = typeof raw === "object" && raw !== null ? raw.reason : void 0; | |
| return { | |
| result, | |
| trace: { | |
| type: "atom", | |
| op: rule.op, | |
| value: rule.value, | |
| result, | |
| meta: { | |
| duration: performance.now() - start, | |
| ...reason && { reason } | |
| } | |
| } | |
| }; | |
| } catch (e) { | |
| return { | |
| result: false, | |
| trace: { | |
| type: "atom", | |
| op: rule.op, | |
| value: rule.value, | |
| result: false, | |
| meta: { | |
| duration: performance.now() - start, | |
| error: e.message | |
| } | |
| } | |
| }; | |
| } | |
| } | |
| } | |
| const isFunction$1 = (input) => typeof input === "function"; | |
| const dual = function(arity, body) { | |
| if (typeof arity === "function") { | |
| return function() { | |
| if (arity(arguments)) { | |
| return body.apply(this, arguments); | |
| } | |
| return (self) => body(self, ...arguments); | |
| }; | |
| } | |
| switch (arity) { | |
| case 0: | |
| case 1: | |
| throw new RangeError(`Invalid arity ${arity}`); | |
| case 2: | |
| return function(a, b) { | |
| if (arguments.length >= 2) { | |
| return body(a, b); | |
| } | |
| return function(self) { | |
| return body(self, a); | |
| }; | |
| }; | |
| case 3: | |
| return function(a, b, c) { | |
| if (arguments.length >= 3) { | |
| return body(a, b, c); | |
| } | |
| return function(self) { | |
| return body(self, a, b); | |
| }; | |
| }; | |
| case 4: | |
| return function(a, b, c, d) { | |
| if (arguments.length >= 4) { | |
| return body(a, b, c, d); | |
| } | |
| return function(self) { | |
| return body(self, a, b, c); | |
| }; | |
| }; | |
| case 5: | |
| return function(a, b, c, d, e) { | |
| if (arguments.length >= 5) { | |
| return body(a, b, c, d, e); | |
| } | |
| return function(self) { | |
| return body(self, a, b, c, d); | |
| }; | |
| }; | |
| default: | |
| return function() { | |
| if (arguments.length >= arity) { | |
| return body.apply(this, arguments); | |
| } | |
| const args = arguments; | |
| return function(self) { | |
| return body(self, ...args); | |
| }; | |
| }; | |
| } | |
| }; | |
| const constant = (value) => () => value; | |
| const constTrue = constant(true); | |
| const constFalse = constant(false); | |
| const constUndefined = constant(void 0); | |
| function pipe(a, ab, bc, cd, de, ef, fg, gh, hi) { | |
| switch (arguments.length) { | |
| case 1: | |
| return a; | |
| case 2: | |
| return ab(a); | |
| case 3: | |
| return bc(ab(a)); | |
| case 4: | |
| return cd(bc(ab(a))); | |
| case 5: | |
| return de(cd(bc(ab(a)))); | |
| case 6: | |
| return ef(de(cd(bc(ab(a))))); | |
| case 7: | |
| return fg(ef(de(cd(bc(ab(a)))))); | |
| case 8: | |
| return gh(fg(ef(de(cd(bc(ab(a))))))); | |
| case 9: | |
| return hi(gh(fg(ef(de(cd(bc(ab(a)))))))); | |
| default: { | |
| let ret = arguments[0]; | |
| for (let i = 1; i < arguments.length; i++) { | |
| ret = arguments[i](ret); | |
| } | |
| return ret; | |
| } | |
| } | |
| } | |
| const make$3 = (isEquivalent) => (self, that) => self === that || isEquivalent(self, that); | |
| const globalStoreId = `effect/GlobalValue`; | |
| let globalStore; | |
| const globalValue = (id2, compute) => { | |
| if (!globalStore) { | |
| globalThis[globalStoreId] ??= new Map(); | |
| globalStore = globalThis[globalStoreId]; | |
| } | |
| if (!globalStore.has(id2)) { | |
| globalStore.set(id2, compute()); | |
| } | |
| return globalStore.get(id2); | |
| }; | |
| const isFunction = isFunction$1; | |
| const isRecordOrArray = (input) => typeof input === "object" && input !== null; | |
| const isObject = (input) => isRecordOrArray(input) || isFunction(input); | |
| const hasProperty = dual(2, (self, property) => isObject(self) && property in self); | |
| const isTagged = dual(2, (self, tag) => hasProperty(self, "_tag") && self["_tag"] === tag); | |
| const getBugErrorMessage = (message) => `BUG: ${message} - please report an issue at https://github.com/Effect-TS/effect/issues`; | |
| let SingleShotGen$1 = class SingleShotGen { | |
| self; | |
| called = false; | |
| constructor(self) { | |
| this.self = self; | |
| } | |
| next(a) { | |
| return this.called ? { | |
| value: a, | |
| done: true | |
| } : (this.called = true, { | |
| value: this.self, | |
| done: false | |
| }); | |
| } | |
| return(a) { | |
| return { | |
| value: a, | |
| done: true | |
| }; | |
| } | |
| throw(e) { | |
| throw e; | |
| } | |
| [Symbol.iterator]() { | |
| return new SingleShotGen(this.self); | |
| } | |
| }; | |
| const YieldWrapTypeId = Symbol.for("effect/Utils/YieldWrap"); | |
| class YieldWrap { | |
| #value; | |
| constructor(value) { | |
| this.#value = value; | |
| } | |
| [YieldWrapTypeId]() { | |
| return this.#value; | |
| } | |
| } | |
| const structuralRegionState = globalValue("effect/Utils/isStructuralRegion", () => ({ | |
| enabled: false, | |
| tester: void 0 | |
| })); | |
| const standard = { | |
| effect_internal_function: (body) => { | |
| return body(); | |
| } | |
| }; | |
| const forced = { | |
| effect_internal_function: (body) => { | |
| try { | |
| return body(); | |
| } finally { | |
| } | |
| } | |
| }; | |
| const isNotOptimizedAway = standard.effect_internal_function(() => new Error().stack)?.includes("effect_internal_function") === true; | |
| const internalCall = isNotOptimizedAway ? standard.effect_internal_function : forced.effect_internal_function; | |
| const randomHashCache = globalValue( Symbol.for("effect/Hash/randomHashCache"), () => new WeakMap()); | |
| const symbol$1 = Symbol.for("effect/Hash"); | |
| const hash = (self) => { | |
| if (structuralRegionState.enabled === true) { | |
| return 0; | |
| } | |
| switch (typeof self) { | |
| case "number": | |
| return number(self); | |
| case "bigint": | |
| return string(self.toString(10)); | |
| case "boolean": | |
| return string(String(self)); | |
| case "symbol": | |
| return string(String(self)); | |
| case "string": | |
| return string(self); | |
| case "undefined": | |
| return string("undefined"); | |
| case "function": | |
| case "object": { | |
| if (self === null) { | |
| return string("null"); | |
| } else if (self instanceof Date) { | |
| if (Number.isNaN(self.getTime())) { | |
| return string("Invalid Date"); | |
| } | |
| return hash(self.toISOString()); | |
| } else if (self instanceof URL) { | |
| return hash(self.href); | |
| } else if (isHash(self)) { | |
| return self[symbol$1](); | |
| } else { | |
| return random(self); | |
| } | |
| } | |
| default: | |
| throw new Error(`BUG: unhandled typeof ${typeof self} - please report an issue at https://github.com/Effect-TS/effect/issues`); | |
| } | |
| }; | |
| const random = (self) => { | |
| if (!randomHashCache.has(self)) { | |
| randomHashCache.set(self, number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))); | |
| } | |
| return randomHashCache.get(self); | |
| }; | |
| const combine = (b) => (self) => self * 53 ^ b; | |
| const optimize = (n) => n & 3221225471 | n >>> 1 & 1073741824; | |
| const isHash = (u) => hasProperty(u, symbol$1); | |
| const number = (n) => { | |
| if (n !== n || n === Infinity) { | |
| return 0; | |
| } | |
| let h = n | 0; | |
| if (h !== n) { | |
| h ^= n * 4294967295; | |
| } | |
| while (n > 4294967295) { | |
| h ^= n /= 4294967295; | |
| } | |
| return optimize(h); | |
| }; | |
| const string = (str) => { | |
| let h = 5381, i = str.length; | |
| while (i) { | |
| h = h * 33 ^ str.charCodeAt(--i); | |
| } | |
| return optimize(h); | |
| }; | |
| const array = (arr) => { | |
| let h = 6151; | |
| for (let i = 0; i < arr.length; i++) { | |
| h = pipe(h, combine(hash(arr[i]))); | |
| } | |
| return optimize(h); | |
| }; | |
| const cached = function() { | |
| if (arguments.length === 1) { | |
| const self2 = arguments[0]; | |
| return function(hash3) { | |
| Object.defineProperty(self2, symbol$1, { | |
| value() { | |
| return hash3; | |
| }, | |
| enumerable: false | |
| }); | |
| return hash3; | |
| }; | |
| } | |
| const self = arguments[0]; | |
| const hash2 = arguments[1]; | |
| Object.defineProperty(self, symbol$1, { | |
| value() { | |
| return hash2; | |
| }, | |
| enumerable: false | |
| }); | |
| return hash2; | |
| }; | |
| const symbol = Symbol.for("effect/Equal"); | |
| function equals() { | |
| if (arguments.length === 1) { | |
| return (self) => compareBoth(self, arguments[0]); | |
| } | |
| return compareBoth(arguments[0], arguments[1]); | |
| } | |
| function compareBoth(self, that) { | |
| if (self === that) { | |
| return true; | |
| } | |
| const selfType = typeof self; | |
| if (selfType !== typeof that) { | |
| return false; | |
| } | |
| if (selfType === "object" || selfType === "function") { | |
| if (self !== null && that !== null) { | |
| if (isEqual(self) && isEqual(that)) { | |
| if (hash(self) === hash(that) && self[symbol](that)) { | |
| return true; | |
| } else { | |
| return structuralRegionState.enabled && structuralRegionState.tester ? structuralRegionState.tester(self, that) : false; | |
| } | |
| } else if (self instanceof Date && that instanceof Date) { | |
| const t1 = self.getTime(); | |
| const t2 = that.getTime(); | |
| return t1 === t2 || Number.isNaN(t1) && Number.isNaN(t2); | |
| } else if (self instanceof URL && that instanceof URL) { | |
| return self.href === that.href; | |
| } | |
| } | |
| if (structuralRegionState.enabled) { | |
| if (Array.isArray(self) && Array.isArray(that)) { | |
| return self.length === that.length && self.every((v, i) => compareBoth(v, that[i])); | |
| } | |
| if (Object.getPrototypeOf(self) === Object.prototype && Object.getPrototypeOf(that) === Object.prototype) { | |
| const keysSelf = Object.keys(self); | |
| const keysThat = Object.keys(that); | |
| if (keysSelf.length === keysThat.length) { | |
| for (const key of keysSelf) { | |
| if (!(key in that && compareBoth(self[key], that[key]))) { | |
| return structuralRegionState.tester ? structuralRegionState.tester(self, that) : false; | |
| } | |
| } | |
| return true; | |
| } | |
| } | |
| return structuralRegionState.tester ? structuralRegionState.tester(self, that) : false; | |
| } | |
| } | |
| return structuralRegionState.enabled && structuralRegionState.tester ? structuralRegionState.tester(self, that) : false; | |
| } | |
| const isEqual = (u) => hasProperty(u, symbol); | |
| const NodeInspectSymbol = Symbol.for("nodejs.util.inspect.custom"); | |
| const toJSON = (x) => { | |
| try { | |
| if (hasProperty(x, "toJSON") && isFunction(x["toJSON"]) && x["toJSON"].length === 0) { | |
| return x.toJSON(); | |
| } else if (Array.isArray(x)) { | |
| return x.map(toJSON); | |
| } | |
| } catch { | |
| return {}; | |
| } | |
| return redact(x); | |
| }; | |
| const format = (x) => JSON.stringify(x, null, 2); | |
| const stringifyCircular = (obj, whitespace) => { | |
| let cache = []; | |
| const retVal = JSON.stringify(obj, (_key, value) => typeof value === "object" && value !== null ? cache.includes(value) ? void 0 : cache.push(value) && (redactableState.fiberRefs !== void 0 && isRedactable(value) ? value[symbolRedactable](redactableState.fiberRefs) : value) : value, whitespace); | |
| cache = void 0; | |
| return retVal; | |
| }; | |
| const symbolRedactable = Symbol.for("effect/Inspectable/Redactable"); | |
| const isRedactable = (u) => typeof u === "object" && u !== null && symbolRedactable in u; | |
| const redactableState = globalValue("effect/Inspectable/redactableState", () => ({ | |
| fiberRefs: void 0 | |
| })); | |
| const redact = (u) => { | |
| if (isRedactable(u) && redactableState.fiberRefs !== void 0) { | |
| return u[symbolRedactable](redactableState.fiberRefs); | |
| } | |
| return u; | |
| }; | |
| const pipeArguments = (self, args) => { | |
| switch (args.length) { | |
| case 0: | |
| return self; | |
| case 1: | |
| return args[0](self); | |
| case 2: | |
| return args[1](args[0](self)); | |
| case 3: | |
| return args[2](args[1](args[0](self))); | |
| case 4: | |
| return args[3](args[2](args[1](args[0](self)))); | |
| case 5: | |
| return args[4](args[3](args[2](args[1](args[0](self))))); | |
| case 6: | |
| return args[5](args[4](args[3](args[2](args[1](args[0](self)))))); | |
| case 7: | |
| return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))); | |
| case 8: | |
| return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))); | |
| case 9: | |
| return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))))); | |
| default: { | |
| let ret = self; | |
| for (let i = 0, len = args.length; i < len; i++) { | |
| ret = args[i](ret); | |
| } | |
| return ret; | |
| } | |
| } | |
| }; | |
| const OP_ASYNC = "Async"; | |
| const OP_COMMIT = "Commit"; | |
| const OP_FAILURE = "Failure"; | |
| const OP_ON_SUCCESS = "OnSuccess"; | |
| const OP_ON_SUCCESS_AND_FAILURE = "OnSuccessAndFailure"; | |
| const OP_SUCCESS = "Success"; | |
| const OP_UPDATE_RUNTIME_FLAGS = "UpdateRuntimeFlags"; | |
| let moduleVersion = "3.19.19"; | |
| const getCurrentVersion = () => moduleVersion; | |
| const EffectTypeId$1 = Symbol.for("effect/Effect"); | |
| const StreamTypeId = Symbol.for("effect/Stream"); | |
| const SinkTypeId = Symbol.for("effect/Sink"); | |
| const ChannelTypeId = Symbol.for("effect/Channel"); | |
| const effectVariance = { | |
| _R: (_) => _, | |
| _E: (_) => _, | |
| _A: (_) => _, | |
| _V: getCurrentVersion() | |
| }; | |
| const sinkVariance = { | |
| _A: (_) => _, | |
| _In: (_) => _, | |
| _L: (_) => _, | |
| _E: (_) => _, | |
| _R: (_) => _ | |
| }; | |
| const channelVariance = { | |
| _Env: (_) => _, | |
| _InErr: (_) => _, | |
| _InElem: (_) => _, | |
| _InDone: (_) => _, | |
| _OutErr: (_) => _, | |
| _OutElem: (_) => _, | |
| _OutDone: (_) => _ | |
| }; | |
| const EffectPrototype = { | |
| [EffectTypeId$1]: effectVariance, | |
| [StreamTypeId]: effectVariance, | |
| [SinkTypeId]: sinkVariance, | |
| [ChannelTypeId]: channelVariance, | |
| [symbol](that) { | |
| return this === that; | |
| }, | |
| [symbol$1]() { | |
| return cached(this, random(this)); | |
| }, | |
| [Symbol.iterator]() { | |
| return new SingleShotGen$1(new YieldWrap(this)); | |
| }, | |
| pipe() { | |
| return pipeArguments(this, arguments); | |
| } | |
| }; | |
| const TypeId$2 = Symbol.for("effect/Option"); | |
| const CommonProto$1 = { | |
| ...EffectPrototype, | |
| [TypeId$2]: { | |
| _A: (_) => _ | |
| }, | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| }, | |
| toString() { | |
| return format(this.toJSON()); | |
| } | |
| }; | |
| const SomeProto = Object.assign( Object.create(CommonProto$1), { | |
| _tag: "Some", | |
| _op: "Some", | |
| [symbol](that) { | |
| return isOption(that) && isSome$1(that) && equals(this.value, that.value); | |
| }, | |
| [symbol$1]() { | |
| return cached(this, combine(hash(this._tag))(hash(this.value))); | |
| }, | |
| toJSON() { | |
| return { | |
| _id: "Option", | |
| _tag: this._tag, | |
| value: toJSON(this.value) | |
| }; | |
| } | |
| }); | |
| const NoneHash = hash("None"); | |
| const NoneProto = Object.assign( Object.create(CommonProto$1), { | |
| _tag: "None", | |
| _op: "None", | |
| [symbol](that) { | |
| return isOption(that) && isNone$1(that); | |
| }, | |
| [symbol$1]() { | |
| return NoneHash; | |
| }, | |
| toJSON() { | |
| return { | |
| _id: "Option", | |
| _tag: this._tag | |
| }; | |
| } | |
| }); | |
| const isOption = (input) => hasProperty(input, TypeId$2); | |
| const isNone$1 = (fa) => fa._tag === "None"; | |
| const isSome$1 = (fa) => fa._tag === "Some"; | |
| const none$3 = Object.create(NoneProto); | |
| const some$1 = (value) => { | |
| const a = Object.create(SomeProto); | |
| a.value = value; | |
| return a; | |
| }; | |
| const TypeId$1 = Symbol.for("effect/Either"); | |
| const CommonProto = { | |
| ...EffectPrototype, | |
| [TypeId$1]: { | |
| _R: (_) => _ | |
| }, | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| }, | |
| toString() { | |
| return format(this.toJSON()); | |
| } | |
| }; | |
| const RightProto = Object.assign( Object.create(CommonProto), { | |
| _tag: "Right", | |
| _op: "Right", | |
| [symbol](that) { | |
| return isEither(that) && isRight(that) && equals(this.right, that.right); | |
| }, | |
| [symbol$1]() { | |
| return combine(hash(this._tag))(hash(this.right)); | |
| }, | |
| toJSON() { | |
| return { | |
| _id: "Either", | |
| _tag: this._tag, | |
| right: toJSON(this.right) | |
| }; | |
| } | |
| }); | |
| const LeftProto = Object.assign( Object.create(CommonProto), { | |
| _tag: "Left", | |
| _op: "Left", | |
| [symbol](that) { | |
| return isEither(that) && isLeft(that) && equals(this.left, that.left); | |
| }, | |
| [symbol$1]() { | |
| return combine(hash(this._tag))(hash(this.left)); | |
| }, | |
| toJSON() { | |
| return { | |
| _id: "Either", | |
| _tag: this._tag, | |
| left: toJSON(this.left) | |
| }; | |
| } | |
| }); | |
| const isEither = (input) => hasProperty(input, TypeId$1); | |
| const isLeft = (ma) => ma._tag === "Left"; | |
| const isRight = (ma) => ma._tag === "Right"; | |
| const left$1 = (left2) => { | |
| const a = Object.create(LeftProto); | |
| a.left = left2; | |
| return a; | |
| }; | |
| const right$1 = (right2) => { | |
| const a = Object.create(RightProto); | |
| a.right = right2; | |
| return a; | |
| }; | |
| const right = right$1; | |
| const left = left$1; | |
| const none$2 = () => none$3; | |
| const some = some$1; | |
| const isNone = isNone$1; | |
| const isSome = isSome$1; | |
| const getOrElse = dual(2, (self, onNone) => isNone(self) ? onNone() : self.value); | |
| const getOrUndefined = getOrElse(constUndefined); | |
| const fromIterable = (collection) => Array.isArray(collection) ? collection : Array.from(collection); | |
| const reverse$1 = (self) => Array.from(self).reverse(); | |
| const reduce$2 = dual(3, (self, b, f) => fromIterable(self).reduce((b2, a, i) => f(b2, a, i), b)); | |
| const TypeId = Symbol.for("effect/Chunk"); | |
| function copy(src, srcPos, dest, destPos, len) { | |
| for (let i = srcPos; i < Math.min(src.length, srcPos + len); i++) { | |
| dest[destPos + i - srcPos] = src[i]; | |
| } | |
| return dest; | |
| } | |
| const emptyArray = []; | |
| const getEquivalence = (isEquivalent) => make$3((self, that) => self.length === that.length && toReadonlyArray(self).every((value, i) => isEquivalent(value, unsafeGet(that, i)))); | |
| const _equivalence = getEquivalence(equals); | |
| const ChunkProto = { | |
| [TypeId]: { | |
| _A: (_) => _ | |
| }, | |
| toString() { | |
| return format(this.toJSON()); | |
| }, | |
| toJSON() { | |
| return { | |
| _id: "Chunk", | |
| values: toReadonlyArray(this).map(toJSON) | |
| }; | |
| }, | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| }, | |
| [symbol](that) { | |
| return isChunk(that) && _equivalence(this, that); | |
| }, | |
| [symbol$1]() { | |
| return cached(this, array(toReadonlyArray(this))); | |
| }, | |
| [Symbol.iterator]() { | |
| switch (this.backing._tag) { | |
| case "IArray": { | |
| return this.backing.array[Symbol.iterator](); | |
| } | |
| case "IEmpty": { | |
| return emptyArray[Symbol.iterator](); | |
| } | |
| default: { | |
| return toReadonlyArray(this)[Symbol.iterator](); | |
| } | |
| } | |
| }, | |
| pipe() { | |
| return pipeArguments(this, arguments); | |
| } | |
| }; | |
| const makeChunk = (backing) => { | |
| const chunk = Object.create(ChunkProto); | |
| chunk.backing = backing; | |
| switch (backing._tag) { | |
| case "IEmpty": { | |
| chunk.length = 0; | |
| chunk.depth = 0; | |
| chunk.left = chunk; | |
| chunk.right = chunk; | |
| break; | |
| } | |
| case "IConcat": { | |
| chunk.length = backing.left.length + backing.right.length; | |
| chunk.depth = 1 + Math.max(backing.left.depth, backing.right.depth); | |
| chunk.left = backing.left; | |
| chunk.right = backing.right; | |
| break; | |
| } | |
| case "IArray": { | |
| chunk.length = backing.array.length; | |
| chunk.depth = 0; | |
| chunk.left = _empty$2; | |
| chunk.right = _empty$2; | |
| break; | |
| } | |
| case "ISingleton": { | |
| chunk.length = 1; | |
| chunk.depth = 0; | |
| chunk.left = _empty$2; | |
| chunk.right = _empty$2; | |
| break; | |
| } | |
| case "ISlice": { | |
| chunk.length = backing.length; | |
| chunk.depth = backing.chunk.depth + 1; | |
| chunk.left = _empty$2; | |
| chunk.right = _empty$2; | |
| break; | |
| } | |
| } | |
| return chunk; | |
| }; | |
| const isChunk = (u) => hasProperty(u, TypeId); | |
| const _empty$2 = makeChunk({ | |
| _tag: "IEmpty" | |
| }); | |
| const empty$3 = () => _empty$2; | |
| const make$2 = (...as2) => unsafeFromNonEmptyArray(as2); | |
| const of = (a) => makeChunk({ | |
| _tag: "ISingleton", | |
| a | |
| }); | |
| const copyToArray = (self, array2, initial) => { | |
| switch (self.backing._tag) { | |
| case "IArray": { | |
| copy(self.backing.array, 0, array2, initial, self.length); | |
| break; | |
| } | |
| case "IConcat": { | |
| copyToArray(self.left, array2, initial); | |
| copyToArray(self.right, array2, initial + self.left.length); | |
| break; | |
| } | |
| case "ISingleton": { | |
| array2[initial] = self.backing.a; | |
| break; | |
| } | |
| case "ISlice": { | |
| let i = 0; | |
| let j = initial; | |
| while (i < self.length) { | |
| array2[j] = unsafeGet(self, i); | |
| i += 1; | |
| j += 1; | |
| } | |
| break; | |
| } | |
| } | |
| }; | |
| const toReadonlyArray_ = (self) => { | |
| switch (self.backing._tag) { | |
| case "IEmpty": { | |
| return emptyArray; | |
| } | |
| case "IArray": { | |
| return self.backing.array; | |
| } | |
| default: { | |
| const arr = new Array(self.length); | |
| copyToArray(self, arr, 0); | |
| self.backing = { | |
| _tag: "IArray", | |
| array: arr | |
| }; | |
| self.left = _empty$2; | |
| self.right = _empty$2; | |
| self.depth = 0; | |
| return arr; | |
| } | |
| } | |
| }; | |
| const toReadonlyArray = toReadonlyArray_; | |
| const reverseChunk = (self) => { | |
| switch (self.backing._tag) { | |
| case "IEmpty": | |
| case "ISingleton": | |
| return self; | |
| case "IArray": { | |
| return makeChunk({ | |
| _tag: "IArray", | |
| array: reverse$1(self.backing.array) | |
| }); | |
| } | |
| case "IConcat": { | |
| return makeChunk({ | |
| _tag: "IConcat", | |
| left: reverse(self.backing.right), | |
| right: reverse(self.backing.left) | |
| }); | |
| } | |
| case "ISlice": | |
| return unsafeFromArray(reverse$1(toReadonlyArray(self))); | |
| } | |
| }; | |
| const reverse = reverseChunk; | |
| const unsafeFromArray = (self) => self.length === 0 ? empty$3() : self.length === 1 ? of(self[0]) : makeChunk({ | |
| _tag: "IArray", | |
| array: self | |
| }); | |
| const unsafeFromNonEmptyArray = (self) => unsafeFromArray(self); | |
| const unsafeGet = dual(2, (self, index) => { | |
| switch (self.backing._tag) { | |
| case "IEmpty": { | |
| throw new Error(`Index out of bounds`); | |
| } | |
| case "ISingleton": { | |
| if (index !== 0) { | |
| throw new Error(`Index out of bounds`); | |
| } | |
| return self.backing.a; | |
| } | |
| case "IArray": { | |
| if (index >= self.length || index < 0) { | |
| throw new Error(`Index out of bounds`); | |
| } | |
| return self.backing.array[index]; | |
| } | |
| case "IConcat": { | |
| return index < self.left.length ? unsafeGet(self.left, index) : unsafeGet(self.right, index - self.left.length); | |
| } | |
| case "ISlice": { | |
| return unsafeGet(self.backing.chunk, index + self.backing.offset); | |
| } | |
| } | |
| }); | |
| const prepend = dual(2, (self, elem) => appendAll(of(elem), self)); | |
| const appendAll = dual(2, (self, that) => { | |
| if (self.backing._tag === "IEmpty") { | |
| return that; | |
| } | |
| if (that.backing._tag === "IEmpty") { | |
| return self; | |
| } | |
| const diff = that.depth - self.depth; | |
| if (Math.abs(diff) <= 1) { | |
| return makeChunk({ | |
| _tag: "IConcat", | |
| left: self, | |
| right: that | |
| }); | |
| } else if (diff < -1) { | |
| if (self.left.depth >= self.right.depth) { | |
| const nr = appendAll(self.right, that); | |
| return makeChunk({ | |
| _tag: "IConcat", | |
| left: self.left, | |
| right: nr | |
| }); | |
| } else { | |
| const nrr = appendAll(self.right.right, that); | |
| if (nrr.depth === self.depth - 3) { | |
| const nr = makeChunk({ | |
| _tag: "IConcat", | |
| left: self.right.left, | |
| right: nrr | |
| }); | |
| return makeChunk({ | |
| _tag: "IConcat", | |
| left: self.left, | |
| right: nr | |
| }); | |
| } else { | |
| const nl = makeChunk({ | |
| _tag: "IConcat", | |
| left: self.left, | |
| right: self.right.left | |
| }); | |
| return makeChunk({ | |
| _tag: "IConcat", | |
| left: nl, | |
| right: nrr | |
| }); | |
| } | |
| } | |
| } else { | |
| if (that.right.depth >= that.left.depth) { | |
| const nl = appendAll(self, that.left); | |
| return makeChunk({ | |
| _tag: "IConcat", | |
| left: nl, | |
| right: that.right | |
| }); | |
| } else { | |
| const nll = appendAll(self, that.left.left); | |
| if (nll.depth === that.depth - 3) { | |
| const nl = makeChunk({ | |
| _tag: "IConcat", | |
| left: nll, | |
| right: that.left.right | |
| }); | |
| return makeChunk({ | |
| _tag: "IConcat", | |
| left: nl, | |
| right: that.right | |
| }); | |
| } else { | |
| const nr = makeChunk({ | |
| _tag: "IConcat", | |
| left: that.left.right, | |
| right: that.right | |
| }); | |
| return makeChunk({ | |
| _tag: "IConcat", | |
| left: nll, | |
| right: nr | |
| }); | |
| } | |
| } | |
| } | |
| }); | |
| const isEmpty = (self) => self.length === 0; | |
| const isNonEmpty = (self) => self.length > 0; | |
| const unsafeHead = (self) => unsafeGet(self, 0); | |
| const headNonEmpty = unsafeHead; | |
| const SIZE = 5; | |
| const BUCKET_SIZE = Math.pow(2, SIZE); | |
| const MASK = BUCKET_SIZE - 1; | |
| const MAX_INDEX_NODE = BUCKET_SIZE / 2; | |
| const MIN_ARRAY_NODE = BUCKET_SIZE / 4; | |
| function popcount(x) { | |
| x -= x >> 1 & 1431655765; | |
| x = (x & 858993459) + (x >> 2 & 858993459); | |
| x = x + (x >> 4) & 252645135; | |
| x += x >> 8; | |
| x += x >> 16; | |
| return x & 127; | |
| } | |
| function hashFragment(shift, h) { | |
| return h >>> shift & MASK; | |
| } | |
| function toBitmap(x) { | |
| return 1 << x; | |
| } | |
| function fromBitmap(bitmap, bit) { | |
| return popcount(bitmap & bit - 1); | |
| } | |
| const make$1 = (value, previous) => ({ | |
| value, | |
| previous | |
| }); | |
| function arrayUpdate(mutate2, at, v, arr) { | |
| let out = arr; | |
| if (!mutate2) { | |
| const len = arr.length; | |
| out = new Array(len); | |
| for (let i = 0; i < len; ++i) out[i] = arr[i]; | |
| } | |
| out[at] = v; | |
| return out; | |
| } | |
| function arraySpliceOut(mutate2, at, arr) { | |
| const newLen = arr.length - 1; | |
| let i = 0; | |
| let g = 0; | |
| let out = arr; | |
| if (mutate2) { | |
| i = g = at; | |
| } else { | |
| out = new Array(newLen); | |
| while (i < at) out[g++] = arr[i++]; | |
| } | |
| ++i; | |
| while (i <= newLen) out[g++] = arr[i++]; | |
| if (mutate2) { | |
| out.length = newLen; | |
| } | |
| return out; | |
| } | |
| function arraySpliceIn(mutate2, at, v, arr) { | |
| const len = arr.length; | |
| if (mutate2) { | |
| let i2 = len; | |
| while (i2 >= at) arr[i2--] = arr[i2]; | |
| arr[at] = v; | |
| return arr; | |
| } | |
| let i = 0, g = 0; | |
| const out = new Array(len + 1); | |
| while (i < at) out[g++] = arr[i++]; | |
| out[at] = v; | |
| while (i < len) out[++g] = arr[i++]; | |
| return out; | |
| } | |
| class EmptyNode { | |
| _tag = "EmptyNode"; | |
| modify(edit, _shift, f, hash2, key, size2) { | |
| const v = f(none$2()); | |
| if (isNone(v)) return new EmptyNode(); | |
| ++size2.value; | |
| return new LeafNode(edit, hash2, key, v); | |
| } | |
| } | |
| function isEmptyNode(a) { | |
| return isTagged(a, "EmptyNode"); | |
| } | |
| function isLeafNode(node) { | |
| return isEmptyNode(node) || node._tag === "LeafNode" || node._tag === "CollisionNode"; | |
| } | |
| function canEditNode(node, edit) { | |
| return isEmptyNode(node) ? false : edit === node.edit; | |
| } | |
| class LeafNode { | |
| edit; | |
| hash; | |
| key; | |
| value; | |
| _tag = "LeafNode"; | |
| constructor(edit, hash2, key, value) { | |
| this.edit = edit; | |
| this.hash = hash2; | |
| this.key = key; | |
| this.value = value; | |
| } | |
| modify(edit, shift, f, hash2, key, size2) { | |
| if (equals(key, this.key)) { | |
| const v2 = f(this.value); | |
| if (v2 === this.value) return this; | |
| else if (isNone(v2)) { | |
| --size2.value; | |
| return new EmptyNode(); | |
| } | |
| if (canEditNode(this, edit)) { | |
| this.value = v2; | |
| return this; | |
| } | |
| return new LeafNode(edit, hash2, key, v2); | |
| } | |
| const v = f(none$2()); | |
| if (isNone(v)) return this; | |
| ++size2.value; | |
| return mergeLeaves(edit, shift, this.hash, this, hash2, new LeafNode(edit, hash2, key, v)); | |
| } | |
| } | |
| class CollisionNode { | |
| edit; | |
| hash; | |
| children; | |
| _tag = "CollisionNode"; | |
| constructor(edit, hash2, children) { | |
| this.edit = edit; | |
| this.hash = hash2; | |
| this.children = children; | |
| } | |
| modify(edit, shift, f, hash2, key, size2) { | |
| if (hash2 === this.hash) { | |
| const canEdit = canEditNode(this, edit); | |
| const list2 = this.updateCollisionList(canEdit, edit, this.hash, this.children, f, key, size2); | |
| if (list2 === this.children) return this; | |
| return list2.length > 1 ? new CollisionNode(edit, this.hash, list2) : list2[0]; | |
| } | |
| const v = f(none$2()); | |
| if (isNone(v)) return this; | |
| ++size2.value; | |
| return mergeLeaves(edit, shift, this.hash, this, hash2, new LeafNode(edit, hash2, key, v)); | |
| } | |
| updateCollisionList(mutate2, edit, hash2, list2, f, key, size2) { | |
| const len = list2.length; | |
| for (let i = 0; i < len; ++i) { | |
| const child = list2[i]; | |
| if ("key" in child && equals(key, child.key)) { | |
| const value = child.value; | |
| const newValue2 = f(value); | |
| if (newValue2 === value) return list2; | |
| if (isNone(newValue2)) { | |
| --size2.value; | |
| return arraySpliceOut(mutate2, i, list2); | |
| } | |
| return arrayUpdate(mutate2, i, new LeafNode(edit, hash2, key, newValue2), list2); | |
| } | |
| } | |
| const newValue = f(none$2()); | |
| if (isNone(newValue)) return list2; | |
| ++size2.value; | |
| return arrayUpdate(mutate2, len, new LeafNode(edit, hash2, key, newValue), list2); | |
| } | |
| } | |
| class IndexedNode { | |
| edit; | |
| mask; | |
| children; | |
| _tag = "IndexedNode"; | |
| constructor(edit, mask, children) { | |
| this.edit = edit; | |
| this.mask = mask; | |
| this.children = children; | |
| } | |
| modify(edit, shift, f, hash2, key, size2) { | |
| const mask = this.mask; | |
| const children = this.children; | |
| const frag = hashFragment(shift, hash2); | |
| const bit = toBitmap(frag); | |
| const indx = fromBitmap(mask, bit); | |
| const exists = mask & bit; | |
| const canEdit = canEditNode(this, edit); | |
| if (!exists) { | |
| const _newChild = new EmptyNode().modify(edit, shift + SIZE, f, hash2, key, size2); | |
| if (!_newChild) return this; | |
| return children.length >= MAX_INDEX_NODE ? expand(edit, frag, _newChild, mask, children) : new IndexedNode(edit, mask | bit, arraySpliceIn(canEdit, indx, _newChild, children)); | |
| } | |
| const current = children[indx]; | |
| const child = current.modify(edit, shift + SIZE, f, hash2, key, size2); | |
| if (current === child) return this; | |
| let bitmap = mask; | |
| let newChildren; | |
| if (isEmptyNode(child)) { | |
| bitmap &= ~bit; | |
| if (!bitmap) return new EmptyNode(); | |
| if (children.length <= 2 && isLeafNode(children[indx ^ 1])) { | |
| return children[indx ^ 1]; | |
| } | |
| newChildren = arraySpliceOut(canEdit, indx, children); | |
| } else { | |
| newChildren = arrayUpdate(canEdit, indx, child, children); | |
| } | |
| if (canEdit) { | |
| this.mask = bitmap; | |
| this.children = newChildren; | |
| return this; | |
| } | |
| return new IndexedNode(edit, bitmap, newChildren); | |
| } | |
| } | |
| class ArrayNode { | |
| edit; | |
| size; | |
| children; | |
| _tag = "ArrayNode"; | |
| constructor(edit, size2, children) { | |
| this.edit = edit; | |
| this.size = size2; | |
| this.children = children; | |
| } | |
| modify(edit, shift, f, hash2, key, size2) { | |
| let count = this.size; | |
| const children = this.children; | |
| const frag = hashFragment(shift, hash2); | |
| const child = children[frag]; | |
| const newChild = (child || new EmptyNode()).modify(edit, shift + SIZE, f, hash2, key, size2); | |
| if (child === newChild) return this; | |
| const canEdit = canEditNode(this, edit); | |
| let newChildren; | |
| if (isEmptyNode(child) && !isEmptyNode(newChild)) { | |
| ++count; | |
| newChildren = arrayUpdate(canEdit, frag, newChild, children); | |
| } else if (!isEmptyNode(child) && isEmptyNode(newChild)) { | |
| --count; | |
| if (count <= MIN_ARRAY_NODE) { | |
| return pack(edit, count, frag, children); | |
| } | |
| newChildren = arrayUpdate(canEdit, frag, new EmptyNode(), children); | |
| } else { | |
| newChildren = arrayUpdate(canEdit, frag, newChild, children); | |
| } | |
| if (canEdit) { | |
| this.size = count; | |
| this.children = newChildren; | |
| return this; | |
| } | |
| return new ArrayNode(edit, count, newChildren); | |
| } | |
| } | |
| function pack(edit, count, removed, elements) { | |
| const children = new Array(count - 1); | |
| let g = 0; | |
| let bitmap = 0; | |
| for (let i = 0, len = elements.length; i < len; ++i) { | |
| if (i !== removed) { | |
| const elem = elements[i]; | |
| if (elem && !isEmptyNode(elem)) { | |
| children[g++] = elem; | |
| bitmap |= 1 << i; | |
| } | |
| } | |
| } | |
| return new IndexedNode(edit, bitmap, children); | |
| } | |
| function expand(edit, frag, child, bitmap, subNodes) { | |
| const arr = []; | |
| let bit = bitmap; | |
| let count = 0; | |
| for (let i = 0; bit; ++i) { | |
| if (bit & 1) arr[i] = subNodes[count++]; | |
| bit >>>= 1; | |
| } | |
| arr[frag] = child; | |
| return new ArrayNode(edit, count + 1, arr); | |
| } | |
| function mergeLeavesInner(edit, shift, h1, n1, h2, n2) { | |
| if (h1 === h2) return new CollisionNode(edit, h1, [n2, n1]); | |
| const subH1 = hashFragment(shift, h1); | |
| const subH2 = hashFragment(shift, h2); | |
| if (subH1 === subH2) { | |
| return (child) => new IndexedNode(edit, toBitmap(subH1) | toBitmap(subH2), [child]); | |
| } else { | |
| const children = subH1 < subH2 ? [n1, n2] : [n2, n1]; | |
| return new IndexedNode(edit, toBitmap(subH1) | toBitmap(subH2), children); | |
| } | |
| } | |
| function mergeLeaves(edit, shift, h1, n1, h2, n2) { | |
| let stack = void 0; | |
| let currentShift = shift; | |
| while (true) { | |
| const res = mergeLeavesInner(edit, currentShift, h1, n1, h2, n2); | |
| if (typeof res === "function") { | |
| stack = make$1(res, stack); | |
| currentShift = currentShift + SIZE; | |
| } else { | |
| let final = res; | |
| while (stack != null) { | |
| final = stack.value(final); | |
| stack = stack.previous; | |
| } | |
| return final; | |
| } | |
| } | |
| } | |
| const HashMapSymbolKey = "effect/HashMap"; | |
| const HashMapTypeId = Symbol.for(HashMapSymbolKey); | |
| const HashMapProto = { | |
| [HashMapTypeId]: HashMapTypeId, | |
| [Symbol.iterator]() { | |
| return new HashMapIterator(this, (k, v) => [k, v]); | |
| }, | |
| [symbol$1]() { | |
| let hash$1 = hash(HashMapSymbolKey); | |
| for (const item of this) { | |
| hash$1 ^= pipe(hash(item[0]), combine(hash(item[1]))); | |
| } | |
| return cached(this, hash$1); | |
| }, | |
| [symbol](that) { | |
| if (isHashMap(that)) { | |
| if (that._size !== this._size) { | |
| return false; | |
| } | |
| for (const item of this) { | |
| const elem = pipe(that, getHash(item[0], hash(item[0]))); | |
| if (isNone(elem)) { | |
| return false; | |
| } else { | |
| if (!equals(item[1], elem.value)) { | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| return false; | |
| }, | |
| toString() { | |
| return format(this.toJSON()); | |
| }, | |
| toJSON() { | |
| return { | |
| _id: "HashMap", | |
| values: Array.from(this).map(toJSON) | |
| }; | |
| }, | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| }, | |
| pipe() { | |
| return pipeArguments(this, arguments); | |
| } | |
| }; | |
| const makeImpl$1 = (editable, edit, root, size2) => { | |
| const map = Object.create(HashMapProto); | |
| map._editable = editable; | |
| map._edit = edit; | |
| map._root = root; | |
| map._size = size2; | |
| return map; | |
| }; | |
| class HashMapIterator { | |
| map; | |
| f; | |
| v; | |
| constructor(map, f) { | |
| this.map = map; | |
| this.f = f; | |
| this.v = visitLazy(this.map._root, this.f, void 0); | |
| } | |
| next() { | |
| if (isNone(this.v)) { | |
| return { | |
| done: true, | |
| value: void 0 | |
| }; | |
| } | |
| const v0 = this.v.value; | |
| this.v = applyCont(v0.cont); | |
| return { | |
| done: false, | |
| value: v0.value | |
| }; | |
| } | |
| [Symbol.iterator]() { | |
| return new HashMapIterator(this.map, this.f); | |
| } | |
| } | |
| const applyCont = (cont) => cont ? visitLazyChildren(cont[0], cont[1], cont[2], cont[3], cont[4]) : none$2(); | |
| const visitLazy = (node, f, cont = void 0) => { | |
| switch (node._tag) { | |
| case "LeafNode": { | |
| if (isSome(node.value)) { | |
| return some({ | |
| value: f(node.key, node.value.value), | |
| cont | |
| }); | |
| } | |
| return applyCont(cont); | |
| } | |
| case "CollisionNode": | |
| case "ArrayNode": | |
| case "IndexedNode": { | |
| const children = node.children; | |
| return visitLazyChildren(children.length, children, 0, f, cont); | |
| } | |
| default: { | |
| return applyCont(cont); | |
| } | |
| } | |
| }; | |
| const visitLazyChildren = (len, children, i, f, cont) => { | |
| while (i < len) { | |
| const child = children[i++]; | |
| if (child && !isEmptyNode(child)) { | |
| return visitLazy(child, f, [len, children, i, f, cont]); | |
| } | |
| } | |
| return applyCont(cont); | |
| }; | |
| const _empty$1 = makeImpl$1(false, 0, new EmptyNode(), 0); | |
| const empty$2 = () => _empty$1; | |
| const isHashMap = (u) => hasProperty(u, HashMapTypeId); | |
| const getHash = dual(3, (self, key, hash2) => { | |
| let node = self._root; | |
| let shift = 0; | |
| while (true) { | |
| switch (node._tag) { | |
| case "LeafNode": { | |
| return equals(key, node.key) ? node.value : none$2(); | |
| } | |
| case "CollisionNode": { | |
| if (hash2 === node.hash) { | |
| const children = node.children; | |
| for (let i = 0, len = children.length; i < len; ++i) { | |
| const child = children[i]; | |
| if ("key" in child && equals(key, child.key)) { | |
| return child.value; | |
| } | |
| } | |
| } | |
| return none$2(); | |
| } | |
| case "IndexedNode": { | |
| const frag = hashFragment(shift, hash2); | |
| const bit = toBitmap(frag); | |
| if (node.mask & bit) { | |
| node = node.children[fromBitmap(node.mask, bit)]; | |
| shift += SIZE; | |
| break; | |
| } | |
| return none$2(); | |
| } | |
| case "ArrayNode": { | |
| node = node.children[hashFragment(shift, hash2)]; | |
| if (node) { | |
| shift += SIZE; | |
| break; | |
| } | |
| return none$2(); | |
| } | |
| default: | |
| return none$2(); | |
| } | |
| } | |
| }); | |
| const set$1 = dual(3, (self, key, value) => modifyAt(self, key, () => some(value))); | |
| const setTree = dual(3, (self, newRoot, newSize) => { | |
| if (self._editable) { | |
| self._root = newRoot; | |
| self._size = newSize; | |
| return self; | |
| } | |
| return newRoot === self._root ? self : makeImpl$1(self._editable, self._edit, newRoot, newSize); | |
| }); | |
| const keys = (self) => new HashMapIterator(self, (key) => key); | |
| const size$2 = (self) => self._size; | |
| const beginMutation$1 = (self) => makeImpl$1(true, self._edit + 1, self._root, self._size); | |
| const modifyAt = dual(3, (self, key, f) => modifyHash(self, key, hash(key), f)); | |
| const modifyHash = dual(4, (self, key, hash2, f) => { | |
| const size2 = { | |
| value: self._size | |
| }; | |
| const newRoot = self._root.modify(self._editable ? self._edit : NaN, 0, f, hash2, key, size2); | |
| return pipe(self, setTree(newRoot, size2.value)); | |
| }); | |
| const forEach$1 = dual(2, (self, f) => reduce$1(self, void 0, (_, value, key) => f(value, key))); | |
| const reduce$1 = dual(3, (self, zero, f) => { | |
| const root = self._root; | |
| if (root._tag === "LeafNode") { | |
| return isSome(root.value) ? f(zero, root.value.value, root.key) : zero; | |
| } | |
| if (root._tag === "EmptyNode") { | |
| return zero; | |
| } | |
| const toVisit = [root.children]; | |
| let children; | |
| while (children = toVisit.pop()) { | |
| for (let i = 0, len = children.length; i < len; ) { | |
| const child = children[i++]; | |
| if (child && !isEmptyNode(child)) { | |
| if (child._tag === "LeafNode") { | |
| if (isSome(child.value)) { | |
| zero = f(zero, child.value.value, child.key); | |
| } | |
| } else { | |
| toVisit.push(child.children); | |
| } | |
| } | |
| } | |
| } | |
| return zero; | |
| }); | |
| const HashSetSymbolKey = "effect/HashSet"; | |
| const HashSetTypeId = Symbol.for(HashSetSymbolKey); | |
| const HashSetProto = { | |
| [HashSetTypeId]: HashSetTypeId, | |
| [Symbol.iterator]() { | |
| return keys(this._keyMap); | |
| }, | |
| [symbol$1]() { | |
| return cached(this, combine(hash(this._keyMap))(hash(HashSetSymbolKey))); | |
| }, | |
| [symbol](that) { | |
| if (isHashSet(that)) { | |
| return size$2(this._keyMap) === size$2(that._keyMap) && equals(this._keyMap, that._keyMap); | |
| } | |
| return false; | |
| }, | |
| toString() { | |
| return format(this.toJSON()); | |
| }, | |
| toJSON() { | |
| return { | |
| _id: "HashSet", | |
| values: Array.from(this).map(toJSON) | |
| }; | |
| }, | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| }, | |
| pipe() { | |
| return pipeArguments(this, arguments); | |
| } | |
| }; | |
| const makeImpl = (keyMap) => { | |
| const set2 = Object.create(HashSetProto); | |
| set2._keyMap = keyMap; | |
| return set2; | |
| }; | |
| const isHashSet = (u) => hasProperty(u, HashSetTypeId); | |
| const _empty = makeImpl( empty$2()); | |
| const empty$1 = () => _empty; | |
| const size$1 = (self) => size$2(self._keyMap); | |
| const beginMutation = (self) => makeImpl(beginMutation$1(self._keyMap)); | |
| const endMutation = (self) => { | |
| self._keyMap._editable = false; | |
| return self; | |
| }; | |
| const mutate = dual(2, (self, f) => { | |
| const transient = beginMutation(self); | |
| f(transient); | |
| return endMutation(transient); | |
| }); | |
| const add$1 = dual(2, (self, value) => self._keyMap._editable ? (set$1(value, true)(self._keyMap), self) : makeImpl(set$1(value, true)(self._keyMap))); | |
| const union$1 = dual(2, (self, that) => mutate(empty$1(), (set2) => { | |
| forEach(self, (value) => add$1(set2, value)); | |
| for (const value of that) { | |
| add$1(set2, value); | |
| } | |
| })); | |
| const forEach = dual(2, (self, f) => forEach$1(self._keyMap, (_, k) => f(k))); | |
| const empty = empty$1; | |
| const size = size$1; | |
| const add = add$1; | |
| const union = union$1; | |
| const FiberIdSymbolKey = "effect/FiberId"; | |
| const FiberIdTypeId = Symbol.for(FiberIdSymbolKey); | |
| const OP_NONE = "None"; | |
| const emptyHash = string(`${FiberIdSymbolKey}-${OP_NONE}`); | |
| class None { | |
| [FiberIdTypeId] = FiberIdTypeId; | |
| _tag = OP_NONE; | |
| id = -1; | |
| startTimeMillis = -1; | |
| [symbol$1]() { | |
| return emptyHash; | |
| } | |
| [symbol](that) { | |
| return isFiberId(that) && that._tag === OP_NONE; | |
| } | |
| toString() { | |
| return format(this.toJSON()); | |
| } | |
| toJSON() { | |
| return { | |
| _id: "FiberId", | |
| _tag: this._tag | |
| }; | |
| } | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| } | |
| } | |
| const none$1 = new None(); | |
| const isFiberId = (self) => hasProperty(self, FiberIdTypeId); | |
| const none = none$1; | |
| const BIT_MASK = 255; | |
| const BIT_SHIFT = 8; | |
| const make = (active, enabled) => (active & BIT_MASK) + ((enabled & active & BIT_MASK) << BIT_SHIFT); | |
| const enable$1 = (flag) => make(flag, flag); | |
| const disable$1 = (flag) => make(flag, 0); | |
| const Interruption = 1 << 0; | |
| const interruption = (self) => isEnabled(self, Interruption); | |
| const isEnabled = dual(2, (self, flag) => (self & flag) !== 0); | |
| const enable = enable$1; | |
| const disable = disable$1; | |
| const OP_DIE = "Die"; | |
| const OP_EMPTY = "Empty"; | |
| const OP_FAIL = "Fail"; | |
| const OP_INTERRUPT = "Interrupt"; | |
| const OP_PARALLEL = "Parallel"; | |
| const OP_SEQUENTIAL = "Sequential"; | |
| const CauseSymbolKey = "effect/Cause"; | |
| const CauseTypeId = Symbol.for(CauseSymbolKey); | |
| const variance = { | |
| _E: (_) => _ | |
| }; | |
| const proto = { | |
| [CauseTypeId]: variance, | |
| [symbol$1]() { | |
| return pipe(hash(CauseSymbolKey), combine(hash(flattenCause(this))), cached(this)); | |
| }, | |
| [symbol](that) { | |
| return isCause(that) && causeEquals(this, that); | |
| }, | |
| pipe() { | |
| return pipeArguments(this, arguments); | |
| }, | |
| toJSON() { | |
| switch (this._tag) { | |
| case "Empty": | |
| return { | |
| _id: "Cause", | |
| _tag: this._tag | |
| }; | |
| case "Die": | |
| return { | |
| _id: "Cause", | |
| _tag: this._tag, | |
| defect: toJSON(this.defect) | |
| }; | |
| case "Interrupt": | |
| return { | |
| _id: "Cause", | |
| _tag: this._tag, | |
| fiberId: this.fiberId.toJSON() | |
| }; | |
| case "Fail": | |
| return { | |
| _id: "Cause", | |
| _tag: this._tag, | |
| failure: toJSON(this.error) | |
| }; | |
| case "Sequential": | |
| case "Parallel": | |
| return { | |
| _id: "Cause", | |
| _tag: this._tag, | |
| left: toJSON(this.left), | |
| right: toJSON(this.right) | |
| }; | |
| } | |
| }, | |
| toString() { | |
| return pretty(this); | |
| }, | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| } | |
| }; | |
| const parallel = (left2, right2) => { | |
| const o = Object.create(proto); | |
| o._tag = OP_PARALLEL; | |
| o.left = left2; | |
| o.right = right2; | |
| return o; | |
| }; | |
| const sequential = (left2, right2) => { | |
| const o = Object.create(proto); | |
| o._tag = OP_SEQUENTIAL; | |
| o.left = left2; | |
| o.right = right2; | |
| return o; | |
| }; | |
| const isCause = (u) => hasProperty(u, CauseTypeId); | |
| const isInterruptedOnly = (self) => reduceWithContext(void 0, IsInterruptedOnlyCauseReducer)(self); | |
| const interruptors = (self) => reduce(self, empty(), (set2, cause) => cause._tag === OP_INTERRUPT ? some(pipe(set2, add(cause.fiberId))) : none$2()); | |
| const causeEquals = (left2, right2) => { | |
| let leftStack = of(left2); | |
| let rightStack = of(right2); | |
| while (isNonEmpty(leftStack) && isNonEmpty(rightStack)) { | |
| const [leftParallel, leftSequential] = pipe(headNonEmpty(leftStack), reduce([empty(), empty$3()], ([parallel2, sequential2], cause) => { | |
| const [par, seq] = evaluateCause(cause); | |
| return some([pipe(parallel2, union(par)), pipe(sequential2, appendAll(seq))]); | |
| })); | |
| const [rightParallel, rightSequential] = pipe(headNonEmpty(rightStack), reduce([empty(), empty$3()], ([parallel2, sequential2], cause) => { | |
| const [par, seq] = evaluateCause(cause); | |
| return some([pipe(parallel2, union(par)), pipe(sequential2, appendAll(seq))]); | |
| })); | |
| if (!equals(leftParallel, rightParallel)) { | |
| return false; | |
| } | |
| leftStack = leftSequential; | |
| rightStack = rightSequential; | |
| } | |
| return true; | |
| }; | |
| const flattenCause = (cause) => { | |
| return flattenCauseLoop(of(cause), empty$3()); | |
| }; | |
| const flattenCauseLoop = (causes, flattened) => { | |
| while (1) { | |
| const [parallel2, sequential2] = pipe(causes, reduce$2([empty(), empty$3()], ([parallel3, sequential3], cause) => { | |
| const [par, seq] = evaluateCause(cause); | |
| return [pipe(parallel3, union(par)), pipe(sequential3, appendAll(seq))]; | |
| })); | |
| const updated = size(parallel2) > 0 ? pipe(flattened, prepend(parallel2)) : flattened; | |
| if (isEmpty(sequential2)) { | |
| return reverse(updated); | |
| } | |
| causes = sequential2; | |
| flattened = updated; | |
| } | |
| throw new Error(getBugErrorMessage("Cause.flattenCauseLoop")); | |
| }; | |
| const evaluateCause = (self) => { | |
| let cause = self; | |
| const stack = []; | |
| let _parallel = empty(); | |
| let _sequential = empty$3(); | |
| while (cause !== void 0) { | |
| switch (cause._tag) { | |
| case OP_EMPTY: { | |
| if (stack.length === 0) { | |
| return [_parallel, _sequential]; | |
| } | |
| cause = stack.pop(); | |
| break; | |
| } | |
| case OP_FAIL: { | |
| _parallel = add(_parallel, make$2(cause._tag, cause.error)); | |
| if (stack.length === 0) { | |
| return [_parallel, _sequential]; | |
| } | |
| cause = stack.pop(); | |
| break; | |
| } | |
| case OP_DIE: { | |
| _parallel = add(_parallel, make$2(cause._tag, cause.defect)); | |
| if (stack.length === 0) { | |
| return [_parallel, _sequential]; | |
| } | |
| cause = stack.pop(); | |
| break; | |
| } | |
| case OP_INTERRUPT: { | |
| _parallel = add(_parallel, make$2(cause._tag, cause.fiberId)); | |
| if (stack.length === 0) { | |
| return [_parallel, _sequential]; | |
| } | |
| cause = stack.pop(); | |
| break; | |
| } | |
| case OP_SEQUENTIAL: { | |
| switch (cause.left._tag) { | |
| case OP_EMPTY: { | |
| cause = cause.right; | |
| break; | |
| } | |
| case OP_SEQUENTIAL: { | |
| cause = sequential(cause.left.left, sequential(cause.left.right, cause.right)); | |
| break; | |
| } | |
| case OP_PARALLEL: { | |
| cause = parallel(sequential(cause.left.left, cause.right), sequential(cause.left.right, cause.right)); | |
| break; | |
| } | |
| default: { | |
| _sequential = prepend(_sequential, cause.right); | |
| cause = cause.left; | |
| break; | |
| } | |
| } | |
| break; | |
| } | |
| case OP_PARALLEL: { | |
| stack.push(cause.right); | |
| cause = cause.left; | |
| break; | |
| } | |
| } | |
| } | |
| throw new Error(getBugErrorMessage("Cause.evaluateCauseLoop")); | |
| }; | |
| const IsInterruptedOnlyCauseReducer = { | |
| emptyCase: constTrue, | |
| failCase: constFalse, | |
| dieCase: constFalse, | |
| interruptCase: constTrue, | |
| sequentialCase: (_, left2, right2) => left2 && right2, | |
| parallelCase: (_, left2, right2) => left2 && right2 | |
| }; | |
| const OP_SEQUENTIAL_CASE = "SequentialCase"; | |
| const OP_PARALLEL_CASE = "ParallelCase"; | |
| const reduce = dual(3, (self, zero, pf) => { | |
| let accumulator = zero; | |
| let cause = self; | |
| const causes = []; | |
| while (cause !== void 0) { | |
| const option = pf(accumulator, cause); | |
| accumulator = isSome(option) ? option.value : accumulator; | |
| switch (cause._tag) { | |
| case OP_SEQUENTIAL: { | |
| causes.push(cause.right); | |
| cause = cause.left; | |
| break; | |
| } | |
| case OP_PARALLEL: { | |
| causes.push(cause.right); | |
| cause = cause.left; | |
| break; | |
| } | |
| default: { | |
| cause = void 0; | |
| break; | |
| } | |
| } | |
| if (cause === void 0 && causes.length > 0) { | |
| cause = causes.pop(); | |
| } | |
| } | |
| return accumulator; | |
| }); | |
| const reduceWithContext = dual(3, (self, context, reducer) => { | |
| const input = [self]; | |
| const output = []; | |
| while (input.length > 0) { | |
| const cause = input.pop(); | |
| switch (cause._tag) { | |
| case OP_EMPTY: { | |
| output.push(right(reducer.emptyCase(context))); | |
| break; | |
| } | |
| case OP_FAIL: { | |
| output.push(right(reducer.failCase(context, cause.error))); | |
| break; | |
| } | |
| case OP_DIE: { | |
| output.push(right(reducer.dieCase(context, cause.defect))); | |
| break; | |
| } | |
| case OP_INTERRUPT: { | |
| output.push(right(reducer.interruptCase(context, cause.fiberId))); | |
| break; | |
| } | |
| case OP_SEQUENTIAL: { | |
| input.push(cause.right); | |
| input.push(cause.left); | |
| output.push(left({ | |
| _tag: OP_SEQUENTIAL_CASE | |
| })); | |
| break; | |
| } | |
| case OP_PARALLEL: { | |
| input.push(cause.right); | |
| input.push(cause.left); | |
| output.push(left({ | |
| _tag: OP_PARALLEL_CASE | |
| })); | |
| break; | |
| } | |
| } | |
| } | |
| const accumulator = []; | |
| while (output.length > 0) { | |
| const either = output.pop(); | |
| switch (either._tag) { | |
| case "Left": { | |
| switch (either.left._tag) { | |
| case OP_SEQUENTIAL_CASE: { | |
| const left2 = accumulator.pop(); | |
| const right2 = accumulator.pop(); | |
| const value = reducer.sequentialCase(context, left2, right2); | |
| accumulator.push(value); | |
| break; | |
| } | |
| case OP_PARALLEL_CASE: { | |
| const left2 = accumulator.pop(); | |
| const right2 = accumulator.pop(); | |
| const value = reducer.parallelCase(context, left2, right2); | |
| accumulator.push(value); | |
| break; | |
| } | |
| } | |
| break; | |
| } | |
| case "Right": { | |
| accumulator.push(either.right); | |
| break; | |
| } | |
| } | |
| } | |
| if (accumulator.length === 0) { | |
| throw new Error("BUG: Cause.reduceWithContext - please report an issue at https://github.com/Effect-TS/effect/issues"); | |
| } | |
| return accumulator.pop(); | |
| }); | |
| const pretty = (cause, options) => { | |
| if (isInterruptedOnly(cause)) { | |
| return "All fibers interrupted without errors."; | |
| } | |
| return prettyErrors(cause).map(function(e) { | |
| { | |
| return e.stack; | |
| } | |
| }).join("\n"); | |
| }; | |
| class PrettyError extends globalThis.Error { | |
| span = void 0; | |
| constructor(originalError) { | |
| const originalErrorIsObject = typeof originalError === "object" && originalError !== null; | |
| const prevLimit = Error.stackTraceLimit; | |
| Error.stackTraceLimit = 1; | |
| super(prettyErrorMessage(originalError), originalErrorIsObject && "cause" in originalError && typeof originalError.cause !== "undefined" ? { | |
| cause: new PrettyError(originalError.cause) | |
| } : void 0); | |
| if (this.message === "") { | |
| this.message = "An error has occurred"; | |
| } | |
| Error.stackTraceLimit = prevLimit; | |
| this.name = originalError instanceof Error ? originalError.name : "Error"; | |
| if (originalErrorIsObject) { | |
| if (spanSymbol in originalError) { | |
| this.span = originalError[spanSymbol]; | |
| } | |
| Object.keys(originalError).forEach((key) => { | |
| if (!(key in this)) { | |
| this[key] = originalError[key]; | |
| } | |
| }); | |
| } | |
| this.stack = prettyErrorStack(`${this.name}: ${this.message}`, originalError instanceof Error && originalError.stack ? originalError.stack : "", this.span); | |
| } | |
| } | |
| const prettyErrorMessage = (u) => { | |
| if (typeof u === "string") { | |
| return u; | |
| } | |
| if (typeof u === "object" && u !== null && u instanceof Error) { | |
| return u.message; | |
| } | |
| try { | |
| if (hasProperty(u, "toString") && isFunction(u["toString"]) && u["toString"] !== Object.prototype.toString && u["toString"] !== globalThis.Array.prototype.toString) { | |
| return u["toString"](); | |
| } | |
| } catch { | |
| } | |
| return stringifyCircular(u); | |
| }; | |
| const locationRegex = /\((.*)\)/g; | |
| const spanToTrace = globalValue("effect/Tracer/spanToTrace", () => new WeakMap()); | |
| const prettyErrorStack = (message, stack, span) => { | |
| const out = [message]; | |
| const lines = stack.startsWith(message) ? stack.slice(message.length).split("\n") : stack.split("\n"); | |
| for (let i = 1; i < lines.length; i++) { | |
| if (lines[i].includes(" at new BaseEffectError") || lines[i].includes(" at new YieldableError")) { | |
| i++; | |
| continue; | |
| } | |
| if (lines[i].includes("Generator.next")) { | |
| break; | |
| } | |
| if (lines[i].includes("effect_internal_function")) { | |
| break; | |
| } | |
| out.push(lines[i].replace(/at .*effect_instruction_i.*\((.*)\)/, "at $1").replace(/EffectPrimitive\.\w+/, "<anonymous>")); | |
| } | |
| if (span) { | |
| let current = span; | |
| let i = 0; | |
| while (current && current._tag === "Span" && i < 10) { | |
| const stackFn = spanToTrace.get(current); | |
| if (typeof stackFn === "function") { | |
| const stack2 = stackFn(); | |
| if (typeof stack2 === "string") { | |
| const locationMatchAll = stack2.matchAll(locationRegex); | |
| let match2 = false; | |
| for (const [, location2] of locationMatchAll) { | |
| match2 = true; | |
| out.push(` at ${current.name} (${location2})`); | |
| } | |
| if (!match2) { | |
| out.push(` at ${current.name} (${stack2.replace(/^at /, "")})`); | |
| } | |
| } else { | |
| out.push(` at ${current.name}`); | |
| } | |
| } else { | |
| out.push(` at ${current.name}`); | |
| } | |
| current = getOrUndefined(current.parent); | |
| i++; | |
| } | |
| } | |
| return out.join("\n"); | |
| }; | |
| const spanSymbol = Symbol.for("effect/SpanAnnotation"); | |
| const prettyErrors = (cause) => reduceWithContext(cause, void 0, { | |
| emptyCase: () => [], | |
| dieCase: (_, unknownError) => { | |
| return [new PrettyError(unknownError)]; | |
| }, | |
| failCase: (_, error) => { | |
| return [new PrettyError(error)]; | |
| }, | |
| interruptCase: () => [], | |
| parallelCase: (_, l, r) => [...l, ...r], | |
| sequentialCase: (_, l, r) => [...l, ...r] | |
| }); | |
| class SingleShotGen2 { | |
| self; | |
| called = false; | |
| constructor(self) { | |
| this.self = self; | |
| } | |
| next(a) { | |
| return this.called ? { | |
| value: a, | |
| done: true | |
| } : (this.called = true, { | |
| value: this.self, | |
| done: false | |
| }); | |
| } | |
| return(a) { | |
| return { | |
| value: a, | |
| done: true | |
| }; | |
| } | |
| throw(e) { | |
| throw e; | |
| } | |
| [Symbol.iterator]() { | |
| return new SingleShotGen2(this.self); | |
| } | |
| } | |
| const EffectTypeId = Symbol.for("effect/Effect"); | |
| class EffectPrimitive { | |
| _op; | |
| effect_instruction_i0 = void 0; | |
| effect_instruction_i1 = void 0; | |
| effect_instruction_i2 = void 0; | |
| trace = void 0; | |
| [EffectTypeId] = effectVariance; | |
| constructor(_op) { | |
| this._op = _op; | |
| } | |
| [symbol](that) { | |
| return this === that; | |
| } | |
| [symbol$1]() { | |
| return cached(this, random(this)); | |
| } | |
| pipe() { | |
| return pipeArguments(this, arguments); | |
| } | |
| toJSON() { | |
| return { | |
| _id: "Effect", | |
| _op: this._op, | |
| effect_instruction_i0: toJSON(this.effect_instruction_i0), | |
| effect_instruction_i1: toJSON(this.effect_instruction_i1), | |
| effect_instruction_i2: toJSON(this.effect_instruction_i2) | |
| }; | |
| } | |
| toString() { | |
| return format(this.toJSON()); | |
| } | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| } | |
| [Symbol.iterator]() { | |
| return new SingleShotGen2(new YieldWrap(this)); | |
| } | |
| } | |
| class EffectPrimitiveFailure { | |
| _op; | |
| effect_instruction_i0 = void 0; | |
| effect_instruction_i1 = void 0; | |
| effect_instruction_i2 = void 0; | |
| trace = void 0; | |
| [EffectTypeId] = effectVariance; | |
| constructor(_op) { | |
| this._op = _op; | |
| this._tag = _op; | |
| } | |
| [symbol](that) { | |
| return exitIsExit(that) && that._op === "Failure" && | |
| equals(this.effect_instruction_i0, that.effect_instruction_i0); | |
| } | |
| [symbol$1]() { | |
| return pipe( | |
| string(this._tag), | |
| combine(hash(this.effect_instruction_i0)), | |
| cached(this) | |
| ); | |
| } | |
| get cause() { | |
| return this.effect_instruction_i0; | |
| } | |
| pipe() { | |
| return pipeArguments(this, arguments); | |
| } | |
| toJSON() { | |
| return { | |
| _id: "Exit", | |
| _tag: this._op, | |
| cause: this.cause.toJSON() | |
| }; | |
| } | |
| toString() { | |
| return format(this.toJSON()); | |
| } | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| } | |
| [Symbol.iterator]() { | |
| return new SingleShotGen2(new YieldWrap(this)); | |
| } | |
| } | |
| class EffectPrimitiveSuccess { | |
| _op; | |
| effect_instruction_i0 = void 0; | |
| effect_instruction_i1 = void 0; | |
| effect_instruction_i2 = void 0; | |
| trace = void 0; | |
| [EffectTypeId] = effectVariance; | |
| constructor(_op) { | |
| this._op = _op; | |
| this._tag = _op; | |
| } | |
| [symbol](that) { | |
| return exitIsExit(that) && that._op === "Success" && | |
| equals(this.effect_instruction_i0, that.effect_instruction_i0); | |
| } | |
| [symbol$1]() { | |
| return pipe( | |
| string(this._tag), | |
| combine(hash(this.effect_instruction_i0)), | |
| cached(this) | |
| ); | |
| } | |
| get value() { | |
| return this.effect_instruction_i0; | |
| } | |
| pipe() { | |
| return pipeArguments(this, arguments); | |
| } | |
| toJSON() { | |
| return { | |
| _id: "Exit", | |
| _tag: this._op, | |
| value: toJSON(this.value) | |
| }; | |
| } | |
| toString() { | |
| return format(this.toJSON()); | |
| } | |
| [NodeInspectSymbol]() { | |
| return this.toJSON(); | |
| } | |
| [Symbol.iterator]() { | |
| return new SingleShotGen2(new YieldWrap(this)); | |
| } | |
| } | |
| const isEffect = (u) => hasProperty(u, EffectTypeId); | |
| const as = dual(2, (self, value) => flatMap(self, () => succeed(value))); | |
| const asVoid = (self) => as(self, void 0); | |
| const custom = function() { | |
| const wrapper = new EffectPrimitive(OP_COMMIT); | |
| switch (arguments.length) { | |
| case 2: { | |
| wrapper.effect_instruction_i0 = arguments[0]; | |
| wrapper.commit = arguments[1]; | |
| break; | |
| } | |
| case 3: { | |
| wrapper.effect_instruction_i0 = arguments[0]; | |
| wrapper.effect_instruction_i1 = arguments[1]; | |
| wrapper.commit = arguments[2]; | |
| break; | |
| } | |
| case 4: { | |
| wrapper.effect_instruction_i0 = arguments[0]; | |
| wrapper.effect_instruction_i1 = arguments[1]; | |
| wrapper.effect_instruction_i2 = arguments[2]; | |
| wrapper.commit = arguments[3]; | |
| break; | |
| } | |
| default: { | |
| throw new Error(getBugErrorMessage("you're not supposed to end up here")); | |
| } | |
| } | |
| return wrapper; | |
| }; | |
| const async_ = (resume, blockingOn = none) => { | |
| return custom(resume, function() { | |
| let backingResume = void 0; | |
| let pendingEffect = void 0; | |
| function proxyResume(effect2) { | |
| if (backingResume) { | |
| backingResume(effect2); | |
| } else if (pendingEffect === void 0) { | |
| pendingEffect = effect2; | |
| } | |
| } | |
| const effect = new EffectPrimitive(OP_ASYNC); | |
| effect.effect_instruction_i0 = (resume2) => { | |
| backingResume = resume2; | |
| if (pendingEffect) { | |
| resume2(pendingEffect); | |
| } | |
| }; | |
| effect.effect_instruction_i1 = blockingOn; | |
| let cancelerRef = void 0; | |
| let controllerRef = void 0; | |
| if (this.effect_instruction_i0.length !== 1) { | |
| controllerRef = new AbortController(); | |
| cancelerRef = internalCall(() => this.effect_instruction_i0(proxyResume, controllerRef.signal)); | |
| } else { | |
| cancelerRef = internalCall(() => this.effect_instruction_i0(proxyResume)); | |
| } | |
| return cancelerRef || controllerRef ? onInterrupt(effect, (_) => { | |
| if (controllerRef) { | |
| controllerRef.abort(); | |
| } | |
| return cancelerRef ?? void_; | |
| }) : effect; | |
| }); | |
| }; | |
| const flatMap = dual(2, (self, f) => { | |
| const effect = new EffectPrimitive(OP_ON_SUCCESS); | |
| effect.effect_instruction_i0 = self; | |
| effect.effect_instruction_i1 = f; | |
| return effect; | |
| }); | |
| const matchCauseEffect = dual(2, (self, options) => { | |
| const effect = new EffectPrimitive(OP_ON_SUCCESS_AND_FAILURE); | |
| effect.effect_instruction_i0 = self; | |
| effect.effect_instruction_i1 = options.onFailure; | |
| effect.effect_instruction_i2 = options.onSuccess; | |
| return effect; | |
| }); | |
| const interruptible = (self) => { | |
| const effect = new EffectPrimitive(OP_UPDATE_RUNTIME_FLAGS); | |
| effect.effect_instruction_i0 = enable(Interruption); | |
| effect.effect_instruction_i1 = () => self; | |
| return effect; | |
| }; | |
| const onExit = dual(2, (self, cleanup) => uninterruptibleMask((restore) => matchCauseEffect(restore(self), { | |
| onFailure: (cause1) => { | |
| const result = exitFailCause(cause1); | |
| return matchCauseEffect(cleanup(result), { | |
| onFailure: (cause2) => exitFailCause(sequential(cause1, cause2)), | |
| onSuccess: () => result | |
| }); | |
| }, | |
| onSuccess: (success) => { | |
| const result = exitSucceed(success); | |
| return zipRight(cleanup(result), result); | |
| } | |
| }))); | |
| const onInterrupt = dual(2, (self, cleanup) => onExit(self, exitMatch({ | |
| onFailure: (cause) => isInterruptedOnly(cause) ? asVoid(cleanup(interruptors(cause))) : void_, | |
| onSuccess: () => void_ | |
| }))); | |
| const succeed = (value) => { | |
| const effect = new EffectPrimitiveSuccess(OP_SUCCESS); | |
| effect.effect_instruction_i0 = value; | |
| return effect; | |
| }; | |
| const uninterruptible = (self) => { | |
| const effect = new EffectPrimitive(OP_UPDATE_RUNTIME_FLAGS); | |
| effect.effect_instruction_i0 = disable(Interruption); | |
| effect.effect_instruction_i1 = () => self; | |
| return effect; | |
| }; | |
| const uninterruptibleMask = (f) => custom(f, function() { | |
| const effect = new EffectPrimitive(OP_UPDATE_RUNTIME_FLAGS); | |
| effect.effect_instruction_i0 = disable(Interruption); | |
| effect.effect_instruction_i1 = (oldFlags) => interruption(oldFlags) ? internalCall(() => this.effect_instruction_i0(interruptible)) : internalCall(() => this.effect_instruction_i0(uninterruptible)); | |
| return effect; | |
| }); | |
| const void_ = succeed(void 0); | |
| const zipRight = dual(2, (self, that) => flatMap(self, () => that)); | |
| const exitIsExit = (u) => isEffect(u) && "_tag" in u && (u._tag === "Success" || u._tag === "Failure"); | |
| const exitFailCause = (cause) => { | |
| const effect = new EffectPrimitiveFailure(OP_FAILURE); | |
| effect.effect_instruction_i0 = cause; | |
| return effect; | |
| }; | |
| const exitMatch = dual(2, (self, { | |
| onFailure, | |
| onSuccess | |
| }) => { | |
| switch (self._tag) { | |
| case OP_FAILURE: | |
| return onFailure(self.effect_instruction_i0); | |
| case OP_SUCCESS: | |
| return onSuccess(self.effect_instruction_i0); | |
| } | |
| }); | |
| const exitSucceed = (value) => { | |
| const effect = new EffectPrimitiveSuccess(OP_SUCCESS); | |
| effect.effect_instruction_i0 = value; | |
| return effect; | |
| }; | |
| const async = async_; | |
| const _void = void_; | |
| async((resume) => { | |
| queueMicrotask(() => resume(_void)); | |
| }); | |
| const evaluator = new RuleEvaluator(defaultRegistry); | |
| const log$1 = Log(false); | |
| const defaultMeta = { pause: false }; | |
| async function match(rule, value) { | |
| const ruleNode = compileRule(rule); | |
| const ctx = { value }; | |
| const evalResult = await evaluator.evaluate(ruleNode, ctx); | |
| return evalResult.result; | |
| } | |
| async function filter(list2, value) { | |
| const results = []; | |
| for (const task2 of list2) { | |
| if (await match(task2.match, value)) { | |
| results.push(task2); | |
| } | |
| } | |
| return results; | |
| } | |
| async function run(task2) { | |
| if (task2.top && top !== window) return; | |
| log$1("start run task = ", task2); | |
| const scripts2 = Array.isArray(task2.script) ? task2.script : [task2.script]; | |
| scripts2.forEach((script) => { | |
| try { | |
| script(task2); | |
| } catch (e) { | |
| console.log(`run script failed`, e); | |
| } | |
| }); | |
| } | |
| async function core(scripts2, url) { | |
| const tasks = await filter(scripts2, url); | |
| tasks.forEach((task2) => { | |
| log$1("match.task", task2); | |
| run({ ...task2, meta: task2.meta || { ...defaultMeta } }); | |
| }); | |
| } | |
| function waitForSelector(selector, options) { | |
| let node = null; | |
| return waitForFunction(() => { | |
| const selectors2 = Array.isArray(selector) ? selector : [selector]; | |
| const callback = (selector2) => { | |
| node = document.querySelector(selector2); | |
| return node != null; | |
| }; | |
| return selectors2.some(callback); | |
| }, { ...options, polling: 100 }).then(() => node); | |
| } | |
| const defaultWaitForFunctionOptions = { | |
| timeout: 3e3, | |
| polling: "raf" | |
| }; | |
| function waitForFunction(fn, options) { | |
| let t = Date.now(); | |
| const opt = { ...defaultWaitForFunctionOptions, ...options }; | |
| return new Promise((resolve, reject) => { | |
| let f = () => { | |
| const has = fn(); | |
| if (has) resolve(true); | |
| else if (typeof opt.polling === "number") { | |
| if (opt.timeout === 0 || Date.now() - t < opt.timeout) { | |
| setTimeout(f, opt.polling); | |
| } else { | |
| reject("timeout"); | |
| } | |
| } else if (opt.polling === "raf") { | |
| requestAnimationFrame(f); | |
| } else if (opt.polling === "mutation") { | |
| let timer = 0; | |
| const observer = new MutationObserver(function() { | |
| const has2 = fn(); | |
| if (has2 == false) return; | |
| if (timer) clearTimeout(timer); | |
| observer.disconnect(); | |
| resolve(true); | |
| }); | |
| let node = document.querySelector("html"); | |
| if (node == null) { | |
| observer.disconnect(); | |
| reject("no root node"); | |
| } else { | |
| observer.observe(node, { childList: true }); | |
| timer = setTimeout(() => { | |
| observer.disconnect(); | |
| reject("timeout"); | |
| }, opt.timeout); | |
| } | |
| } else { | |
| reject("not support"); | |
| } | |
| }; | |
| f(); | |
| }); | |
| } | |
| function useBlockSelector(selector) { | |
| return () => { | |
| waitForSelector(selector).then(() => { | |
| (Array.isArray(selector) ? selector : [selector]).forEach((selector2) => { | |
| const node = document.querySelector(selector2); | |
| if (node == null) return; | |
| const next = node.nextElementSibling; | |
| if (next) next.remove(); | |
| }); | |
| }); | |
| }; | |
| } | |
| function useRedirect() { | |
| return function() { | |
| if (top !== window) return; | |
| let search = new URLSearchParams(location.search); | |
| for (let value of search.values()) { | |
| if (URL.canParse(value)) { | |
| location.href = value; | |
| } | |
| } | |
| }; | |
| } | |
| function useRebuildUrl(fn) { | |
| return () => { | |
| const next = fn(location.href); | |
| if (next) location.href = next; | |
| }; | |
| } | |
| const task$3 = [ | |
| { | |
| match: new URLPattern({ hostname: `outlook.live.com` }), | |
| script: useBlockSelector(`[data-max-width="2400"]`) | |
| }, | |
| { | |
| match: [ | |
| "https://cdn.jellow.site/", | |
| "https://cdnv2.ruguoapp.com/" | |
| ], | |
| script: useRebuildUrl((url) => url.includes("?") ? url.replace(/\?.+$/, "") : "") | |
| }, | |
| { | |
| match: { | |
| or: [ | |
| (url) => { | |
| const u = new URL(url); | |
| const pathname = u.pathname.toLowerCase(); | |
| const keywords = ["goto", "link", "redirect", "jump"]; | |
| return keywords.some((key) => pathname.includes(key)); | |
| }, | |
| new URLPattern({ "hostname": "(link|go).*" }) | |
| ] | |
| }, | |
| script: useRedirect() | |
| }, | |
| { | |
| match: "http://uz.yurixu.com/", | |
| script: () => { | |
| const useHost = "www.newsmth.net"; | |
| const hosts = [ | |
| "www.newsmth.net", | |
| "www.mysmth.net" | |
| ]; | |
| document.addEventListener("click", (e) => { | |
| const target = e.target; | |
| if (target == null) return; | |
| const link = target.closest("a"); | |
| if (link == null) return; | |
| if (hosts.some((host) => link.host === host)) { | |
| link.href = link.href.replace(/^https?:\/\/(.+?)\//, () => `https://${useHost}/`); | |
| } | |
| }, true); | |
| } | |
| } | |
| ]; | |
| const bingTask = [ | |
| { | |
| match: new URLPattern({ hostname: "cn.bing.com" }), | |
| script: task$2, | |
| top: true | |
| } | |
| ]; | |
| const selectors = [ | |
| "#bgDiv", | |
| ".hp_top_cover", | |
| ".img_cont" | |
| ]; | |
| function task$2() { | |
| let nodes = document.querySelectorAll(selectors.join(",")); | |
| if (nodes.length === 0) return; | |
| Array.from(nodes).some((node) => { | |
| let style = window.getComputedStyle(node); | |
| let backgroundImage = style.backgroundImage; | |
| let res = ""; | |
| backgroundImage.replace(/url\(('|")?(.*?)\1\)/, (_, __, src) => { | |
| res = src; | |
| return ""; | |
| }); | |
| return res ? (console.log("%c wallpaper:", `color: red`, res), true) : false; | |
| }); | |
| } | |
| const doubanTask = [ | |
| { | |
| match: "book.douban.com", | |
| script: bookTask, | |
| top: true | |
| }, | |
| { | |
| match: "https://zebra.9farm.com/", | |
| script: bookBeforeSearchTask, | |
| top: true | |
| }, | |
| { | |
| match: "movie.douban.com", | |
| script: movieTask, | |
| top: true | |
| }, | |
| { | |
| match: "fm.douban.com", | |
| script: musicTask, | |
| top: true | |
| } | |
| ]; | |
| function createLinkElement(template, keyword) { | |
| let a = document.createElement("a"); | |
| a.href = template.replaceAll("%s", encodeURIComponent(keyword)); | |
| a.target = "_blank"; | |
| a.setAttribute("target", "_blank"); | |
| a.setAttribute("rel", "noopener"); | |
| a.setAttribute("referrerpolicy", "no-referrer"); | |
| return a; | |
| } | |
| function createElement(source, title, target, keyword) { | |
| let span = document.createElement("span"); | |
| span.className = "pl"; | |
| span.append(document.createTextNode(source)); | |
| const a = createLinkElement(target, keyword ? keyword : title); | |
| a.append(document.createTextNode(title)); | |
| let fragment = document.createDocumentFragment(); | |
| fragment.appendChild(span); | |
| fragment.appendChild(a); | |
| let br = document.createElement("br"); | |
| fragment.appendChild(br); | |
| return fragment; | |
| } | |
| function createElements(list2) { | |
| let fragment = document.createDocumentFragment(); | |
| for (let i = 0; i < list2.length; ++i) { | |
| let item = list2[i]; | |
| let element = createElement( | |
| item.description, | |
| item.title, | |
| item.template, | |
| item.keyword | |
| ); | |
| fragment.appendChild(element); | |
| } | |
| return fragment; | |
| } | |
| function movieTask() { | |
| let node = document.querySelector("#content > h1 span:first-child"); | |
| if (!node) return; | |
| let title = node.innerText.trim(); | |
| let infoNode = document.querySelector("#info"); | |
| if (!infoNode) return; | |
| let list2 = [ | |
| { | |
| description: "g(ddz):", | |
| title, | |
| keyword: title, | |
| template: "https://www.google.com/search?newwindow=1&safe=strict&source=hp&ei=--05W5X6CoqD8wX_zZmwCg&btnG=Google+%E6%90%9C%E7%B4%A2&q=%s&oq=beego&gs_l=psy-ab.3..0j0i203k1l2j0j0i203k1j0i10i203k1j0i203k1l4.6311.7597.0.7829.9.6.0.0.0.0.132.522.2j3.6.0....0...1c.1.64.psy-ab..3.6.609.6..35i39k1j0i131k1j0i67k1j0i10k1.87.jNu-vssuoKQ".replace("%s", `%s ${encodeURIComponent("site:dandanzan.club")}`) | |
| } | |
| ]; | |
| let fragment = createElements(list2); | |
| infoNode.appendChild(fragment); | |
| } | |
| function findCodeText(node) { | |
| const pl = node.querySelectorAll("span.pl"); | |
| const list2 = Array.from(pl); | |
| for (let i = 0; i < list2.length; ++i) { | |
| const item = list2[i]; | |
| const text = item.innerHTML; | |
| if (text.includes("ISBN")) { | |
| let code = item.nextSibling; | |
| if (code) { | |
| const value = code.nodeValue; | |
| if (value) { | |
| return value.trim(); | |
| } | |
| } | |
| } | |
| } | |
| return ""; | |
| } | |
| function bookTask() { | |
| let node = document.querySelector("#wrapper > h1"); | |
| if (!node) return; | |
| let infoNode = document.querySelector("#info"); | |
| if (!infoNode) return; | |
| let title = node.innerText.trim(); | |
| let code = findCodeText(infoNode); | |
| let list2 = [ | |
| { description: "Annas-Archive:", title, template: "https://annas-archive.org/search?q=%s", keyword: code } | |
| ]; | |
| let fragment = createElements(list2); | |
| infoNode.appendChild(fragment); | |
| } | |
| function bookBeforeSearchTask() { | |
| const qs = new URLSearchParams(location.search); | |
| const q = qs.get("q"); | |
| if (q == null) return; | |
| const key = "session"; | |
| const value = JSON.stringify({ | |
| name: q, | |
| author: "", | |
| lang: "", | |
| publisher: "", | |
| ext: "", | |
| isbn: "", | |
| id: "" | |
| }); | |
| const old = localStorage.getItem(key); | |
| localStorage.setItem(key, value); | |
| if (old != value) { | |
| location.reload(); | |
| } | |
| } | |
| function musicTask() { | |
| const _send = XMLHttpRequest.prototype.send; | |
| const _open = XMLHttpRequest.prototype.open; | |
| XMLHttpRequest.prototype.open = function(_, url) { | |
| _open.apply(this, arguments); | |
| this.__url = url; | |
| }; | |
| XMLHttpRequest.prototype.send = function() { | |
| let t = this.onreadystatechange; | |
| this.onreadystatechange = function(e) { | |
| if (t) t.call(this, e); | |
| const readyState = this.readyState; | |
| if (readyState === 4) { | |
| const type = this.responseType || "text"; | |
| if (type === "text" && this.response) { | |
| let data; | |
| try { | |
| data = JSON.parse(this.response); | |
| } catch (e2) { | |
| console.log("douban.fm.parse.response.failed"); | |
| } | |
| if (data && data.song) { | |
| const songs = data.song; | |
| songs.forEach((song) => { | |
| console.log(`%c${song.title}`, "color: red", song.url); | |
| }); | |
| } | |
| } | |
| } | |
| return this; | |
| }; | |
| _send.apply(this, arguments); | |
| return this; | |
| }; | |
| } | |
| function stopImmediatePropagation() { | |
| ["click"].forEach((name) => { | |
| document.addEventListener(name, function(e) { | |
| e.stopImmediatePropagation(); | |
| }, true); | |
| }); | |
| } | |
| function createHiddenNodesBySelectorsTask(selectors2) { | |
| return () => { | |
| selectors2.forEach((selector) => { | |
| let nodes = document.querySelectorAll(selector); | |
| nodes.forEach((node) => { | |
| if (node) node.style.display = "none"; | |
| }); | |
| }); | |
| }; | |
| } | |
| function removeRemovedAdBlockerModal() { | |
| let elements = document.querySelectorAll("cloudflare-app"); | |
| Array.from(elements).forEach((element) => { | |
| let style = window.getComputedStyle(element, null); | |
| let zIndex = style.getPropertyValue("z-index"); | |
| if (+zIndex >= 400) { | |
| element.style.display = "none"; | |
| } | |
| }); | |
| } | |
| function remove(node) { | |
| let previous; | |
| while (node && (previous = node.previousSibling)) { | |
| previous.remove(); | |
| } | |
| } | |
| function sleep(n) { | |
| return new Promise(function(resolve) { | |
| setTimeout(resolve, n * 1e3); | |
| }); | |
| } | |
| function useObserver(selector, options = { childList: true }) { | |
| let observer; | |
| return (handler2) => { | |
| return (task2) => { | |
| if (observer) observer.disconnect(); | |
| observer = new MutationObserver(() => { | |
| const scripts2 = Array.isArray(handler2) ? handler2 : [handler2]; | |
| scripts2.forEach((script) => script(task2)); | |
| }); | |
| let node = document.querySelector(selector); | |
| if (node) observer.observe(node, options); | |
| }; | |
| }; | |
| } | |
| let fetchInit = false; | |
| function fetchLocationPerMinute() { | |
| fetch(location.href).finally(() => { | |
| sleep(60).then(fetchLocationPerMinute); | |
| }); | |
| } | |
| function addEventListener(task2) { | |
| let box = document.querySelector(".board-list"); | |
| if (box) { | |
| let links = box.querySelectorAll("a"); | |
| Array.from(links).forEach((link) => { | |
| link.setAttribute("target", "_blank"); | |
| }); | |
| const f = () => handler(); | |
| window.removeEventListener("hashchange", f); | |
| window.addEventListener("hashchange", f); | |
| } else { | |
| sleep(0.2).then(() => addEventListener()); | |
| } | |
| } | |
| function handler(task2) { | |
| addEventListener(); | |
| let body = document.body; | |
| if (body) body.style.cssText = "max-width: 1280px; margin: 0 auto;"; | |
| createHiddenNodesBySelectorsTask(["#ban_ner", "#banner_slider"])(); | |
| if (fetchInit == false) { | |
| fetchInit = true; | |
| fetchLocationPerMinute(); | |
| } | |
| let style = document.createElement("style"); | |
| style.innerText = ".board-list tr { line-height: 2 } .board-list td { padding: 4px 0 } .title_9 a { font-size: 1.2em } .title_10 { width: 120px !important }"; | |
| let head = document.querySelector("head"); | |
| if (head) head.appendChild(style); | |
| } | |
| const mysmthTask = { | |
| match: [ | |
| "https://www.newsmth.net/", | |
| "https://www.mysmth.net/" | |
| ], | |
| script: useObserver("#body")(handler) | |
| }; | |
| function nextTick(fn) { | |
| return Promise.resolve().then(fn); | |
| } | |
| const log = Log(false); | |
| const weChatTask = [ | |
| { | |
| match: /https:\/\/mp\.weixin\.qq\.com\/s.*/, | |
| script: task$1 | |
| }, | |
| { | |
| match: /weixin110\.qq.com/, | |
| script: linkTask | |
| } | |
| ]; | |
| function linkTask() { | |
| let node = document.querySelector("p"); | |
| if (node == null) return; | |
| let text = node.innerText.trim(); | |
| if (/https?:\/\//i.test(text)) { | |
| location.href = text; | |
| return; | |
| } | |
| } | |
| function task$1() { | |
| stopImmediatePropagation(); | |
| weChatTextToLink(); | |
| weChatQRCodeToLink(); | |
| logAudioLink(); | |
| } | |
| function logAudioLink() { | |
| let template = `https://res.wx.qq.com/voice/getvoice?mediaid=`; | |
| sleep(1).then(() => { | |
| if (typeof window == "undefined") return; | |
| if (typeof window.voiceList !== "undefined") { | |
| let list2 = window.voiceList.voice_in_appmsg; | |
| if (Array.isArray(list2)) { | |
| list2.forEach((item, index) => { | |
| let voice_id = item.voice_id; | |
| let url = `${template}${voice_id}`; | |
| log(`音频(${index + 1})地址: ${url}`); | |
| }); | |
| } | |
| } | |
| }); | |
| } | |
| let weChatQRCodeToLinkDone = false; | |
| function weChatQRCodeToLink() { | |
| if (weChatQRCodeToLinkDone) return; | |
| let nodes = document.querySelectorAll("span[data-src] img"); | |
| Array.from(nodes).forEach((node) => { | |
| let a = document.createElement("a"); | |
| let p = node.parentNode; | |
| let href = p.dataset.src; | |
| if (href == null) return; | |
| a.href = href; | |
| a.target = "_blank"; | |
| a.style.display = "block"; | |
| a.appendChild(document.createTextNode(href)); | |
| p.appendChild(a); | |
| }); | |
| if (nodes.length) { | |
| weChatQRCodeToLinkDone = true; | |
| } | |
| } | |
| function weChatTextToLink() { | |
| if (document.body == null) { | |
| return sleep(0.2).then(() => { | |
| nextTick(weChatTextToLink); | |
| }); | |
| } | |
| log("enter wechat textToLink func"); | |
| let walker = document.createTreeWalker( | |
| document.body, | |
| NodeFilter.SHOW_TEXT, | |
| { | |
| acceptNode: (node) => { | |
| let p = node.parentNode; | |
| while (p && ["A", "SCRIPT", "STYLE"].indexOf(p.nodeName) === -1) { | |
| p = p.parentNode; | |
| } | |
| if (p) return NodeFilter.FILTER_SKIP; | |
| let text = node.nodeValue; | |
| if (text && /https?:\/\//i.test(text)) { | |
| return NodeFilter.FILTER_ACCEPT; | |
| } | |
| return NodeFilter.FILTER_REJECT; | |
| } | |
| } | |
| ); | |
| let links = []; | |
| while (walker.nextNode()) { | |
| let node = walker.currentNode; | |
| let text = node.nodeValue.toLowerCase(); | |
| let offset = text.indexOf("http"); | |
| let linkTextNode = node.splitText(offset); | |
| if (linkTextNode == null) continue; | |
| if (linkTextNode.nodeValue == null) continue; | |
| let spaceOffset = linkTextNode.nodeValue.search(/\s|[))]/); | |
| let linkNode = linkTextNode; | |
| if (spaceOffset > -1) { | |
| let t = linkTextNode.splitText(spaceOffset).previousSibling; | |
| if (t) linkNode = t; | |
| } | |
| let a = document.createElement("a"); | |
| if (linkNode.nodeValue) a.href = linkNode.nodeValue; | |
| a.setAttribute("target", "_blank"); | |
| linkNode.parentNode.insertBefore(a, linkNode); | |
| a.appendChild(linkNode); | |
| links.push(a); | |
| } | |
| if (links.length) { | |
| suptolink(links); | |
| } | |
| return; | |
| } | |
| function suptolink(links) { | |
| let sups = document.querySelectorAll("sup"); | |
| let lastFindedNode; | |
| Array.from(sups).reverse().forEach((sup) => { | |
| let text = sup.innerText.trim(); | |
| if (text === "") return; | |
| let link = findLinkByText(text, lastFindedNode || links[links.length - 1]); | |
| if (link == null) return; | |
| lastFindedNode = link; | |
| let a = document.createElement("a"); | |
| a.href = link.href; | |
| a.setAttribute("target", "_blank"); | |
| sup.parentNode.insertBefore(a, sup); | |
| a.appendChild(sup); | |
| }); | |
| } | |
| function findLinkByText(text, link) { | |
| let find; | |
| let node = link.previousSibling || link.parentNode; | |
| while (node && (node.nodeType == 1 || node.nodeType === 3)) { | |
| let t = node.innerText || node.nodeValue || ""; | |
| if (node.nodeType === 1) { | |
| if (node.nodeName === "A") link = node; | |
| else { | |
| let a = node.querySelector("a"); | |
| if (a) link = a; | |
| } | |
| } | |
| if (t.indexOf(text) > -1) { | |
| find = link; | |
| break; | |
| } | |
| node = node.previousSibling || node.parentNode; | |
| } | |
| return find; | |
| } | |
| function mutationObserver(meta, callback, selector, options = { childList: true }) { | |
| if (meta == null) return; | |
| if (meta.observer) { | |
| meta.observer.disconnect(); | |
| } | |
| meta.observer = new MutationObserver(function() { | |
| callback(); | |
| }); | |
| let node = document.querySelector(selector); | |
| if (node) { | |
| meta.observer.observe(node, options); | |
| } | |
| } | |
| const zhihuTask = [ | |
| { | |
| match: /^https?:\/\/.*?\.zhihu\.com/, | |
| script: [ | |
| replaceExternalLinkTask, | |
| replaceToRawImage | |
| ], | |
| exclude: "link.zhihu.com" | |
| }, | |
| { | |
| match: new URLPattern("https://{*.}?zhihu.com"), | |
| script: () => { | |
| function updateTitle() { | |
| const title = document.title; | |
| document.title = title.replace(/^\(.*?\)/, ""); | |
| requestAnimationFrame(updateTitle); | |
| } | |
| updateTitle(); | |
| } | |
| }, | |
| { | |
| match: new URLPattern("/people/*", "https://www.zhihu.com/"), | |
| script: removeReadQuestionsTask | |
| }, | |
| { | |
| match: new URLPattern("/question/*", "https://www.zhihu.com/"), | |
| script: removeFixedHeader | |
| } | |
| ]; | |
| function removeFixedHeader() { | |
| function fixed() { | |
| const t = document.querySelector(".Sticky.is-fixed"); | |
| if (t) t.style.position = "relative"; | |
| requestAnimationFrame(fixed); | |
| } | |
| fixed(); | |
| } | |
| function removeReadQuestionsTask() { | |
| function handler2() { | |
| let selector = "#Profile-activities .List-item"; | |
| let list2 = document.querySelectorAll(selector); | |
| let max = 40; | |
| if (list2.length > max) { | |
| let index = list2.length - max; | |
| let node = list2[index]; | |
| remove(node); | |
| } | |
| } | |
| window.addEventListener("scroll", handler2); | |
| } | |
| function replaceExternalLinkTask({ meta }) { | |
| function handler2() { | |
| let selector = 'a[href^="https://link.zhihu.com/"]'; | |
| let links = document.querySelectorAll(selector); | |
| Array.from(links).forEach((node) => { | |
| let href = node.href; | |
| let url = new URL(href); | |
| let search = new URLSearchParams(url.search); | |
| let target = search.get("target"); | |
| if (target) { | |
| node.href = decodeURIComponent(target); | |
| } | |
| }); | |
| } | |
| mutationObserver(meta, handler2, "body"); | |
| handler2(); | |
| } | |
| function replaceToRawImage() { | |
| document.addEventListener("click", (e) => { | |
| const target = e.target; | |
| if (target == null) return; | |
| const node = target; | |
| if (node.nodeType != 1) return; | |
| if (node.nodeName !== "IMG") return; | |
| const token = node.dataset.originalToken; | |
| if (token == null) return; | |
| const src = node.getAttribute("src"); | |
| if (src == null) return; | |
| const original = src.replace(/v2-.*?(?=\.)/, token); | |
| node.setAttribute("src", original); | |
| }); | |
| } | |
| const weiboTask = [ | |
| { | |
| match: /(?:t|weibo)\.cn/i, | |
| script: task | |
| }, | |
| { | |
| match: /wx\d+\.sinaimg\.cn/i, | |
| script: navigateToRawImageTask | |
| } | |
| ]; | |
| function task() { | |
| let node = document.querySelector(".link,.desc,.navigate_link"); | |
| if (node == null) return; | |
| if (node.tagName === "A") { | |
| location.href = node.getAttribute("href"); | |
| return; | |
| } | |
| let text = node.innerText.trim(); | |
| if (/https?:\/\//i.test(text)) { | |
| location.href = text; | |
| return; | |
| } | |
| } | |
| function navigateToRawImageTask() { | |
| let url = location.href; | |
| if (url.includes("/oslarge/")) return; | |
| let i = new URL(url); | |
| i.pathname = `/oslarge` + i.pathname.replace(/\/[^\/]*/, ""); | |
| let newUrl = i.toString(); | |
| location.href = newUrl; | |
| } | |
| function toRedirectUrl(raw, source, dest) { | |
| const p = new URLPattern(source); | |
| const result = p.exec(raw); | |
| if (!result) return ""; | |
| const pathname = result.pathname; | |
| const groups = pathname.groups; | |
| let url = dest; | |
| Object.keys(groups).forEach((key) => { | |
| url = url.replace(`:${key}`, groups[key]); | |
| }); | |
| return url; | |
| } | |
| function initialize(url, list2) { | |
| for (let i = 0; i < list2.length; ++i) { | |
| const config = list2[i]; | |
| if (config.skip) continue; | |
| let destination = url; | |
| if (config.pattern) { | |
| destination = toRedirectUrl(url, config.source, config.destination || config.source); | |
| } else if (url == config.source && config.destination) { | |
| destination = config.destination; | |
| } | |
| if (url !== destination) { | |
| return destination; | |
| } | |
| } | |
| return url; | |
| } | |
| const list = [ | |
| { source: "https://store.pailixiang.com/album/:album/:name.jpg" }, | |
| { source: "https://www.baidu.com/", destination: "https://google.com/", pattern: false, skip: true } | |
| ]; | |
| const last = initialize(location.href, list); | |
| const redirectTask = { | |
| match: (url) => last !== url, | |
| script: () => { | |
| location.href = last; | |
| } | |
| }; | |
| var _GM = (() => typeof GM != "undefined" ? GM : void 0)(); | |
| var _GM_getValue = (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)(); | |
| var _GM_info = (() => typeof GM_info != "undefined" ? GM_info : void 0)(); | |
| var _GM_openInTab = (() => typeof GM_openInTab != "undefined" ? GM_openInTab : void 0)(); | |
| var _GM_registerMenuCommand = (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)(); | |
| var _GM_setClipboard = (() => typeof GM_setClipboard != "undefined" ? GM_setClipboard : void 0)(); | |
| var _GM_setValue = (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)(); | |
| var _GM_xmlhttpRequest = (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)(); | |
| var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)(); | |
| function promisifyRequest(request) { | |
| return new Promise((resolve, reject) => { | |
| request.oncomplete = request.onsuccess = () => resolve(request.result); | |
| request.onabort = request.onerror = () => reject(request.error); | |
| }); | |
| } | |
| function createStore(dbName, storeName) { | |
| const request = indexedDB.open(dbName); | |
| request.onupgradeneeded = () => request.result.createObjectStore(storeName); | |
| const dbp = promisifyRequest(request); | |
| return (txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName))); | |
| } | |
| let defaultGetStoreFunc; | |
| function defaultGetStore() { | |
| if (!defaultGetStoreFunc) { | |
| defaultGetStoreFunc = createStore("keyval-store", "keyval"); | |
| } | |
| return defaultGetStoreFunc; | |
| } | |
| function get(key, customStore = defaultGetStore()) { | |
| return customStore("readonly", (store) => promisifyRequest(store.get(key))); | |
| } | |
| function set(key, value, customStore = defaultGetStore()) { | |
| return customStore("readwrite", (store) => { | |
| store.put(value, key); | |
| return promisifyRequest(store.transaction); | |
| }); | |
| } | |
| function del(key, customStore = defaultGetStore()) { | |
| return customStore("readwrite", (store) => { | |
| store.delete(key); | |
| return promisifyRequest(store.transaction); | |
| }); | |
| } | |
| function requestNotificationPermission() { | |
| const p = Notification.permission; | |
| if (p === "granted") return Promise.resolve(true); | |
| if (p === "denied") return Promise.resolve(false); | |
| return Notification.requestPermission().then((p2) => { | |
| return Promise.resolve(p2 == "granted"); | |
| }); | |
| } | |
| async function notify(message, options) { | |
| const permission = await requestNotificationPermission(); | |
| if (!permission) return; | |
| new Notification(message, options); | |
| } | |
| function post(path, data) { | |
| let token = _GM_getValue("telegram-token"); | |
| if (!token) { | |
| token = prompt(`Please input telegram token:`); | |
| if (token) _GM_setValue("telegram-token", token); | |
| else return Promise.reject("token is empty"); | |
| } | |
| data.append("chat_id", "@connect2026"); | |
| const url = `https://api.telegram.org/bot${token}`; | |
| return _GM.xmlHttpRequest({ | |
| method: "POST", | |
| url: url + path, | |
| data | |
| }); | |
| } | |
| function sendMessage(text, parse_mode = "") { | |
| const data = new FormData(); | |
| data.append("text", text); | |
| data.append("parse_mode", parse_mode); | |
| return post("/sendMessage", data); | |
| } | |
| function sendPhoto(photo, caption = "") { | |
| const data = new FormData(); | |
| data.append("photo", photo); | |
| data.append("caption", caption); | |
| return post("/sendPhoto", data); | |
| } | |
| function sendMediaGroup(group) { | |
| const data = new FormData(); | |
| data.append("media", JSON.stringify(group)); | |
| return post("/sendMediaGroup", data); | |
| } | |
| const idbKey = "directory"; | |
| const id = "photo-viewer"; | |
| const userSaveButtonClass = "user-save-btn"; | |
| function ping(image) { | |
| const domain = "https://x181.cn"; | |
| const url = `${domain}/api/us/save?url=${encodeURIComponent(image)}`; | |
| return _GM_xmlhttpRequest({ | |
| method: "GET", | |
| url, | |
| headers: { | |
| "Content-Type": "application/json" | |
| } | |
| }); | |
| } | |
| function createTwitterSaveImageOption() { | |
| function imageUrlMatcher(node) { | |
| const urlRegexp = /\/media\//; | |
| return urlRegexp.test(node.src); | |
| } | |
| function siblingsMatcher(node, debug = false) { | |
| const p = node.previousElementSibling; | |
| if (p == null) return false; | |
| const style = p.style.backgroundImage; | |
| const url = style.replace(/url\("(.*?)"\)/, "$1"); | |
| const src = node.src; | |
| const match2 = url == src; | |
| if (match2 && debug) console.log("url: ", url); | |
| return match2; | |
| } | |
| function toImageUrl(rawImageUrl, debug = false) { | |
| const src = rawImageUrl; | |
| debug && console.log("url.raw", src); | |
| const tmp = src.replace(/&name=.*$/, ""); | |
| debug && console.log("url.name.remove", tmp); | |
| const url = tmp + "&name=4096x4096"; | |
| debug && console.log("url.name.fix", url); | |
| return url; | |
| } | |
| function getImageUrls(node, debug = false) { | |
| const images = node.querySelectorAll("img"); | |
| const matchUrlList = Array.from(images).filter((node2) => imageUrlMatcher(node2)); | |
| const checkedUrlList = matchUrlList.filter((node2) => siblingsMatcher(node2, debug)); | |
| return checkedUrlList.map((node2) => { | |
| const url = toImageUrl(node2.src, debug); | |
| let page = ""; | |
| const a = node2.closest("a"); | |
| if (a) page = a.href; | |
| return { url, page }; | |
| }); | |
| } | |
| function getSingleImageUrl(node, debug = false) { | |
| const x = window.innerWidth / 2; | |
| const y = window.innerHeight / 2; | |
| const elements = document.elementsFromPoint(x, y); | |
| for (let i = 0; i < elements.length; ++i) { | |
| const element = elements[i]; | |
| if (element.nodeType !== 1) continue; | |
| if (element.nodeName != "IMG") continue; | |
| const pos = node.compareDocumentPosition(element); | |
| if (!(pos & Node.DOCUMENT_POSITION_CONTAINED_BY)) continue; | |
| const el = element; | |
| const m1 = imageUrlMatcher(el); | |
| if (!m1) continue; | |
| const m2 = siblingsMatcher(el, debug); | |
| if (!m2) continue; | |
| return toImageUrl(el.src, debug); | |
| } | |
| return null; | |
| } | |
| const tweetDialogSelector = '[role="dialog"]'; | |
| const tweetSelector = 'article[data-testid="tweet"]'; | |
| function injectSaveButton(group) { | |
| const is = group.querySelector("[data-save]"); | |
| if (is) return; | |
| if (group == null) return; | |
| if (typeof window.showDirectoryPicker === "function") { | |
| group.append(createSaveButtonNode("save")); | |
| } | |
| group.append(createSaveButtonNode("telegram")); | |
| } | |
| let cancelInjectAction; | |
| function doInjectAction(target) { | |
| if (cancelInjectAction) cancelInjectAction(); | |
| const dialog = target.querySelector(tweetDialogSelector); | |
| if (dialog) { | |
| const s = () => { | |
| const group = dialog.querySelectorAll(`[role="group"] [role="group"]`); | |
| if (group.length) { | |
| const last2 = group[group.length - 1]; | |
| injectSaveButton(last2); | |
| cancelInjectAction(); | |
| } | |
| }; | |
| cancelInjectAction = action(s); | |
| } | |
| const list2 = target.querySelectorAll(tweetSelector); | |
| Array.from(list2).forEach((node) => { | |
| const urls = getImageUrls(node); | |
| if (urls.length === 0) return; | |
| const group = node.querySelector('[role="group"]'); | |
| injectSaveButton(group); | |
| }); | |
| } | |
| function tryInjectSaveButton(node) { | |
| const cancel = action(() => { | |
| doInjectAction(node); | |
| }); | |
| const observer = new MutationObserver(() => { | |
| doInjectAction(node); | |
| cancel(); | |
| }); | |
| observer.observe(node, { childList: true, subtree: true }); | |
| } | |
| return { | |
| inject() { | |
| const selectors2 = ["#react-root"]; | |
| selectors2.forEach((selector) => { | |
| waitForSelector(selector).then(() => { | |
| const node = document.querySelector(selector); | |
| if (node == null) return; | |
| tryInjectSaveButton(node); | |
| }); | |
| }); | |
| }, | |
| query(element) { | |
| const selectors2 = ['[role="dialog"]', tweetSelector]; | |
| for (let i = 0; i < selectors2.length; ++i) { | |
| const node = element.closest(selectors2[i]); | |
| if (node == null) continue; | |
| let list2 = []; | |
| const debug = true; | |
| const is = node.closest(tweetSelector); | |
| if (is) { | |
| list2 = getImageUrls(node, debug); | |
| } else { | |
| const single = getSingleImageUrl(node, debug); | |
| if (single) { | |
| list2 = [{ url: single, page: location.href }]; | |
| } | |
| } | |
| if (list2.length === 0) continue; | |
| return list2.map((item) => { | |
| const { url, page } = item; | |
| return { | |
| url, | |
| page, | |
| filename: url.replace(/.*?\/media\/(.*?)\?.*/, "$1") | |
| }; | |
| }); | |
| } | |
| return []; | |
| } | |
| }; | |
| } | |
| function createXHSSaveImageOption() { | |
| function doInjectAction() { | |
| const selector = ".bottom-container"; | |
| waitForSelector(selector).then(() => { | |
| const node = document.querySelector(selector); | |
| if (node == null) return; | |
| const is = node.querySelector("[data-save]"); | |
| if (is) return; | |
| node.append( | |
| createSaveButtonNode() | |
| ); | |
| }); | |
| } | |
| return { | |
| query() { | |
| const selector = ".swiper-wrapper"; | |
| const node = document.querySelector(selector); | |
| if (node == null) return []; | |
| const images = node.querySelectorAll("img"); | |
| if (images.length == 0) return []; | |
| return Array.from(images).map((img) => { | |
| let url = img.src; | |
| if (url.includes("/notes_pre_post/")) { | |
| const id2 = url.split("/notes_pre_post/")[1].split("!")[0]; | |
| url = `https://sns-img-hw.xhscdn.com/notes_pre_post/${id2}?imageView2/2/w/0/format/jpg`; | |
| } | |
| return { | |
| url, | |
| page: location.href, | |
| filename: url.replace(/^[^?]*\//, "").split("?")[0] | |
| }; | |
| }); | |
| }, | |
| inject() { | |
| const observer = new MutationObserver(() => { | |
| doInjectAction(); | |
| }); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| } | |
| }; | |
| } | |
| const twitterTask = [ | |
| { | |
| match: /(?:x|twitter)\.com/, | |
| script: createSaveImageScript( | |
| createTwitterSaveImageOption() | |
| ) | |
| }, | |
| { | |
| match: new URLPattern("/explore/:id?", "https://www.xiaohongshu.com"), | |
| script: createSaveImageScript( | |
| createXHSSaveImageOption() | |
| ) | |
| } | |
| ]; | |
| function createSaveImageScript(option) { | |
| return () => saveImageScript(option); | |
| } | |
| function trySendToTelegram(images) { | |
| const mediaList = images.map((item) => { | |
| return { | |
| type: "photo", | |
| media: item.url, | |
| caption: `${item.url} ${item.page ? `source: ${item.page}` : ""}`, | |
| show_caption_above_media: false | |
| }; | |
| }); | |
| return sendMediaGroup(mediaList); | |
| } | |
| async function saveImageScript(option) { | |
| document.addEventListener("click", (e) => { | |
| const target = e.target; | |
| if (target == null) return; | |
| const can = target.closest(`.${userSaveButtonClass}`); | |
| if (!can) return; | |
| const images = option.query(target); | |
| if (images.length === 0) return; | |
| const type = can.dataset.save; | |
| let task2 = void 0; | |
| if (type == "save") task2 = trySaveImagesToLocale(images); | |
| if (type == "telegram") task2 = trySendToTelegram(images); | |
| if (task2) { | |
| can.style.opacity = "0.4"; | |
| task2.finally(() => { | |
| can.style.opacity = ""; | |
| }); | |
| } | |
| e.preventDefault(); | |
| e.stopImmediatePropagation(); | |
| }, true); | |
| option.inject(); | |
| } | |
| function createSaveButtonNode(type = "save", cssText = "") { | |
| const div = document.createElement("div"); | |
| div.dataset.save = type; | |
| div.classList.add(userSaveButtonClass); | |
| div.style.cssText = `cursor: pointer; display: flex;` + (cssText ? cssText : `align-self: center;`); | |
| const telegram = `<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --><svg xmlns="http://www.w3.org/2000/svg" aria-label="Telegram" role="img" viewBox="0 0 512 512" width="24px" height="24px"><rect width="512" height="512" rx="15%" fill="#37aee2"/><path fill="#c8daea" d="M199 404c-11 0-10-4-13-14l-32-105 245-144"/><path fill="#a9c9dd" d="M199 404c7 0 11-4 16-8l45-43-56-34"/><path fill="#f6fbfe" d="M204 319l135 99c14 9 26 4 30-14l55-258c5-22-9-32-24-25L79 245c-21 8-21 21-4 26l83 26 190-121c9-5 17-3 11 4"/></svg>`; | |
| const save = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 451.296 451.296" xml:space="preserve" width="24px" height="24px"><circle style="fill:#45b39c" cx="225.648" cy="225.638" r="225.638"/><path style="opacity:.1;enable-background:new" d="m450.855 239.322-99.451-99.451c-.076-.08-.13-.176-.209-.255l-39.537-39.491a12.776 12.776 0 0 0-9.026-3.76H109.178c-7.052 0-12.834 5.735-12.834 12.834v232.898c0 3.672 1.566 6.958 4.035 9.295l98.236 98.236c8.87 1.06 17.878 1.668 27.034 1.668 120.028 0 218.126-93.724 225.206-211.974z"/><path style="fill:#64798a" d="m351.176 139.612-39.501-39.501a12.823 12.823 0 0 0-9.066-3.755H109.186c-7.081 0-12.821 5.74-12.821 12.821V342.1c0 7.082 5.74 12.822 12.821 12.822H342.11c7.081 0 12.821-5.74 12.821-12.822V148.678c0-3.401-1.351-6.662-3.755-9.066z"/><path style="fill:#fff" d="M310.065 212.47H141.231c-6.129 0-11.098 4.969-11.098 11.098v88.637c0 6.129 4.969 11.098 11.098 11.098h168.833c6.129 0 11.098-4.969 11.098-11.098v-88.637c0-6.129-4.968-11.098-11.097-11.098z"/><path style="fill:#ebf0f3" d="M149.565 233.626h152.177v9.4H149.565zM149.565 263.168h152.177v9.4H149.565zM149.565 292.762h152.177v9.4H149.565zM156.714 96.355v58.059c0 5.443 4.413 9.856 9.856 9.856h118.156c5.443 0 9.856-4.413 9.856-9.856V96.355H156.714z"/><path style="fill:#3a556a" d="M259.491 107.622h15.698v44.022h-15.698z"/></svg>`; | |
| div.innerHTML = type === "save" ? save : telegram; | |
| return div; | |
| } | |
| async function onSelectFolder() { | |
| const dirHandle = await window.showDirectoryPicker({ id, mode: "readwrite" }); | |
| await set(idbKey, dirHandle); | |
| return dirHandle; | |
| } | |
| async function writeImage(item, dirHandler) { | |
| const fileHandle = await get(item.url); | |
| if (fileHandle) { | |
| try { | |
| const file = await fileHandle.getFile(); | |
| if (file) return console.log(`url=${item.url} exists`); | |
| } catch (e) { | |
| if (e.code == DOMException.NOT_FOUND_ERR) { | |
| console.log(`url=${item.url} file has removed, pls download regain`); | |
| } | |
| } | |
| } | |
| let filetype = ""; | |
| const image = await fetch(item.url).then((res) => { | |
| const headers = res.headers; | |
| const contentType = headers.get("Content-Type"); | |
| if (contentType) filetype = contentType.replace(/image\//, ""); | |
| return res; | |
| }).then((res) => res.blob()); | |
| const filename = item.filename + "." + filetype; | |
| for await (let name of dirHandler.keys()) if (name == filename) return; | |
| const fileHandler = await dirHandler.getFileHandle(filename, { create: true }); | |
| const w = await fileHandler.createWritable(); | |
| await w.write(image); | |
| await w.close(); | |
| await set(item.url, fileHandler); | |
| } | |
| async function onWriteImage(item, dirHandler) { | |
| if (!item.url) return; | |
| ping(item.url); | |
| await writeImage(item, dirHandler); | |
| } | |
| function onSaveImagesToLocal(list2, folder) { | |
| return new Promise((resolve) => { | |
| function save(list22, index = 0) { | |
| if (list22.length === index) { | |
| resolve(true); | |
| return; | |
| } | |
| const p = onWriteImage(list22[index], folder); | |
| p.finally(() => { | |
| save(list22, index + 1); | |
| }); | |
| } | |
| save(list2); | |
| }); | |
| } | |
| async function ensureDirectory(path, root) { | |
| const segments = path.split("/").filter((segment) => segment.length > 0); | |
| let current = root; | |
| for (const segment of segments) { | |
| current = await current.getDirectoryHandle(segment, { create: true }); | |
| } | |
| return current; | |
| } | |
| async function trySaveImagesToLocale(images) { | |
| let dirHandle = await get(idbKey); | |
| if (!dirHandle) dirHandle = await onSelectFolder(); | |
| const date = new Date(); | |
| const dirname = `${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, "0")}`; | |
| let permission = true; | |
| let folder = null; | |
| try { | |
| folder = await ensureDirectory(dirname, dirHandle); | |
| } catch (e) { | |
| permission = false; | |
| } | |
| if (permission === false) { | |
| await del(idbKey); | |
| return trySaveImagesToLocale(images); | |
| } | |
| if (folder == null) { | |
| console.log("no folder selected."); | |
| return; | |
| } | |
| try { | |
| await onSaveImagesToLocal(images, folder); | |
| notify("Saved!"); | |
| } catch (e) { | |
| console.log("save directory handle failed"); | |
| } | |
| } | |
| function action(fn) { | |
| let timer = 0; | |
| function run2() { | |
| if (typeof fn === "function") { | |
| try { | |
| fn(); | |
| } catch (e) { | |
| } | |
| } | |
| timer = setTimeout(() => { | |
| run2(); | |
| }, 60); | |
| } | |
| run2(); | |
| return function cancel() { | |
| if (timer) { | |
| clearTimeout(timer); | |
| timer = 0; | |
| } | |
| }; | |
| } | |
| function* treeWalker(root = document.body, filter2 = () => NodeFilter.FILTER_ACCEPT) { | |
| const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filter2); | |
| do { | |
| yield walker.currentNode; | |
| const shadowRoot = walker.currentNode.shadowRoot; | |
| for (let child = shadowRoot ? shadowRoot.firstElementChild : walker.currentNode.firstElementChild; child; child = child.nextElementSibling) { | |
| yield* treeWalker(child, filter2); | |
| } | |
| } while (walker.nextNode()); | |
| } | |
| function useInterval(n, handler2) { | |
| return (task2) => { | |
| const inner = () => { | |
| const scripts2 = Array.isArray(handler2) ? handler2 : [handler2]; | |
| scripts2.forEach((script) => script(task2)); | |
| setTimeout(() => { | |
| if (task2.meta?.pause == false) { | |
| inner(); | |
| } | |
| }, n * 1e3); | |
| }; | |
| inner(); | |
| }; | |
| } | |
| const otherTask = [ | |
| { | |
| match: "https://www.cguardian.com/auctions/live-bidding", | |
| meta: { pause: false }, | |
| script: useInterval(0.1, (task2) => { | |
| for (let node of treeWalker()) { | |
| if (node.nodeName == "VIDEO") { | |
| node.setAttribute("controls", ""); | |
| task2.meta.pause = true; | |
| break; | |
| } | |
| } | |
| }) | |
| }, | |
| { | |
| match: "https://helloacm.com/", | |
| script: removeRemovedAdBlockerModal | |
| }, | |
| { | |
| match: "https://www.flickr.com/photos/", | |
| script: createHiddenNodesBySelectorsTask([ | |
| ".facade-of-protection-zoom" | |
| ]) | |
| }, | |
| { | |
| match: true, | |
| script: () => { | |
| const tags = [ | |
| "html", | |
| "body", | |
| ".grayTheme" | |
| ]; | |
| tags.forEach((tag) => { | |
| const nodeList = document.querySelectorAll(tag); | |
| nodeList.forEach((node) => { | |
| node.style.filter = "initial"; | |
| }); | |
| }); | |
| } | |
| }, | |
| { | |
| match: new URLPattern({ protocol: "https", hostname: "paulgraham.com" }), | |
| script: function() { | |
| const selectors2 = ["table", "td"]; | |
| selectors2.forEach((selector) => { | |
| const elements = document.querySelectorAll(selector); | |
| Array.from(elements).forEach((element) => { | |
| if (element.hasAttribute("width")) { | |
| element.removeAttribute("width"); | |
| } | |
| }); | |
| }); | |
| } | |
| }, | |
| { | |
| match: new URLPattern({ protocol: "https", hostname: "www.zhangxinxu.com" }), | |
| script: function() { | |
| const selectors2 = [".col-main"]; | |
| waitForSelector(selectors2).then(() => { | |
| selectors2.forEach((selector) => { | |
| const elements = document.querySelectorAll(selector); | |
| Array.from(elements).forEach((element) => { | |
| element.style.margin = "auto 30px"; | |
| }); | |
| }); | |
| }); | |
| } | |
| }, | |
| { | |
| match: true, | |
| script: function() { | |
| let url = location.href; | |
| let ts = [ | |
| { | |
| pattern: new URLPattern({ protocol: "https", hostname: "www.zhangxinxu.com" }), | |
| selectors: [ | |
| "[class^=col-left]", | |
| "[class^=col-right]" | |
| ] | |
| } | |
| ]; | |
| ts.forEach(async (t) => { | |
| const result = await match(t.pattern, url); | |
| if (result) { | |
| waitForSelector(t.selectors).then(() => { | |
| t.selectors.forEach((s) => { | |
| const node = document.querySelector(s); | |
| if (node == null) return; | |
| node.style.display = "none"; | |
| }); | |
| }); | |
| } | |
| }); | |
| } | |
| }, | |
| { | |
| match: true, | |
| script: () => { | |
| let contextmenuTarget = { | |
| type: "", | |
| payload: null | |
| }; | |
| function clear() { | |
| contextmenuTarget = { | |
| type: "", | |
| payload: null | |
| }; | |
| } | |
| function setValue(type, payload) { | |
| contextmenuTarget = { type, payload }; | |
| } | |
| window.addEventListener("contextmenu", (e) => { | |
| const target = e.target; | |
| if (target == null) return; | |
| const node = target; | |
| let type = "url"; | |
| let payload = `${document.title} | |
| ${location.href}`; | |
| if (node.nodeName === "IMG") { | |
| let src = node.getAttribute("src"); | |
| if (src) { | |
| const pattern = new URLPattern({ hostname: "{*.}?zhihu.com" }); | |
| if (pattern.test(location.href)) { | |
| const token = node.getAttribute("data-original-token"); | |
| if (token) src = src.replace(/v2-.*?(?=\.)/, token); | |
| } | |
| type = "image"; | |
| payload = src; | |
| } | |
| } else { | |
| const selection = document.getSelection(); | |
| if (selection) { | |
| const st = selection.type; | |
| if (st === "Range") { | |
| const raw = selection.toString(); | |
| const text = raw.trim(); | |
| if (text) { | |
| type = "selection"; | |
| payload = text; | |
| } | |
| } | |
| } | |
| } | |
| setValue(type, payload); | |
| }); | |
| window.addEventListener("scroll", clear); | |
| window.addEventListener("pointerdown", () => { | |
| if (contextmenuTarget.type !== "") clear(); | |
| }); | |
| _GM_registerMenuCommand("Telegram Channel[039]", () => { | |
| switch (contextmenuTarget.type) { | |
| case "image": | |
| sendPhoto(contextmenuTarget.payload, location.href); | |
| break; | |
| case "selection": | |
| sendMessage( | |
| contextmenuTarget.payload + ` | |
| Ref: [${document.title.trim() || location.href}](${location.href})`, | |
| "MarkdownV2" | |
| ); | |
| break; | |
| case "url": | |
| sendMessage(contextmenuTarget.payload); | |
| break; | |
| default: | |
| sendMessage(`${document.title} | |
| ${location.href}`); | |
| break; | |
| } | |
| clear(); | |
| }); | |
| _GM_registerMenuCommand("Copy as markdown", function() { | |
| let md = ``; | |
| switch (contextmenuTarget.type) { | |
| case "image": | |
| md = ``; | |
| break; | |
| case "selection": | |
| md = `> ${contextmenuTarget.payload} [Ref](${location.href})`; | |
| break; | |
| default: | |
| md = `[${document.title}](${location.href})`; | |
| break; | |
| } | |
| _GM_setClipboard(md, "text"); | |
| clear(); | |
| }); | |
| } | |
| }, | |
| { | |
| match: true, | |
| script: () => { | |
| _GM_registerMenuCommand("分享到 Telegram", function() { | |
| const url = `https://t.me/share/url?url=${encodeURIComponent(top.location.href)}&text=${encodeURIComponent(top.document.title)}`; | |
| _GM_openInTab(url, { active: true }); | |
| }); | |
| _GM_registerMenuCommand("更新脚本", function() { | |
| const url = _GM_info.scriptUpdateURL; | |
| if (url) _GM_openInTab(url, { active: true }); | |
| }); | |
| } | |
| }, | |
| { | |
| match: true, | |
| script: () => { | |
| _GM_registerMenuCommand("Remover", function() { | |
| document.cookie.split(";").forEach(function(c) { | |
| document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + ( new Date()).toUTCString() + ";path=/"); | |
| }); | |
| window.localStorage.clear(); | |
| window.sessionStorage.clear(); | |
| location.reload(); | |
| }); | |
| } | |
| }, | |
| { | |
| match: true, | |
| script: function() { | |
| const url = new URL(location.href); | |
| const paramsToRemove = [ | |
| "utm_source", | |
| "utm_medium", | |
| "utm_campaign", | |
| "utm_term", | |
| "utm_content", | |
| "_spm_id" | |
| ]; | |
| let changed = false; | |
| for (const param of paramsToRemove) { | |
| if (url.searchParams.has(param)) { | |
| url.searchParams.delete(param); | |
| changed = true; | |
| } | |
| } | |
| if (changed) { | |
| history.replaceState(null, "", url.href); | |
| } | |
| } | |
| } | |
| ]; | |
| function asyncTasks({ | |
| list: list2 = [], | |
| count = 5, | |
| step, | |
| complete, | |
| start = 0, | |
| end = list2.length | |
| }) { | |
| let doing = 0; | |
| return (function action2() { | |
| while (doing < count && start < end) { | |
| list2[start]( | |
| (() => { | |
| start++; | |
| doing++; | |
| return (...rest) => { | |
| if (typeof step === "function") step(start, ...rest); | |
| doing--; | |
| action2(); | |
| }; | |
| })() | |
| ); | |
| } | |
| if (doing === 0 && start === end && typeof complete === "function") complete(); | |
| })(); | |
| } | |
| _unsafeWindow.telegram = { | |
| sendPhoto, | |
| sendMediaGroup, | |
| sendMessage | |
| }; | |
| function toResponse(res) { | |
| const headersText = (res.responseHeaders || "").trim(); | |
| const headers = headersText.split("\r\n").map((line) => line.split(":")).reduce((headers2, item) => { | |
| const [key, value] = item; | |
| if (key) headers2.append(key, value); | |
| return headers2; | |
| }, new Headers()); | |
| return new Response(res.response, { | |
| status: res.status, | |
| statusText: res.statusText, | |
| headers | |
| }); | |
| } | |
| function toRequest(req) { | |
| const method = (req.method || "GET").toUpperCase(); | |
| const headers = {}; | |
| const rawHeaders = req.headers ? req.headers : {}; | |
| if (Array.isArray(rawHeaders)) { | |
| rawHeaders.forEach(([key, value]) => { | |
| headers[key] = value; | |
| }); | |
| } else if (rawHeaders instanceof Headers) { | |
| for (let key of rawHeaders.keys()) { | |
| const value = rawHeaders.get(key); | |
| if (value) headers[key] = value; | |
| } | |
| } | |
| const gmXhrRequest = { | |
| url: "", | |
| method, | |
| headers, | |
| redirect: req.redirect, | |
| anonymous: req.credentials == void 0 || req.credentials == "omit" ? true : false, | |
| responseType: "blob" | |
| }; | |
| const body = req.body; | |
| if (body && method === "GET") { | |
| gmXhrRequest.data = body; | |
| } | |
| return gmXhrRequest; | |
| } | |
| function _xmlHttpRequest(req) { | |
| const raw = _GM.xmlHttpRequest(req); | |
| const promise = raw.then(toResponse); | |
| promise.abort = raw.abort; | |
| return promise; | |
| } | |
| _unsafeWindow.x181 = { | |
| post(url, options = {}) { | |
| const req = toRequest(options); | |
| return _xmlHttpRequest({ ...req, method: "POST", url }); | |
| }, | |
| get(url, options = {}) { | |
| const req = toRequest(options); | |
| return _xmlHttpRequest({ ...req, method: "GET", url }); | |
| }, | |
| fetch(url, options = {}) { | |
| const method = String(options && options.method || "GET"); | |
| return method.toUpperCase() === "POST" ? this.post(url, options) : this.get(url, options); | |
| }, | |
| async saveFile(dirHandler, filename, data) { | |
| const fileHandler = await dirHandler.getFileHandle(filename, { create: true }); | |
| const w = await fileHandler.createWritable(); | |
| await w.write(data); | |
| await w.close(); | |
| }, | |
| selectFolder() { | |
| return window.showDirectoryPicker({ id: String(Date.now()), mode: "readwrite" }); | |
| }, | |
| async save(map) { | |
| const folder = await this.selectFolder(); | |
| if (folder == null) return; | |
| for (let [filename, url] of Object.entries(map)) { | |
| url = url.startsWith("//") ? "https:" + url : url.startsWith("/") ? location.origin + url : url; | |
| const blob = await this.fetch(url).then((res) => res.blob()); | |
| await this.saveFile(folder, filename, blob); | |
| } | |
| }, | |
| asyncTasks, | |
| async download(list2) { | |
| const map = {}; | |
| for (const url of list2) { | |
| const match2 = url.match(/([^\/]+)-[^\/]*\.(\w+)$/); | |
| if (match2) { | |
| const [_, base, ext] = match2; | |
| const filename = `${base}.${ext}`; | |
| map[filename] = url; | |
| } | |
| } | |
| return await this.save(map); | |
| } | |
| }; | |
| const scripts = [ | |
| task$3, | |
| bingTask, | |
| doubanTask, | |
| mysmthTask, | |
| otherTask, | |
| weiboTask, | |
| weChatTask, | |
| zhihuTask, | |
| redirectTask, | |
| twitterTask | |
| ].flat(Infinity); | |
| core(scripts, location.href); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment