您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
2/15/2025, 4:56:23 PM
// ==UserScript== // @name Streameast Theater Mode // @namespace Violentmonkey Scripts // @include /https:\/\/[\w]*\.(thestreameast|streameast)\.[\w]*/ // @grant none // @version 1.0.1 // @author - // @description 2/15/2025, 4:56:23 PM // ==/UserScript== const streameastUrlRegex = /https:\/\/[\w]*\.(thestreameast|streameast)\.[\w]*\/(mlb|nba|soccer|nhl|nfl|cfb|f1|boxing|ufc|wwe)/; const debugMode = false; const searchTime = 10 * 1000; // how long to search for dom nodes? in ms const searchInterval = 100; // check for dom nodes every how many ms? const maxIterationCount = searchTime / searchInterval; const theaterModeVideoWidth = 80; // A number from 0 to 100, represents how wide (in percent of screen width) you want the video to be const theaterModeVideoWidthStyle = `${theaterModeVideoWidth}%` const theaterModeChatWidthStyle = `${100 - theaterModeVideoWidth}%` let isTheaterModeEnabled = false; const config = { button: { node: null, getNode: () => { return document.getElementById("TiyatroModu"); }, disabled: {}, enabled: { position: "fixed", zIndex: "1001", bottom: "70px", right: `calc(${theaterModeChatWidthStyle} + 10px)` }, }, video: { node: null, getNode: () => { return document.getElementById("PlayerDuzenBolumu"); }, disabled: {}, enabled: { position: "fixed", top: "0px", bottom: "0px", left: "0px", right: theaterModeVideoWidthStyle, width: theaterModeVideoWidthStyle, zIndex: "1000", }, }, iframe: { node: null, getNode: () => { return document.getElementById("iframe"); }, disabled: {}, enabled: { height: "100%", }, }, chat: { node: null, getNode: () => { return document.getElementById("live-chat-iframe"); }, disabled: {}, enabled: { position: "fixed", top: "0px", left: theaterModeVideoWidthStyle, right: "0px", bottom: "0px", width: theaterModeChatWidthStyle, zIndex: "1000" }, } } const applyStyles = (node, styleJson) => { for (const [key, value] of Object.entries(styleJson)) { node.style[key] = value; } } const storeStyles = (node, styleKeys, storageObj) => { for (const key of styleKeys) { storageObj[key] = node.style[key]; } } const applyTheaterModeStyles = () => { for (const key of Object.keys(config)) { const node = config[key].node; storeStyles( node, Object.keys(config[key].enabled), config[key].disabled, ); applyStyles( node, config[key].enabled ); } config["button"].node.onclick = disableTheaterModeStyles; } const disableTheaterModeStyles = () => { for (const key of Object.keys(config)) { const node = config[key].node; applyStyles( node, config[key].disabled ) } config["button"].node.onclick = applyTheaterModeStyles; } const validateConfig = () => { if (typeof theaterModeVideoWidth === "number" && theaterModeVideoWidth >= 0 && theaterModeVideoWidth <= 100) { return true; } return false; } /** * Searches for required dom nodes * and returns true if they are * all found */ const findDomNodes = () => { const nodeKeys = Object.keys(config); for (const key of nodeKeys) { config[key].node = config[key].getNode() } let hasAllNodes = true; for (const key of nodeKeys) { hasAllNodes = hasAllNodes && Boolean(config[key].node) } return hasAllNodes; } const runScript = () => { let intervalCount = 0; let interval = setInterval(() => { intervalCount = intervalCount + 1; const gatheredAllNodes = findDomNodes(); if (gatheredAllNodes || intervalCount > maxIterationCount) { clearInterval(interval); } if (gatheredAllNodes) { config["button"].node.onclick = applyTheaterModeStyles; } }, searchInterval); } const main = () => { const href = window.location.href; const isMatch = href.match(streameastUrlRegex); if (isMatch) { const isValidConfig = validateConfig(); if (isValidConfig) { runScript(); } } } main();