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);
    });
})();