Auto-retry for Doubledouble.top

Automatically retries downloads on doubledouble.top after 10 seconds if an error is encountered. Gives up after 15 retries. Also ensures the 'private' checkbox is checked. Based on 'Auto Retry for lucida.to' by cracktorio.

// ==UserScript==
// @name         Auto-retry for Doubledouble.top
// @author       ap
// @namespace    https://github.com/appel/userscripts
// @version      0.1
// @description  Automatically retries downloads on doubledouble.top after 10 seconds if an error is encountered. Gives up after 15 retries. Also ensures the 'private' checkbox is checked. Based on 'Auto Retry for lucida.to' by cracktorio.
// @match        *://doubledouble.top/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const MAX_RETRIES = 15; // Max retry attempts
    const RETRY_SECONDS = 10; // Configurable countdown time in seconds
    let retryCount = 0;
    let isRetryScheduled = false;
    let retriesHalted = false;
    let countdownIntervalId = null;

    const errorDivSelector = '#error';
    const downloadButtonSelector = '#dl-button';
    const privateCheckboxSelector = '#private';

    console.log(`Retry countdown set to ${RETRY_SECONDS} seconds.`);

    const bannerElement = document.createElement('div');
    const messageSpan = document.createElement('span');
    const cancelButton = document.createElement('button');

    Object.assign(bannerElement.style, {
        position: 'fixed',
        top: '0',
        left: '0',
        width: '100%',
        padding: '12px',
        backgroundColor: 'rgba(20, 20, 20, 0.9)',
        color: 'white',
        zIndex: '9999',
        fontFamily: 'sans-serif',
        fontSize: '16px',
        textAlign: 'center',
        display: 'none',
        boxSizing: 'border-box'
    });

    Object.assign(cancelButton.style, {
        marginLeft: '20px',
        padding: '5px 10px',
        border: '1px solid #ccc',
        borderRadius: '4px',
        backgroundColor: '#555',
        color: 'white',
        cursor: 'pointer'
    });
    cancelButton.textContent = 'Cancel retries';

    bannerElement.appendChild(messageSpan);
    bannerElement.appendChild(cancelButton);
    document.body.appendChild(bannerElement);

    cancelButton.addEventListener('click', () => {
        console.log("Retry cancelled by user.");
        clearInterval(countdownIntervalId);
        retriesHalted = true;
        isRetryScheduled = false;
        messageSpan.textContent = 'Auto-retry cancelled. Reload to try again.';
        bannerElement.style.color = '#FF4136'; // Red
        cancelButton.style.display = 'none';
    });


    const runTasks = () => {
        const privateCheckbox = document.querySelector(privateCheckboxSelector);
        if (privateCheckbox) {
            if (privateCheckbox.disabled) privateCheckbox.disabled = false;
            if (!privateCheckbox.checked) privateCheckbox.checked = true;
        }

        const isErrorVisible = document.querySelector(errorDivSelector) && window.getComputedStyle(document.querySelector(errorDivSelector)).display !== 'none';

        if (isErrorVisible) {
            if (isRetryScheduled || retriesHalted) return; // A retry is busy or has been stopped

            if (retryCount < MAX_RETRIES) {
                isRetryScheduled = true;
                retryCount++;
                let countdown = RETRY_SECONDS; // Use the configurable variable

                console.log(`Error detected. Starting ${RETRY_SECONDS}s countdown for retry #${retryCount}.`);
                messageSpan.textContent = `Error detected. Auto-retry attempt ${retryCount} of ${MAX_RETRIES} in ${countdown}...`;
                bannerElement.style.color = '#FFD700'; // Gold
                cancelButton.style.display = 'inline-block';
                bannerElement.style.display = 'block';

                countdownIntervalId = setInterval(() => {
                    countdown--;
                    messageSpan.textContent = `Error detected. Auto-retry attempt ${retryCount} of ${MAX_RETRIES} in ${countdown}...`;
                    if (countdown <= 0) {
                        clearInterval(countdownIntervalId);
                        console.log(`Executing retry attempt #${retryCount}.`);
                        document.querySelector(downloadButtonSelector)?.click();
                        isRetryScheduled = false;
                        bannerElement.style.display = 'none'; // Hide banner after click
                    }
                }, 1000);

            } else {
                retriesHalted = true;
                console.log("Max retry limit reached. Halting auto-retry.");
                messageSpan.textContent = `Max retry limit of ${MAX_RETRIES} was reached. Please intervene manually.`;
                bannerElement.style.color = '#FF4136';
                cancelButton.style.display = 'none';
                bannerElement.style.display = 'block';
            }

        } else {
            if (isRetryScheduled) {
                clearInterval(countdownIntervalId);
                isRetryScheduled = false;
            }
            if (retryCount > 0 || retriesHalted) {
                console.log("No error detected. Resetting retry state.");
                retryCount = 0;
                retriesHalted = false;
                bannerElement.style.display = 'none';
            }
        }
    };

    // Run the main task function every second to keep checking the page state.
    setInterval(runTasks, 1000);

})();

QingJ © 2025

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