// ==UserScript==
// @name 修复copymanga图片错误
// @namespace https://github.com/IronKinoko/userscripts/tree/master/packages/copymanga
// @version 1.3.0
// @license MIT
// @description 处理图片资源加载失败时自动重新加载
// @author IronKinoko
// @match https://www.copymanga.org/*
// @match https://www.copymanga.site/*
// @icon https://www.google.com/s2/favicons?domain=www.copymanga.org
// @grant none
// @noframes
// ==/UserScript==
(function () {
'use strict';
function s2d(string) {
return new DOMParser().parseFromString(string, "text/html").body.firstChild;
}
function addErrorListener(img) {
if (img.dataset.errorFix === "true")
return;
img.dataset.errorFix = "true";
img.onerror = () => {
const url = new URL(img.src);
let v = parseInt(url.searchParams.get("v")) || 0;
if (v > 5)
return img.onerror = null;
url.searchParams.set("v", ++v + "");
img.src = url.toString();
img.alt = "\u56FE\u7247\u52A0\u8F7D\u51FA\u9519";
};
}
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject(value) {
var type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/**
* Gets the timestamp of the number of milliseconds that have elapsed since
* the Unix epoch (1 January 1970 00:00:00 UTC).
*
* @static
* @memberOf _
* @since 2.4.0
* @category Date
* @returns {number} Returns the timestamp.
* @example
*
* _.defer(function(stamp) {
* console.log(_.now() - stamp);
* }, _.now());
* // => Logs the number of milliseconds it took for the deferred invocation.
*/
var now = function() {
return root.Date.now();
};
/** Used to match a single whitespace character. */
var reWhitespace = /\s/;
/**
* Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
* character of `string`.
*
* @private
* @param {string} string The string to inspect.
* @returns {number} Returns the index of the last non-whitespace character.
*/
function trimmedEndIndex(string) {
var index = string.length;
while (index-- && reWhitespace.test(string.charAt(index))) {}
return index;
}
/** Used to match leading whitespace. */
var reTrimStart = /^\s+/;
/**
* The base implementation of `_.trim`.
*
* @private
* @param {string} string The string to trim.
* @returns {string} Returns the trimmed string.
*/
function baseTrim(string) {
return string
? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
: string;
}
/** Built-in value references. */
var Symbol = root.Symbol;
/** Used for built-in method references. */
var objectProto$1 = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto$1.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString$1 = objectProto$1.toString;
/** Built-in value references. */
var symToStringTag$1 = Symbol ? Symbol.toStringTag : undefined;
/**
* A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the raw `toStringTag`.
*/
function getRawTag(value) {
var isOwn = hasOwnProperty.call(value, symToStringTag$1),
tag = value[symToStringTag$1];
try {
value[symToStringTag$1] = undefined;
var unmasked = true;
} catch (e) {}
var result = nativeObjectToString$1.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag$1] = tag;
} else {
delete value[symToStringTag$1];
}
}
return result;
}
/** Used for built-in method references. */
var objectProto = Object.prototype;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString = objectProto.toString;
/**
* Converts `value` to a string using `Object.prototype.toString`.
*
* @private
* @param {*} value The value to convert.
* @returns {string} Returns the converted string.
*/
function objectToString(value) {
return nativeObjectToString.call(value);
}
/** `Object#toString` result references. */
var nullTag = '[object Null]',
undefinedTag = '[object Undefined]';
/** Built-in value references. */
var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
/**
* The base implementation of `getTag` without fallbacks for buggy environments.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function baseGetTag(value) {
if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
return (symToStringTag && symToStringTag in Object(value))
? getRawTag(value)
: objectToString(value);
}
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return value != null && typeof value == 'object';
}
/** `Object#toString` result references. */
var symbolTag = '[object Symbol]';
/**
* Checks if `value` is classified as a `Symbol` primitive or object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
* @example
*
* _.isSymbol(Symbol.iterator);
* // => true
*
* _.isSymbol('abc');
* // => false
*/
function isSymbol(value) {
return typeof value == 'symbol' ||
(isObjectLike(value) && baseGetTag(value) == symbolTag);
}
/** Used as references for various `Number` constants. */
var NAN = 0 / 0;
/** Used to detect bad signed hexadecimal string values. */
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
/** Used to detect binary string values. */
var reIsBinary = /^0b[01]+$/i;
/** Used to detect octal string values. */
var reIsOctal = /^0o[0-7]+$/i;
/** Built-in method references without a dependency on `root`. */
var freeParseInt = parseInt;
/**
* Converts `value` to a number.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to process.
* @returns {number} Returns the number.
* @example
*
* _.toNumber(3.2);
* // => 3.2
*
* _.toNumber(Number.MIN_VALUE);
* // => 5e-324
*
* _.toNumber(Infinity);
* // => Infinity
*
* _.toNumber('3.2');
* // => 3.2
*/
function toNumber(value) {
if (typeof value == 'number') {
return value;
}
if (isSymbol(value)) {
return NAN;
}
if (isObject(value)) {
var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
value = isObject(other) ? (other + '') : other;
}
if (typeof value != 'string') {
return value === 0 ? value : +value;
}
value = baseTrim(value);
var isBinary = reIsBinary.test(value);
return (isBinary || reIsOctal.test(value))
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
: (reIsBadHex.test(value) ? NAN : +value);
}
/** Error message constants. */
var FUNC_ERROR_TEXT$1 = 'Expected a function';
/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeMax = Math.max,
nativeMin = Math.min;
/**
* Creates a debounced function that delays invoking `func` until after `wait`
* milliseconds have elapsed since the last time the debounced function was
* invoked. The debounced function comes with a `cancel` method to cancel
* delayed `func` invocations and a `flush` method to immediately invoke them.
* Provide `options` to indicate whether `func` should be invoked on the
* leading and/or trailing edge of the `wait` timeout. The `func` is invoked
* with the last arguments provided to the debounced function. Subsequent
* calls to the debounced function return the result of the last `func`
* invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the debounced function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.debounce` and `_.throttle`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to debounce.
* @param {number} [wait=0] The number of milliseconds to delay.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.leading=false]
* Specify invoking on the leading edge of the timeout.
* @param {number} [options.maxWait]
* The maximum time `func` is allowed to be delayed before it's invoked.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.
* @example
*
* // Avoid costly calculations while the window size is in flux.
* jQuery(window).on('resize', _.debounce(calculateLayout, 150));
*
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
* jQuery(element).on('click', _.debounce(sendMail, 300, {
* 'leading': true,
* 'trailing': false
* }));
*
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
* var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
* var source = new EventSource('/stream');
* jQuery(source).on('message', debounced);
*
* // Cancel the trailing debounced invocation.
* jQuery(window).on('popstate', debounced.cancel);
*/
function debounce(func, wait, options) {
var lastArgs,
lastThis,
maxWait,
result,
timerId,
lastCallTime,
lastInvokeTime = 0,
leading = false,
maxing = false,
trailing = true;
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT$1);
}
wait = toNumber(wait) || 0;
if (isObject(options)) {
leading = !!options.leading;
maxing = 'maxWait' in options;
maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
trailing = 'trailing' in options ? !!options.trailing : trailing;
}
function invokeFunc(time) {
var args = lastArgs,
thisArg = lastThis;
lastArgs = lastThis = undefined;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
// Reset any `maxWait` timer.
lastInvokeTime = time;
// Start the timer for the trailing edge.
timerId = setTimeout(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
var timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime,
timeWaiting = wait - timeSinceLastCall;
return maxing
? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
: timeWaiting;
}
function shouldInvoke(time) {
var timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
}
function timerExpired() {
var time = now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// Restart the timer.
timerId = setTimeout(timerExpired, remainingWait(time));
}
function trailingEdge(time) {
timerId = undefined;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = lastThis = undefined;
return result;
}
function cancel() {
if (timerId !== undefined) {
clearTimeout(timerId);
}
lastInvokeTime = 0;
lastArgs = lastCallTime = lastThis = timerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(now());
}
function debounced() {
var time = now(),
isInvoking = shouldInvoke(time);
lastArgs = arguments;
lastThis = this;
lastCallTime = time;
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime);
}
if (maxing) {
// Handle invocations in a tight loop.
clearTimeout(timerId);
timerId = setTimeout(timerExpired, wait);
return invokeFunc(lastCallTime);
}
}
if (timerId === undefined) {
timerId = setTimeout(timerExpired, wait);
}
return result;
}
debounced.cancel = cancel;
debounced.flush = flush;
return debounced;
}
/** Error message constants. */
var FUNC_ERROR_TEXT = 'Expected a function';
/**
* Creates a throttled function that only invokes `func` at most once per
* every `wait` milliseconds. The throttled function comes with a `cancel`
* method to cancel delayed `func` invocations and a `flush` method to
* immediately invoke them. Provide `options` to indicate whether `func`
* should be invoked on the leading and/or trailing edge of the `wait`
* timeout. The `func` is invoked with the last arguments provided to the
* throttled function. Subsequent calls to the throttled function return the
* result of the last `func` invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the throttled function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.throttle` and `_.debounce`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to throttle.
* @param {number} [wait=0] The number of milliseconds to throttle invocations to.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.leading=true]
* Specify invoking on the leading edge of the timeout.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new throttled function.
* @example
*
* // Avoid excessively updating the position while scrolling.
* jQuery(window).on('scroll', _.throttle(updatePosition, 100));
*
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
* var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
* jQuery(element).on('click', throttled);
*
* // Cancel the trailing throttled invocation.
* jQuery(window).on('popstate', throttled.cancel);
*/
function throttle(func, wait, options) {
var leading = true,
trailing = true;
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
if (isObject(options)) {
leading = 'leading' in options ? !!options.leading : leading;
trailing = 'trailing' in options ? !!options.trailing : trailing;
}
return debounce(func, wait, {
'leading': leading,
'maxWait': wait,
'trailing': trailing
});
}
function sleep(time) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
async function wait(selector) {
let bool = selector();
while (!bool) {
await sleep();
bool = selector();
}
}
async function waitDOM(selector) {
await wait(() => !!document.querySelector(selector));
return document.querySelector(selector);
}
function normalizeKeyEvent(e) {
const SPECIAL_KEY_EN = "`-=[]\\;',./~!@#$%^&*()_+{}|:\"<>?".split("");
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("");
let key = e.key;
if (e.code === "Space") {
key = "Space";
}
if (/^[a-z]$/.test(key)) {
key = key.toUpperCase();
} else if (SPECIAL_KEY_ZH.includes(key)) {
key = SPECIAL_KEY_EN[SPECIAL_KEY_ZH.indexOf(key)];
}
let keyArr = [];
e.ctrlKey && keyArr.push("ctrl");
e.metaKey && keyArr.push("meta");
e.shiftKey && !SPECIAL_KEY_EN.includes(key) && keyArr.push("shift");
e.altKey && keyArr.push("alt");
if (!/Control|Meta|Shift|Alt/i.test(key))
keyArr.push(key);
keyArr = [...new Set(keyArr)];
return keyArr.join("+");
}
function keybind(keys, keydown, keyup) {
const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
keys = keys.filter((key) => !key.includes(isMac ? "ctrl" : "meta"));
function createProcess(callback) {
return function(e) {
var _a;
if (((_a = document.activeElement) == null ? void 0 : _a.tagName) === "INPUT")
return;
const normalizedKey = normalizeKeyEvent(e).toLowerCase();
for (const key of keys) {
if (key.toLowerCase() === normalizedKey)
callback(e, key);
}
};
}
window.addEventListener("keydown", createProcess(keydown));
if (keyup)
window.addEventListener("keyup", createProcess(keyup));
}
async function openControl() {
const li = await waitDOM("li.comicContentPopupImageItem");
li.dispatchEvent(fakeClickEvent());
await sleep(0);
li.dispatchEvent(fakeClickEvent());
}
function fakeClickEvent() {
const { width, height } = document.body.getBoundingClientRect();
return new MouseEvent("click", { clientX: width / 2, clientY: height / 2 });
}
async function currentPage() {
try {
if (!/h5\/comicContent\/.*/.test(location.href))
return;
const scrollHeight = document.scrollingElement.scrollTop;
const list = await waitHasComicContent();
let height = 0;
for (let i = 0; i < list.length; i++) {
const item = list[i];
height += item.getBoundingClientRect().height;
if (height > scrollHeight) {
const dom = document.querySelector(".comicContentPopup .comicFixed");
dom.textContent = dom.textContent.replace(/(.*)\//, `${i + 1}/`);
break;
}
}
} catch (e) {
}
}
let trackId = { current: 0 };
async function runH5main() {
try {
if (!/h5\/comicContent\/.*/.test(location.href))
return;
let runTrackId = ++trackId.current;
const ulDom = await waitDOM(".comicContentPopupImageList");
if (runTrackId !== trackId.current)
return;
const uuid = getComicId();
const domUUID = ulDom.dataset.uuid;
if (domUUID !== uuid) {
ulDom.dataset.uuid = uuid;
}
injectFixImg$1();
injectFastLoadImg$1();
const main = ulDom.parentElement;
main.style.position = "unset";
main.style.overflowY = "unset";
createNextPartDom();
} catch (error) {
throw error;
}
}
async function createNextPartDom() {
let nextPartDom = document.querySelector("#comicContentMain .next-part-btn");
let nextButton = document.querySelector(".comicControlBottomTop > div:nth-child(3) > span");
if (!nextPartDom) {
if (!nextButton) {
await openControl();
nextButton = document.querySelector(".comicControlBottomTop > div:nth-child(3) > span");
}
nextPartDom = document.createElement("div");
nextPartDom.className = "next-part-btn";
nextPartDom.textContent = "\u4E0B\u4E00\u8BDD";
nextPartDom.onclick = async (e) => {
e.stopPropagation();
nextButton && nextButton.click();
document.scrollingElement.scrollTop = 0;
};
document.getElementById("comicContentMain").appendChild(nextPartDom);
}
nextPartDom.style.display = nextButton.parentElement.classList.contains("noneUuid") ? "none" : "block";
let fixedNextBtn = document.querySelector(".next-part-btn-fixed");
if (!fixedNextBtn) {
fixedNextBtn = document.createElement("div");
fixedNextBtn.className = "next-part-btn-fixed";
fixedNextBtn.textContent = "\u4E0B\u4E00\u8BDD";
document.body.appendChild(fixedNextBtn);
window.addEventListener("scroll", throttle(() => {
if (!/h5\/comicContent\/.*/.test(location.href)) {
fixedNextBtn == null ? void 0 : fixedNextBtn.classList.add("hide");
return;
}
const dom = document.scrollingElement;
if (dom.scrollTop < 50 || dom.scrollTop + dom.clientHeight > dom.scrollHeight - 800) {
fixedNextBtn == null ? void 0 : fixedNextBtn.classList.remove("hide");
} else {
fixedNextBtn == null ? void 0 : fixedNextBtn.classList.add("hide");
}
}, 100));
}
fixedNextBtn.onclick = nextPartDom.onclick;
fixedNextBtn.style.display = nextPartDom.style.display;
}
function getComicId() {
const [, uuid] = location.href.match(/h5\/comicContent\/.*\/(.*)/);
return uuid;
}
async function waitHasComicContent() {
return document.querySelectorAll(".comicContentPopupImageItem");
}
async function addH5HistoryListener() {
history.pushState = _historyWrap("pushState");
history.replaceState = _historyWrap("replaceState");
window.addEventListener("pushState", runH5main);
window.addEventListener("replaceState", runH5main);
window.addEventListener("popstate", runH5main);
window.addEventListener("scroll", throttle(currentPage, 100));
runH5main();
}
const _historyWrap = function(type) {
const orig = history[type];
const e = new Event(type);
return function() {
const rv = orig.apply(this, arguments);
window.dispatchEvent(e);
return rv;
};
};
async function injectFixImg$1() {
const listDOM = await waitDOM(".comicContentPopupImageList");
async function injectEvent() {
const imgs = document.querySelectorAll("ul li img");
imgs.forEach(addErrorListener);
}
const ob = new MutationObserver(injectEvent);
ob.observe(listDOM, { childList: true, subtree: true });
injectEvent();
}
async function injectFastLoadImg$1() {
const $list = await waitDOM(".comicContentPopupImageList");
function fastLoad() {
const $imgs = document.querySelectorAll("ul li img");
$imgs.forEach(($img) => {
if ($img.dataset.fastLoad === $img.dataset.src)
return;
$img.dataset.fastLoad = $img.dataset.src;
$img.src = $img.dataset.src;
});
}
const ob = new MutationObserver(fastLoad);
ob.observe($list, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["data-src"]
});
}
function h5() {
addH5HistoryListener();
}
function replaceHeader() {
const header = document.querySelector(".container.header-log .row");
if (header) {
header.style.flexWrap = "nowrap";
header.querySelector("div:nth-child(6)").replaceWith(s2d(`<div class="col-1">
<div class="log-txt">
<a href="/web/person/shujia">\u6211\u7684\u4E66\u67B6</a>
<div class="log-unboder"></div>
</div>
</div>`));
header.querySelector("div:nth-child(7)").replaceWith(s2d(`<div class="col-1">
<div class="log-txt">
<a href="/web/person/liulan">\u6211\u7684\u6D4F\u89C8</a>
<div class="log-unboder"></div>
</div>
</div>`));
header.querySelector("div:nth-child(8)").className = "col";
header.querySelector("div.col > div > div").style.justifyContent = "flex-end";
}
}
async function injectFixImg() {
const listDOM = await waitDOM("ul.comicContent-list");
async function injectEvent2() {
const imgs = document.querySelectorAll("ul li img");
imgs.forEach(addErrorListener);
}
const ob = new MutationObserver(injectEvent2);
ob.observe(listDOM, { childList: true, subtree: true });
injectEvent2();
}
async function injectFastLoadImg() {
const $list = await waitDOM(".comicContent-list");
function fastLoad() {
const $imgs = $list.querySelectorAll("li img");
$imgs.forEach(($img) => {
if ($img.dataset.fastLoad === "true")
return;
$img.dataset.fastLoad = "true";
$img.src = $img.dataset.src;
});
}
const ob = new MutationObserver(fastLoad);
ob.observe($list, { childList: true, subtree: true });
}
async function removeMouseupEvent() {
await wait(() => !!document.body.onmouseup);
document.body.onmouseup = null;
}
async function injectEvent() {
keybind(["z", "x"], (e, key) => {
var _a, _b;
switch (key) {
case "z": {
(_a = document.querySelector(`[class='comicContent-prev'] a`)) == null ? void 0 : _a.click();
break;
}
case "x": {
(_b = document.querySelector(`[class='comicContent-next'] a`)) == null ? void 0 : _b.click();
break;
}
}
});
}
function pc() {
if (/comic\/.*\/chapter/.test(location.href)) {
injectFixImg();
injectFastLoadImg();
removeMouseupEvent();
injectEvent();
}
replaceHeader();
}
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}}
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}";
n(css,{});
document.body.classList.add("k-copymanga");
if (location.pathname.startsWith("/h5")) {
h5();
} else {
pc();
}
})();