MusicBrainz: Cover Art Uploader Parallel Submissions

Allows for multiple cover art images to be uploaded simultaneously.

当前为 2025-08-01 提交的版本,查看 最新版本

// ==UserScript==
// @name         MusicBrainz: Cover Art Uploader Parallel Submissions
// @namespace    https://musicbrainz.org/user/chaban
// @version      1.0.2
// @tag          ai-created
// @description  Allows for multiple cover art images to be uploaded simultaneously.
// @author       chaban
// @license      MIT
// @match        *://*.musicbrainz.org/release/*/add-cover-art*
// @match        *://*.musicbrainz.org/event/*/add-event-art*
// @grant        none
// @icon         https://musicbrainz.org/static/images/favicons/android-chrome-512x512.png
// @run-at       document-start
// ==/UserScript==


(function() {
    'use strict';

    // --- CONFIGURATION ---
    // The number of images to upload at the same time.
    const CONCURRENCY_LIMIT = 4;

    // --- CORE LOGIC ---

    // This is our replacement for the original `iteratePromises` function.
    // It runs a set number of promise-generating functions in parallel.
    function runPromisesInParallel(promiseFuncs) {
        const masterDeferred = $.Deferred();
        const totalTasks = promiseFuncs.length;
        let completedTasks = 0;
        let activeTasks = 0;
        let taskIndex = 0;
        let hasFailed = false;

        function updateMasterProgress() {
            // Update the main progress bar based on overall completion.
            const overallProgress = (completedTasks / totalTasks) * 100;
            // We can't access the specific view model here easily, but we can
            // create a visual indicator if we wanted to. For now, we'll rely on the
            // individual progress bars.
        }

        function runNext() {
            if (taskIndex >= totalTasks) {
                // No more tasks to run. If all active tasks are finished, we're done.
                if (activeTasks === 0) {
                    if (hasFailed) {
                        masterDeferred.reject();
                    } else {
                        masterDeferred.resolve();
                    }
                }
                return;
            }

            const currentTaskIndex = taskIndex++;
            const promiseFunc = promiseFuncs[currentTaskIndex];
            activeTasks++;

            promiseFunc()
                .always(() => { // 'always' is like 'finally' for jQuery promises
                    completedTasks++;
                    activeTasks--;
                    updateMasterProgress();
                    runNext(); // Start the next task in the queue
                })
                .fail(() => {
                    hasFailed = true;
                    // Individual failure is already marked on the UI by MB's code.
                });
        }

        // Start the initial pool of workers.
        for (let i = 0; i < CONCURRENCY_LIMIT && i < totalTasks; i++) {
            runNext();
        }

        return masterDeferred.promise();
    }


    // We must wait for the MB object to be available.
    // Using `@run-at document-start` means we need to be careful.
    const checkMB = setInterval(() => {
        if (window.MB && window.MB.Art && window.MB.Art.add_art_submit) {
            clearInterval(checkMB);
            overrideUploader();
        }
    }, 50);


    function overrideUploader() {
        // Store the original function
        const original_add_art_submit = MB.Art.add_art_submit;

        // Overwrite it with our new version
        MB.Art.add_art_submit = function(gid, upvm) {
            // This part is mostly copied from the original function
            var pos = parseInt($(`#id-add-cover-art\\.position`).val(), 10);

            $('.add-files.row').hide();
            $(`#cover-art-position-row`).hide();
            $('#content')[0].scrollIntoView();
            $(`#add-cover-art-submit`).prop('disabled', true);

            var queue = MB.Art.process_upload_queue(gid, upvm, pos);

            // This is the key change: call our parallel function instead of the original.
            runPromisesInParallel(queue)
                .done(function() {
                    window.location.href = `/release/${gid}/cover-art`;
                })
                .fail(function() {
                    // Re-enable the submit button if any of the parallel uploads fail
                    $(`#add-cover-art-submit`).prop('disabled', false);
                    alert('One or more uploads failed. Please review the upload statuses and try again.');
                });
        };

        console.log('[MusicBrainz: Cover Art Uploader Parallel Submissions] is active.');
    }

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址