Auto Refresh on Network Errors

Automatically refreshes page when network errors occur

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.greasyfork.org/scripts/551832/1673255/Auto%20Refresh%20on%20Network%20Errors.js

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name Auto Refresh on Network Errors
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Automatically refreshes page when network errors occur - Retries indefinitely
// @author Assistant Pro
// @match *://*/*
// @grant none
// @run-at document-start
// ==/UserScript==

(function() {
    'use strict';

    const config = {
        enableConsoleLogs: true,
        refreshDelay: 5000, // 5 seconds delay before refresh
        checkInterval: 3000, // Check every 3 seconds
        retryDelay: 10000, // Wait 10 seconds between retries
        enableSoundAlert: false // Play sound when network recovers
    };

    let state = {
        refreshCount: 0,
        lastRefreshTime: 0,
        isNetworkError: false,
        lastCheckTime: Date.now()
    };

    // Network error patterns to detect
    const networkErrorPatterns = [
        "We're having trouble finding that site",
        "We can't connect to the server",
        "Try again later",
        "Check your network connection",
        "behind a firewall",
        "This site can't be reached",
        "Unable to connect",
        "Server not found",
        "Network Error",
        "ERR_CONNECTION_",
        "ERR_NAME_NOT_RESOLVED",
        "ERR_INTERNET_DISCONNECTED",
        "Problem loading page",
        "The connection has timed out",
        "The site is temporarily unavailable"
    ];

    // Check if current page shows network error
    function isNetworkErrorPage() {
        // Check page title
        const title = document.title.toLowerCase();
        if (title.includes("problem loading") || 
            title.includes("not found") || 
            title.includes("unable to connect") ||
            title.includes("server not found") ||
            title.includes("this site can't be reached")) {
            return true;
        }

        // Check body text content
        const bodyText = document.body.innerText.toLowerCase();
        for (const pattern of networkErrorPatterns) {
            if (bodyText.includes(pattern.toLowerCase())) {
                return true;
            }
        }

        // Check common error elements
        const errorSelectors = [
            '[class*="error"]',
            '[id*="error"]',
            '[class*="offline"]',
            '[id*="offline"]',
            '.network-error',
            '.dns-error',
            '.connection-error',
            '.error-page',
            '.http-error'
        ];

        for (const selector of errorSelectors) {
            const elements = document.querySelectorAll(selector);
            for (const element of elements) {
                const text = element.innerText.toLowerCase();
                for (const pattern of networkErrorPatterns) {
                    if (text.includes(pattern.toLowerCase())) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    // Check network connectivity
    function checkNetworkConnectivity() {
        return new Promise((resolve) => {
            // Method 1: Navigator online status
            if (!navigator.onLine) {
                resolve(false);
                return;
            }

            // Method 2: Try to fetch a small resource
            const testUrls = [
                'https://www.google.com/favicon.ico?t=' + Date.now(),
                'https://www.cloudflare.com/favicon.ico?t=' + Date.now(),
                'https://www.microsoft.com/favicon.ico?t=' + Date.now()
            ];

            let successCount = 0;
            let completed = 0;

            testUrls.forEach(url => {
                fetch(url, { 
                    method: 'HEAD',
                    cache: 'no-store',
                    mode: 'no-cors'
                })
                .then(() => {
                    successCount++;
                })
                .catch(() => {})
                .finally(() => {
                    completed++;
                    if (completed === testUrls.length) {
                        resolve(successCount > 0);
                    }
                });
            });

            // Timeout after 5 seconds
            setTimeout(() => {
                resolve(successCount > 0);
            }, 5000);
        });
    }

    // Perform smart refresh - NO MAX RETRY LIMIT
    function performSmartRefresh() {
        const now = Date.now();
        const timeSinceLastRefresh = now - state.lastRefreshTime;

        // Don't refresh too frequently
        if (timeSinceLastRefresh < config.retryDelay) {
            if (config.enableConsoleLogs) console.log(`⏳ Too soon to refresh, waiting... (${Math.round((config.retryDelay - timeSinceLastRefresh)/1000)}s)`);
            return;
        }

        state.refreshCount++;
        state.lastRefreshTime = now;
        state.isNetworkError = true;

        if (config.enableConsoleLogs) {
            console.log(`🔄 Auto-refresh attempt ${state.refreshCount} (Retrying until death)`);
            console.log("🌐 Network error detected, refreshing page...");
        }

        // Play sound alert if enabled
        if (config.enableSoundAlert) {
            playNotificationSound();
        }

        // Refresh with a small delay
        setTimeout(() => {
            if (config.enableConsoleLogs) console.log("🔥 FORCING REFRESH NOW!");
            window.location.reload();
        }, config.refreshDelay);
    }

    // Play notification sound
    function playNotificationSound() {
        try {
            const audioContext = new (window.AudioContext || window.webkitAudioContext)();
            const oscillator = audioContext.createOscillator();
            const gainNode = audioContext.createGain();
            
            oscillator.connect(gainNode);
            gainNode.connect(audioContext.destination);
            
            oscillator.frequency.value = 800;
            oscillator.type = 'sine';
            
            gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
            gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);
            
            oscillator.start(audioContext.currentTime);
            oscillator.stop(audioContext.currentTime + 0.5);
        } catch (error) {
            // Sound not supported, continue silently
        }
    }

    // Main monitoring function - RETRY UNTIL DEATH
    function monitorNetworkStatus() {
        const now = Date.now();

        // Check if we're on a network error page
        if (isNetworkErrorPage()) {
            if (config.enableConsoleLogs && !state.isNetworkError) {
                console.log("🚨 NETWORK ERROR PAGE DETECTED! Starting infinite retry...");
            }
            
            // Check if we actually have network connectivity
            checkNetworkConnectivity().then(isOnline => {
                if (isOnline) {
                    if (config.enableConsoleLogs) console.log("✅ Network is online, but page failed to load - REFRESHING!");
                    performSmartRefresh();
                } else {
                    if (config.enableConsoleLogs) console.log("🌐 Network is offline, waiting for connection...");
                    // Wait for network to come back online and retry
                    setTimeout(() => {
                        if (config.enableConsoleLogs) console.log("🔄 Checking again after offline period...");
                        monitorNetworkStatus();
                    }, config.retryDelay);
                    return;
                }
            });
        } else {
            // Reset counter if page loaded successfully
            if (state.isNetworkError) {
                state.isNetworkError = false;
                if (config.enableConsoleLogs) console.log(`✅ Page loaded successfully after ${state.refreshCount} attempts! Continuing to monitor...`);
                state.refreshCount = 0;
            }
        }

        // Continue monitoring FOREVER
        setTimeout(monitorNetworkStatus, config.checkInterval);
    }

    // Setup event listeners
    function setupEventListeners() {
        // Listen for online/offline events
        window.addEventListener('online', () => {
            if (config.enableConsoleLogs) console.log("🌐 NETWORK CONNECTION RESTORED!");
            if (state.isNetworkError) {
                if (config.enableConsoleLogs) console.log("🔄 Network restored, refreshing page in 3 seconds...");
                setTimeout(() => {
                    if (config.enableConsoleLogs) console.log("🔥 REFRESHING AFTER NETWORK RECOVERY!");
                    window.location.reload();
                }, 3000);
            }
        });

        window.addEventListener('offline', () => {
            if (config.enableConsoleLogs) console.log("🌐 NETWORK CONNECTION LOST!");
            state.isNetworkError = true;
        });

        // Listen for page load errors
        window.addEventListener('error', (event) => {
            const error = event.error || event;
            const errorMsg = error.toString();
            if (errorMsg.includes('Loading') || errorMsg.includes('Network') || errorMsg.includes('Fetch')) {
                if (config.enableConsoleLogs) console.log("🚨 Page load error detected:", errorMsg);
                state.isNetworkError = true;
            }
        });

        // Listen for fetch errors
        const originalFetch = window.fetch;
        window.fetch = function(...args) {
            return originalFetch.apply(this, args)
                .catch(error => {
                    if (config.enableConsoleLogs) console.log("🌐 Fetch error detected");
                    state.isNetworkError = true;
                    throw error;
                });
        };

        // Listen for XMLHttpRequest errors
        const originalXHROpen = XMLHttpRequest.prototype.open;
        XMLHttpRequest.prototype.open = function(...args) {
            this.addEventListener('error', () => {
                if (config.enableConsoleLogs) console.log("🌐 XHR error detected");
                state.isNetworkError = true;
            });
            return originalXHROpen.apply(this, args);
        };
    }

    // Initialize
    function init() {
        if (config.enableConsoleLogs) {
            console.log("🔄 AUTO REFRESH ON NETWORK ERRORS - STARTED");
            console.log("🔥 WILL RETRY UNTIL DEATH - NO LIMITS");
            console.log("🌐 Current network status:", navigator.onLine ? "ONLINE" : "OFFLINE");
            console.log("🔧 Monitoring all pages for network errors...");
        }

        setupEventListeners();
        
        // Start monitoring - WILL NEVER STOP
        setTimeout(monitorNetworkStatus, 2000);

        // Add status display
        if (config.enableConsoleLogs) {
            const statusDiv = document.createElement('div');
            statusDiv.innerHTML = `
                <div style="
                    position: fixed;
                    top: 10px;
                    left: 10px;
                    background: #ff4444;
                    color: white;
                    padding: 10px;
                    border-radius: 5px;
                    font-family: Arial;
                    font-size: 12px;
                    z-index: 9999;
                    border: 2px solid #cc0000;
                ">
                    🔄 AUTO-REFRESH ACTIVE<br>
                    Retries: <span id="retryCount">0</span><br>
                    Status: <span id="networkStatus">MONITORING</span>
                </div>
            `;
            document.body.appendChild(statusDiv);
            
            // Update status display
            setInterval(() => {
                const retryElement = document.getElementById('retryCount');
                const statusElement = document.getElementById('networkStatus');
                if (retryElement) retryElement.textContent = state.refreshCount;
                if (statusElement) {
                    statusElement.textContent = state.isNetworkError ? 'RETRYING' : 'MONITORING';
                    statusElement.style.color = state.isNetworkError ? '#ffcc00' : '#00ff00';
                }
            }, 1000);
        }
    }

    // Start the script IMMEDIATELY
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    // Emergency fallback - if somehow monitoring stops, restart it
    setInterval(() => {
        if (!state.lastCheckTime || (Date.now() - state.lastCheckTime > 30000)) {
            if (config.enableConsoleLogs) console.log("🔄 EMERGENCY RESTART OF MONITORING");
            state.lastCheckTime = Date.now();
            monitorNetworkStatus();
        }
    }, 15000);

})();