// ==UserScript==
// @name ☄️拷贝漫画增强☄️
// @namespace http://tampermonkey.net/
// @version 11.4
// @description 拷贝漫画去广告🚫、加速访问🚀、并排布局📖、图片高度自适应↕️、辅助翻页↔️、页码显示⏱、侧边目录栏📑、暗夜模式🌙、章节评论💬
// @author Byaidu
// @match *://*.copymanga.com/*
// @match *://*.copymanga.org/*
// @match *://*.copymanga.net/*
// @match *://*.copymanga.info/*
// @match *://*.copymanga.site/*
// @match *://*.copymanga.tv/*
// @match *://*.mangacopy.com/*
// @match *://copymanga.com/*
// @match *://copymanga.org/*
// @match *://copymanga.net/*
// @match *://copymanga.info/*
// @match *://copymanga.site/*
// @match *://copymanga.tv/*
// @match *://mangacopy.com/*
// @license GNU General Public License v3.0 or later
// @resource element_css https://unpkg.com/[email protected]/lib/theme-chalk/index.css
// @resource animate_css https://unpkg.com/[email protected]/animate.min.css
// @require https://unpkg.com/[email protected]/dist/vue.min.js
// @require https://unpkg.com/[email protected]/lib/index.js
// @require https://unpkg.com/[email protected]/dist/axios.min.js
// @require https://unpkg.com/[email protected]/store.js
// @require https://unpkg.com/[email protected]/dist/jquery.min.js
// @require https://unpkg.com/[email protected]/dist/jszip.min.js
// @require https://unpkg.com/[email protected]/dist/FileSaver.min.js
// @require https://unpkg.com/[email protected]/crypto-js.js
// @grant GM_addStyle
// @grant GM_getResourceText
// @grant GM_xmlhttpRequest
// @run-at document-start
// ==/UserScript==
var largeMode = 1;
var enableDownload = 0;
// retry
axios.interceptors.response.use(undefined, (err) => {
return new Promise((resolve) => { setTimeout(() => { resolve() }, 1000) }).then(() => axios(err.config));
});
function route() {
if (document.getElementsByClassName('ban').length) banPage();
else if (/^\/comic\/.*\/.*$/.test(location.pathname)) comicPage(1);
else if (/^\/comic\/[^\/]*$/.test(location.pathname)) tablePage(1);
else if (/^\/$/.test(location.pathname)) homePage();
else if (/^\/h5\/details\/comic\/[^\/]*$/.test(location.pathname)) tablePage(0);
else if (/^\/h5\/comicContent\/.*$/.test(location.pathname)) comicPage(0);
}
route();
if (/^\/h5.*$/.test(location.pathname)) {
let previousUrl = location.href;
const observer = new MutationObserver(function (mutations) {
if (location.href !== previousUrl) {
previousUrl = location.href;
route();
}
});
const config = { subtree: true, childList: true };
observer.observe(document, config);
}
async function loadCSS() {
var element_css, animate_css;
if (typeof (GM_getResourceText) == 'undefined') {
await axios.get('https://unpkg.com/[email protected]/lib/theme-chalk/index.css')
.then(function (response) {
element_css = response.data;
})
await axios.get('https://unpkg.com/[email protected]/animate.min.css')
.then(function (response) {
animate_css = response.data;
})
} else {
element_css = GM_getResourceText("element_css");
animate_css = GM_getResourceText("animate_css");
}
GM_addStyle(element_css);
GM_addStyle(animate_css);
}
function banPage() {
window.stop();
document.querySelectorAll('main')[0].innerHTML = `
<p class="ban"><img class="banIcon" src="https://hi.est152.com/static/websitefree/jpg/logo.png" alt=""></p>
<p class="textItem">来自 ☄️拷贝漫画增强☄️ 的消息:</p>
<p class="textItem">请安装 <a href="https://chrome.google.com/webstore/detail/user-agent-switcher-and-m/bhchdcejhohfmigjafbampogmaanbfkg">User-Agent Switcher and Manager</a> 插件并切换浏览器 UA</p>
`
}
function homePage() {
GM_addStyle('.header-jum {display:none;}');
}
function makeRequest(url,isPC) {
if (isPC) {
// axios
return axios.get(url)
} else {
// gm绕过ua
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url: url,
headers:{'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0'},
responseType:'json',
onload: function(response) {
resolve({data:response.response});
},
onerror: function(error) {
reject(error);
}
});
});
}
}
function apiChapters(comic,isPC) {
return makeRequest('https://www.mangacopy.com/comicdetail/' + comic + '/chapters',isPC)
.then((response) => {
let iv = response.data.results.substring(0, 16),
cipher = response.data.results.substring(16),
result = JSON.parse(CryptoJS.AES.decrypt(
CryptoJS.enc.Base64.stringify(
CryptoJS.enc.Hex.parse(cipher)
),
CryptoJS.enc.Utf8.parse('xxxmanga.woo.key'),
{
'iv': CryptoJS.enc.Utf8.parse(iv),
'mode': CryptoJS.mode.CBC,
'padding': CryptoJS.pad.Pkcs7
}
).toString(CryptoJS.enc.Utf8));
let type_map = new Map();
result.build.type.forEach((v, index) => {
type_map.set(v.id, v.name);
});
result.groups.default.chapters.forEach((v, index) => {
v.index = index;
let type_name = type_map.get(v.type);
v.name = "【" + type_name + "】" + v.name;
v.type_name = type_name;
});
return result;
})
}
function tablePage(isPC) {
loadCSS();
var collect, save,
comic,
content_comic = [],
app;
if (isPC)
comic = window.location.pathname.split('/')[2];
else
comic = window.location.pathname.split('/')[4];
$(() => {
if (enableDownload) {
GM_addStyle('.comicParticulars-botton:nth-of-type(4) {background: lightskyblue;}');
if (isPC)
collect = document.getElementsByClassName('collect')[0];
else
collect = document.getElementsByTagName('button')[2];
save = collect.cloneNode();
save.innerHTML = '批量下载';
save.onclick = saveComic;
collect.after(save);
var app_html = document.createElement("div");
app_html.innerHTML = `
<div id="app_save">
下载范围:
<el-select v-model="begin" placeholder="起始话" size="mini" style="width:150px;">
<el-option
v-for="item in content_comic"
:key="item.index"
:label="item.name"
:value="item.index">
</el-option>
</el-select>
至
<el-select v-model="end" placeholder="终止话" size="mini" style="width:150px;margin-right:20px;">
<el-option
v-for="item in content_comic"
:key="item.index"
:label="item.name"
:value="item.index">
</el-option>
</el-select>
</div>
`
collect.after(app_html);
if (isPC)
document.getElementById('app_save').setAttribute('style', 'margin-top:18px;');
else
document.getElementsByClassName('detailsTextContentItem')[0].setAttribute('style', 'flex-wrap:wrap;');
app = new Vue({
el: '#app_save',
data: {
content_comic: [],
begin: '',
end: '',
},
})
GM_addStyle('.el-input__suffix {display:none !important;}');
apiChapters(comic,isPC)
.then(function (response) {
content_comic = response.groups.default.chapters;
app.content_comic = content_comic;
app.begin = content_comic.at(0).index;
app.end = content_comic.at(-1).index;
}).catch(function (error) {
save.innerHTML = '下载失败';
})
}
cookieStore.get('token')
.then(function (token) {
if (token) {
axios.get('https://api.mangacopy.com/api/v3/comic2/query/' + comic, {
headers: {
'authorization': 'Token ' + token.value
}
}).then(function (response) {
if (response.data.results.browse != null) {
var read = document.getElementsByClassName('comicParticulars-botton')[0];
read.innerHTML = response.data.results.browse.chapter_name;
read.href = 'https://mangacopy.com/comic/' + comic + '/chapter/' + response.data.results.browse.chapter_uuid;
GM_addStyle('.comicParticulars-botton {max-width:80px; overflow: hidden;text-overflow: ellipsis; white-space: nowrap;}');
}
});
}
})
})
let sleep = function (time) {
return new Promise((resolve) => {
setTimeout(resolve, time)
})
}
async function saveComic() {
let zip = new JSZip();
let task_cnt = 0;
let date_created_chapter_map = new Map();
let comic_name = null;
for (let idx = app.begin; idx <= app.end; idx++) {
let c = content_comic[idx];
task_cnt++;
save.innerHTML = task_cnt + '/' + (app.end - app.begin + 1);
await axios.get('https://api.mangacopy.com/api/v3/comic/' + comic + '/chapter/' + c.id)
.then(async function (response) {
let task_chapter = [];
var chpt_index = Number(response.data.results.chapter.index) + 1
let dir_chpt_name = response.data.results.chapter.name
if (c.type_name !== undefined) {
dir_chpt_name = "【" + chpt_index + "】【" + c.type_name + "】" + dir_chpt_name;
}
let dir_comic = zip.folder(response.data.results.comic.name)
let content = response.data.results.chapter.contents,
size = content.length,
dict = {};
comic_name = response.data.results.comic.name;
let date_created_chapter = new Date(response.data.results.chapter.datetime_created);
if (idx != app.begin && date_created_chapter.getTime() <= date_created_chapter_map.get(idx - 1).getTime()) {
date_created_chapter = new Date(date_created_chapter_map.get(idx - 1).getTime() + 2000);
}
date_created_chapter_map.set(idx, date_created_chapter);
dir_comic.file(dir_chpt_name, null, {
dir: true,
date: date_created_chapter,
});
let dir_chpt = dir_comic.folder(dir_chpt_name);
for (let i = 0; i < size; i++) {
(() => {
let self = i;
let img_url = content[i].url;
if (largeMode) img_url = img_url.replace('c800x.jpg', 'c1500x.jpg');
task_chapter.push(axios.get(img_url, { responseType: 'arraybuffer' })
.then(function (response) {
let date_created_file = new Date(date_created_chapter.getTime() + 2000 * self);
dir_chpt.file((self + 1) + '.jpg', response.data, { date: date_created_file });
}).catch(function (error) {
save.innerHTML = '下载失败';
}))
})()
}
await axios.all(task_chapter);
}).catch(function (error) {
save.innerHTML = '下载失败';
})
await sleep(1000);
}
zip.generateAsync({ type: "blob" }, function (metadata) {
save.innerHTML = metadata.percent.toFixed(0) + '%';
}).then(function (blob) {
saveAs(blob, comic_name + ".zip");
save.innerHTML = '下载完成';
})
}
}
async function comicPage(isPC) {
// 停止加载原生网页
window.stop();
// 解析 URL
if (isPC) {
comic = window.location.pathname.split('/')[2];
chapter = window.location.pathname.split('/')[4];
} else {
comic = window.location.pathname.split('/')[3];
chapter = window.location.pathname.split('/')[4];
}
// 加载 HTML
document.querySelectorAll('html')[0].innerHTML = `
<head></head>
<body>
<div id="app">
<div @mouseleave="drawer=false">
<div @mouseover="drawer=true" style="top:0px;left:0px;height:100vh;width:10vw;position: fixed;"></div>
<el-drawer
id="sidebar"
:size="size"
:modal="modal"
:visible="drawer"
:with-header="false"
:direction="direction"
@open="handleOpen">
<el-menu
background-color="transparent"
text-color="#fff"
active-text-color="#ffd04b"
@select="handleSelect">
<template v-for="(item, index) in sidebar_data">
<el-menu-item v-bind:index="index">{{item.title}}</el-menu-item>
</template>
</el-menu>
</el-drawer>
</div>
<div id="matrix">
<template v-for="(item, index) in comic_data">
<img class="inner_img" v-bind:src="item.url">
</template>
</div>
<ul style="margin-top:20px;">
<template v-for="(item, index) in comment_data">
<li style="display:inline-block;">
<p class="comment" v-bind:index="index">{{item.user_name}} : {{item.comment}}</p>
</li>
</template>
<ul>
<el-input v-model="comment_input" placeholder="吐槽" style="width:300px;margin:20px;" @keyup.enter.native="send_comment" @focus="is_input=1" @blur="is_input=0">
<el-button slot="append" type="primary" @click="send_comment">发表</el-button>
</el-input>
<ul style="margin-bottom:20px;">
<el-button type="primary" @click="prev_chapter">上一章</el-button>
<el-button type="primary" @click="next_chapter">下一章</el-button>
</ul>
<div id="info" @mouseover="show=1" @mouseleave="show=0">
<transition name="custom-classes-transition" enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
<template v-if="show"><div id="info_scroll" class="info_item" @click="switch_scroll" style="cursor:pointer;">{{message_scroll}}</div></template></transition>
<transition name="custom-classes-transition" enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
<template v-if="show"><div id="info_page" class="info_item" @click="switch_page" style="cursor:pointer;">{{message_page}}</div></template></transition>
<transition name="custom-classes-transition" enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
<template v-if="show"><div id="info_skip" class="info_item" @click="switch_skip" style="cursor:pointer;">{{message_skip}}</div></template></transition>
<transition name="custom-classes-transition" enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
<template v-if="show"><div id="info_switch" class="info_item" @click="switch_night" style="cursor:pointer;">{{message_switch}}</div></template></transition>
<transition name="custom-classes-transition" enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
<template v-if="show"><div id="info_full" class="info_item" @click="switch_full" style="cursor:pointer;">{{message_full}}</div></template></transition>
<transition name="custom-classes-transition" enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
<template v-if="show"><div id="info_home" class="info_item" @click="switch_home" style="cursor:pointer;">{{message_home}}</div></template></transition>
<template><div id="info_count" class="info_item">{{message_count}}</div></template>
</div>
</div>
<style>
body {
text-align: center;
font-size: 12px;
line-height: normal;
background: #edecea;
margin: unset !important;
}
body.dark {
background: #212121;
}
::-webkit-scrollbar {
width: 4px;height: 0px;
}
::-webkit-scrollbar-thumb {
background-color: rgb(48,48,48);
border-radius: 2px;
}
#matrix {
display: grid;
justify-items: center;
justify-content: center;
overflow-x: hidden;
user-select: none;
margin: 0 auto;
max-width: 190vh;
}
.page #matrix {
display: flex;
flex-direction: row-reverse;
flex-wrap: wrap;
}
.scroll #matrix {
display: flex;
flex-direction: row-reverse;
flex-wrap: wrap;
justify-content: unset;
flex-wrap: unset;
overflow-x: scroll;
}
.scroll .inner_img {
height: 100vh;
object-fit: contain;
}
.page .inner_img {
height: 100vh;
object-fit: contain;
}
.inner_img {
max-width: 100%;
}
.el-menu {
border-right: 0px;
}
.el-drawer__wrapper {
width: 20%;
}
.el-drawer {
background: transparent;
}
.el-drawer__body {
background: rgba(0,0,0,.8);
overflow-y: auto
}
#info {
bottom: 2%;
right: 2%;
padding: 5px 5px;
background: rgba(48,48,48,.7);
position: fixed;
color: rgba(255,255,255,.7);
border-radius: 3px;
}
.info_item {
padding:5px 0px;
width:120px;
}
.skip .blank {
display:none;
}
.dark .comment {
color: rgba(255,255,255,.7);
}
.dark .el-input__inner {
background-color:rgba(255,255,255,.05);
color: rgba(255,255,255,.7);
}
.dark .el-input-group__append {
background-color:rgba(255,255,255,.2);
color: rgba(255,255,255,.7);
}
.dark .el-button {
background-color:rgba(255,255,255,.2);
color: rgba(255,255,255,.7);
border: 1px solid #DCDFE6;
}
.comment {
padding: 10px 13px;
margin:5px 5px;
font-size:14px;
background-color:rgb(127,127,127,.15);
}
ul {
margin: 5px;
padding: unset;
}
</style>
</body>
`;
loadCSS();
// 加载 LocalStorage
let dark = store.get('dark');
let skip = store.get('skip');
let page = store.get('page');
let scroll = store.get('scroll');
if (dark == undefined)
dark = true;
if (skip == undefined)
skip = true;
if (page == undefined)
page = true;
if (scroll == undefined)
scroll = false;
if (dark) {
document.body.classList.add('dark');
}
if (skip) {
document.body.classList.add('skip');
}
if (page) {
document.body.classList.add('page');
}
if (scroll) {
document.body.classList.add('scroll');
}
// 加载 Vue
var app = new Vue({
el: '#app',
data: {
drawer: false,
size: '100%',
modal: false,
direction: 'ltr',
sidebar_data: [], // 章节数据源
comic_data: [], // 图片数据源
comment_data: [], // 评论数据源
comment_input: '',
is_input: 0,
cur_lock: 0,
cur_id: 0,
cur_ch: 0,
dark: dark,
page: page,
skip: skip,
scroll: scroll,
show: 0,
full: 0,
},
computed: {
message_home: function () {
return '⬅️返回目录';
},
message_full: function () {
return this.full ? '↩️退出全屏' : '↕️进入全屏';
},
message_switch: function () {
return this.dark ? '☀️日间模式' : '🌙夜间模式';
},
message_page: function () {
return this.page ? '1️⃣单页排布' : '2️⃣双页排布';
},
message_skip: function () {
return this.skip ? '📑添加空页' : '📄移除空页';
},
message_scroll: function () {
return this.scroll ? '⏬纵向滚动' : '⏪横向滚动';
},
message_count: function () {
return (this.skip ? (this.cur_id <= 1 ? this.cur_id : this.cur_id - 1) : this.cur_id) + '/' + (this.comic_data.length + 1 - this.skip);
}
},
methods: {
handleSelect(key) {
location.href = this.sidebar_data[key].href;
},
handleOpen() {
setTimeout(() => {
let sidebar = document.getElementsByClassName('el-drawer__body')[0],
ch_list = sidebar.children[0].children;
sidebar.scrollTop = ch_list[Math.max(app.cur_ch - 2, 0)].offsetTop;
}, 0);
},
switch_home: function () {
location.href = 'https://mangacopy.com/comic/' + comic;
},
switch_full: function () {
this.full = !this.full;
if (this.full) {
document.documentElement.requestFullscreen();
} else {
document.exitFullscreen();
}
},
switch_night: function () {
this.dark = !this.dark;
store.set('dark', this.dark);
document.body.classList.toggle('dark');
},
switch_skip: function () {
this.skip = !this.skip;
store.set('skip', this.skip);
document.body.classList.toggle('skip');
},
switch_page: function () {
this.page = !this.page;
store.set('page', this.page);
document.body.classList.toggle('page');
},
switch_scroll: function () {
this.scroll = !this.scroll;
store.set('scroll', this.scroll);
document.body.classList.toggle('scroll');
},
send_comment: async function () {
let token = await cookieStore.get('token');
await axios.post('https://api.mangacopy.com/api/v3/member/roast', 'chapter_id=' + chapter + '&roast=' + this.comment_input + '&_update=true', {
headers: {
'authorization': 'Token ' + token.value
}
}).then(function (response) {
app.comment_input = response.data.message;
});
await this.load_comment();
},
load_comment: async function () {
await axios.get('https://api.mangacopy.com/api/v3/roasts?chapter_id=' + chapter + '&limit=100&offset=0&_update=true')
.then(function (response) {
app.comment_data = response.data.results.list;
})
},
prev_chapter: function () {
location.href = app.sidebar_data[app.cur_ch - 1].href;
},
next_chapter: function () {
location.href = app.sidebar_data[app.cur_ch + 1].href;
},
}
});
// 加载图片
makeRequest('https://api.mangacopy.com/api/v3/comic/' + comic + '/chapter/' + chapter,isPC)
.then(function (response) {
document.title = response.data.results.comic.name + ' - ' + response.data.results.chapter.name;
var content = response.data.results.chapter.contents,
matrix = document.getElementById('matrix'),
size = content.length,
dict = {};
for (var i = 0; i < size; i++) {
var img_url = content[i].url;
if (largeMode) img_url = img_url.replace('c800x.jpg', 'c1500x.jpg');
app.comic_data.push({
url: img_url
})
}
// TODO
setTimeout(() => {
let $blank = $('.inner_img:eq(0)').clone();
$blank.addClass('blank');
$blank.css('filter', 'brightness(0) invert(1)');
$('#matrix').prepend($blank);
}, 0);
})
// 加载章节
apiChapters(comic,isPC)
.then(function (response) {
// var content = response.groups.default.chapters;
var content = Object.values(response.groups).flatMap(obj => obj.chapters);
content.forEach((i,index) => {
if (location.href.indexOf(i.id) >= 0) {
app.cur_ch = index;
GM_addStyle('.el-menu>li:nth-child(' + (index + 1) + '){background:rgba(255,165,0,.5) !important}');
}
app.sidebar_data.push({
title: i.name,
href: 'https://mangacopy.com/comic/' + comic + '/chapter/' + i.id
})
})
})
// 加载评论
app.load_comment();
//上下方向键滚动页面,左右方向键切换章节
function scrollUp() {
let img_list = document.querySelectorAll('.inner_img'),
first_img = img_list[app.skip ? 1 : 0],
last_img = img_list[img_list.length - 1];
if (app.cur_id == 0) return;
var id = img_list.length + 1;
for (var i = (app.skip ? 1 : 0) + 1; i <= Math.min(app.cur_id, img_list.length); i++) {
if (((app.cur_lock && app.cur_id >= 1 && app.cur_id <= img_list.length) ? img_list[app.cur_id - 1].offsetTop : pageYOffset) < img_list[i - 1].offsetTop + img_list[i - 1].offsetHeight + 5) {
id = i;
break;
}
}
if (((app.cur_lock && app.cur_id >= 1 && app.cur_id <= img_list.length) ? img_list[app.cur_id - 1].offsetTop : pageYOffset) < first_img.offsetTop + 5) {
id = 0;
}
app.cur_lock++;
app.cur_id = id;
setTimeout(function () { app.cur_lock--; }, 500);
// TODO
$("html").stop();
if (id == 0) {
$("html").animate({ scrollTop: 0 }, 500);
} else {
$("html").animate({ scrollTop: img_list[id - 1].offsetTop }, 500);
}
}
function scrollDown() {
let img_list = document.querySelectorAll('.inner_img'),
first_img = img_list[app.skip ? 1 : 0],
last_img = img_list[img_list.length - 1];
if (app.cur_id == img_list.length + 1) return;
var id = img_list.length + 1;
for (var i = Math.max(app.cur_id, (app.skip ? 1 : 0) + 1); i <= img_list.length; i++) {
if (((app.cur_lock && app.cur_id >= 1 && app.cur_id <= img_list.length) ? img_list[app.cur_id - 1].offsetTop : pageYOffset) < img_list[i - 1].offsetTop - 5) {
id = i;
break;
}
}
app.cur_lock++;
app.cur_id = id;
setTimeout(function () { app.cur_lock--; }, 500);
// TODO
$("html").stop();
if (id == img_list.length + 1) {
$("html").animate({ scrollTop: last_img.offsetTop + last_img.offsetHeight }, 500);
} else {
$("html").animate({ scrollTop: img_list[id - 1].offsetTop }, 500);
}
}
document.getElementById('matrix').onclick = function (event) {
if (event.clientY > $(window).height() / 2) {
if (app.page) scrollDown();
} else {
if (app.page) scrollUp();
}
}
document.body.onkeydown = function (event) {
if (!app.is_input) {
if (event.keyCode == 38) {
if (app.page) scrollUp();
} else if (event.keyCode == 40) {
if (app.page) scrollDown();
}
if (!app.scroll) {
if (event.keyCode == 37) {
app.prev_chapter();
} else if (event.keyCode == 39) {
app.next_chapter();
}
}
if (event.keyCode == 13) {
app.switch_full();
} else if (event.keyCode == 8) {
location.href = 'https://mangacopy.com/comic/' + comic;
}
}
}
// 加载当前页码
function getID() {
let cur_id = 0,
img_list = document.querySelectorAll('.inner_img'),
first_img = img_list[app.skip ? 1 : 0],
last_img = img_list[img_list.length - 1];
if (img_list.length > 0) {
img_list.forEach((i, index) => {
if (pageYOffset > i.offsetTop - 5 && pageYOffset < i.offsetTop + i.offsetHeight - 5 && cur_id == 0) {
cur_id = index + 1;
}
});
if (pageYOffset > last_img.offsetTop + last_img.offsetHeight - 5)
cur_id = img_list.length + 1;
if (app.cur_lock == 0) app.cur_id = cur_id;
}
}
setInterval(getID, 100);
window.addEventListener('mousewheel', getID);
window.addEventListener('error', event => {
let target = event.target || event.srcElement;
let isElementTarget = target instanceof HTMLImageElement;
if (!isElementTarget) return false;
let url = target.src;
setTimeout(() => {
target.src = url;
}, Math.floor(Math.random() * 2000) + 1);
}, true);
}