Allows for multiple cover art images to be uploaded simultaneously.
当前为
// ==UserScript==
// @name MusicBrainz: Cover Art Uploader Parallel Submissions
// @namespace https://musicbrainz.org/user/chaban
// @version 1.0.1
// @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
// @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.');
}
})();