Streameast Theater Mode

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