您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Takes the Latency to Broadcaster in the video settings menu and places it in the player controls
// ==UserScript== // @name Twitch Latency on Player Controls // @namespace http://tampermonkey.net/ // @version 0.8 // @description Takes the Latency to Broadcaster in the video settings menu and places it in the player controls // @author tunacan_man // @match https://www.twitch.tv/* // @grant none // ==/UserScript== (function() { 'use strict'; const LATENCY_UPDATE_INTERVAL = 1000; // 1 seconds const REINITIALIZE_INTERVAL = 2000; let initialized = false; let latencyDiv = null; let chatLatencyDiv = null; let updateIntervalId = null; function waitForElement(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { observer.disconnect(); resolve(document.querySelector(selector)); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } async function createLatencyDiv() { const controlGroup = await waitForElement(".player-controls__right-control-group"); if (!controlGroup) return null; const existingDiv = document.getElementById('userScript_latencyDiv'); if (existingDiv) return existingDiv; const latencyDiv = document.createElement('div'); latencyDiv.id = 'userScript_latencyDiv'; latencyDiv.textContent = '0:00'; controlGroup.insertAdjacentElement("afterbegin", latencyDiv); return latencyDiv; } async function createChatLatencyDiv() { const chatTextArea = await waitForElement(".chat-input__textarea"); if (!chatTextArea) return null; const existingDiv = document.getElementById('userScript_chatLatencyDiv'); if (existingDiv) return existingDiv; const chatLatencyDiv = document.createElement('span'); chatLatencyDiv.id = 'userScript_chatLatencyDiv'; chatLatencyDiv.textContent = '0.00'; chatLatencyDiv.setAttribute("style", "position: absolute;top: -6px;left: 40px;font-size: smaller;color: #eb0400;background-color: #18181b; padding:0px 4px;display: none;"); chatTextArea.insertAdjacentElement("beforeend", chatLatencyDiv); return chatLatencyDiv; } async function openVideoStats() { const settingsButton = await waitForElement("button[data-a-target='player-settings-button']"); settingsButton.click(); const advancedButton = await waitForElement("button[data-a-target='player-settings-menu-item-advanced']"); advancedButton.click(); const toggleInput = await waitForElement("div[data-a-target='player-settings-submenu-advanced-video-stats']"); toggleInput.children[0].click(); const videoStatsDiv = await waitForElement("div[data-a-target='player-overlay-video-stats']"); videoStatsDiv.style.display = "none"; settingsButton.click(); // Close the settings menu } function updateLatency() { if (!latencyDiv) return; if (!chatLatencyDiv) return; const latencyElement = document.querySelector("p[aria-label='Latency To Broadcaster']"); if (latencyElement) { latencyDiv.textContent = latencyElement.textContent; let latency = parseFloat(latencyDiv.textContent.slice(0, -5)); if (latency > 12) { // latencyDiv.style.color = "#eb0400"; chatLatencyDiv.textContent = "⚠️" + latency.toFixed(2); chatLatencyDiv.style.display = "inherit"; chatLatencyDiv.style.border = "1px solid #eb0400"; chatLatencyDiv.style.color = "#eb0400"; // document.querySelector("div[data-a-target='chat-input']").style.borderTop = "2px solid #eb0400"; document.querySelector("div[data-a-target='chat-input']").style.borderRadius = "inherit"; } else if (latency > 7) { // latencyDiv.style.color = "#eb0400"; chatLatencyDiv.textContent = "⚠️" + latency.toFixed(2); chatLatencyDiv.style.display = "inherit"; // chatLatencyDiv.style.border = "1px solid #eacb00"; chatLatencyDiv.style.border = "none"; chatLatencyDiv.style.color = "#eacb00"; // document.querySelector("div[data-a-target='chat-input']").style.borderTop = "1px solid #eacb00"; document.querySelector("div[data-a-target='chat-input']").style.borderRadius = "inherit"; } else { latencyDiv.style.color = "#ececec"; chatLatencyDiv.style.display = "none"; // document.querySelector("div[data-a-target='chat-input']").style.borderTop = "inherit"; document.querySelector("div[data-a-target='chat-input']").style.borderRadius = "inherit"; } } } function startUpdatingLatency() { if (updateIntervalId !== null) { clearInterval(updateIntervalId); } updateIntervalId = setInterval(updateLatency, LATENCY_UPDATE_INTERVAL); } async function init() { if (initialized) return; latencyDiv = await createLatencyDiv(); if (!latencyDiv) { console.error('LATENCY SCRIPT: Failed to create latency div'); return; } chatLatencyDiv = await createChatLatencyDiv(); if (!chatLatencyDiv) { console.error('LATENCY SCRIPT: Failed to create chat latency div'); return; } await openVideoStats(); startUpdatingLatency(); initialized = true; console.log('LATENCY SCRIPT: initialized'); } function reinitialize() { if (!document.querySelector(".player-controls__right-control-group") || !document.body.contains(latencyDiv) || !document.querySelector("div[data-a-target='player-overlay-video-stats']") || !document.body.contains(chatLatencyDiv)) { initialized = false; latencyDiv = null; chatLatencyDiv = null; if (updateIntervalId !== null) { clearInterval(updateIntervalId); updateIntervalId = null; } console.log('LATENCY SCRIPT: Reinitializing script due to missing elements'); init(); } } // Initial setup if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // Periodic reinitialization check setInterval(reinitialize, REINITIALIZE_INTERVAL); })();