您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Scrape a full lezhin chapter. Creates a zip with PNGs
// ==UserScript== // @name Lezhin Comics Downloader // @namespace lezhin-comics-scraper // @version 1.1.1 // @description Scrape a full lezhin chapter. Creates a zip with PNGs // @author TzurS11 // @match https://www.lezhinus.com/* // @match https://www.lezhin.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=lezhinus.com // @grant GM_setValue // @grant GM_getValue // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js // @license MIT // ==/UserScript== (function() { async function getImageSrcFromElement(imageElementString,index) { // Create a temporary div element to hold the image element const tempDiv = document.createElement('div'); tempDiv.innerHTML = imageElementString; // Find the image element within the temporary div const imageElement = tempDiv.querySelector('img'); if (imageElement) { const imageUrl = imageElement.src; try { await timeout(500); const response = await fetch(imageUrl); const blob = await response.blob(); // Create a temporary anchor element to trigger the download const downloadLink = document.createElement('a'); downloadLink.href = URL.createObjectURL(blob); downloadLink.download = `image-${index}.jpg`; downloadLink.style.display = 'none'; return downloadLink; } catch (error) { return false; } } else { return false } } function timeout(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function downloadImagesAsZip(anchorElements) { const zip = new JSZip(); const promises = Array.from(anchorElements).map((anchor, index) => { const url = anchor.href; return fetch(url) .then(response => response.blob()) .then(blob => { const filename = `image_${index + 1}.jpg`; // Customize the filename as needed zip.file(filename, blob); }); }); Promise.all(promises) .then(() => { return zip.generateAsync({ type: 'blob' }); }) .then(zipBlob => { let pathNames = window.location.pathname.split('/'); const zipFilename = `${pathNames[3]} ${pathNames[4]}.zip`; const link = document.createElement('a'); link.href = URL.createObjectURL(zipBlob); link.download = zipFilename; link.style.display = 'none'; document.body.appendChild(link); link.click(); document.body.removeChild(link); }) .catch(error => { console.error('Error:', error); }); } function waitForImgInDiv(targetDiv) { return new Promise(resolve => { if (!(targetDiv instanceof HTMLDivElement)) { resolve(false); return; } // Check if there's already an <img> element inside the div if (targetDiv.querySelector('img')) { resolve(true); return; } const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node instanceof HTMLImageElement && node.tagName === 'IMG') { observer.disconnect(); // Stop observing once an <img> is added resolve(true); return; } }); }); }); const config = { childList: true, subtree: true }; observer.observe(targetDiv, config); let skip = setTimeout(async () => { observer.disconnect(); // Disconnect the observer resolve(true); // Resolve with true after the timeout }, 1000); }); } function waitForDivChanges(divId) { return new Promise(resolve => { const targetDiv = document.getElementById(divId); if (!targetDiv) { console.error(`Element with ID "${divId}" not found.`); resolve(false); return; } const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.type === 'attributes' || mutation.type === 'characterData') { resolve(true); observer.disconnect(); } else if (mutation.type === 'childList') { for (const addedNode of mutation.addedNodes) { if (addedNode instanceof HTMLElement && addedNode.id === divId) { resolve(true); observer.disconnect(); return; } } } }); }); const config = { attributes: true, childList: true, characterData: true, subtree: true }; observer.observe(targetDiv, config); }); } let pathNames = window.location.pathname.split('/'); if(pathNames[2] == "comic"){ waitForDivChanges("scroll-list").then(x=>{ let button = document.createElement("button"); button.innerHTML = "Download Chapter"; button.style.position = "fixed"; button.style.bottom = 0 button.style.zIndex = 10000; button.style.fontSize = "30px" button.style.marginLeft = "10px" button.id = "DownloadButton" button.onclick=function(){downloadChapter()} document.body.appendChild(button); }) } let scrollList = document.getElementById("scroll-list"); if(scrollList != null){ if(localStorage.getItem("firstTime") == null){ localStorage.setItem("firstTime", "no") alert("To use the Lezhin downloader wait for a button to appear on the bottom left corner and press it. This alert will not appear again.") } } async function downloadChapter(){ let downloadButton= document.getElementById("DownloadButton"); downloadButton.innerHTML = "Scraping..." downloadButton.disabled = true; let elements = [] if(scrollList == null){ alert("You are not viewing a chapter"); return; } let descendents = scrollList.getElementsByTagName('*'); let imgLen = descendents.length; for (let i = 0; i < descendents.length; ++i) { downloadButton.innerHTML = `Scraping... (${i+1}/${imgLen})` let element = descendents[i]; element.scrollIntoView(); await waitForImgInDiv(element) let image = element.innerHTML; //await timeout(500); let res = await getImageSrcFromElement(image,i); if (res != false){ elements.push(res) //console.log(i+1 + "/" + imgLen) } } //console.log("creating zip") downloadImagesAsZip(elements) downloadButton.innerHTML = "Download Chapter"; downloadButton.disabled = false; } })();