EhBatchUpload

Upload a large gallery in small batches

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         EhBatchUpload
// @namespace    http://tampermonkey.net/
// @version      2025-06-17
// @description  Upload a large gallery in small batches
// @author       4piu
// @license      MIT
// @match        https://upload.e-hentai.org/managegallery*
// @match        https://upld.exhentai.org/upld/managegallery*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=e-hentai.org
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let batchSize = 5;
    let filesToUpload = [];

    let filesUploaded = 0;
    let totalFiles = 0;
    let currentBatch = 0;
    let totalBatches = 0;
    let batchPercent = 0;
    let uploadInProgress = false;
    let uploadMessage = '';

    // Create a progress display element
    function createProgressDisplay() {
        const progressDiv = document.createElement('div');
        progressDiv.id = 'batchProgress';
        progressDiv.style.cssText = 'padding: 10px; border: 1px solid;';
        progressDiv.innerHTML = '<p id="uploadMessage" style="font-weight: bold;"></p>' +
                              '<p>Status: <span id="batchStatus">Idle</span></p>' +
                              '<p>Files Uploaded: <span id="filesUploaded">0</span>/<span id="totalFiles">0</span> <span id="totalPercent"></span></p>' +
                              '<p>Current Batch: <span id="currentBatch">0</span>/<span id="totalBatches">0</span> <span id="batchPercent"></span></p>';
        document.getElementById('u').appendChild(progressDiv);
    }

    // Create a input box for batch size
    function createBatchSizeInput() {
       const batchSizeInputDiv = document.createElement('div');
       batchSizeInputDiv.innerHTML = '<label for="batchSizeInput">Batch size</label>' +
                             `<input type="number" id="batchSizeInput" name="batchSizeInput" value="${batchSize}" style="width: 40px; line-height: 19px; border: 2px solid; margin: 3px 1px 0; padding: 1px 3px 3px; border-radius: 3px;">`;
       document.getElementById('uploadbutton').parentNode.appendChild(batchSizeInputDiv);
    }

    // Update progress display
    function updateProgressDisplay() {
        document.getElementById('batchStatus').textContent = uploadInProgress ? 'Uploading...' : 'Idle';
        document.getElementById('filesUploaded').textContent = filesUploaded;
        document.getElementById('totalFiles').textContent = totalFiles;
        document.getElementById('totalPercent').textContent = uploadInProgress? `[${(filesUploaded / totalFiles * 100).toFixed(1)}%]` : '';
        document.getElementById('currentBatch').textContent = currentBatch + 1;
        document.getElementById('totalBatches').textContent = totalBatches;
        document.getElementById('batchPercent').textContent = uploadInProgress? `[${batchPercent.toFixed(1)}%]` : '';
        document.getElementById('uploadMessage').textContent = uploadMessage;
    }

    // Upload a single batch of files
    function uploadBatch(batchFiles) {
        if (batchFiles.length === 0) {
            currentBatch++;
            uploadNextBatch();
            return;
        }

        const formData = new FormData();
        batchFiles.forEach(file => formData.append('files[]', file));

        // Copy hidden inputs from original form
        const originalForm = document.getElementById('uploadform');
        const hiddenInputs = originalForm.querySelectorAll('input[type="hidden"]');
        hiddenInputs.forEach(input => {
            formData.append(input.name, input.value);
        });

        uploadInProgress = true;
        updateProgressDisplay();

        const xhr = new XMLHttpRequest();
        xhr.open('POST', originalForm.action, true);

        xhr.upload.onprogress = function(e) {
            if (e.lengthComputable) {
                batchPercent = (e.loaded / e.total) * 100;
                updateProgressDisplay();
            }
        };

        xhr.onload = function() {
            if (xhr.status === 200) {
                currentBatch < totalBatches && currentBatch++;
                filesToUpload = filesToUpload.slice(batchFiles.length);
                filesUploaded = totalFiles - filesToUpload.length;
                uploadInProgress = false;
                updateProgressDisplay();
                uploadNextBatch();
            } else {
                uploadMessage = `Error uploading batch ${currentBatch + 1}: ${xhr.statusText}`;
                uploadInProgress = false;
                updateProgressDisplay();
                document.getElementById('batchSizeInput').disabled = false;
            }
        };

        xhr.onerror = function() {
            uploadMessage = `Error uploading batch ${currentBatch + 1}: Network Error`;
            uploadInProgress = false;
            updateProgressDisplay();
            document.getElementById('batchSizeInput').disabled = false;
        };

        xhr.send(formData);
    }

    // Start uploading the next batch
    function uploadNextBatch() {
        if (currentBatch >= totalBatches || filesToUpload.length === 0) {
            uploadMessage = 'All batches uploaded successfully! Please refresh page to see results. ';
            uploadInProgress = false;
            updateProgressDisplay();
            document.getElementById('batchSizeInput').disabled = false;
            return;
        }

        const start = 0;
        const end = Math.min(batchSize, filesToUpload.length);
        const batchFiles = filesToUpload.slice(start, end);
        uploadBatch(batchFiles);
    }

    // Override the original submit_upload function
    function overrideSubmitUpload() {
        window.submit_upload = function() {
            if (uploadInProgress) {
                alert('Upload in progress. Please wait until the current batch completes.');
                return;
            }

            const fileInput = document.getElementById('uploadfiles');
            if (!fileInput.files.length) {
                alert('Please select files to upload.');
                return;
            }

            if (!disable_submit()) {
                return;
            }

            const batchSizeInput = document.getElementById('batchSizeInput');
            batchSize = parseInt(batchSizeInput.value) || batchSize; // Fallback to current value if invalid
            batchSizeInput.disabled = true;

            filesToUpload = Array.from(fileInput.files);
            totalFiles = filesToUpload.length;
            filesUploaded = 0;
            totalBatches = Math.ceil(filesToUpload.length / batchSize);
            currentBatch = 0;
            document.getElementById('uploadbutton').value = 'Uploading...';
            updateProgressDisplay();
            uploadNextBatch();
        };
    }

    // Initialize the script
    function init() {
        createProgressDisplay();
        createBatchSizeInput();
        overrideSubmitUpload();
        console.info('EhBatchUpload loaded');
    }

    // Run initialization when DOM is fully loaded
    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
    }
})();