您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Bulk upload JSONs, save images to ZIP, download all at once
// ==UserScript== // @name Bulk ZIP Upload & Collect Images as ZIP // @namespace http://tampermonkey.net/ // @version 0.4 // @description Bulk upload JSONs, save images to ZIP, download all at once // @match https://cardconjurer.com/creator* // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js // @grant none // ==/UserScript== (function () { 'use strict'; function waitForFileInput() { const fileInput = document.querySelector('input#file[type="file"][multiple][accept=".json"]'); if (fileInput) { addBulkButton(fileInput); } else { setTimeout(waitForFileInput, 500); } } function addBulkButton(fileInput) { const container = document.createElement('div'); container.style.marginTop = '20px'; container.style.padding = '10px'; container.style.borderTop = '2px dashed #ccc'; container.style.textAlign = 'center'; const bulkBtn = document.createElement('button'); bulkBtn.textContent = '📦 Bulk Upload ZIP & Download All Images'; bulkBtn.style.margin = '10px'; bulkBtn.style.padding = '8px 16px'; bulkBtn.style.border = '1px solid #999'; bulkBtn.style.borderRadius = '6px'; bulkBtn.style.background = '#f5f5f5'; bulkBtn.style.fontSize = '14px'; bulkBtn.style.cursor = 'pointer'; const zipInput = document.createElement('input'); zipInput.type = 'file'; zipInput.accept = '.zip'; zipInput.style.display = 'none'; bulkBtn.addEventListener('click', () => { zipInput.click(); }); zipInput.addEventListener('change', async (e) => { if (!e.target.files.length) return; const zipFile = e.target.files[0]; const jszip = new JSZip(); const zip = await jszip.loadAsync(zipFile); const jsonFiles = Object.keys(zip.files).filter(name => name.toLowerCase().endsWith('.json')); const outputZip = new JSZip(); for (const name of jsonFiles) { const content = await zip.files[name].async('blob'); const jsonFile = new File([content], name, { type: "application/json" }); // Simulate selecting this JSON file const dt = new DataTransfer(); dt.items.add(jsonFile); fileInput.files = dt.files; fileInput.dispatchEvent(new Event('change', { bubbles: true })); // Wait until Save Image button appears const saveBtn = await waitForElement(() => Array.from(document.querySelectorAll('button')) .find(btn => btn.innerText.trim().includes('Save Image')), 10000 ); if (!saveBtn) { console.warn(`Save Image button not found for ${name}`); continue; } // Get image URL from the "Save Image" button saveBtn.click(); await new Promise(res => setTimeout(res, 3500)); // Try to detect downloaded image from <a> or canvas let imgData = await getImageFromCanvasOrLink(); if (imgData) { outputZip.file(name.replace(/\.json$/i, '.png'), imgData, { base64: true }); console.log(`Added ${name.replace(/\.json$/i, '.png')} to ZIP`); } else { console.warn(`Could not capture image for ${name}`); } } // Download ZIP const zipBlob = await outputZip.generateAsync({ type: "blob" }); const a = document.createElement('a'); a.href = URL.createObjectURL(zipBlob); a.download = 'all_cards.zip'; a.click(); console.log("All images zipped and downloaded."); }); container.appendChild(bulkBtn); fileInput.closest('outline-card').after(container); document.body.appendChild(zipInput); } async function waitForElement(fn, timeout = 5000) { const start = Date.now(); return new Promise(resolve => { (function check() { const el = fn(); if (el) return resolve(el); if (Date.now() - start > timeout) return resolve(null); setTimeout(check, 200); })(); }); } async function getImageFromCanvasOrLink() { // Try <a download> approach const aTag = document.querySelector('a[download]'); if (aTag && aTag.href.startsWith('data:image')) { return aTag.href.split(',')[1]; } // Try canvas element const canvas = document.querySelector('canvas'); if (canvas) { return canvas.toDataURL('image/png').split(',')[1]; } return null; } waitForFileInput(); })();