您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Download all images in a article as ZIP
当前为
// ==UserScript== // @name Zip images on your article // @namespace http://tampermonkey.net/ // @version 0.2 // @description Download all images in a article as ZIP // @license MIT // @author onanymous // @match https://kone.gg/s/* // @icon https://www.google.com/s2/favicons?sz=64&domain=kone.gg // @grant GM_xmlhttpRequest // @run-at document-idle // ==/UserScript== (function() { 'use strict'; function loadJsZip() { return new Promise((resolve) => { if (window.JSZip) return resolve(); const script = document.createElement('script'); script.src = "https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"; script.onload = () => { window.JSZip = window.JSZip || JSZip; resolve(); }; document.head.appendChild(script); }); } function getImageUrls() { return Array.from(document.querySelectorAll('.overflow-hidden > .relative > [class*="md:"] img')) .map(img => img.src) .filter(Boolean); } function sanitizeFilename(name) { return name.replace(/[\/\\\:\*\?\"\<\>\|]/g, '').trim(); } function getExtension(url, contentType) { let match = url.match(/\.([a-zA-Z0-9]+)(\?|$)/); if (match) { let ext = match[1].toLowerCase(); if (["jpg","jpeg","png","gif","webp","bmp"].includes(ext)) return ext === "jpeg" ? "jpg" : ext; } if (contentType) { if (contentType.includes("jpeg")) return "jpg"; if (contentType.includes("png")) return "png"; if (contentType.includes("gif")) return "gif"; if (contentType.includes("webp")) return "webp"; if (contentType.includes("bmp")) return "bmp"; } return "jpg"; } function downloadImageAsArrayBuffer(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: url, responseType: "arraybuffer", onload: function(response) { let contentType = ""; try { const headers = response.responseHeaders?.split('\n'); if (headers) { for (const h of headers) { if (h.toLowerCase().startsWith('content-type:')) { contentType = h.split(':')[1].trim(); break; } } } } catch {} resolve({ data: new Uint8Array(response.response), contentType }); }, onerror: function(err) { console.error('[이미지 다운로드 실패]', url, err); reject(err); } }); }); } async function downloadImagesAsZip(imgUrls) { await loadJsZip(); const zip = new window.JSZip(); for (let i = 0; i < imgUrls.length; i++) { const url = imgUrls[i]; try { const { data, contentType } = await downloadImageAsArrayBuffer(url); const ext = getExtension(url, contentType); const fileName = `image_${(i+1).toString().padStart(3,'0')}.${ext}`; zip.file(fileName, data); } catch (e) { // 실패시만 출력 } } let zipName = sanitizeFilename(document.title) || 'images'; const content = await zip.generateAsync({ type: 'uint8array', streamFiles: true, compression: 'STORE' }); const blob = new Blob([content]); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = zipName + '.zip'; document.body.appendChild(a); a.click(); setTimeout(() => a.remove(), 1000); } function isArticlePage() { const path = location.pathname.split('/'); return path.length === 4 && path[1] === 's'; } function observeShareButton(onFound) { const observer = new MutationObserver(() => { if (!isArticlePage()) return; const shareBtn = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent.includes('공유') || btn.getAttribute('aria-label') === '공유' || (btn.innerHTML && btn.innerHTML.includes('lucide-share2')) ); if (!shareBtn) return; if (shareBtn.parentNode.querySelector('.tampermonkey-download-btn')) return; onFound(shareBtn); }); observer.observe(document.body, { childList: true, subtree: true }); } // 공유 버튼 옆에 ZIP 버튼 삽입 function insertDownloadButton(shareBtn) { const btn = document.createElement('button'); btn.innerText = '이미지 ZIP'; btn.type = 'button'; btn.setAttribute('data-slot', 'button'); btn.className = shareBtn.className + ' tampermonkey-download-btn'; btn.onclick = async function() { btn.disabled = true; btn.innerText = '다운로드 중...'; const urls = getImageUrls(); if (!urls.length) { btn.innerText = '이미지 없음'; return; } await downloadImagesAsZip(urls); btn.disabled = false; btn.innerText = '이미지 ZIP'; }; shareBtn.parentNode.insertBefore(btn, shareBtn.nextSibling); } observeShareButton(insertDownloadButton); })();