Greasy Fork is available in English.
Displays the Twitch and Kick play latency
当前为
// ==UserScript==
// @name Twitch & Kick Latency
// @namespace latency
// @version 1.3
// @description Displays the Twitch and Kick play latency
// @author frz
// @match https://www.twitch.tv/*
// @match https://kick.com/*
// @icon https://www.allkeyshop.com/blog/wp-content/uploads/Twitch-vs-Kick_featured.png
// @grant none
// ==/UserScript==
(function () {
'use strict';
let header = null;
const platform = location.hostname.includes('kick.com') ? 'kick' : 'twitch';
function styleHeader(el) {
el.style.display = 'flex';
el.style.alignItems = 'center';
el.style.justifyContent = 'center';
el.style.color = '#FFFFFF';
el.style.fontWeight = '600';
el.style.fontSize = '15px';
el.style.cursor = 'pointer';
el.style.gap = '6px';
}
function createRedDot() {
const dot = document.createElement('span');
dot.style.display = 'inline-block';
dot.style.width = '8px';
dot.style.height = '8px';
dot.style.borderRadius = '50%';
dot.style.backgroundColor = '#FF4B4B';
dot.id = 'latency-red-dot';
return dot;
}
function getLatency() {
const video = document.querySelector('video');
if (!video || !video.buffered || video.buffered.length === 0) return null;
const latency = video.buffered.end(video.buffered.length - 1) - video.currentTime;
return latency > 0 ? latency.toFixed(2) : '0.00';
}
function updateText() {
if (!header) return;
const latency = getLatency();
if (latency === null) return;
// Очищаем текст, чтобы убрать "Чат"/"Чат трансляции"
header.textContent = '';
let dot = document.getElementById('latency-red-dot');
if (!dot) {
dot = createRedDot();
}
header.appendChild(dot);
const textNode = document.createElement('span');
textNode.className = 'latency-text';
textNode.textContent = `Latency: ${latency}s`;
header.appendChild(textNode);
}
function createPlatformSpinner() {
let spinner = document.getElementById('latency-spinner');
if (!spinner) {
let spinnerTemplate;
if (platform === 'twitch') {
spinnerTemplate = document.querySelector('[data-a-target="tw-loading-spinner"]');
} else {
spinnerTemplate = document.querySelector('[data-testid="loading-spinner"]');
}
spinner = spinnerTemplate ? spinnerTemplate.cloneNode(true) : document.createElement('div');
spinner.id = 'latency-spinner';
spinner.style.position = 'absolute';
spinner.style.top = '50%';
spinner.style.left = '50%';
spinner.style.transform = 'translate(-50%, -50%)';
spinner.style.zIndex = '9999';
spinner.style.display = 'none';
const video = document.querySelector('video');
if (video && video.parentElement) video.parentElement.appendChild(spinner);
}
return spinner;
}
function reloadPlayerWithSpinner() {
const video = document.querySelector('video');
if (!video) return;
const spinner = createPlatformSpinner();
spinner.style.display = 'block';
const currentTime = video.currentTime;
video.pause();
setTimeout(() => {
try {
video.currentTime = currentTime;
video.play().catch(() => {});
} catch {
location.reload();
}
spinner.style.display = 'none';
}, 1200);
}
function observeHeader() {
let candidate;
if (platform === 'twitch') {
candidate = document.querySelector('#chat-room-header-label');
} else {
candidate = Array.from(document.querySelectorAll('span.absolute')).find(
el => el.textContent.trim() === 'Чат'
);
}
if (candidate && candidate !== header) {
header = candidate;
styleHeader(header);
header.addEventListener('click', reloadPlayerWithSpinner);
updateText();
}
}
const observer = new MutationObserver(observeHeader);
observer.observe(document.body, { childList: true, subtree: true });
setInterval(updateText, 2000);
})();