From 70b4db63ac63d3e97a076b693152a244ec693341 Mon Sep 17 00:00:00 2001 From: hymbz Date: Fri, 9 Aug 2024 16:40:26 +0800 Subject: [PATCH] chore: :bookmark: Release 9.6.0 --- ComicRead-AdGuard.user.js | 708 ++++++++++++++++++++++++++---------- ComicRead.user.js | 708 ++++++++++++++++++++++++++---------- docs/.other/CHANGELOG.md | 13 + docs/.other/LatestChange.md | 12 +- package.json | 2 +- 5 files changed, 1048 insertions(+), 395 deletions(-) diff --git a/ComicRead-AdGuard.user.js b/ComicRead-AdGuard.user.js index b9a02c46..042fa75b 100644 --- a/ComicRead-AdGuard.user.js +++ b/ComicRead-AdGuard.user.js @@ -1,9 +1,9 @@ // ==UserScript== // @name ComicRead // @namespace ComicRead -// @version 9.5.0 +// @version 9.6.0 // @description 为漫画站增加双页阅读、翻译等优化体验的增强功能。百合会(记录阅读历史、自动签到等)、百合会新站、动漫之家(解锁隐藏漫画)、E-Hentai(关联 nhentai、快捷收藏、标签染色、识别广告页等)、nhentai(彻底屏蔽漫画、无限滚动)、Yurifans(自动签到)、拷贝漫画(copymanga)(显示最后阅读记录)、PonpomuYuri、明日方舟泰拉记事社、禁漫天堂、漫画柜(manhuagui)、漫画DB(manhuadb)、动漫屋(dm5)、绅士漫画(wnacg)、mangabz、komiic、无限动漫、新新漫画、hitomi、koharu、kemono、nekohouse、welovemanga -// @description:en Add enhanced features to the comic site for optimized experience, including dual-page reading and translation. E-Hentai (Associate nhentai, Quick favorite, Colorize tags, etc.) | nhentai (Totally block comics, Auto page turning) | hitomi | Anchira | kemono | nekohouse | welovemanga. +// @description:en Add enhanced features to the comic site for optimized experience, including dual-page reading and translation. E-Hentai (Associate nhentai, Quick favorite, Colorize tags, Floating tag list, etc.) | nhentai (Totally block comics, Auto page turning) | hitomi | Anchira | kemono | nekohouse | welovemanga. // @description:ru Добавляет расширенные функции для удобства на сайт, такие как двухстраничный режим и перевод. // @author hymbz // @license AGPL-3.0-or-later @@ -109,12 +109,12 @@ // @grant GM.deleteValue // @grant unsafeWindow // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAACBUExURUxpcWB9i2B9i2B9i2B9i2B9i2B9i2B9i2B9i2B9i2B9i2B9i2B9i2B9i2B9i////198il17idng49DY3PT297/K0MTP1M3X27rHzaCxupmstbTByK69xOfr7bfFy3WOmqi4wPz9/X+XomSBjqW1vZOmsN/l6GmFkomeqe7x8vn6+kv+1vUAAAAOdFJOUwDsAoYli9zV+lIqAZEDwV05SQAAAUZJREFUOMuFk+eWgjAUhGPBiLohjZACUqTp+z/gJkqJy4rzg3Nn+MjhwB0AANjv4BEtdITBHjhtQ4g+CIZbC4Qb9FGb0J4P0YrgCezQqgIA14EDGN8fYz+f3BGMASFkTJ+GDAYMUSONzrFL7SVvjNQIz4B9VERRmV0rbJWbrIwidnsd6ACMlEoip3uad3X2HJmqb3gCkkJELwk5DExRDxA6HnKaDEPSsBnAsZoANgJaoAkg12IJqBiPACImXQKF9IDULIHUkOk7kDpeAMykHqCEWACy8ACdSM7LGSg5F3HtAU1rrkaK9uGAshXS2lZ5QH/nVhmlD8rKlmbO3ZsZwLe8qnpdxJRnLaci1X1V5R32fjd5CndVkfYdGpy3D+htU952C/ypzPtdt3JflzZYBy7fi/O1euvl/XH1Pp+Cw3/1P1xOZwB+AWMcP/iw0AlKAAAAV3pUWHRSYXcgcHJvZmlsZSB0eXBlIGlwdGMAAHic4/IMCHFWKCjKT8vMSeVSAAMjCy5jCxMjE0uTFAMTIESANMNkAyOzVCDL2NTIxMzEHMQHy4BIoEouAOoXEXTyQjWVAAAAAElFTkSuQmCC -// @resource solid-js https://cdn.jsdelivr.net/npm/solid-js@1.8.17/dist/solid.cjs +// @resource solid-js https://cdn.jsdelivr.net/npm/solid-js@1.8.19/dist/solid.cjs // @resource fflate https://cdn.jsdelivr.net/npm/fflate@0.8.2/umd/index.js // @resource qr-scanner https://cdn.jsdelivr.net/npm/qr-scanner@1.4.2/qr-scanner.legacy.min.js // @resource dmzjDecrypt https://greasyfork.org/scripts/467177/code/dmzjDecrypt.js?version=1207199 -// @resource solid-js|store https://cdn.jsdelivr.net/npm/solid-js@1.8.17/store/dist/store.cjs -// @resource solid-js|web https://cdn.jsdelivr.net/npm/solid-js@1.8.17/web/dist/web.cjs +// @resource solid-js|store https://cdn.jsdelivr.net/npm/solid-js@1.8.19/store/dist/store.cjs +// @resource solid-js|web https://cdn.jsdelivr.net/npm/solid-js@1.8.19/web/dist/web.cjs // @supportURL https://github.com/hymbz/ComicReadScript/issues // @updateURL https://github.com/hymbz/ComicReadScript/raw/master/ComicRead-AdGuard.user.js // @downloadURL https://github.com/hymbz/ComicReadScript/raw/master/ComicRead-AdGuard.user.js @@ -458,13 +458,6 @@ const inRange = (min, val, max) => val >= min && val <= max; /** 判断两个数是否在指定误差范围内相等 */ const approx = (val, target, range) => Math.abs(target - val) <= range; -/** 根据传入的条件列表的真假,对 val 进行取反 */ -const ifNot = (val, ...conditions) => { - let res = Boolean(val); - for (const v of conditions) if (v) res = !res; - return res; -}; - /** * 对 document.querySelector 的封装 * 将默认返回类型改为 HTMLElement @@ -525,9 +518,6 @@ const isUrl = text => { } }; -/** 将对象转为 URLParams 类型的字符串 */ -const dataToParams = data => Object.entries(data).map(([key, val]) => \`\${key}=\${String(val)}\`).join('&'); - /** 将 blob 数据作为文件保存至本地 */ const saveAs = (blob, name = 'download') => { const a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a'); @@ -542,12 +532,6 @@ const scrollIntoView = (selector, behavior = 'instant') => querySelector(selecto behavior }); -/** 循环执行指定函数 */ -const loop = async (fn, ms = 0) => { - await fn(); - setTimeout(loop, ms, fn); -}; - /** 使指定函数延迟运行期间的多次调用直到运行结束 */ const singleThreaded = (callback, defaultContinueRun = true) => { const state = { @@ -686,25 +670,6 @@ const triggerEleLazyLoad = async (e, time, isLazyLoaded) => { } }; -/** 获取图片尺寸 */ -const getImgSize = async (url, breakFn) => { - let error = false; - const image = new Image(); - try { - image.onerror = () => { - error = true; - }; - image.src = url; - await wait(() => !error && (image.naturalWidth || image.naturalHeight) && (breakFn ? !breakFn() : true)); - if (error) return null; - return [image.naturalWidth, image.naturalHeight]; - } catch (error_) { - return null; - } finally { - image.src = ''; - } -}; - /** 测试图片 url 能否正确加载 */ const testImgUrl = url => new Promise(resolve => { const img = new Image(); @@ -842,12 +807,21 @@ const linstenKeydown = handler => window.addEventListener('keydown', e => { return handler(e); }); +/** 劫持修改原网页上的函数 */ +const hijackFn = (fnName, fn) => { + const rawFn = unsafeWindow[fnName]; + unsafeWindow[fnName] = (...args) => fn(rawFn, args); +}; + /* eslint-disable no-console */ const prefix = ['%cComicRead', 'background-color: #607d8b; color: white; padding: 2px 4px; border-radius: 4px;']; -const log = (...args) => Reflect.apply(console.log, null, [...prefix, ...args]); -log.warn = (...args) => Reflect.apply(console.warn, null, [...prefix, ...args]); -log.error = (...args) => Reflect.apply(console.error, null, [...prefix, ...args]); +const log = (...args) => console.log(...prefix, ...args); +log.warn = (...args) => console.warn(...prefix, ...args); +log.error = (...args) => { + console.error(...prefix, ...args); + if (args[0] instanceof Error) throw args[0]; +}; const zh = { alert: { @@ -889,6 +863,7 @@ const zh = { hotkeys: { enter_read_mode: "进入阅读模式", exit: "退出", + float_tag_list: "悬浮标签列表", jump_to_end: "跳至尾页", jump_to_home: "跳至首页", page_down: "向下翻页", @@ -1025,6 +1000,7 @@ const zh = { block_totally: "彻底屏蔽漫画", colorize_tag: "标签染色", detect_ad: "识别广告页", + float_tag_list: "悬浮标签列表", hotkeys: "快捷键", load_original_image: "加载原图", open_link_new_page: "在新页面中打开链接", @@ -1161,6 +1137,7 @@ const en = { hotkeys: { enter_read_mode: "Enter reading mode", exit: "Exit", + float_tag_list: "Floating tag list", jump_to_end: "Jump to the last page", jump_to_home: "Jump to the first page", page_down: "Turn the page to the down", @@ -1297,6 +1274,7 @@ const en = { block_totally: "Totally block comics", colorize_tag: "Colorize tags", detect_ad: "Detect advertise page", + float_tag_list: "Floating tag list", hotkeys: "Hotkeys", load_original_image: "Load original image", open_link_new_page: "Open links in a new page", @@ -1433,6 +1411,7 @@ const ru = { hotkeys: { enter_read_mode: "Режим чтения", exit: "Выход", + float_tag_list: "Плавающий список тегов", jump_to_end: "Перейти к последней странице", jump_to_home: "Перейти к первой странице", page_down: "Перелистнуть страницу вниз", @@ -1569,6 +1548,7 @@ const ru = { block_totally: "Глобально заблокировать комиксы", colorize_tag: "Раскрасить теги", detect_ad: "Detect advertise page", + float_tag_list: "Плавающий список тегов", hotkeys: "Горячие клавиши", load_original_image: "Загружать оригинальное изображение", open_link_new_page: "Открывать ссылки в новой вкладке", @@ -1715,7 +1695,7 @@ const t = solidJs.createRoot(() => { }; }); -var css$3 = ".root{align-items:flex-end;bottom:0;flex-direction:column;font-size:16px;pointer-events:none;position:fixed;right:0;z-index:2147483647}.item,.root{display:flex}.item{align-items:center;animation:bounceInRight .5s 1;background:#fff;border-radius:4px;box-shadow:0 1px 10px 0 #0000001a,0 2px 15px 0 #0000000d;color:#000;cursor:pointer;margin:1em;max-width:min(30em,100vw);overflow:hidden;padding:.8em 1em;pointer-events:auto;position:relative;width:-moz-fit-content;width:fit-content}.item>svg{color:var(--theme);margin-right:.5em;width:1.5em}.item[data-exit]{animation:bounceOutRight .5s 1}.schedule{background-color:var(--theme);bottom:0;height:.2em;left:0;position:absolute;transform-origin:left;width:100%}.item[data-schedule] .schedule{transition:transform .1s}.item:not([data-schedule]) .schedule{animation:schedule linear 1 forwards}:is(.item:hover,.item[data-schedule],.root[data-paused]) .schedule{animation-play-state:paused}.msg{line-height:1.4em;text-align:start;white-space:break-spaces;width:-moz-fit-content;width:fit-content;word-break:break-word}.msg h2{margin:0}.msg h3{margin:.7em 0}.msg ul{margin:0;text-align:left}.msg button{background-color:#eee;border:none;border-radius:.4em;cursor:pointer;font-size:inherit;margin:0 .5em;outline:none;padding:.2em .6em}.msg button:hover{background:#e0e0e0}p{margin:0}@keyframes schedule{0%{transform:scaleX(1)}to{transform:scaleX(0)}}@keyframes bounceInRight{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(3000px,0,0) scaleX(3)}60%{opacity:1;transform:translate3d(-25px,0,0) scaleX(1)}75%{transform:translate3d(10px,0,0) scaleX(.98)}90%{transform:translate3d(-5px,0,0) scaleX(.995)}to{transform:translateZ(0)}}@keyframes bounceOutRight{20%{opacity:1;transform:translate3d(-20px,0,0) scaleX(.9)}to{opacity:0;transform:translate3d(2000px,0,0) scaleX(2)}}"; +var css$3 = ".root{align-items:flex-end;bottom:0;flex-direction:column;font-size:16px;pointer-events:none;position:fixed;right:0;z-index:2147483647}.item,.root{display:flex}.item{align-items:center;animation:bounceInRight .5s 1;background:#fff;border-radius:4px;box-shadow:0 1px 10px 0 #0000001a,0 2px 15px 0 #0000000d;color:#000;cursor:pointer;margin:1em;max-width:min(30em,100vw);overflow:hidden;padding:.8em 1em;pointer-events:auto;position:relative;width:fit-content}.item>svg{color:var(--theme);margin-right:.5em;width:1.5em}.item[data-exit]{animation:bounceOutRight .5s 1}.schedule{background-color:var(--theme);bottom:0;height:.2em;left:0;position:absolute;transform-origin:left;width:100%}.item[data-schedule] .schedule{transition:transform .1s}.item:not([data-schedule]) .schedule{animation:schedule linear 1 forwards}:is(.item:hover,.item[data-schedule],.root[data-paused]) .schedule{animation-play-state:paused}.msg{line-height:1.4em;text-align:start;white-space:break-spaces;width:fit-content;word-break:break-word}.msg h2{margin:0}.msg h3{margin:.7em 0}.msg ul{margin:0;text-align:left}.msg button{background-color:#eee;border:none;border-radius:.4em;cursor:pointer;font-size:inherit;margin:0 .5em;outline:none;padding:.2em .6em}:is(.msg button):hover{background:#e0e0e0}p{margin:0}@keyframes schedule{0%{transform:scaleX(1)}to{transform:scaleX(0)}}@keyframes bounceInRight{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(3000px,0,0) scaleX(3)}60%{opacity:1;transform:translate3d(-25px,0,0) scaleX(1)}75%{transform:translate3d(10px,0,0) scaleX(.98)}90%{transform:translate3d(-5px,0,0) scaleX(.995)}to{transform:translateZ(0)}}@keyframes bounceOutRight{20%{opacity:1;transform:translate3d(-20px,0,0) scaleX(.9)}to{opacity:0;transform:translate3d(2000px,0,0) scaleX(2)}}"; var modules_c21c94f2$3 = {"root":"root","item":"item","bounceInRight":"bounceInRight","bounceOutRight":"bounceOutRight","schedule":"schedule","msg":"msg"}; const [_state$1, _setState$1] = store$2.createStore({ @@ -2044,6 +2024,7 @@ const request$1 = async (url, details, retryNum = 0, errorNum = 0) => { method: 'GET', headers, ...details, + // eslint-disable-next-line unicorn/no-invalid-fetch-options body: details?.data, signal: AbortSignal.timeout?.(details?.timeout ?? 1000 * 10) }); @@ -2137,7 +2118,7 @@ const MdAutoFlashOff = ((props = {}) => (() => { return _el$; })()); -var css$2 = ".iconButtonItem{position:relative}.iconButton,.iconButtonItem{align-items:center;display:flex}.iconButton{background-color:transparent;border-radius:9999px;border-style:none;color:var(--text,#fff);cursor:pointer;font-size:1.5em;height:1.5em;justify-content:center;margin:.1em;outline:none;padding:0;width:1.5em}.iconButton:focus,.iconButton:hover{background-color:var(--hover-bg-color,#fff3)}.iconButton.enabled{background-color:var(--text,#fff);color:var(--text-bg,#121212)}.iconButton.enabled:focus,.iconButton.enabled:hover{background-color:var(--hover-bg-color-enable,#fffa)}.iconButton>svg{width:1em}.iconButtonPopper{align-items:center;background-color:#303030;border-radius:.3em;color:#fff;display:flex;font-size:.8em;opacity:0;padding:.4em .5em;pointer-events:none;position:absolute;top:50%;transform:translateY(-50%);-webkit-user-select:none;user-select:none;white-space:nowrap}.iconButtonPopper[data-placement=right]{left:calc(100% + 1.5em)}.iconButtonPopper[data-placement=right]:before{border-right-color:var(--switch-bg,#6e6e6e);border-right-width:.5em;right:calc(100% + .5em)}.iconButtonPopper[data-placement=left]{right:calc(100% + 1.5em)}.iconButtonPopper[data-placement=left]:before{border-left-color:var(--switch-bg,#6e6e6e);border-left-width:.5em;left:calc(100% + .5em)}.iconButtonPopper:before{background-color:transparent;border:.4em solid transparent;content:\\"\\";pointer-events:none;position:absolute;transition:opacity .15s}.iconButtonItem:is(:hover,:focus,[data-show=true]) .iconButtonPopper{opacity:1}.hidden{display:none}"; +var css$2 = ".iconButtonItem{position:relative}.iconButton,.iconButtonItem{align-items:center;display:flex}.iconButton{background-color:initial;border-radius:9999px;border-style:none;color:var(--text,#fff);cursor:pointer;font-size:1.5em;height:1.5em;justify-content:center;margin:.1em;outline:none;padding:0;width:1.5em}.iconButton:focus,.iconButton:hover{background-color:var(--hover-bg-color,#fff3)}.iconButton.enabled{background-color:var(--text,#fff);color:var(--text-bg,#121212)}.iconButton.enabled:focus,.iconButton.enabled:hover{background-color:var(--hover-bg-color-enable,#fffa)}.iconButton>svg{width:1em}.iconButtonPopper{align-items:center;background-color:#303030;border-radius:.3em;color:#fff;display:flex;font-size:.8em;opacity:0;padding:.4em .5em;pointer-events:none;position:absolute;top:50%;transform:translateY(-50%);-webkit-user-select:none;user-select:none;white-space:nowrap}.iconButtonPopper[data-placement=right]{left:calc(100% + 1.5em)}.iconButtonPopper[data-placement=right]:before{border-right-color:var(--switch-bg,#6e6e6e);border-right-width:.5em;right:calc(100% + .5em)}.iconButtonPopper[data-placement=left]{right:calc(100% + 1.5em)}.iconButtonPopper[data-placement=left]:before{border-left-color:var(--switch-bg,#6e6e6e);border-left-width:.5em;left:calc(100% + .5em)}.iconButtonPopper:before{background-color:initial;border:.4em solid #0000;content:\\"\\";pointer-events:none;position:absolute;transition:opacity .15s}.iconButtonItem:is(:hover,:focus,[data-show=true]) .iconButtonPopper{opacity:1}.hidden{display:none}"; var modules_c21c94f2$2 = {"iconButtonItem":"iconButtonItem","iconButton":"iconButton","enabled":"enabled","iconButtonPopper":"iconButtonPopper","hidden":"hidden"}; var _tmpl$$F = /*#__PURE__*/web.template(\`