Rule34 Bulk Unfavorite

Automatically remove all favorites from rule34.xxx using AJAX and auto-refresh to handle pagination.

// ==UserScript==
// @name         Rule34 Bulk Unfavorite
// @version      1.5
// @description  Automatically remove all favorites from rule34.xxx using AJAX and auto-refresh to handle pagination.
// @author       https://github.com/binge-coder
// @match        *://rule34.xxx/index.php?page=favorites*
// @run-at       document-end
// @namespace    https://github.com/binge-coder
// @license      GNU GPLv3
// ==/UserScript==


(function() {
    'use strict';

    // Delay (in ms) between individual removals
    const removalDelay = 1000;
    // Delay (in ms) before refreshing the page after processing a batch
    const refreshDelay = 2000;
    // Set to true to auto-run the removal process on page load if favorites are found
    const autoRun = true;

    function processFavoritesBatch() {
        // Find all <b> elements whose text is exactly "Remove" (ignoring case/whitespace)
        let removeButtons = Array.from(document.querySelectorAll('b'))
            .filter(b => b.textContent.trim().toLowerCase() === "remove")
            .map(b => b.closest('a'))
            .filter(a => a !== null);

        console.log("Found", removeButtons.length, "remove buttons on this page.");

        if(removeButtons.length === 0) {
            console.log("No favorites found on this page. Process complete.");
            return;
        }

        let index = 0;
        function removeNext() {
            if(index >= removeButtons.length) {
                console.log("Batch complete. Refreshing page in", refreshDelay, "ms...");
                // After processing the current page, refresh it to load the next batch (if any)
                setTimeout(() => location.reload(), refreshDelay);
                return;
            }
            let button = removeButtons[index];
            let onclickStr = button.getAttribute("onclick");
            // Extract the URL from the onclick attribute, e.g. document.location='index.php?page=favorites&s=delete&id=12345&return_pid=0'
            let match = onclickStr && onclickStr.match(/document\.location\s*=\s*'(.*?)'/);
            if(match && match[1]) {
                let url = match[1];
                console.log("Removing favorite via URL:", url);
                // Use fetch to perform the removal without reloading the page
                fetch(url, { credentials: 'include' })
                    .then(response => response.text())
                    .then(text => {
                        console.log("Removed favorite at index", index);
                        // Optionally, remove the element from the DOM:
                        // button.closest('div')?.remove();
                        index++;
                        setTimeout(removeNext, removalDelay);
                    })
                    .catch(err => {
                        console.error("Error removing favorite at index", index, err);
                        index++;
                        setTimeout(removeNext, removalDelay);
                    });
            } else {
                console.warn("No URL found in onclick for button", button);
                index++;
                setTimeout(removeNext, removalDelay);
            }
        }
        removeNext();
    }

    // Optionally add a manual "Remove All Favorites" button in the top-right corner
    function addManualButton() {
        let startButton = document.createElement("button");
        startButton.innerText = "Remove All Favorites";
        startButton.style.position = "fixed";
        startButton.style.top = "10px";
        startButton.style.right = "10px";
        startButton.style.zIndex = "1000";
        startButton.style.padding = "10px";
        startButton.style.backgroundColor = "red";
        startButton.style.color = "white";
        startButton.style.border = "none";
        startButton.style.cursor = "pointer";
        startButton.onclick = processFavoritesBatch;
        document.body.appendChild(startButton);
    }

    addManualButton();

    // Auto-run the removal process on page load if favorites exist on the current page.
    if(autoRun) {
        let removeButtons = Array.from(document.querySelectorAll('b'))
            .filter(b => b.textContent.trim().toLowerCase() === "remove");
        if(removeButtons.length > 0) {
            console.log("Auto-run enabled and favorites found. Starting removal process...");
            processFavoritesBatch();
        } else {
            console.log("Auto-run enabled but no favorites found on this page.");
        }
    }
})();