yacu - Yet another CC98 userscript

CC98 增强脚本

  1. // ==UserScript==
  2. // @name yacu - Yet another CC98 userscript
  3. // @description CC98 增强脚本
  4. // @namespace https://github.com/CoolSpring8/
  5. // @match *://www.cc98.org/*
  6. // @match *://www-cc98-org-s.webvpn.zju.edu.cn:8001/*
  7. // @run-at document-idle
  8. // @version 1.0.1
  9. // @homepage https://github.com/CoolSpring8/yacu
  10. // @author CoolSpring8
  11. // @license MIT
  12. // @grant none
  13. // ==/UserScript==
  14. function _defineProperty(obj, key, value) {
  15. return (
  16. key in obj
  17. ? Object.defineProperty(obj, key, {
  18. value: value,
  19. enumerable: !0,
  20. configurable: !0,
  21. writable: !0,
  22. })
  23. : (obj[key] = value),
  24. obj
  25. );
  26. }
  27. function noop() {}
  28. function run(fn) {
  29. return fn();
  30. }
  31. function blank_object() {
  32. return Object.create(null);
  33. }
  34. function run_all(fns) {
  35. fns.forEach(run);
  36. }
  37. function is_function(thing) {
  38. return "function" == typeof thing;
  39. }
  40. function safe_not_equal(a, b) {
  41. return a != a
  42. ? b == b
  43. : a !== b || (a && "object" == typeof a) || "function" == typeof a;
  44. }
  45. function append(target, node) {
  46. target.appendChild(node);
  47. }
  48. function append_styles(target, style_sheet_id, styles) {
  49. const append_styles_to = (function (node) {
  50. if (!node) return document;
  51. const root = node.getRootNode ? node.getRootNode() : node.ownerDocument;
  52. if (root && root.host) return root;
  53. return node.ownerDocument;
  54. })(target);
  55. if (!append_styles_to.getElementById(style_sheet_id)) {
  56. const style = element("style");
  57. (style.id = style_sheet_id),
  58. (style.textContent = styles),
  59. (function (node, style) {
  60. append(node.head || node, style);
  61. })(append_styles_to, style);
  62. }
  63. }
  64. function insert(target, node, anchor) {
  65. target.insertBefore(node, anchor || null);
  66. }
  67. function detach(node) {
  68. node.parentNode.removeChild(node);
  69. }
  70. function element(name) {
  71. return document.createElement(name);
  72. }
  73. function text(data) {
  74. return document.createTextNode(data);
  75. }
  76. function space() {
  77. return text(" ");
  78. }
  79. function listen(node, event, handler, options) {
  80. return (
  81. node.addEventListener(event, handler, options),
  82. () => node.removeEventListener(event, handler, options)
  83. );
  84. }
  85. function attr(node, attribute, value) {
  86. null == value
  87. ? node.removeAttribute(attribute)
  88. : node.getAttribute(attribute) !== value &&
  89. node.setAttribute(attribute, value);
  90. }
  91. function set_data(text, data) {
  92. (data = "" + data), text.wholeText !== data && (text.data = data);
  93. }
  94. function set_input_value(input, value) {
  95. input.value = null == value ? "" : value;
  96. }
  97. function toggle_class(element, name, toggle) {
  98. element.classList[toggle ? "add" : "remove"](name);
  99. }
  100. let current_component;
  101. function set_current_component(component) {
  102. current_component = component;
  103. }
  104. function onMount(fn) {
  105. (function () {
  106. if (!current_component)
  107. throw new Error("Function called outside component initialization");
  108. return current_component;
  109. })().$$.on_mount.push(fn);
  110. }
  111. !(function (css, ref) {
  112. void 0 === ref && (ref = {});
  113. var insertAt = ref.insertAt;
  114. if (css && "undefined" != typeof document) {
  115. var head = document.head || document.getElementsByTagName("head")[0],
  116. style = document.createElement("style");
  117. (style.type = "text/css"),
  118. "top" === insertAt && head.firstChild
  119. ? head.insertBefore(style, head.firstChild)
  120. : head.appendChild(style),
  121. style.styleSheet
  122. ? (style.styleSheet.cssText = css)
  123. : style.appendChild(document.createTextNode(css));
  124. }
  125. })(
  126. "*,:after,:before{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.flex{display:flex}.hidden{display:none}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.rounded-lg{border-radius:.5rem}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.text-3xl{font-size:1.875rem;line-height:2.25rem}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}"
  127. );
  128. const dirty_components = [],
  129. binding_callbacks = [],
  130. render_callbacks = [],
  131. flush_callbacks = [],
  132. resolved_promise = Promise.resolve();
  133. let update_scheduled = !1;
  134. function add_render_callback(fn) {
  135. render_callbacks.push(fn);
  136. }
  137. const seen_callbacks = new Set();
  138. let flushidx = 0;
  139. function flush() {
  140. const saved_component = current_component;
  141. do {
  142. for (; flushidx < dirty_components.length; ) {
  143. const component = dirty_components[flushidx];
  144. flushidx++, set_current_component(component), update(component.$$);
  145. }
  146. for (
  147. set_current_component(null), dirty_components.length = 0, flushidx = 0;
  148. binding_callbacks.length;
  149.  
  150. )
  151. binding_callbacks.pop()();
  152. for (let i = 0; i < render_callbacks.length; i += 1) {
  153. const callback = render_callbacks[i];
  154. seen_callbacks.has(callback) ||
  155. (seen_callbacks.add(callback), callback());
  156. }
  157. render_callbacks.length = 0;
  158. } while (dirty_components.length);
  159. for (; flush_callbacks.length; ) flush_callbacks.pop()();
  160. (update_scheduled = !1),
  161. seen_callbacks.clear(),
  162. set_current_component(saved_component);
  163. }
  164. function update($$) {
  165. if (null !== $$.fragment) {
  166. $$.update(), run_all($$.before_update);
  167. const dirty = $$.dirty;
  168. ($$.dirty = [-1]),
  169. $$.fragment && $$.fragment.p($$.ctx, dirty),
  170. $$.after_update.forEach(add_render_callback);
  171. }
  172. }
  173. const outroing = new Set();
  174. let outros, defaultGetStoreFunc;
  175. function transition_in(block, local) {
  176. block && block.i && (outroing.delete(block), block.i(local));
  177. }
  178. function transition_out(block, local, detach, callback) {
  179. if (block && block.o) {
  180. if (outroing.has(block)) return;
  181. outroing.add(block),
  182. outros.c.push(() => {
  183. outroing.delete(block), callback && (detach && block.d(1), callback());
  184. }),
  185. block.o(local);
  186. }
  187. }
  188. function mount_component(component, target, anchor, customElement) {
  189. const {
  190. fragment: fragment,
  191. on_mount: on_mount,
  192. on_destroy: on_destroy,
  193. after_update: after_update,
  194. } = component.$$;
  195. fragment && fragment.m(target, anchor),
  196. customElement ||
  197. add_render_callback(() => {
  198. const new_on_destroy = on_mount.map(run).filter(is_function);
  199. on_destroy
  200. ? on_destroy.push(...new_on_destroy)
  201. : run_all(new_on_destroy),
  202. (component.$$.on_mount = []);
  203. }),
  204. after_update.forEach(add_render_callback);
  205. }
  206. function destroy_component(component, detaching) {
  207. const $$ = component.$$;
  208. null !== $$.fragment &&
  209. (run_all($$.on_destroy),
  210. $$.fragment && $$.fragment.d(detaching),
  211. ($$.on_destroy = $$.fragment = null),
  212. ($$.ctx = []));
  213. }
  214. function make_dirty(component, i) {
  215. -1 === component.$$.dirty[0] &&
  216. (dirty_components.push(component),
  217. update_scheduled || ((update_scheduled = !0), resolved_promise.then(flush)),
  218. component.$$.dirty.fill(0)),
  219. (component.$$.dirty[(i / 31) | 0] |= 1 << i % 31);
  220. }
  221. function init(
  222. component,
  223. options,
  224. instance,
  225. create_fragment,
  226. not_equal,
  227. props,
  228. append_styles,
  229. dirty = [-1]
  230. ) {
  231. const parent_component = current_component;
  232. set_current_component(component);
  233. const $$ = (component.$$ = {
  234. fragment: null,
  235. ctx: null,
  236. props: props,
  237. update: noop,
  238. not_equal: not_equal,
  239. bound: blank_object(),
  240. on_mount: [],
  241. on_destroy: [],
  242. on_disconnect: [],
  243. before_update: [],
  244. after_update: [],
  245. context: new Map(
  246. options.context || (parent_component ? parent_component.$$.context : [])
  247. ),
  248. callbacks: blank_object(),
  249. dirty: dirty,
  250. skip_bound: !1,
  251. root: options.target || parent_component.$$.root,
  252. });
  253. append_styles && append_styles($$.root);
  254. let ready = !1;
  255. if (
  256. (($$.ctx = instance
  257. ? instance(component, options.props || {}, (i, ret, ...rest) => {
  258. const value = rest.length ? rest[0] : ret;
  259. return (
  260. $$.ctx &&
  261. not_equal($$.ctx[i], ($$.ctx[i] = value)) &&
  262. (!$$.skip_bound && $$.bound[i] && $$.bound[i](value),
  263. ready && make_dirty(component, i)),
  264. ret
  265. );
  266. })
  267. : []),
  268. $$.update(),
  269. (ready = !0),
  270. run_all($$.before_update),
  271. ($$.fragment = !!create_fragment && create_fragment($$.ctx)),
  272. options.target)
  273. ) {
  274. if (options.hydrate) {
  275. const nodes = (function (element) {
  276. return Array.from(element.childNodes);
  277. })(options.target);
  278. $$.fragment && $$.fragment.l(nodes), nodes.forEach(detach);
  279. } else $$.fragment && $$.fragment.c();
  280. options.intro && transition_in(component.$$.fragment),
  281. mount_component(
  282. component,
  283. options.target,
  284. options.anchor,
  285. options.customElement
  286. ),
  287. flush();
  288. }
  289. set_current_component(parent_component);
  290. }
  291. class SvelteComponent {
  292. $destroy() {
  293. destroy_component(this, 1), (this.$destroy = noop);
  294. }
  295. $on(type, callback) {
  296. const callbacks = this.$$.callbacks[type] || (this.$$.callbacks[type] = []);
  297. return (
  298. callbacks.push(callback),
  299. () => {
  300. const index = callbacks.indexOf(callback);
  301. -1 !== index && callbacks.splice(index, 1);
  302. }
  303. );
  304. }
  305. $set($$props) {
  306. var obj;
  307. this.$$set &&
  308. ((obj = $$props), 0 !== Object.keys(obj).length) &&
  309. ((this.$$.skip_bound = !0),
  310. this.$$set($$props),
  311. (this.$$.skip_bound = !1));
  312. }
  313. }
  314. function add_css$2(target) {
  315. append_styles(
  316. target,
  317. "svelte-1hz6wor",
  318. ".award-info-stats.svelte-1hz6wor{display:flex;gap:2px;font-size:12px}.item.svelte-1hz6wor{color:grey;margin-right:4px}"
  319. );
  320. }
  321. function get_each_context(ctx, list, i) {
  322. const child_ctx = ctx.slice();
  323. return (child_ctx[1] = list[i]), child_ctx;
  324. }
  325. function create_each_block(ctx) {
  326. let p,
  327. t0,
  328. t1,
  329. t2,
  330. t3,
  331. t0_value = ctx[1][0] + "",
  332. t2_value = ctx[1][1] + "";
  333. return {
  334. c() {
  335. (p = element("p")),
  336. (t0 = text(t0_value)),
  337. (t1 = text("×")),
  338. (t2 = text(t2_value)),
  339. (t3 = text(";")),
  340. attr(p, "class", "item svelte-1hz6wor");
  341. },
  342. m(target, anchor) {
  343. insert(target, p, anchor),
  344. append(p, t0),
  345. append(p, t1),
  346. append(p, t2),
  347. append(p, t3);
  348. },
  349. p(ctx, dirty) {
  350. 1 & dirty &&
  351. t0_value !== (t0_value = ctx[1][0] + "") &&
  352. set_data(t0, t0_value),
  353. 1 & dirty &&
  354. t2_value !== (t2_value = ctx[1][1] + "") &&
  355. set_data(t2, t2_value);
  356. },
  357. d(detaching) {
  358. detaching && detach(p);
  359. },
  360. };
  361. }
  362. function create_fragment$2(ctx) {
  363. let div,
  364. p,
  365. t1,
  366. each_value = ctx[0],
  367. each_blocks = [];
  368. for (let i = 0; i < each_value.length; i += 1)
  369. each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
  370. return {
  371. c() {
  372. (div = element("div")),
  373. (p = element("p")),
  374. (p.textContent = "统计:"),
  375. (t1 = space());
  376. for (let i = 0; i < each_blocks.length; i += 1) each_blocks[i].c();
  377. attr(div, "class", "award-info-stats svelte-1hz6wor");
  378. },
  379. m(target, anchor) {
  380. insert(target, div, anchor), append(div, p), append(div, t1);
  381. for (let i = 0; i < each_blocks.length; i += 1)
  382. each_blocks[i].m(div, null);
  383. },
  384. p(ctx, [dirty]) {
  385. if (1 & dirty) {
  386. let i;
  387. for (each_value = ctx[0], i = 0; i < each_value.length; i += 1) {
  388. const child_ctx = get_each_context(ctx, each_value, i);
  389. each_blocks[i]
  390. ? each_blocks[i].p(child_ctx, dirty)
  391. : ((each_blocks[i] = create_each_block(child_ctx)),
  392. each_blocks[i].c(),
  393. each_blocks[i].m(div, null));
  394. }
  395. for (; i < each_blocks.length; i += 1) each_blocks[i].d(1);
  396. each_blocks.length = each_value.length;
  397. }
  398. },
  399. i: noop,
  400. o: noop,
  401. d(detaching) {
  402. detaching && detach(div),
  403. (function (iterations, detaching) {
  404. for (let i = 0; i < iterations.length; i += 1)
  405. iterations[i] && iterations[i].d(detaching);
  406. })(each_blocks, detaching);
  407. },
  408. };
  409. }
  410. function instance$2($$self, $$props, $$invalidate) {
  411. let { stats: stats } = $$props;
  412. return (
  413. ($$self.$$set = ($$props) => {
  414. "stats" in $$props && $$invalidate(0, (stats = $$props.stats));
  415. }),
  416. [stats]
  417. );
  418. }
  419. class AwardInfoStats$1 extends SvelteComponent {
  420. constructor(options) {
  421. super(),
  422. init(
  423. this,
  424. options,
  425. instance$2,
  426. create_fragment$2,
  427. safe_not_equal,
  428. { stats: 0 },
  429. add_css$2
  430. );
  431. }
  432. }
  433. function promisifyRequest(request) {
  434. return new Promise((resolve, reject) => {
  435. (request.oncomplete = request.onsuccess = () => resolve(request.result)),
  436. (request.onabort = request.onerror = () => reject(request.error));
  437. });
  438. }
  439. function createStore(dbName, storeName) {
  440. const dbp = (
  441. !navigator.userAgentData &&
  442. /Safari\//.test(navigator.userAgent) &&
  443. !/Chrom(e|ium)\//.test(navigator.userAgent) &&
  444. indexedDB.databases
  445. ? new Promise(function (resolve) {
  446. var tryIdb = function () {
  447. return indexedDB.databases().finally(resolve);
  448. };
  449. (intervalId = setInterval(tryIdb, 100)), tryIdb();
  450. }).finally(function () {
  451. return clearInterval(intervalId);
  452. })
  453. : Promise.resolve()
  454. ).then(() => {
  455. const request = indexedDB.open(dbName);
  456. return (
  457. (request.onupgradeneeded = () =>
  458. request.result.createObjectStore(storeName)),
  459. promisifyRequest(request)
  460. );
  461. });
  462. var intervalId;
  463. return (txMode, callback) =>
  464. dbp.then((db) =>
  465. callback(db.transaction(storeName, txMode).objectStore(storeName))
  466. );
  467. }
  468. function defaultGetStore() {
  469. return (
  470. defaultGetStoreFunc ||
  471. (defaultGetStoreFunc = createStore("keyval-store", "keyval")),
  472. defaultGetStoreFunc
  473. );
  474. }
  475. function get(key, customStore = defaultGetStore()) {
  476. return customStore("readonly", (store) => promisifyRequest(store.get(key)));
  477. }
  478. function add_css$1(target) {
  479. append_styles(
  480. target,
  481. "svelte-4qi5da",
  482. ".user-preference-modal.svelte-4qi5da{position:fixed;left:50%;top:50%;transform:translate(-50%, -50%);z-index:100;width:400px;height:300px;background-color:whitesmoke;padding:40px}"
  483. );
  484. }
  485. function create_fragment$1(ctx) {
  486. let div5,
  487. div1,
  488. h2,
  489. t1,
  490. div0,
  491. t3,
  492. div4,
  493. div3,
  494. h3,
  495. t5,
  496. div2,
  497. input,
  498. t6,
  499. button,
  500. mounted,
  501. dispose;
  502. return {
  503. c() {
  504. (div5 = element("div")),
  505. (div1 = element("div")),
  506. (h2 = element("h2")),
  507. (h2.textContent = "偏好设置"),
  508. (t1 = space()),
  509. (div0 = element("div")),
  510. (div0.textContent = "×"),
  511. (t3 = space()),
  512. (div4 = element("div")),
  513. (div3 = element("div")),
  514. (h3 = element("h3")),
  515. (h3.textContent = "屏蔽用户发言"),
  516. (t5 = space()),
  517. (div2 = element("div")),
  518. (input = element("input")),
  519. (t6 = space()),
  520. (button = element("button")),
  521. (button.textContent = "保存"),
  522. attr(div0, "class", "text-3xl cursor-pointer"),
  523. attr(div1, "class", "flex justify-between items-center"),
  524. attr(input, "type", "text"),
  525. attr(div2, "class", "flex gap-2"),
  526. attr(div3, "class", "block-users"),
  527. attr(div4, "class", "user-preference-items"),
  528. attr(
  529. div5,
  530. "class",
  531. "user-preference-modal bg-gray-100 shadow-2xl rounded-lg svelte-4qi5da"
  532. ),
  533. toggle_class(div5, "hidden", !ctx[0]);
  534. },
  535. m(target, anchor) {
  536. insert(target, div5, anchor),
  537. append(div5, div1),
  538. append(div1, h2),
  539. append(div1, t1),
  540. append(div1, div0),
  541. append(div5, t3),
  542. append(div5, div4),
  543. append(div4, div3),
  544. append(div3, h3),
  545. append(div3, t5),
  546. append(div3, div2),
  547. append(div2, input),
  548. set_input_value(input, ctx[1]),
  549. append(div2, t6),
  550. append(div2, button),
  551. mounted ||
  552. ((dispose = [
  553. listen(div0, "click", ctx[2]),
  554. listen(input, "input", ctx[3]),
  555. listen(button, "click", ctx[4]),
  556. ]),
  557. (mounted = !0));
  558. },
  559. p(ctx, [dirty]) {
  560. 2 & dirty && input.value !== ctx[1] && set_input_value(input, ctx[1]),
  561. 1 & dirty && toggle_class(div5, "hidden", !ctx[0]);
  562. },
  563. i: noop,
  564. o: noop,
  565. d(detaching) {
  566. detaching && detach(div5), (mounted = !1), run_all(dispose);
  567. },
  568. };
  569. }
  570. function instance$1($$self, $$props, $$invalidate) {
  571. let blockedUsers,
  572. { open: open } = $$props;
  573. onMount(async () => {
  574. $$invalidate(
  575. 1,
  576. (blockedUsers = [...(await get("blocked-users"))]?.join(" ") || "")
  577. );
  578. });
  579. return (
  580. ($$self.$$set = ($$props) => {
  581. "open" in $$props && $$invalidate(0, (open = $$props.open));
  582. }),
  583. [
  584. open,
  585. blockedUsers,
  586. () => $$invalidate(0, (open = !1)),
  587. function () {
  588. (blockedUsers = this.value), $$invalidate(1, blockedUsers);
  589. },
  590. () => {
  591. !(function (key, value, customStore = defaultGetStore()) {
  592. customStore(
  593. "readwrite",
  594. (store) => (
  595. store.put(value, key), promisifyRequest(store.transaction)
  596. )
  597. );
  598. })("blocked-users", new Set(blockedUsers.split(" ")));
  599. },
  600. ]
  601. );
  602. }
  603. class Modal extends SvelteComponent {
  604. constructor(options) {
  605. super(),
  606. init(
  607. this,
  608. options,
  609. instance$1,
  610. create_fragment$1,
  611. safe_not_equal,
  612. { open: 0 },
  613. add_css$1
  614. );
  615. }
  616. }
  617. function add_css(target) {
  618. append_styles(
  619. target,
  620. "svelte-w6hddt",
  621. ".user-preference-button.svelte-w6hddt{position:fixed;right:30px;top:80px;z-index:2;background-color:white}"
  622. );
  623. }
  624. function create_if_block(ctx) {
  625. let userpreferencemodal, updating_open, current;
  626. function userpreferencemodal_open_binding(value) {
  627. ctx[2](value);
  628. }
  629. let userpreferencemodal_props = {};
  630. return (
  631. void 0 !== ctx[0] && (userpreferencemodal_props.open = ctx[0]),
  632. (userpreferencemodal = new Modal({ props: userpreferencemodal_props })),
  633. binding_callbacks.push(() =>
  634. (function (component, name, callback) {
  635. const index = component.$$.props[name];
  636. void 0 !== index &&
  637. ((component.$$.bound[index] = callback),
  638. callback(component.$$.ctx[index]));
  639. })(userpreferencemodal, "open", userpreferencemodal_open_binding)
  640. ),
  641. {
  642. c() {
  643. var block;
  644. (block = userpreferencemodal.$$.fragment) && block.c();
  645. },
  646. m(target, anchor) {
  647. mount_component(userpreferencemodal, target, anchor), (current = !0);
  648. },
  649. p(ctx, dirty) {
  650. const userpreferencemodal_changes = {};
  651. var fn;
  652. !updating_open &&
  653. 1 & dirty &&
  654. ((updating_open = !0),
  655. (userpreferencemodal_changes.open = ctx[0]),
  656. (fn = () => (updating_open = !1)),
  657. flush_callbacks.push(fn)),
  658. userpreferencemodal.$set(userpreferencemodal_changes);
  659. },
  660. i(local) {
  661. current ||
  662. (transition_in(userpreferencemodal.$$.fragment, local),
  663. (current = !0));
  664. },
  665. o(local) {
  666. transition_out(userpreferencemodal.$$.fragment, local), (current = !1);
  667. },
  668. d(detaching) {
  669. destroy_component(userpreferencemodal, detaching);
  670. },
  671. }
  672. );
  673. }
  674. function create_fragment(ctx) {
  675. let button,
  676. t1,
  677. if_block_anchor,
  678. current,
  679. mounted,
  680. dispose,
  681. if_block = ctx[0] && create_if_block(ctx);
  682. return {
  683. c() {
  684. (button = element("button")),
  685. (button.textContent = "偏好设置"),
  686. (t1 = space()),
  687. if_block && if_block.c(),
  688. (if_block_anchor = text("")),
  689. attr(button, "class", "user-preference-button svelte-w6hddt");
  690. },
  691. m(target, anchor) {
  692. insert(target, button, anchor),
  693. insert(target, t1, anchor),
  694. if_block && if_block.m(target, anchor),
  695. insert(target, if_block_anchor, anchor),
  696. (current = !0),
  697. mounted ||
  698. ((dispose = listen(button, "click", ctx[1])), (mounted = !0));
  699. },
  700. p(ctx, [dirty]) {
  701. ctx[0]
  702. ? if_block
  703. ? (if_block.p(ctx, dirty), 1 & dirty && transition_in(if_block, 1))
  704. : ((if_block = create_if_block(ctx)),
  705. if_block.c(),
  706. transition_in(if_block, 1),
  707. if_block.m(if_block_anchor.parentNode, if_block_anchor))
  708. : if_block &&
  709. ((outros = { r: 0, c: [], p: outros }),
  710. transition_out(if_block, 1, 1, () => {
  711. if_block = null;
  712. }),
  713. outros.r || run_all(outros.c),
  714. (outros = outros.p));
  715. },
  716. i(local) {
  717. current || (transition_in(if_block), (current = !0));
  718. },
  719. o(local) {
  720. transition_out(if_block), (current = !1);
  721. },
  722. d(detaching) {
  723. detaching && detach(button),
  724. detaching && detach(t1),
  725. if_block && if_block.d(detaching),
  726. detaching && detach(if_block_anchor),
  727. (mounted = !1),
  728. dispose();
  729. },
  730. };
  731. }
  732. function instance($$self, $$props, $$invalidate) {
  733. let open = !1;
  734. return [
  735. open,
  736. () => $$invalidate(0, (open = !0)),
  737. function (value) {
  738. (open = value), $$invalidate(0, open);
  739. },
  740. ];
  741. }
  742. class UserPreference$1 extends SvelteComponent {
  743. constructor(options) {
  744. super(),
  745. init(
  746. this,
  747. options,
  748. instance,
  749. create_fragment,
  750. safe_not_equal,
  751. {},
  752. add_css
  753. );
  754. }
  755. }
  756. class BasicError extends Error {
  757. constructor(message) {
  758. super(`[yacu] ${message}`);
  759. }
  760. }
  761. const emitter = (() => {
  762. const emitter = {
  763. all: (n = n || new Map()),
  764. on: function (t, e) {
  765. var i = n.get(t);
  766. i ? i.push(e) : n.set(t, [e]);
  767. },
  768. off: function (t, e) {
  769. var i = n.get(t);
  770. i && (e ? i.splice(i.indexOf(e) >>> 0, 1) : n.set(t, []));
  771. },
  772. emit: function (t, e) {
  773. var i = n.get(t);
  774. i &&
  775. i.slice().map(function (n) {
  776. n(e);
  777. }),
  778. (i = n.get("*")) &&
  779. i.slice().map(function (n) {
  780. n(t, e);
  781. });
  782. },
  783. };
  784. var n;
  785. return emitter.on("*", (...arguments_) => console.log(arguments_)), emitter;
  786. })();
  787. class ReactInteropError extends BasicError {
  788. constructor(message) {
  789. super(message), (this.name = "ReactInteropError");
  790. }
  791. }
  792. function renderToNewElement(component, properties) {
  793. const element = (function ({ className: className, id: id } = {}) {
  794. const element = document.createElement("div");
  795. return (
  796. className && (element.className = className),
  797. id && (element.id = id),
  798. element
  799. );
  800. })();
  801. return new component({ target: element, props: properties }), element;
  802. }
  803. class AwardInfoStats {
  804. constructor() {
  805. _defineProperty(this, "pending", !1),
  806. emitter.on("after-url-change", ({ to: to }) => {
  807. to?.startsWith("/topic/") && this.activate();
  808. });
  809. }
  810. async activate() {
  811. this.pending = !0;
  812. const cancel = (function (selector, callback) {
  813. let start,
  814. canceled = !1,
  815. elapsed = 0;
  816. const processedElements = new WeakSet();
  817. return (
  818. requestAnimationFrame(function step(timestamp) {
  819. const elements = document.querySelectorAll(selector);
  820. for (const element of elements.values())
  821. processedElements.has(element) ||
  822. (console.log(element),
  823. callback(element),
  824. processedElements.add(element));
  825. canceled ||
  826. (timestamp &&
  827. (void 0 === start && (start = timestamp),
  828. (elapsed = timestamp - start)),
  829. elapsed < 1e4
  830. ? requestAnimationFrame(step)
  831. : setTimeout(step, 5e3));
  832. }),
  833. () => {
  834. canceled = !0;
  835. }
  836. );
  837. })(".awardInfo", (element) => this._activate(element));
  838. emitter.on("before-url-change", () => cancel());
  839. }
  840. _activate(element) {
  841. const r = (function (element) {
  842. const [, instance] =
  843. Object.entries(element).find(([name]) =>
  844. name.startsWith("__reactInternalInstance")
  845. ) ?? [];
  846. if (!instance) throw new ReactInteropError("未发现 React 实例");
  847. return (function (instance) {
  848. let parent = instance.return;
  849. for (; "string" == typeof parent.type; ) parent = parent.return;
  850. return parent;
  851. })(instance).stateNode;
  852. })(element),
  853. accumulator = {};
  854. for (const award of r.props.awardInfo)
  855. accumulator[award.content]
  856. ? accumulator[award.content]++
  857. : (accumulator[award.content] = 1);
  858. const stats = Object.entries(accumulator),
  859. statsElement = renderToNewElement(AwardInfoStats$1, { stats: stats });
  860. element.prepend(statsElement), (this.pending = !1);
  861. }
  862. }
  863. const beforeRequestHooks = [],
  864. afterResponseHooks = [];
  865. function addAfterResponseHooks(hook) {
  866. afterResponseHooks.push(async (request, response) => {
  867. if (!hook.url.some((regex) => regex.test(request.url))) return;
  868. const oldData = await response.json(),
  869. newData = hook.process(oldData);
  870. if (Array.isArray(oldData) && Array.isArray(newData)) {
  871. const count = oldData.length - newData.length;
  872. 0 === count
  873. ? console.log("没有内容需要过滤")
  874. : console.log(`过滤了${count}条内容`);
  875. }
  876. return new Response(JSON.stringify(newData), response);
  877. });
  878. }
  879. class BlockUserTopic {
  880. constructor() {
  881. _defineProperty(this, "blockedUsers", void 0);
  882. const newTopics = new RegExp("^https://api.cc98.org/topic/new?"),
  883. topicPosts = new RegExp("^https://api.cc98.org/Topic/\\d+/post?");
  884. this.getBlockedUsers().then(() => {
  885. addAfterResponseHooks({
  886. url: [newTopics],
  887. process: (topics) =>
  888. topics.filter(
  889. (topic) =>
  890. null === topic.userName || !this.blockedUsers?.has(topic.userName)
  891. ),
  892. }),
  893. addAfterResponseHooks({
  894. url: [topicPosts],
  895. process: (posts) =>
  896. posts.filter(
  897. (post) =>
  898. null === post.userName || !this.blockedUsers?.has(post.userName)
  899. ),
  900. });
  901. });
  902. }
  903. async getBlockedUsers() {
  904. this.blockedUsers = await get("blocked-users");
  905. }
  906. }
  907. class UserPreference {
  908. constructor() {
  909. const element = renderToNewElement(UserPreference$1);
  910. document.body.append(element);
  911. }
  912. }
  913. const defaultOptions = {
  914. apiBase: ["https://math.vercel.app", "https://math.now.sh"],
  915. color: "black",
  916. },
  917. getPostsRequestRegExp = /post\/\d+\/original$/,
  918. putPostRequestRegExp = /post\/\d+$/,
  919. newPostRequestRegExp = /topic\/\d+\/post$/,
  920. newTopicRequestRegExp = /board\/\d+\/topic$/,
  921. texImageURLRegExp =
  922. /(?<=\n|^)( *(?:> *)*)<center>\s*!\[.*?]\((.+?)\)\s*<\/center>|!\[.*?]\((.+?)\)/g,
  923. texInlineRegExp = /\$(\S|(?:\S.*?\S))\$/g,
  924. blockquoteAwareTexBlockRegExp =
  925. /(?<=^|\n)( *(?:> *)*)\${2}((?:\n\1[^\n$]+)+)\n\1\${2}(?=\n|$)/g;
  926. function standardizeColor(string_) {
  927. const context = document.createElement("canvas").getContext("2d");
  928. return (context.fillStyle = string_), context.fillStyle;
  929. }
  930. class MarkdownMath {
  931. constructor() {
  932. var hook;
  933. addAfterResponseHooks({
  934. url: [getPostsRequestRegExp],
  935. process: (post) => (
  936. 1 === post.contentType &&
  937. (post.content = (function (
  938. content,
  939. { apiBase: apiBase = defaultOptions.apiBase } = defaultOptions
  940. ) {
  941. return content.replace(
  942. texImageURLRegExp,
  943. function (match, indent, blockURLString, inlineURLString) {
  944. const url = new URL(blockURLString || inlineURLString);
  945. if (apiBase.includes(url.origin)) {
  946. const searchParameters = url.searchParams;
  947. return searchParameters.has("from")
  948. ? ["$$", searchParameters.get("from").trim(), "$$"]
  949. .join("\n")
  950. .replace(/(?<=^|\n)/g, indent)
  951. : searchParameters.has("inline")
  952. ? `$${searchParameters.get("inline")}$`
  953. : match;
  954. }
  955. return match;
  956. }
  957. );
  958. })(post.content)),
  959. post
  960. ),
  961. }),
  962. (hook = {
  963. url: [
  964. putPostRequestRegExp,
  965. newPostRequestRegExp,
  966. newTopicRequestRegExp,
  967. ],
  968. process: (post) => (
  969. 1 === post.contentType &&
  970. (post.content = (function (
  971. content,
  972. {
  973. apiBase: apiBase = defaultOptions.apiBase,
  974. color: color = defaultOptions.color,
  975. alternateColor: alternateColor = defaultOptions.alternateColor,
  976. } = defaultOptions
  977. ) {
  978. function isInsideCodeFence(quoteLayers, precedingLines) {
  979. for (let index = quoteLayers; index >= 0; --index) {
  980. let backtickDelimiterCount = 0,
  981. tildeDelimiterCount = 0;
  982. for (const line of precedingLines.reverse()) {
  983. const matchResult = line.match(
  984. new RegExp(String.raw`^ *(?:> *){${index}}(\`\`\`|~~~)?`)
  985. );
  986. if (null === matchResult) break;
  987. if (void 0 !== matchResult[1])
  988. switch (matchResult[1]) {
  989. case "```":
  990. ++backtickDelimiterCount;
  991. break;
  992. case "~~~":
  993. ++tildeDelimiterCount;
  994. }
  995. }
  996. if (
  997. backtickDelimiterCount % 2 == 1 ||
  998. tildeDelimiterCount % 2 == 1
  999. )
  1000. return !0;
  1001. }
  1002. return !1;
  1003. }
  1004. return content
  1005. .replace(
  1006. blockquoteAwareTexBlockRegExp,
  1007. function (match, quote, quotedTex, offset, string) {
  1008. const precedingString = string.slice(0, offset);
  1009. if (
  1010. isInsideCodeFence(
  1011. (quote.match(/>/g) || []).length,
  1012. precedingString.replace(/\n$/, "").split("\n")
  1013. )
  1014. )
  1015. return match;
  1016. const url = new URL(apiBase[0]),
  1017. searchParameters = url.searchParams;
  1018. return (
  1019. searchParameters.set(
  1020. "from",
  1021. quotedTex.replaceAll(quote, "").trim()
  1022. ),
  1023. void 0 !== color &&
  1024. searchParameters.set("color", standardizeColor(color)),
  1025. void 0 !== alternateColor &&
  1026. searchParameters.set("alternateColor", alternateColor),
  1027. `${quote}<center>![](${url.href})</center>`
  1028. );
  1029. }
  1030. )
  1031. .replace(
  1032. texInlineRegExp,
  1033. function (match, tex, offset, string) {
  1034. const precedingString = string.slice(0, offset),
  1035. precedingLines = precedingString.split("\n"),
  1036. currentLine = precedingLines.pop();
  1037. if (
  1038. (precedingString.split("\n").pop().match(/`/g) || [])
  1039. .length %
  1040. 2 ==
  1041. 1
  1042. )
  1043. return match;
  1044. if (
  1045. isInsideCodeFence(
  1046. (
  1047. currentLine.match(/^( *(?:> *)*)/)[0].match(/>/g) ||
  1048. []
  1049. ).length,
  1050. precedingLines
  1051. )
  1052. )
  1053. return match;
  1054. const url = new URL(apiBase[0]),
  1055. searchParameters = url.searchParams;
  1056. return (
  1057. searchParameters.set("inline", tex),
  1058. void 0 !== color &&
  1059. searchParameters.set("color", standardizeColor(color)),
  1060. void 0 !== alternateColor &&
  1061. searchParameters.set("alternateColor", alternateColor),
  1062. `![](${url.href})`
  1063. );
  1064. }
  1065. );
  1066. })(post.content)),
  1067. post
  1068. ),
  1069. }),
  1070. beforeRequestHooks.push(async (request, options) => {
  1071. if (!hook.url.some((regex) => regex.test(request.url))) return;
  1072. let oldData;
  1073. options.body && (oldData = JSON.parse(options.body));
  1074. const newData = hook.process(oldData);
  1075. return new Request(request, { body: JSON.stringify(newData) });
  1076. });
  1077. }
  1078. }
  1079. const changeStates = ["pushState", "replaceState"];
  1080. for (const c of [AwardInfoStats, BlockUserTopic, UserPreference, MarkdownMath])
  1081. new c();
  1082. for (const f of [
  1083. function () {
  1084. emitter.emit("after-url-change", { to: window.location.pathname });
  1085. for (const changeState of changeStates)
  1086. window.History.prototype[changeState] = new Proxy(
  1087. window.History.prototype[changeState],
  1088. {
  1089. apply: (target, thisArgument, arguments_) => {
  1090. const url = arguments_[2],
  1091. from = window.location.pathname,
  1092. to = url ? String(url) : void 0;
  1093. emitter.emit("before-url-change", { from: from, to: to }),
  1094. Reflect.apply(target, thisArgument, arguments_),
  1095. setTimeout(() =>
  1096. emitter.emit("after-url-change", { from: from, to: to })
  1097. );
  1098. },
  1099. }
  1100. );
  1101. },
  1102. function () {
  1103. var hooks;
  1104. (hooks = {
  1105. beforeRequest: beforeRequestHooks,
  1106. afterResponse: afterResponseHooks,
  1107. }),
  1108. (window.fetch = new Proxy(window.fetch, {
  1109. async apply(target, thisArgument, arguments_) {
  1110. const [input, init] = arguments_;
  1111. let request = new Request(input, init);
  1112. for (const preProcess of hooks.beforeRequest) {
  1113. const temporary = await preProcess(request, init);
  1114. if (temporary instanceof Response) return temporary;
  1115. if (temporary instanceof Request) {
  1116. request = temporary;
  1117. break;
  1118. }
  1119. }
  1120. let response = await Reflect.apply(target, thisArgument, [request]);
  1121. for (const postProcess of hooks.afterResponse) {
  1122. const temporary = await postProcess(request, response.clone());
  1123. temporary instanceof Response && (response = temporary);
  1124. }
  1125. return response;
  1126. },
  1127. }));
  1128. },
  1129. ])
  1130. f();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址