// ==UserScript== // @name MB: CoverArt Uploads Auto Retry on Error // @namespace https://greasyfork.org/users/321857-anakunda // @version 1.00 // @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'; const button = document.body.querySelector('button#add-cover-art-submit'); if (button == null) throw 'Submit button not found'; let hadErrors = false, active = true, retryDelay = GM_getValue('retry_delay', 5); const retry = elem => { if (active && elem instanceof HTMLElement && !elem.disabled) elem.click() }; new MutationObserver(function(ml, mo) { 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()))) { hadErrors = true; if (active) setTimeout(retry, retryDelay * 1000 || 0, mutation.target); let btnCancel = document.body.querySelector('button#autoretry'); if (btnCancel == null) { const captions = ['Suspend AutoRetry', 'Resume AutoRetry']; btnCancel = Object.assign(document.createElement('button'), { textContent: captions[0], id: 'autoretry', style: 'padding: 5px 10px 5px 7px;', onclick: function(evt) { evt.currentTarget.textContent = captions[(active = !active) ? 0 : 1]; return false; }, }); button.insertAdjacentElement('afterend', btnCancel); } } else if (hadErrors) { //mo.disconnect(); let btnCancel = document.body.querySelector('button#cancel-autoretry'); if (btnCancel != null) btnCancel.remove(); active = true; GM_notification({ text: 'Successfully completed', title: 'MusicBrainz', highlight: true, silent: false, }); } }).observe(button, { attributes: true, attributeFilter: ['disabled'] }); }