// ==UserScript== // @name MB: CoverArt Uploads Auto Retry on Error // @namespace https://greasyfork.org/users/321857-anakunda // @version 1.01 // @match https://musicbrainz.org/release/*/add-cover-art // @match https://musicbrainz.org/release/*/add-cover-art?* // @description Try to take over the world! // @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 // @downloadURL none // ==/UserScript== { 'use strict'; function clearTimeouts(elem) { if (timer != undefined) { clearTimeout(timer); timer = undefined; } if (countdown != undefined) { clearInterval(countdown); countdown = undefined; } if (elem != null) elem.textContent = '--- '; } const btnSubmit = document.body.querySelector('button#add-cover-art-submit'); if (btnSubmit == null) throw 'Submit button not found'; let haveErrors = false, active = true, btnSuspend = null, counter = null, delay = null; let retryCounter = 0, retryDelay = GM_getValue('retry_delay', 5), timer, countdown, s; 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 (btnSuspend == null) btnSubmit.parentNode.append(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; }, })); if (counter == null || delay == null) { const wrapper = Object.assign(document.createElement('span'), { textContent: 'Retry ', style: 'display: inline-block; padding: 5pt 10pt;', }); wrapper.append(counter = Object.assign(document.createElement('span'), { style: 'font-weight: bold; color: red;', }), ' in ', delay = Object.assign(document.createElement('span'), { style: 'font-weight: bold;', }), 's'); btnSuspend.parentNode.append(wrapper); } const e = Math.log10(retryCounter++); if (active) { if (e > 0 && e == ~~e) retryDelay *= e + 1; timer = setTimeout(function retry(elem) { clearTimeouts(); if (active && elem instanceof HTMLElement && !elem.disabled) elem.click(); }, retryDelay * 1000 || 0, mutation.target); if ((s = retryDelay) > 0) { delay.textContent = retryDelay; countdown = setInterval(() => { delay.textContent = --s }, 1000, mutation.target); } } counter.textContent = retryCounter; } else if (haveErrors) { mo.disconnect(); if (btnSuspend != null) btnSuspend.remove(); if (counter != null) counter.parentNode.remove(); GM_notification({ text: 'Successfully completed', title: 'MusicBrainz', highlight: true, }); } }).observe(btnSubmit, { attributes: true, attributeFilter: ['disabled'] }); }