修复copymanga图片错误

处理图片资源加载失败时自动重新加载

目前为 2022-10-26 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 修复copymanga图片错误
  3. // @namespace https://github.com/IronKinoko/userscripts/tree/master/packages/copymanga
  4. // @version 1.3.0
  5. // @license MIT
  6. // @description 处理图片资源加载失败时自动重新加载
  7. // @author IronKinoko
  8. // @match https://www.copymanga.org/*
  9. // @match https://www.copymanga.site/*
  10. // @icon https://www.google.com/s2/favicons?domain=www.copymanga.org
  11. // @grant none
  12. // @noframes
  13. // ==/UserScript==
  14. (function () {
  15. 'use strict';
  16.  
  17. function addErrorListener(img) {
  18. if (img.dataset.errorFix === "true")
  19. return;
  20. img.dataset.errorFix = "true";
  21. img.onerror = () => {
  22. const url = new URL(img.src);
  23. let v = parseInt(url.searchParams.get("v")) || 0;
  24. if (v > 5)
  25. return img.onerror = null;
  26. url.searchParams.set("v", ++v + "");
  27. img.src = url.toString();
  28. img.alt = "\u56FE\u7247\u52A0\u8F7D\u51FA\u9519";
  29. };
  30. }
  31.  
  32. /**
  33. * Checks if `value` is the
  34. * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
  35. * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
  36. *
  37. * @static
  38. * @memberOf _
  39. * @since 0.1.0
  40. * @category Lang
  41. * @param {*} value The value to check.
  42. * @returns {boolean} Returns `true` if `value` is an object, else `false`.
  43. * @example
  44. *
  45. * _.isObject({});
  46. * // => true
  47. *
  48. * _.isObject([1, 2, 3]);
  49. * // => true
  50. *
  51. * _.isObject(_.noop);
  52. * // => true
  53. *
  54. * _.isObject(null);
  55. * // => false
  56. */
  57. function isObject(value) {
  58. var type = typeof value;
  59. return value != null && (type == 'object' || type == 'function');
  60. }
  61.  
  62. /** Detect free variable `global` from Node.js. */
  63. var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
  64.  
  65. /** Detect free variable `self`. */
  66. var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
  67.  
  68. /** Used as a reference to the global object. */
  69. var root = freeGlobal || freeSelf || Function('return this')();
  70.  
  71. /**
  72. * Gets the timestamp of the number of milliseconds that have elapsed since
  73. * the Unix epoch (1 January 1970 00:00:00 UTC).
  74. *
  75. * @static
  76. * @memberOf _
  77. * @since 2.4.0
  78. * @category Date
  79. * @returns {number} Returns the timestamp.
  80. * @example
  81. *
  82. * _.defer(function(stamp) {
  83. * console.log(_.now() - stamp);
  84. * }, _.now());
  85. * // => Logs the number of milliseconds it took for the deferred invocation.
  86. */
  87. var now = function() {
  88. return root.Date.now();
  89. };
  90.  
  91. /** Used to match a single whitespace character. */
  92. var reWhitespace = /\s/;
  93.  
  94. /**
  95. * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
  96. * character of `string`.
  97. *
  98. * @private
  99. * @param {string} string The string to inspect.
  100. * @returns {number} Returns the index of the last non-whitespace character.
  101. */
  102. function trimmedEndIndex(string) {
  103. var index = string.length;
  104.  
  105. while (index-- && reWhitespace.test(string.charAt(index))) {}
  106. return index;
  107. }
  108.  
  109. /** Used to match leading whitespace. */
  110. var reTrimStart = /^\s+/;
  111.  
  112. /**
  113. * The base implementation of `_.trim`.
  114. *
  115. * @private
  116. * @param {string} string The string to trim.
  117. * @returns {string} Returns the trimmed string.
  118. */
  119. function baseTrim(string) {
  120. return string
  121. ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
  122. : string;
  123. }
  124.  
  125. /** Built-in value references. */
  126. var Symbol = root.Symbol;
  127.  
  128. /** Used for built-in method references. */
  129. var objectProto$1 = Object.prototype;
  130.  
  131. /** Used to check objects for own properties. */
  132. var hasOwnProperty = objectProto$1.hasOwnProperty;
  133.  
  134. /**
  135. * Used to resolve the
  136. * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
  137. * of values.
  138. */
  139. var nativeObjectToString$1 = objectProto$1.toString;
  140.  
  141. /** Built-in value references. */
  142. var symToStringTag$1 = Symbol ? Symbol.toStringTag : undefined;
  143.  
  144. /**
  145. * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
  146. *
  147. * @private
  148. * @param {*} value The value to query.
  149. * @returns {string} Returns the raw `toStringTag`.
  150. */
  151. function getRawTag(value) {
  152. var isOwn = hasOwnProperty.call(value, symToStringTag$1),
  153. tag = value[symToStringTag$1];
  154.  
  155. try {
  156. value[symToStringTag$1] = undefined;
  157. var unmasked = true;
  158. } catch (e) {}
  159.  
  160. var result = nativeObjectToString$1.call(value);
  161. if (unmasked) {
  162. if (isOwn) {
  163. value[symToStringTag$1] = tag;
  164. } else {
  165. delete value[symToStringTag$1];
  166. }
  167. }
  168. return result;
  169. }
  170.  
  171. /** Used for built-in method references. */
  172. var objectProto = Object.prototype;
  173.  
  174. /**
  175. * Used to resolve the
  176. * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
  177. * of values.
  178. */
  179. var nativeObjectToString = objectProto.toString;
  180.  
  181. /**
  182. * Converts `value` to a string using `Object.prototype.toString`.
  183. *
  184. * @private
  185. * @param {*} value The value to convert.
  186. * @returns {string} Returns the converted string.
  187. */
  188. function objectToString(value) {
  189. return nativeObjectToString.call(value);
  190. }
  191.  
  192. /** `Object#toString` result references. */
  193. var nullTag = '[object Null]',
  194. undefinedTag = '[object Undefined]';
  195.  
  196. /** Built-in value references. */
  197. var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
  198.  
  199. /**
  200. * The base implementation of `getTag` without fallbacks for buggy environments.
  201. *
  202. * @private
  203. * @param {*} value The value to query.
  204. * @returns {string} Returns the `toStringTag`.
  205. */
  206. function baseGetTag(value) {
  207. if (value == null) {
  208. return value === undefined ? undefinedTag : nullTag;
  209. }
  210. return (symToStringTag && symToStringTag in Object(value))
  211. ? getRawTag(value)
  212. : objectToString(value);
  213. }
  214.  
  215. /**
  216. * Checks if `value` is object-like. A value is object-like if it's not `null`
  217. * and has a `typeof` result of "object".
  218. *
  219. * @static
  220. * @memberOf _
  221. * @since 4.0.0
  222. * @category Lang
  223. * @param {*} value The value to check.
  224. * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
  225. * @example
  226. *
  227. * _.isObjectLike({});
  228. * // => true
  229. *
  230. * _.isObjectLike([1, 2, 3]);
  231. * // => true
  232. *
  233. * _.isObjectLike(_.noop);
  234. * // => false
  235. *
  236. * _.isObjectLike(null);
  237. * // => false
  238. */
  239. function isObjectLike(value) {
  240. return value != null && typeof value == 'object';
  241. }
  242.  
  243. /** `Object#toString` result references. */
  244. var symbolTag = '[object Symbol]';
  245.  
  246. /**
  247. * Checks if `value` is classified as a `Symbol` primitive or object.
  248. *
  249. * @static
  250. * @memberOf _
  251. * @since 4.0.0
  252. * @category Lang
  253. * @param {*} value The value to check.
  254. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
  255. * @example
  256. *
  257. * _.isSymbol(Symbol.iterator);
  258. * // => true
  259. *
  260. * _.isSymbol('abc');
  261. * // => false
  262. */
  263. function isSymbol(value) {
  264. return typeof value == 'symbol' ||
  265. (isObjectLike(value) && baseGetTag(value) == symbolTag);
  266. }
  267.  
  268. /** Used as references for various `Number` constants. */
  269. var NAN = 0 / 0;
  270.  
  271. /** Used to detect bad signed hexadecimal string values. */
  272. var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
  273.  
  274. /** Used to detect binary string values. */
  275. var reIsBinary = /^0b[01]+$/i;
  276.  
  277. /** Used to detect octal string values. */
  278. var reIsOctal = /^0o[0-7]+$/i;
  279.  
  280. /** Built-in method references without a dependency on `root`. */
  281. var freeParseInt = parseInt;
  282.  
  283. /**
  284. * Converts `value` to a number.
  285. *
  286. * @static
  287. * @memberOf _
  288. * @since 4.0.0
  289. * @category Lang
  290. * @param {*} value The value to process.
  291. * @returns {number} Returns the number.
  292. * @example
  293. *
  294. * _.toNumber(3.2);
  295. * // => 3.2
  296. *
  297. * _.toNumber(Number.MIN_VALUE);
  298. * // => 5e-324
  299. *
  300. * _.toNumber(Infinity);
  301. * // => Infinity
  302. *
  303. * _.toNumber('3.2');
  304. * // => 3.2
  305. */
  306. function toNumber(value) {
  307. if (typeof value == 'number') {
  308. return value;
  309. }
  310. if (isSymbol(value)) {
  311. return NAN;
  312. }
  313. if (isObject(value)) {
  314. var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
  315. value = isObject(other) ? (other + '') : other;
  316. }
  317. if (typeof value != 'string') {
  318. return value === 0 ? value : +value;
  319. }
  320. value = baseTrim(value);
  321. var isBinary = reIsBinary.test(value);
  322. return (isBinary || reIsOctal.test(value))
  323. ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
  324. : (reIsBadHex.test(value) ? NAN : +value);
  325. }
  326.  
  327. /** Error message constants. */
  328. var FUNC_ERROR_TEXT$1 = 'Expected a function';
  329.  
  330. /* Built-in method references for those with the same name as other `lodash` methods. */
  331. var nativeMax = Math.max,
  332. nativeMin = Math.min;
  333.  
  334. /**
  335. * Creates a debounced function that delays invoking `func` until after `wait`
  336. * milliseconds have elapsed since the last time the debounced function was
  337. * invoked. The debounced function comes with a `cancel` method to cancel
  338. * delayed `func` invocations and a `flush` method to immediately invoke them.
  339. * Provide `options` to indicate whether `func` should be invoked on the
  340. * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
  341. * with the last arguments provided to the debounced function. Subsequent
  342. * calls to the debounced function return the result of the last `func`
  343. * invocation.
  344. *
  345. * **Note:** If `leading` and `trailing` options are `true`, `func` is
  346. * invoked on the trailing edge of the timeout only if the debounced function
  347. * is invoked more than once during the `wait` timeout.
  348. *
  349. * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
  350. * until to the next tick, similar to `setTimeout` with a timeout of `0`.
  351. *
  352. * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
  353. * for details over the differences between `_.debounce` and `_.throttle`.
  354. *
  355. * @static
  356. * @memberOf _
  357. * @since 0.1.0
  358. * @category Function
  359. * @param {Function} func The function to debounce.
  360. * @param {number} [wait=0] The number of milliseconds to delay.
  361. * @param {Object} [options={}] The options object.
  362. * @param {boolean} [options.leading=false]
  363. * Specify invoking on the leading edge of the timeout.
  364. * @param {number} [options.maxWait]
  365. * The maximum time `func` is allowed to be delayed before it's invoked.
  366. * @param {boolean} [options.trailing=true]
  367. * Specify invoking on the trailing edge of the timeout.
  368. * @returns {Function} Returns the new debounced function.
  369. * @example
  370. *
  371. * // Avoid costly calculations while the window size is in flux.
  372. * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
  373. *
  374. * // Invoke `sendMail` when clicked, debouncing subsequent calls.
  375. * jQuery(element).on('click', _.debounce(sendMail, 300, {
  376. * 'leading': true,
  377. * 'trailing': false
  378. * }));
  379. *
  380. * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
  381. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
  382. * var source = new EventSource('/stream');
  383. * jQuery(source).on('message', debounced);
  384. *
  385. * // Cancel the trailing debounced invocation.
  386. * jQuery(window).on('popstate', debounced.cancel);
  387. */
  388. function debounce(func, wait, options) {
  389. var lastArgs,
  390. lastThis,
  391. maxWait,
  392. result,
  393. timerId,
  394. lastCallTime,
  395. lastInvokeTime = 0,
  396. leading = false,
  397. maxing = false,
  398. trailing = true;
  399.  
  400. if (typeof func != 'function') {
  401. throw new TypeError(FUNC_ERROR_TEXT$1);
  402. }
  403. wait = toNumber(wait) || 0;
  404. if (isObject(options)) {
  405. leading = !!options.leading;
  406. maxing = 'maxWait' in options;
  407. maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
  408. trailing = 'trailing' in options ? !!options.trailing : trailing;
  409. }
  410.  
  411. function invokeFunc(time) {
  412. var args = lastArgs,
  413. thisArg = lastThis;
  414.  
  415. lastArgs = lastThis = undefined;
  416. lastInvokeTime = time;
  417. result = func.apply(thisArg, args);
  418. return result;
  419. }
  420.  
  421. function leadingEdge(time) {
  422. // Reset any `maxWait` timer.
  423. lastInvokeTime = time;
  424. // Start the timer for the trailing edge.
  425. timerId = setTimeout(timerExpired, wait);
  426. // Invoke the leading edge.
  427. return leading ? invokeFunc(time) : result;
  428. }
  429.  
  430. function remainingWait(time) {
  431. var timeSinceLastCall = time - lastCallTime,
  432. timeSinceLastInvoke = time - lastInvokeTime,
  433. timeWaiting = wait - timeSinceLastCall;
  434.  
  435. return maxing
  436. ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
  437. : timeWaiting;
  438. }
  439.  
  440. function shouldInvoke(time) {
  441. var timeSinceLastCall = time - lastCallTime,
  442. timeSinceLastInvoke = time - lastInvokeTime;
  443.  
  444. // Either this is the first call, activity has stopped and we're at the
  445. // trailing edge, the system time has gone backwards and we're treating
  446. // it as the trailing edge, or we've hit the `maxWait` limit.
  447. return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
  448. (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
  449. }
  450.  
  451. function timerExpired() {
  452. var time = now();
  453. if (shouldInvoke(time)) {
  454. return trailingEdge(time);
  455. }
  456. // Restart the timer.
  457. timerId = setTimeout(timerExpired, remainingWait(time));
  458. }
  459.  
  460. function trailingEdge(time) {
  461. timerId = undefined;
  462.  
  463. // Only invoke if we have `lastArgs` which means `func` has been
  464. // debounced at least once.
  465. if (trailing && lastArgs) {
  466. return invokeFunc(time);
  467. }
  468. lastArgs = lastThis = undefined;
  469. return result;
  470. }
  471.  
  472. function cancel() {
  473. if (timerId !== undefined) {
  474. clearTimeout(timerId);
  475. }
  476. lastInvokeTime = 0;
  477. lastArgs = lastCallTime = lastThis = timerId = undefined;
  478. }
  479.  
  480. function flush() {
  481. return timerId === undefined ? result : trailingEdge(now());
  482. }
  483.  
  484. function debounced() {
  485. var time = now(),
  486. isInvoking = shouldInvoke(time);
  487.  
  488. lastArgs = arguments;
  489. lastThis = this;
  490. lastCallTime = time;
  491.  
  492. if (isInvoking) {
  493. if (timerId === undefined) {
  494. return leadingEdge(lastCallTime);
  495. }
  496. if (maxing) {
  497. // Handle invocations in a tight loop.
  498. clearTimeout(timerId);
  499. timerId = setTimeout(timerExpired, wait);
  500. return invokeFunc(lastCallTime);
  501. }
  502. }
  503. if (timerId === undefined) {
  504. timerId = setTimeout(timerExpired, wait);
  505. }
  506. return result;
  507. }
  508. debounced.cancel = cancel;
  509. debounced.flush = flush;
  510. return debounced;
  511. }
  512.  
  513. /** Error message constants. */
  514. var FUNC_ERROR_TEXT = 'Expected a function';
  515.  
  516. /**
  517. * Creates a throttled function that only invokes `func` at most once per
  518. * every `wait` milliseconds. The throttled function comes with a `cancel`
  519. * method to cancel delayed `func` invocations and a `flush` method to
  520. * immediately invoke them. Provide `options` to indicate whether `func`
  521. * should be invoked on the leading and/or trailing edge of the `wait`
  522. * timeout. The `func` is invoked with the last arguments provided to the
  523. * throttled function. Subsequent calls to the throttled function return the
  524. * result of the last `func` invocation.
  525. *
  526. * **Note:** If `leading` and `trailing` options are `true`, `func` is
  527. * invoked on the trailing edge of the timeout only if the throttled function
  528. * is invoked more than once during the `wait` timeout.
  529. *
  530. * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
  531. * until to the next tick, similar to `setTimeout` with a timeout of `0`.
  532. *
  533. * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
  534. * for details over the differences between `_.throttle` and `_.debounce`.
  535. *
  536. * @static
  537. * @memberOf _
  538. * @since 0.1.0
  539. * @category Function
  540. * @param {Function} func The function to throttle.
  541. * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
  542. * @param {Object} [options={}] The options object.
  543. * @param {boolean} [options.leading=true]
  544. * Specify invoking on the leading edge of the timeout.
  545. * @param {boolean} [options.trailing=true]
  546. * Specify invoking on the trailing edge of the timeout.
  547. * @returns {Function} Returns the new throttled function.
  548. * @example
  549. *
  550. * // Avoid excessively updating the position while scrolling.
  551. * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
  552. *
  553. * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
  554. * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
  555. * jQuery(element).on('click', throttled);
  556. *
  557. * // Cancel the trailing throttled invocation.
  558. * jQuery(window).on('popstate', throttled.cancel);
  559. */
  560. function throttle(func, wait, options) {
  561. var leading = true,
  562. trailing = true;
  563.  
  564. if (typeof func != 'function') {
  565. throw new TypeError(FUNC_ERROR_TEXT);
  566. }
  567. if (isObject(options)) {
  568. leading = 'leading' in options ? !!options.leading : leading;
  569. trailing = 'trailing' in options ? !!options.trailing : trailing;
  570. }
  571. return debounce(func, wait, {
  572. 'leading': leading,
  573. 'maxWait': wait,
  574. 'trailing': trailing
  575. });
  576. }
  577.  
  578. function sleep(time) {
  579. return new Promise((resolve) => {
  580. setTimeout(resolve, time);
  581. });
  582. }
  583.  
  584. async function wait(selector) {
  585. let bool = selector();
  586. while (!bool) {
  587. await sleep();
  588. bool = selector();
  589. }
  590. }
  591.  
  592. function normalizeKeyEvent(e) {
  593. const SPECIAL_KEY_EN = "`-=[]\\;',./~!@#$%^&*()_+{}|:\"<>?".split("");
  594. const SPECIAL_KEY_ZH = "\xB7-=\u3010\u3011\u3001\uFF1B\u2018\uFF0C\u3002/\uFF5E\uFF01@#\xA5%\u2026&*\uFF08\uFF09\u2014+\u300C\u300D\uFF5C\uFF1A\u201C\u300A\u300B\uFF1F".split("");
  595. let key = e.key;
  596. if (e.code === "Space") {
  597. key = "Space";
  598. }
  599. if (/^[a-z]$/.test(key)) {
  600. key = key.toUpperCase();
  601. } else if (SPECIAL_KEY_ZH.includes(key)) {
  602. key = SPECIAL_KEY_EN[SPECIAL_KEY_ZH.indexOf(key)];
  603. }
  604. let keyArr = [];
  605. e.ctrlKey && keyArr.push("ctrl");
  606. e.metaKey && keyArr.push("meta");
  607. e.shiftKey && !SPECIAL_KEY_EN.includes(key) && keyArr.push("shift");
  608. e.altKey && keyArr.push("alt");
  609. if (!/Control|Meta|Shift|Alt/i.test(key))
  610. keyArr.push(key);
  611. keyArr = [...new Set(keyArr)];
  612. return keyArr.join("+");
  613. }
  614. function keybind(keys, keydown, keyup) {
  615. const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
  616. keys = keys.filter((key) => !key.includes(isMac ? "ctrl" : "meta"));
  617. function createProcess(callback) {
  618. return function(e) {
  619. var _a;
  620. if (((_a = document.activeElement) == null ? void 0 : _a.tagName) === "INPUT")
  621. return;
  622. const normalizedKey = normalizeKeyEvent(e).toLowerCase();
  623. for (const key of keys) {
  624. if (key.toLowerCase() === normalizedKey)
  625. callback(e, key);
  626. }
  627. };
  628. }
  629. window.addEventListener("keydown", createProcess(keydown));
  630. if (keyup)
  631. window.addEventListener("keyup", createProcess(keyup));
  632. }
  633.  
  634. function s2d(string) {
  635. return new DOMParser().parseFromString(string, "text/html").body.childNodes;
  636. }
  637. async function waitDOM(selector) {
  638. await wait(() => !!document.querySelector(selector));
  639. return document.querySelector(selector);
  640. }
  641.  
  642. async function openControl() {
  643. const li = await waitDOM("li.comicContentPopupImageItem");
  644. li.dispatchEvent(fakeClickEvent());
  645. await sleep(0);
  646. li.dispatchEvent(fakeClickEvent());
  647. }
  648. function fakeClickEvent() {
  649. const { width, height } = document.body.getBoundingClientRect();
  650. return new MouseEvent("click", { clientX: width / 2, clientY: height / 2 });
  651. }
  652. async function currentPage() {
  653. try {
  654. if (!/h5\/comicContent\/.*/.test(location.href))
  655. return;
  656. const scrollHeight = document.scrollingElement.scrollTop;
  657. const list = await waitHasComicContent();
  658. let height = 0;
  659. for (let i = 0; i < list.length; i++) {
  660. const item = list[i];
  661. height += item.getBoundingClientRect().height;
  662. if (height > scrollHeight) {
  663. const dom = document.querySelector(".comicContentPopup .comicFixed");
  664. dom.textContent = dom.textContent.replace(/(.*)\//, `${i + 1}/`);
  665. break;
  666. }
  667. }
  668. } catch (e) {
  669. }
  670. }
  671. let trackId = { current: 0 };
  672. async function runH5main() {
  673. try {
  674. if (!/h5\/comicContent\/.*/.test(location.href))
  675. return;
  676. let runTrackId = ++trackId.current;
  677. const ulDom = await waitDOM(".comicContentPopupImageList");
  678. if (runTrackId !== trackId.current)
  679. return;
  680. const uuid = getComicId();
  681. const domUUID = ulDom.dataset.uuid;
  682. if (domUUID !== uuid) {
  683. ulDom.dataset.uuid = uuid;
  684. }
  685. injectFixImg$1();
  686. injectFastLoadImg$1();
  687. const main = ulDom.parentElement;
  688. main.style.position = "unset";
  689. main.style.overflowY = "unset";
  690. createNextPartDom();
  691. } catch (error) {
  692. throw error;
  693. }
  694. }
  695. async function createNextPartDom() {
  696. let nextPartDom = document.querySelector("#comicContentMain .next-part-btn");
  697. let nextButton = document.querySelector(".comicControlBottomTop > div:nth-child(3) > span");
  698. if (!nextPartDom) {
  699. if (!nextButton) {
  700. await openControl();
  701. nextButton = document.querySelector(".comicControlBottomTop > div:nth-child(3) > span");
  702. }
  703. nextPartDom = document.createElement("div");
  704. nextPartDom.className = "next-part-btn";
  705. nextPartDom.textContent = "\u4E0B\u4E00\u8BDD";
  706. nextPartDom.onclick = async (e) => {
  707. e.stopPropagation();
  708. nextButton && nextButton.click();
  709. document.scrollingElement.scrollTop = 0;
  710. };
  711. document.getElementById("comicContentMain").appendChild(nextPartDom);
  712. }
  713. nextPartDom.style.display = nextButton.parentElement.classList.contains("noneUuid") ? "none" : "block";
  714. let fixedNextBtn = document.querySelector(".next-part-btn-fixed");
  715. if (!fixedNextBtn) {
  716. fixedNextBtn = document.createElement("div");
  717. fixedNextBtn.className = "next-part-btn-fixed";
  718. fixedNextBtn.textContent = "\u4E0B\u4E00\u8BDD";
  719. document.body.appendChild(fixedNextBtn);
  720. window.addEventListener("scroll", throttle(() => {
  721. if (!/h5\/comicContent\/.*/.test(location.href)) {
  722. fixedNextBtn == null ? void 0 : fixedNextBtn.classList.add("hide");
  723. return;
  724. }
  725. const dom = document.scrollingElement;
  726. if (dom.scrollTop < 50 || dom.scrollTop + dom.clientHeight > dom.scrollHeight - 800) {
  727. fixedNextBtn == null ? void 0 : fixedNextBtn.classList.remove("hide");
  728. } else {
  729. fixedNextBtn == null ? void 0 : fixedNextBtn.classList.add("hide");
  730. }
  731. }, 100));
  732. }
  733. fixedNextBtn.onclick = nextPartDom.onclick;
  734. fixedNextBtn.style.display = nextPartDom.style.display;
  735. }
  736. function getComicId() {
  737. const [, uuid] = location.href.match(/h5\/comicContent\/.*\/(.*)/);
  738. return uuid;
  739. }
  740. async function waitHasComicContent() {
  741. return document.querySelectorAll(".comicContentPopupImageItem");
  742. }
  743. async function addH5HistoryListener() {
  744. history.pushState = _historyWrap("pushState");
  745. history.replaceState = _historyWrap("replaceState");
  746. window.addEventListener("pushState", runH5main);
  747. window.addEventListener("replaceState", runH5main);
  748. window.addEventListener("popstate", runH5main);
  749. window.addEventListener("scroll", throttle(currentPage, 100));
  750. runH5main();
  751. }
  752. const _historyWrap = function(type) {
  753. const orig = history[type];
  754. const e = new Event(type);
  755. return function() {
  756. const rv = orig.apply(this, arguments);
  757. window.dispatchEvent(e);
  758. return rv;
  759. };
  760. };
  761. async function injectFixImg$1() {
  762. const listDOM = await waitDOM(".comicContentPopupImageList");
  763. async function injectEvent() {
  764. const imgs = document.querySelectorAll("ul li img");
  765. imgs.forEach(addErrorListener);
  766. }
  767. const ob = new MutationObserver(injectEvent);
  768. ob.observe(listDOM, { childList: true, subtree: true });
  769. injectEvent();
  770. }
  771. async function injectFastLoadImg$1() {
  772. const $list = await waitDOM(".comicContentPopupImageList");
  773. function fastLoad() {
  774. const $imgs = document.querySelectorAll("ul li img");
  775. $imgs.forEach(($img) => {
  776. if ($img.dataset.fastLoad === $img.dataset.src)
  777. return;
  778. $img.dataset.fastLoad = $img.dataset.src;
  779. $img.src = $img.dataset.src;
  780. });
  781. }
  782. const ob = new MutationObserver(fastLoad);
  783. ob.observe($list, {
  784. childList: true,
  785. subtree: true,
  786. attributes: true,
  787. attributeFilter: ["data-src"]
  788. });
  789. }
  790. function h5() {
  791. addH5HistoryListener();
  792. }
  793.  
  794. function replaceHeader() {
  795. const header = document.querySelector(".container.header-log .row");
  796. if (header) {
  797. header.style.flexWrap = "nowrap";
  798. header.querySelector("div:nth-child(6)").replaceWith(...s2d(`<div class="col-1">
  799. <div class="log-txt">
  800. <a href="/web/person/shujia">\u6211\u7684\u4E66\u67B6</a>
  801. <div class="log-unboder"></div>
  802. </div>
  803. </div>`));
  804. header.querySelector("div:nth-child(7)").replaceWith(...s2d(`<div class="col-1">
  805. <div class="log-txt">
  806. <a href="/web/person/liulan">\u6211\u7684\u6D4F\u89C8</a>
  807. <div class="log-unboder"></div>
  808. </div>
  809. </div>`));
  810. header.querySelector("div:nth-child(8)").className = "col";
  811. header.querySelector("div.col > div > div").style.justifyContent = "flex-end";
  812. }
  813. }
  814. async function injectFixImg() {
  815. const listDOM = await waitDOM("ul.comicContent-list");
  816. async function injectEvent2() {
  817. const imgs = document.querySelectorAll("ul li img");
  818. imgs.forEach(addErrorListener);
  819. }
  820. const ob = new MutationObserver(injectEvent2);
  821. ob.observe(listDOM, { childList: true, subtree: true });
  822. injectEvent2();
  823. }
  824. async function injectFastLoadImg() {
  825. const $list = await waitDOM(".comicContent-list");
  826. function fastLoad() {
  827. const $imgs = $list.querySelectorAll("li img");
  828. $imgs.forEach(($img) => {
  829. if ($img.dataset.fastLoad === "true")
  830. return;
  831. $img.dataset.fastLoad = "true";
  832. $img.src = $img.dataset.src;
  833. });
  834. }
  835. const ob = new MutationObserver(fastLoad);
  836. ob.observe($list, { childList: true, subtree: true });
  837. }
  838. async function removeMouseupEvent() {
  839. await wait(() => !!document.body.onmouseup);
  840. document.body.onmouseup = null;
  841. }
  842. async function injectEvent() {
  843. keybind(["z", "x"], (e, key) => {
  844. var _a, _b;
  845. switch (key) {
  846. case "z": {
  847. (_a = document.querySelector(`[class='comicContent-prev'] a`)) == null ? void 0 : _a.click();
  848. break;
  849. }
  850. case "x": {
  851. (_b = document.querySelector(`[class='comicContent-next'] a`)) == null ? void 0 : _b.click();
  852. break;
  853. }
  854. }
  855. });
  856. }
  857. function pc() {
  858. if (/comic\/.*\/chapter/.test(location.href)) {
  859. injectFixImg();
  860. injectFastLoadImg();
  861. removeMouseupEvent();
  862. injectEvent();
  863. }
  864. replaceHeader();
  865. }
  866.  
  867. var e=[],t=[];function n(n,r){if(n&&"undefined"!=typeof document){var a,s=!0===r.prepend?"prepend":"append",d=!0===r.singleTag,i="string"==typeof r.container?document.querySelector(r.container):document.getElementsByTagName("head")[0];if(d){var u=e.indexOf(i);-1===u&&(u=e.push(i)-1,t[u]={}),a=t[u]&&t[u][s]?t[u][s]:t[u][s]=c();}else a=c();65279===n.charCodeAt(0)&&(n=n.substring(1)),a.styleSheet?a.styleSheet.cssText+=n:a.appendChild(document.createTextNode(n));}function c(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),r.attributes)for(var t=Object.keys(r.attributes),n=0;n<t.length;n++)e.setAttribute(t[n],r.attributes[t[n]]);var a="prepend"===s?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}}
  868.  
  869. var css = ".k-copymanga .next-part-btn {\n height: 150px;\n line-height: 50px;\n text-align: center;\n font-size: 16px;\n}\n.k-copymanga .next-part-btn-fixed {\n position: fixed;\n right: 0;\n top: 25vh;\n font-size: 16px;\n background: white;\n padding: 8px;\n writing-mode: vertical-lr;\n box-shadow: rgba(0, 0, 0, 0.2) -1px 1px 10px 0px;\n transition: all 0.2s ease;\n transform: translateX(0);\n border-radius: 4px 0 0 4px;\n opacity: 1;\n}\n.k-copymanga .next-part-btn-fixed.hide {\n opacity: 0;\n pointer-events: none;\n transform: translateX(100%);\n}";
  870. n(css,{});
  871.  
  872. document.body.classList.add("k-copymanga");
  873. if (location.pathname.startsWith("/h5")) {
  874. h5();
  875. } else {
  876. pc();
  877. }
  878.  
  879. })();

QingJ © 2025

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