Greasy Fork is available in English.

Twitch Latency on Player Controls

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.4
// @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 = 1100; // 1.1 seconds

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

    function createLatencyDiv() {
        const controlGroup = document.querySelector(".player-controls__right-control-group");
        const latencyDiv = document.createElement('div');
        latencyDiv.id = 'userScript_latencyDiv';
        latencyDiv.textContent = '0:00';
        controlGroup.insertAdjacentElement("afterbegin", latencyDiv);
        return latencyDiv;
    }

    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(latencyDiv) {
        const latencyElement = document.querySelector("p[aria-label='Latency To Broadcaster']");
        if (latencyElement) {
            latencyDiv.textContent = latencyElement.textContent;
        }
    }

    async function init() {
        const latencyDiv = createLatencyDiv();
        await openVideoStats();

        setInterval(() => updateLatency(latencyDiv), LATENCY_UPDATE_INTERVAL);
    }

    // Wait for the page to load before initializing
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();