Bulk ZIP Upload & Collect Images as ZIP

Bulk upload JSONs, save images to ZIP, download all at once

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==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();
})();