// ==UserScript==
// @name 快看漫画一键保存
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 单击保存即可下载漫画
// @author You
// @icon https://www.kuaikanmanhua.com/favicon.ico
// @grant none
// @license MIT
// @include https://www.kuaikanmanhua.com/web/comic/*
// @downloadURL none
// ==/UserScript==
(function () {
'use strict';
async function AsyncErgodic(
data,
callBack
) {
const ps = new Set()
if ('forEach' in data) {
data.forEach((a, b, c) => {
ps.add(callBack(a, b, c))
})
} else {
for (const k in data) {
ps.add(callBack(data[k], k, data))
}
}
return await Promise.all(ps)
}
let count = 0
function run() {
const el = document.querySelector('.bodyContent')
if (!el) {
count++
if (count >= 100) {
console.log(`多次重启失败`)
return
}
setTimeout(run, 50)
console.log(`第${count}次尝试重启`)
return
}
// 下载进度条
el.insertAdjacentHTML('afterbegin', `
`)
document.body.insertAdjacentHTML('afterbegin', ``)
// 顶部下载
document.querySelector('.titleBox>.tab>div').insertAdjacentHTML('beforebegin', ``)
const fc_sop = document.querySelector('.fc_sop')
/**@type {HTMLDivElement} */
const fc_sop_line_l = document.querySelector('.fc_sop_line_l')
const fc_sop_info = document.querySelector('.fc_sop_info')
function cancel() {
fc_sop.classList.remove('fc_show')
fc_sop_line_l.style.width = '0%'
fc_sop_info.innerText = '正在准备'
}
// 防重锁
let lock = false
function downloadCvs(cvs, ext) {
console.log(`download canvas`)
let a = document.createElement('a')
a.href = cvs.toDataURL('image/png')
a.download = document.title.replace('漫画全集在线观看-快看', '') + ext + '.png'
a.click()
cancel()
lock = false
a.remove()
}
function drawCvs(imgs, width, height) {
console.log(`draw canvas`)
const cvs = document.createElement('canvas')
cvs.id = 'fc_cvs'
// document.querySelector('.bodyContent').append(cvs)
cvs.width = width
cvs.height = height
let th = 0
const ctx = cvs.getContext('2d')
for (let i = 0; i < imgs.length; i++) {
const e = imgs[i]
th += e.height
ctx.drawImage(e, 0, th)
}
return cvs
}
async function download() {
if (lock) return
lock = true
fc_sop.classList.add('fc_show')
const imgEles = [...document.querySelectorAll('.imgList .img-box .img[data-src]')]
if (imgEles.length === 0) return console.log('空元素异常')
console.log(`准备下载${imgEles.length}张图片`)
const imgUrls = imgEles.map(e => e.getAttribute('data-src'))
/** @type {HTMLImageElement[]} */
const imgObjs = await AsyncErgodic(imgUrls, (e, i) => new Promise(n => {
const el = document.createElement('img')
el.onload = () => {
const b = (i + 1) / imgUrls.length * 100
fc_sop_line_l.style.width = b + '%'
n(el)
}
el.src = e
el.setAttribute("crossOrigin", 'Anonymous')
}))
const width = imgObjs[0].width
const height = imgObjs.reduce((v, e) => v + e.height, 0)
console.log(`图片尺寸${width}×${height}`)
// 分组,保证每组图片高度不超过32000
const groups = [{height: 0, items: []}]
for (let i = 0; i < imgObjs.length; i++) {
const e = imgObjs[i]
const pi = groups[groups.length - 1]
if (pi.height + e.height > 32000) {
groups.push({
height: e.height,
items: [e]
})
continue
}
pi.height += e.height
pi.items.push(e)
}
console.log(groups)
if (groups.length === 1) {
const cvs = drawCvs(groups[0].items, width, groups[0].height)
downloadCvs(cvs)
} else {
if (height > 30000) {
const info = `图片高度超过限制,将拆分为${groups.length}个文件`
console.log(info)
fc_sop_info.innerText = info
}
groups.forEach((e, i) => {
const cvs = drawCvs(e.items, width, e.height)
downloadCvs(cvs, '_' + i)
})
}
}
document.querySelectorAll('.fc_dl').forEach(e => e.addEventListener('click', download))
}
setTimeout(run, 20)
})();