Greasy Fork is available in English.

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