Discogs Draft Cleaner

Deletes All Discog Submission Drafts on the Page. Adds a "Delete All" button under "Add a Release" on Discogs submissions/drafts pages to delete all submissions. Clicking the button will click all delete-draft buttons and confirm, shoutout Foolz_.

// ==UserScript==
// @name         Discogs Draft Cleaner
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Deletes All Discog Submission Drafts on the Page. Adds a "Delete All" button under "Add a Release" on Discogs submissions/drafts pages to delete all submissions. Clicking the button will click all delete-draft buttons and confirm, shoutout Foolz_.
// @author       nj4442
// @license      CC-BY-4.0
// @match        https://www.discogs.com/*
// @match        https://www.discogs.com/users/drafts*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Utility to wait for an element to appear
    function waitForElement(selector, timeout = 10000) {
        return new Promise((resolve, reject) => {
            const interval = 100;
            let elapsed = 0;
            const timer = setInterval(() => {
                const el = document.querySelector(selector);
                if (el) {
                    clearInterval(timer);
                    resolve(el);
                } else if (elapsed >= timeout) {
                    clearInterval(timer);
                    reject(new Error('Element not found: ' + selector));
                }
                elapsed += interval;
            }, interval);
        });
    }

    // Simulate a click
    function simulateClick(element) {
        if (!element) return;
        element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
    }

    // Main deletion logic
    async function autoDelete() {
        let deleteButtons = Array.from(document.querySelectorAll('button.button-red.delete-draft'));

        // If none found, exit
        if (deleteButtons.length === 0) {
            alert("No delete buttons found.");
            return;
        }

        for (let btn of deleteButtons) {
            // Click the delete button
            simulateClick(btn);

            // Wait for the modal to appear
            try {
                await waitForElement('.react-modal .react-modal-title');
                // Confirm it's the correct modal by checking title/content
                let title = document.querySelector('.react-modal .react-modal-title');
                if (title && /confirm/i.test(title.textContent)) {
                    // Find and click the Okay button in the modal (look for span "Okay")
                    let okayBtn = Array.from(document.querySelectorAll('.react-modal button')).find(b =>
                        Array.from(b.querySelectorAll('span')).some(s => /okay/i.test(s.textContent))
                    );
                    if (okayBtn) {
                        simulateClick(okayBtn);
                        // Wait for DOM to update/remove the deleted item
                        await new Promise(r => setTimeout(r, 1500));
                    }
                }
            } catch (e) {
                // Modal didn't appear, skip
                continue;
            }
        }
        alert("All visible drafts/submissions deleted. Refresh to check for more.");
    }

    // Create and inject the "Delete All" button below the "Add a Release" button
    function addDeleteAllButton() {
        if (document.getElementById('userscript-delete-all-btn')) return; // avoid duplicates

        // Find the "Add a Release" button
        let addReleaseBtn = document.querySelector('a.button.button-green.fright[href="/release/add"]');
        if (!addReleaseBtn) return;

        // Create the Delete All button
        let btn = document.createElement('button');
        btn.id = 'userscript-delete-all-btn';
        btn.innerHTML = `<span style="display:inline-block;vertical-align:middle;font-size:20px;line-height:20px;color:#fff;background:none;margin-right:8px;">
            <svg width="20" height="20" viewBox="0 2 20 20" style="vertical-align:middle;">
                <rect x="4" y="9" width="15" height="3.5" rx="2" fill="#fff"/>
            </svg>
        </span>
        <span style="vertical-align:middle;">Delete All Drafts</span>`;

        btn.className = 'Info';
        btn.style.marginTop = '0px';
        btn.style.marginLeft = '100px';
        btn.style.background = '#c00';
        btn.style.color = '#fff';
        btn.style.padding = '4.5px 15px';
        btn.style.border = 'none';
        btn.style.borderRadius = '4px';
        btn.style.fontSize = '15px';
        btn.style.fontWeight = 'normal';
        btn.style.cursor = 'pointer';
        btn.style.boxShadow = '0 0px 0px rgba(0,0,0,0.2)';
        btn.onmouseenter = () => btn.style.background = '#a00';
        btn.onmouseleave = () => btn.style.background = '#c00';
        btn.onclick = function() {
            if (confirm('Are you sure you want to delete ALL visible drafts/submissions? This cannot be undone!')) {
                autoDelete();
            }
        };

        // Insert after the Add a Release button
        addReleaseBtn.parentNode.insertBefore(btn, addReleaseBtn.nextSibling);
    }

    // Only show button on likely drafts/submissions page
    function maybeAddButton() {
        if (/submissions|drafts/i.test(window.location.pathname)) {
            addDeleteAllButton();
        }
    }

    // Initial run
    maybeAddButton();

    // Listen for SPA navigation
    let lastUrl = location.href;
    setInterval(() => {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            maybeAddButton();
        }
    }, 1000);
})();

QingJ © 2025

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