Pulls from TrackerStatus API and displays status on supported trackers
// ==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);
});
})();