Is it Down? (Updated)

Pulls from TrackerStatus API and displays status on supported trackers

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Is it Down? (Updated)
// @version      0.6.2
// @namespace    https://trackerstatus.info/
// @description  Pulls from TrackerStatus API and displays status on supported trackers
// @match        https://redacted.sh/*
// @match        https://orpheus.network/*
// @match        https://passthepopcorn.me/*
// @match        https://broadcasthe.net/*
// @match        https://gazellegames.net/*
// @match        https://alpharatio.cc/*
// @match        https://anthelion.me/*
// @match        https://nebulance.io/*
// @grant        GM.xmlHttpRequest
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    const Settings = {
        showIfStable: false,
        checkInterval: 120000, // check every 2 mins by default
        apiEndpoints: {
            'redacted.sh': 'https://red.trackerstatus.info/api/all/',
            'orpheus.network': 'https://ops.trackerstatus.info/api/all/',
            'passthepopcorn.me': 'https://ptp.trackerstatus.info/api/all/',
            'broadcasthe.net': 'https://btn.trackerstatus.info/api/all/',
            'gazellegames.net': 'https://ggn.trackerstatus.info/api/all/',
            'alpharatio.cc': 'https://ar.trackerstatus.info/api/all/',
            'anthelion.me': 'https://ant.trackerstatus.info/api/all/',
            'nebulance.io': 'https://nbl.trackerstatus.info/api/all/'
        }
    };

    const styles = `
        .tracker-status {
            position: fixed;
            z-index: 9999;
            box-sizing: border-box;
            width: 100%;
            display: none;
            padding: 0.2rem;
            bottom: 0;
            left: 0;
            font-size: 14px;
            text-align: center;
        }
        .tracker-status--stable { background-color: #056B00; }
        .tracker-status--offline { background-color: #A00E0E; }
        .tracker-status--unstable { background-color: #FFA500; }
        .tracker-status--both { background-color: #FF4B33; }
        .tracker-status__message {
            color: white;
            font-weight: bold;
            margin: 0;
            padding-right: 30px;
        }
        .tracker-status__link {
            color: white;
            text-decoration: underline;
        }
        .tracker-status__close {
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            color: white;
            font-size: 20px;
            cursor: pointer;
            border: none;
            background: none;
            padding: 0;
            width: 20px;
            height: 20px;
            line-height: 20px;
            text-align: center;
        }
        .tracker-status__close:hover {
            opacity: 0.8;
        }
        body {
            transition: margin-bottom 0.3s ease;
        }
    `;

    function createStatusElement() {
        const trackerStatus = document.createElement('div');
        trackerStatus.className = 'tracker-status';

        const message = document.createElement('p');
        message.className = 'tracker-status__message';

        const closeButton = document.createElement('button');
        closeButton.className = 'tracker-status__close';
        closeButton.innerHTML = '×';
        closeButton.title = 'Close';

        trackerStatus.appendChild(message);
        trackerStatus.appendChild(closeButton);
        document.body.append(trackerStatus);

        return { trackerStatus, closeButton };
    }

    function updateMarginBottom(trackerStatus) {
        const statusHeight = trackerStatus.offsetHeight;
        document.body.style.marginBottom = trackerStatus.style.display !== 'none' ? `${statusHeight}px` : '0';
    }

    function updateStatus(trackerStatus) {
        const currentDomain = window.location.hostname;
        const apiUrl = Settings.apiEndpoints[currentDomain];

        if (!apiUrl) {
            console.error('No API endpoint found for the current domain');
            return;
        }

        const infoUrl = apiUrl.replace('/api/all/', '');

        GM.xmlHttpRequest({
            method: 'GET',
            url: apiUrl,
            onload: function(response) {
                const messageElement = trackerStatus.querySelector('.tracker-status__message');

                if (response.status >= 200 && response.status < 400) {
                    let services;
                    try {
                        services = JSON.parse(response.responseText);
                    } catch (e) {
                        console.error('Failed to parse API response:', e);
                        trackerStatus.className = 'tracker-status tracker-status--offline';
                        messageElement.innerHTML = 'Error parsing tracker status.';
                        trackerStatus.style.display = 'block';
                        updateMarginBottom(trackerStatus);
                        return;
                    }

                    const entries = Object.entries(services);
                    const downServices = entries.filter(service => service[1].Status === '0');
                    const unstableServices = entries.filter(service => service[1].Status === '2');

                    let isStable = false;
                    if (downServices.length > 0 && unstableServices.length > 0) {
                        trackerStatus.className = 'tracker-status tracker-status--both';
                        messageElement.innerHTML = `The following services are currently offline or unstable: ${downServices.concat(unstableServices).map(service => service[0]).join(', ')}. <a class="tracker-status__link" href="${infoUrl}">More info</a>`;
                    } else if (downServices.length > 0) {
                        trackerStatus.className = 'tracker-status tracker-status--offline';
                        messageElement.innerHTML = `The following services are currently offline: ${downServices.map(service => service[0]).join(', ')}. <a class="tracker-status__link" href="${infoUrl}">More info</a>`;
                    } else if (unstableServices.length > 0) {
                        trackerStatus.className = 'tracker-status tracker-status--unstable';
                        messageElement.innerHTML = `The following services are unstable: ${unstableServices.map(service => service[0]).join(', ')}. <a class="tracker-status__link" href="${infoUrl}">More info</a>`;
                    } else {
                        isStable = true;
                        trackerStatus.className = 'tracker-status tracker-status--stable';
                        messageElement.textContent = 'All systems operational.';
                        trackerStatus.style.display = Settings.showIfStable ? 'block' : 'none';
                    }

                    if (!isStable && trackerStatus.style.display !== 'block') {
                        trackerStatus.style.display = 'block';
                    }
                } else {
                    console.error('Error fetching tracker status');
                    trackerStatus.className = 'tracker-status tracker-status--offline';
                    messageElement.innerHTML = 'Error fetching tracker status.';
                    trackerStatus.style.display = 'block';
                }

                updateMarginBottom(trackerStatus);
            },
            onerror: function(error) {
                console.error('Error fetching tracker status:', error);
                const messageElement = trackerStatus.querySelector('.tracker-status__message');
                trackerStatus.className = 'tracker-status tracker-status--offline';
                messageElement.innerHTML = 'Error fetching tracker status.';
                trackerStatus.style.display = 'block';

                updateMarginBottom(trackerStatus);
            }
        });
    }

    const styleElement = document.createElement('style');
    styleElement.textContent = styles;
    document.head.appendChild(styleElement);

    const { trackerStatus, closeButton } = createStatusElement();
    updateStatus(trackerStatus);
    const intervalId = setInterval(() => updateStatus(trackerStatus), Settings.checkInterval);

    closeButton.addEventListener('click', () => {
        trackerStatus.style.display = 'none';
        updateMarginBottom(trackerStatus);
        clearInterval(intervalId);
    });

    window.addEventListener('resize', () => {
        updateMarginBottom(trackerStatus);
    });
})();