Greasy Fork

来自缓存

MB: CoverArt Uploads Auto Retry on Error

Try to take over the world!

目前为 2023-09-14 提交的版本。查看 最新版本

// ==UserScript==
// @name         MB: CoverArt Uploads Auto Retry on Error
// @namespace    https://greasyfork.org/users/321857-anakunda
// @version      1.02
// @match        https://musicbrainz.org/release/*/add-cover-art
// @match        https://musicbrainz.org/release/*/add-cover-art?*
// @run-at       document-end
// @author       Anakunda
// @copyright    2023, Anakunda (https://greasyfork.org/users/321857-anakunda)
// @license      GPL-3.0-or-later
// @grant        GM_notification
// @grant        GM_getValue
// @description Try to take over the world!
// ==/UserScript==

{

'use strict';

function clearTimeouts(countdown) {
	if (timer != undefined) { clearTimeout(timer); timer = undefined; }
	if (countdownTimer != undefined) { clearInterval(countdownTimer); countdownTimer = undefined; }
	if (controls == null) return;
	if ((countdown || (countdown = controls.querySelector('span#countdown'))) != null) countdown.textContent = '--- ';
}

const btnSubmit = document.body.querySelector('button#add-cover-art-submit');
if (btnSubmit == null) throw 'Submit button not found';
let haveErrors = false, active = true, controls = null, timer, countdownTimer, countdownTime;
let retryCounter = 0, retryDelay = GM_getValue('retry_delay', 5);
const captions = ['Suspend', 'Resume'];
new MutationObserver(function(ml, mo) {
	clearTimeouts();
	for (let mutation of ml) if (!mutation.target.disabled)
		if (Array.prototype.some.call(document.querySelectorAll('form#add-cover-art > table > tbody > tr > td > span.msg.error'),
				span => span.style.display != 'none' && /^⚠ (?:Server busy|Error)\b/.test(span.textContent.trim()))) {
			haveErrors = true;
			if (controls == null) {
				controls = document.createElement('span');
				var btnSuspend = Object.assign(document.createElement('button'), {
					textContent: captions[0],
					id: 'autoretry',
					style: 'padding: 5px 10px 5px 7px; margin-left: 1em;',
					onclick: function(evt) {
						evt.currentTarget.textContent = captions[(active = !active) ? 0 : 1] + ' autoretry';
						clearTimeouts();
						return false;
					},
				});
				const wrapper = Object.assign(document.createElement('span'), {
					style: 'display: inline-block; padding: 5pt 10pt;',
				});
				var retryCounter = Object.assign(document.createElement('span'), {
					style: 'font-weight: bold; color: red;',
					id: 'retry-counter',
				}), countdown = Object.assign(document.createElement('span'), {
					style: 'font-weight: bold;',
					id: 'countdown',
				});
				wrapper.append('Retry ', retryCounter, ' in ', countdown, 's');
				controls.append(btnSuspend, wrapper);
				btnSuspend.parentNode.append(controls);
			} else [retryCounter, countdown] =
				['retry-counter', 'countdown'].map(id => controls.querySelector('span#' + id));
			if (retryCounter != null) retryCounter.textContent = retryCounter;
			const e = Math.log10(retryCounter++);
			if (e > 0 && e == ~~e) retryDelay *= e + 1;
			if (active) timer = setTimeout(function(elem) {
				clearTimeouts(countdown);
				if (active && elem instanceof HTMLElement && !elem.disabled) elem.click();
			}, retryDelay * 1000 || 0, mutation.target); else continue;
			if (countdown != null && (countdownTime = retryDelay) > 0) {
				countdown.textContent = retryDelay;
				countdown = setInterval(elem => { elem.textContent = --countdownTime }, 1000, countdown);
			}
		} else if (haveErrors) {
			mo.disconnect();
			if (controls != null) controls.remove();
			GM_notification({ text: 'Successfully completed', title: 'MusicBrainz', highlight: true });
		}
}).observe(btnSubmit, { attributes: true, attributeFilter: ['disabled'] });

}