// ==UserScript==
// @name Another cmoa.jp Downloader
// @namespace Ziran
// @version 2.1.0
// @description 用于网站cmoa.jp的下载。在顶部菜单选项左侧点击download按钮开始下载。按钮没有显示的话尝试刷新页面。图片每50页分为一部分进行压缩下载,压缩需要40-60秒,请不要关闭或刷新页面。
// @author Ziran
// @match https://www.cmoa.jp/bib/*
// @match https://yomiho.cmoa.jp/bib/*
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js
// @grant none
// @license MIT
// ==/UserScript==
(function () {
"use strict";
let quality = "high";
//Original
function addSpeedreaderCanvas() {
let canvas = document.createElement("canvas");
canvas.id = "temp-canvas";
canvas.style.cssText = `position: fixed;
top: 15%;
left: 5%;
height: 268px;
width: 187px;
background-color: pink;
z-index: 19;
visibility:hidden;`;
document.body.appendChild(canvas);
}
function addSpeedreaderRadio() {
let labelHigh = document.createElement("label");
labelHigh.id = "quality-label-high";
labelHigh.innerText = "高清";
labelHigh.style.cssText = `position: fixed;
top: 11px;
left: 175px;
font-size:16px;`;
let radioHigh = document.createElement("input");
radioHigh.type = "radio";
radioHigh.name = "quality";
radioHigh.value = "high";
radioHigh.checked = true;
radioHigh.onclick = function (value) {
quality = radioHigh.value;
}
let labelOriginal = document.createElement("label");
labelOriginal.id = "quality-label-original";
labelOriginal.innerText = "原图";
labelOriginal.style.cssText = `position: fixed;
top: 11px;
left: 240px;
font-size: 16px;`;
let radioOriginal = document.createElement("input");
radioOriginal.type = "radio";
radioOriginal.name = "quality";
radioOriginal.value = "original";
radioOriginal.onclick = function (value) {
quality = radioOriginal.value;
}
let downloadingMessage = document.createElement("span");
downloadingMessage.id = "downloading-message";
downloadingMessage.innerText = "downloading……";
downloadingMessage.style.cssText = `position: fixed;
top: 10px;
left: 70px;
font-size: 16px;
font-weight: 500;
visibility:hidden;`;
let menu_header = document.getElementById("menu_header");
menu_header.appendChild(labelHigh);
labelHigh.appendChild(radioHigh);
menu_header.appendChild(labelOriginal);
labelOriginal.appendChild(radioOriginal);
menu_header.appendChild(downloadingMessage);
}
function addSpeedreaderButton() {
let button = document.createElement("button");
button.id = "download-button";
button.innerHTML = "download";
button.style.cssText = `position: fixed;
top: 11px;
left: 70px;
font-size:16px;
border-style: none;
text-align:center;
vertical-align:baseline;`;
button.onclick = async function () {
changeDownloadStatus("on");
let zip = new JSZip();
let folder = zip.folder(__sreaderFunc__.contentInfo.items[0].SubTitle);
let partCounter = 0;
let partPages = 50;
for (let i = 0; i < __sreaderFunc__.currentPageInfo.endPageNumber; i++) {
partCounter = i + 1;
if (partCounter % partPages == 0) {
await zip.generateAsync({ type: "blob" })
.then(function (content) {
saveAs(content, __sreaderFunc__.contentInfo.items[0].SubTitle + "_part" + Math.floor(partCounter / partPages).toString());
});
zip = new JSZip();
folder = zip.folder(__sreaderFunc__.contentInfo.items[0].SubTitle);
}
__sreaderFunc__.moveTo(i, !1);
let content = document.getElementById("content-p" + (i + 1).toString());
while (!content.hasChildNodes()) {
await sleep(200);
}
let ptimg = content.firstElementChild;
while (!ptimg.hasChildNodes()) {
await sleep(200);
ptimg = content.firstElementChild;
}
let child = ptimg.firstElementChild;
let img1 = child.firstElementChild;
while (!img1.complete) {
await sleep(200);
}
child = child.nextElementSibling;
let img2 = child.firstElementChild;
while (!img2.complete) {
await sleep(200);
}
let img2Inset = parseFloat(child.style.inset.substring(0, child.style.inset.indexOf("%"))) / 100;
child = child.nextElementSibling;
let img3 = child.firstElementChild;
while (!img3.complete) {
await sleep(200);
}
let img3Inset = parseFloat(child.style.inset.substring(0, child.style.inset.indexOf("%"))) / 100;
let canvas = document.getElementById("temp-canvas");
let ctx = canvas.getContext('2d');
if (quality == "high") {
if (img1.naturalWidth > 800) {
let COQ = 800 / img1.naturalWidth;
canvas.width = 800;
canvas.height = COQ * (img3.naturalHeight / (1 - img3Inset));
ctx.drawImage(img1, 0, 0, 800, COQ * img1.naturalHeight);
ctx.drawImage(img2, 0, canvas.height * img2Inset, 800, COQ * img2.naturalHeight);
ctx.drawImage(img3, 0, canvas.height * img3Inset, 800, COQ * img3.naturalHeight);
} else {
canvas.width = img1.naturalWidth;
canvas.height = img3.naturalHeight / (1 - img3Inset);
ctx.drawImage(img1, 0, 0);
ctx.drawImage(img2, 0, canvas.height * img2Inset);
ctx.drawImage(img3, 0, canvas.height * img3Inset);
}
folder.file((i + 1).toString() + ".png", canvas.toDataURL().split(',')[1], { base64: true });
} else if (quality == "original") {
canvas.width = img1.naturalWidth;
canvas.height = img3.naturalHeight / (1 - img3Inset);
ctx.drawImage(img1, 0, 0);
ctx.drawImage(img2, 0, canvas.height * img2Inset);
ctx.drawImage(img3, 0, canvas.height * img3Inset);
folder.file((i + 1).toString() + ".png", canvas.toDataURL().split(',')[1], { base64: true });
} else {
console.log("quality does not exist.");
}
}
if (partCounter % partPages != 0) {
await zip.generateAsync({ type: "blob" })
.then(function (content) {
saveAs(content, __sreaderFunc__.contentInfo.items[0].SubTitle + "_part" + Math.ceil(partCounter / partPages).toString());
});
}
changeDownloadStatus("off");
};
let menu_header = document.getElementById("menu_header");
menu_header.appendChild(button);
}
function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function changeDownloadStatus(status) {
let button = document.getElementById("download-button");
let labelHigh = document.getElementById("quality-label-high");
let labelOriginal = document.getElementById("quality-label-original");
let downloadingMessage = document.getElementById("downloading-message");
if (status == "on") {
button.style.visibility = "hidden";
labelHigh.style.visibility = "hidden";
labelOriginal.style.visibility = "hidden";
downloadingMessage.style.visibility = "visible";
}
else if (status == "off") {
button.style.visibility = "visible";
labelHigh.style.visibility = "visible";
labelOriginal.style.visibility = "visible";
downloadingMessage.style.visibility = "hidden";
}
return
}
function addReaderButton() {
let button = document.createElement("button");
button.id = "download-button";
button.innerHTML = "download";
button.style.cssText = `position: fixed;
top: 11px;
left: 70px;
font-size:16px;
border-style: none;
text-align:center;
vertical-align:baseline;`;
button.onclick = async function () {
let text = ZOM0KK.ZZN0AE.value;
let title = '';
title = text.match(/(?<=<title>).*(?=<\/title>)/)[0];
text = text.replace(/<head>.*?<\/head>/s, '');
text = text.replace(/<t-param indent="0".*?>/g, '\n');
text = text.replace(/<.*?>/g, '');
let sss = text.match(/&\$.*?;/g, '');
for (let i = 0; i < sss.length; i++) {
text = text.replace(sss[i], theZ2Q0F5(sss[i].slice(2,sss[i].length-1)));
}
while(text[0] === '\n'){
text = text.slice(1,text.length);
}
let blob = new Blob([text], { type: "text/plain;charset=utf-8" });
saveAs(blob, title + ".txt");
};
let menu_header = document.getElementById("ctmble_menu_upper_component_holder");
menu_header.appendChild(button);
}
function theZ2Q0F5(ss) {
let vs = Z2Q0F5(ss);
let sb;
let sp;
let cd1;
let cd2;
ss = "";
if (vs < 256) {
sb = vs % 256;
ss = String.fromCharCode(sb)
} else if (vs >= 65536) {
sp = vs - 65536;
cd1 = 55296 | sp >> 10;
cd2 = 56320 | sp & 1023;
ss = String.fromCharCode(cd1, cd2)
} else {
ss = String.fromCharCode(vs)
}
return ss;
}
// Run script
window.addEventListener("load", function () {
if (document.documentURI.indexOf('cmoa.jp/bib/speedreader/') != -1) {
addSpeedreaderButton();
addSpeedreaderCanvas();
addSpeedreaderRadio();
}
if (document.documentURI.indexOf('cmoa.jp/bib/reader/') != -1) {
addReaderButton();
}
});
})();