Twitch Auto Theater and Statistics

Auto theater Twitch video and show statistics

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Twitch Auto Theater and Statistics
// @namespace    http://tampermonkey.net/
// @version      2.0.0
// @description  Auto theater Twitch video and show statistics
// @author       JoseBaGra
// @match        *.twitch.tv/*
// @match        twitch.tv/*
// @match        https://twitch.tv/*
// @icon         https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://twitch.tv
// @license      MIT
// ==/UserScript==
const videoStatsTheatreClass = 'video-stats-theatre';
const videoStatsPlayerControlsVisible = 'video-stats-player-controls-vissible';
const videoStatsVolumeSliderFullWidth = 'video-stats-volume-full-width';

const style = `<style id="xCustomCSS" type="text/css" class="stylus">
:root {
    --zindex: 1;
}
.${videoStatsTheatreClass} {
    position: fixed;
    bottom: 0;
    left: 0;
    z-index: 99999;
    font-weight: bold;
    opacity:0.7;
    zoom:0.9;
    pointer-events: none;
    padding: 10px;
}
.${videoStatsPlayerControlsVisible} {
  padding-left: 70px;
}
.${videoStatsVolumeSliderFullWidth} {
  padding-left: 190px;
}
</style>`;

const videoStatsQuery =
  '.metadata-layout__support + div > div:nth-child(2) div div div';
const videoPlayerQuery = '.video-player__container';
const theatreModeButtonQuery = '[aria-label="Theatre Mode (alt+t)"]';
const videoPlayerTheatreClass = 'video-player__container--theatre';
const videoPlayerControlsClass = '.player-controls';
const volumeSliderClass = '.volume-slider__slider-container';
const sevenTVStylesheetID = '#seventv-stylesheet';

const stylesIntervalID = setInterval(() => {
  if (!document.getElementById('xCustomCSS')) {
    document.body.insertAdjacentHTML('afterend', style);
    clearInterval(stylesIntervalID);
  }
}, 200);

const videoObserver = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.attributeName === 'class') {
      const videoStats = document.querySelector(videoStatsQuery);
      if (videoStats) {
        if (mutation.target.classList.contains(videoPlayerTheatreClass)) {
          videoStats.classList.add(videoStatsTheatreClass);
        } else {
          videoStats.classList.remove(videoStatsTheatreClass);
        }
      }
    }
  });
});

const videoPlayerControlsObserver = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.attributeName === 'data-a-visible') {
      const videoStats = document.querySelector(videoStatsQuery);
      const videoPlayerControls = document.querySelector(
        videoPlayerControlsClass,
      );
      if (videoPlayerControls && videoStats) {
        if (videoPlayerControls.dataset.aVisible === 'true') {
          videoStats.classList.add(videoStatsPlayerControlsVisible);
        } else {
          videoStats.classList.remove(videoStatsPlayerControlsVisible);
        }
      }
    }
  });
});

const volumeSliderObserver = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.attributeName === 'aria-hidden') {
      const videoStats = document.querySelector(videoStatsQuery);
      const volumeSlider = document.querySelector(volumeSliderClass);
      if (volumeSlider && videoStats) {
        if (volumeSlider.getAttribute('aria-hidden') !== 'true') {
          videoStats.classList.add(videoStatsVolumeSliderFullWidth);
        } else {
          videoStats.classList.remove(videoStatsVolumeSliderFullWidth);
        }
      }
    }
  });
});

const createObsever = setInterval(() => {
  const videoPlayer = document.querySelector(videoPlayerQuery);
  const videoPlayerControls = document.querySelector(videoPlayerControlsClass);
  const volumeSlider = document.querySelector(volumeSliderClass);
  if (videoPlayer) {
    videoObserver.observe(videoPlayer, { attributes: true });
    videoPlayerControlsObserver.observe(videoPlayerControls, {
      attributes: true,
    });
    volumeSliderObserver.observe(volumeSlider, { attributes: true });
    clearInterval(createObsever);
  }
}, 200);

const waitForNewVideoStatsForAddTheTheatreClass = (videoStats) => {
  const newVideoStats = document.querySelector(videoStatsQuery);
  if (newVideoStats !== videoStats) {
    newVideoStats.classList.add(videoStatsTheatreClass);
    return;
  }
  setTimeout(waitForNewVideoStatsForAddTheTheatreClass, 0, videoStats);
};

const enterTheaterMode = setInterval(() => {
  const videoStats = document.querySelector(videoStatsQuery);
  const sevenTVStylesheet = document.querySelector(sevenTVStylesheetID);
  if (videoStats) {
    clearInterval(enterTheaterMode);
    document.querySelector(theatreModeButtonQuery).click();
    waitForNewVideoStatsForAddTheTheatreClass(videoStats);

    if (sevenTVStylesheet) {
      setInterval(() => {
        const videoPlayer = document.querySelector(videoPlayerQuery);
        const videoStats = document.querySelector(videoStatsQuery);
        if (videoPlayer.classList.contains(videoPlayerTheatreClass)) {
          videoStats.classList.add(videoStatsTheatreClass);
        } else {
          videoStats.classList.remove(videoStatsTheatreClass);
        }
      }, 1000 * 60); // 1000ms & 60 = 60 seconds
    }
  }
}, 200);