您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A userscript that allow you download all images in Tora EBook Viewer
// ==UserScript== // @name Tora EBook Downloader // @namespace http://tampermonkey.net/ // @version 0.12 // @description A userscript that allow you download all images in Tora EBook Viewer // @author https://github.com/Amarillys // @match http://viewer.toraebook.com/imageviewer/index.php* // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.9/dat.gui.min.js // @icon https://www.toranoana.jp/favicon.ico // @grant GM_xmlhttpRequest // @grant unsafeWindow // @run-at document-end // @license MIT // ==/UserScript== (function() { 'use strict'; const bookInfoApi = `http://viewer.toraebook.com/bookinfo_php73.php` const imageInfoApi = `http://viewer.toraebook.com/image_php73.php` window = unsafeWindow const bookCode = window.location.search.slice(1) const gui = new dat.GUI({ autoPlace: false, useLocalStorage: false }) let options = { progress: 0 } const clickHandler = { text() {}, download: () => { console.log('start downloading') main() } } gui.add(clickHandler, 'text').name('Tora-Ebook-Downloader') const progressCtl = gui.add(options, 'progress', 0, 100, 0.01).name('Progress') gui.add(clickHandler, 'download').name('download') gui.open() setTimeout(() => { gui.domElement.style['z-index'] = 10 gui.domElement.style.position = 'fixed' gui.domElement.style.left = '100px' gui.domElement.style.top = '100px' window.document.body.appendChild(gui.domElement) window.document.getElementById('page0-screen').remove() }, 1500) async function main() { const bookInfoXMLStr = await gmRequireText(`${bookInfoApi}?${bookCode}`) const parser = new DOMParser() const bookInfo = parser.parseFromString(bookInfoXMLStr, `application/xml`) const imageList = Array.from(bookInfo.documentElement.children[1].children[2].children) const zip = new JSZip() let total = 0 for (let i = 0; i < imageList.length; ++i) { const imageInfoURL = `${imageInfoApi}?sp=${bookCode}&x1=${imageList[i].children[7].innerHTML}&x2=${imageList[i].children[8].innerHTML}&t=${9999999999 * Math.random()}` const imageInfoText = await gmRequireText(imageInfoURL) const imageInfo = JSON.parse(imageInfoText) const imageURL = imageInfo.image let imageBlockInfo = imageInfo.x const image = await gmRequire(imageURL) const imageBlobURL = URL.createObjectURL(image) const imageEl = await loadImage(imageBlobURL) const canvasEl = window.document.createElement('canvas') canvasEl.style.position = 'fixed' canvasEl.style.left = 0 canvasEl.width = imageEl.width canvasEl.height = imageEl.height window.document.body.appendChild(canvasEl) const ctx = canvasEl.getContext('2d') imageBlockInfo = imageBlockInfo.slice(1) for (let j = 0; j < imageBlockInfo.length - 1; ++j) { ctx.drawImage(imageEl, imageBlockInfo[j][2], imageBlockInfo[j][3], imageBlockInfo[j][4], imageBlockInfo[j][5], imageBlockInfo[j][0], imageBlockInfo[j][1], imageBlockInfo[j][4], imageBlockInfo[j][5]) } canvasEl.toBlob(blob => { zip.folder(purifyName(window.document.title)).file(`${purifyName(i)}.jpg`, blob, { compression: 'STORE' }) total++ setTimeout(() => canvasEl.remove(), 1200) progressCtl.setValue(total / imageList.length * 100) if (total === imageList.length) { zip.generateAsync({ type: 'blob', compression: 'STORE' }).then(zipBlob => saveBlob(zipBlob, `${purifyName(window.document.title)}.zip`)) } }, "image/jpeg", 0.95) } } function gmRequire(url, index, overrideMimeType, responseType) { return new Promise((resolve) => GM_xmlhttpRequest({ method: 'GET', url, overrideMimeType: overrideMimeType || 'image/jpeg', responseType: responseType || 'blob', asynchrouns: true, credentials: "include", onload: res => { if (responseType === 'json') resolve(res.responseText) else resolve(res.response) }, onerror: console.error }) ) } function gmRequireText(url, index) { return gmRequire(url, index, 'application/json', 'json') } function loadImage(url) { return new Promise(r => { let i = new Image(); i.onload = (() => r(i)); i.src = url; }); } function purifyName(filename) { return (filename + '').replaceAll(':', '').replaceAll('/', '').replaceAll('\\', '').replaceAll('>', '').replaceAll('<', '') .replaceAll('*:', '').replaceAll('|', '').replaceAll('?', '').replaceAll('"', '') } function saveBlob(blob, fileName) { let downloadDom = document.createElement('a') document.body.appendChild(downloadDom) downloadDom.style = `display: none` let url = window.URL.createObjectURL(blob) downloadDom.href = url downloadDom.download = fileName downloadDom.click() window.URL.revokeObjectURL(url) } })();