Greasy Fork is available in English.

YouTube Video Auto Pop-out

Pop-out video to bottom-right when scrolling down to comments

Nainstalovat skript?
Skript doporučený autorem

Mohlo by se vám také líbit YouTube Auto Like.

Nainstalovat skript
// ==UserScript==
// @name         YouTube Video Auto Pop-out
// @namespace    http://tampermonkey.net/
// @version      1.04
// @description  Pop-out video to bottom-right when scrolling down to comments
// @author       You
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function() {
  "use strict";

  let originalStyles;
  const fixedStyles = {
    position: "fixed",
    top: "auto",
    left: "auto",
    bottom: "20px",
    right: "50px",
    zIndex: "1000",
    transition: "none",
  };

  const playButton = `
    <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%">
      <path
        class="ytp-svg-fill"
        d="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z"
      />
    </svg>
  `;
  const pauseButton = `
    <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%">
      <path
        class="ytp-svg-fill"
        d="M 12,26 16,26 16,10 12,10 z M 21,26 25,26 25,10 21,10 z"
      />
    </svg>
  `;

  function printLog(message) {
    console.log(`[YouTube Video Pop-out]: ${message}`);
  }

  function getVideoPlayer() {
    return document.querySelector("video.html5-main-video");
  }

  function videoHasEnded() {
    const video = getVideoPlayer();
    const progress = video.currentTime / video.duration;
    return progress === 1;
  }

  function isValidVideo() {
    return getVideoPlayer().duration > 0;
  }

  function setStyles(elem, propertyObject) {
    for (let property in propertyObject) elem.style[property] = propertyObject[property];
  }

  function getVideoSize(fixed = false) {
    const rect = getVideoPlayer().getBoundingClientRect();
    const width = fixed ? rect.width / 2 : rect.width;
    const height = fixed ? rect.height / 2 : rect.height;
    return {
      width: `${width}px`,
      height: `${height}px`
    };
  }

  function setPlayIcon(button, paused) {
    const icon = paused ? playButton : pauseButton;
    button.innerHTML = icon;
  }

  function setButtonVisible(button, visible) {
    button.style.display = visible ? "block" : "none";
  }

  function removeFixedContainer() {
    const container = document.querySelector("#fixed-container");
    if (container) container.remove();
  }

  function moveVideoToCorner() {
    const videoPlayer = getVideoPlayer();
    if (videoPlayer.classList.contains("in-corner")) return false;

    originalStyles = {
      position: videoPlayer.style.position,
      // top: videoPlayer.style.top,
      // left: videoPlayer.style.left,
      width: getVideoSize().width,
      height: getVideoSize().height,
      zIndex: videoPlayer.style.zIndex,
      transition: videoPlayer.style.transition,
    };
    fixedStyles.width = getVideoSize(true).width;
    fixedStyles.height = getVideoSize(true).height;

    const videoContainer = document.createElement("div");
    videoContainer.setAttribute("id", "fixed-container");
    const containerStyle = {
      ...fixedStyles,
      cursor: "move"
    };
    setStyles(videoContainer, containerStyle);

    const pauseButton = document.createElement("div");
    setPlayIcon(pauseButton, videoPlayer.paused);
    pauseButton.addEventListener("click", () => {
      videoPlayer.paused ? videoPlayer.play() : videoPlayer.pause();
    });
    videoPlayer.addEventListener("play", () => setPlayIcon(pauseButton, false));
    videoPlayer.addEventListener("pause", () => setPlayIcon(pauseButton, true));
    videoPlayer.addEventListener("ended", () => restoreVideoPosition());

    const buttonStyles = {
      display: "none",
      position: "absolute",
      height: "36px",
      top: "calc(50% - 18px)",
      left: "calc(50% - 18px)",
      cursor: "pointer",
      zIndex: "1100",
    };
    setStyles(pauseButton, buttonStyles);
    videoContainer.appendChild(pauseButton);

    setStyles(videoPlayer, {
      width: "100%",
      height: "100%"
    });

    videoPlayer.style.pointerEvents = "none";
    videoPlayer.classList.add("in-corner");
    videoContainer.appendChild(videoPlayer);
    document.querySelector("body").appendChild(videoContainer);

    videoContainer.addEventListener("mouseenter", () => setButtonVisible(pauseButton, true));
    videoContainer.addEventListener("mouseleave", () => setButtonVisible(pauseButton, false));

    makeDraggable(videoContainer);
  }

  function restoreVideoPosition() {
    const videoPlayer = getVideoPlayer();
    if (!videoPlayer.classList.contains("in-corner")) return false;

    setStyles(originalStyles);
    videoPlayer.style.pointerEvents = "auto";
    videoPlayer.classList.remove("in-corner");
    document.querySelector(".html5-video-container").appendChild(videoPlayer);
    document.querySelector("#fixed-container").remove();
  }

  function makeDraggable(elem) {
    let pos1 = 0,
      pos2 = 0,
      pos3 = 0,
      pos4 = 0;

    elem.onmousedown = dragMouseDown;

    function dragMouseDown(e) {
      e = e || window.event;
      // get the mouse cursor position at startup:
      pos3 = e.clientX;
      pos4 = e.clientY;
      document.onmouseup = closeDragElement;
      // call a function whenever the cursor moves:
      document.onmousemove = elementDrag;
    }

    function elementDrag(e) {
      e = e || window.event;
      // calculate the new cursor position:
      pos1 = pos3 - e.clientX;
      pos2 = pos4 - e.clientY;
      pos3 = e.clientX;
      pos4 = e.clientY;
      // set the element's new position:
      const topPosition = elem.offsetTop - pos2 + "px";
      elem.style.top = topPosition;
      fixedStyles.top = topPosition;
      const leftPosition = elem.offsetLeft - pos1 + "px";
      elem.style.left = leftPosition;
      fixedStyles.left = leftPosition;
      fixedStyles.right = "auto";
    }

    function closeDragElement() {
      // stop moving when mouse button is released:
      document.onmouseup = null;
      document.onmousemove = null;
    }
  }

  function isElementInvisible(el) {
    const rect = el.getBoundingClientRect();

    return (
      rect.bottom <= 0 ||
      rect.right <= 0 ||
      rect.top >= (window.innerHeight || document.documentElement.clientHeight) ||
      rect.left >= (window.innerWidth || document.documentElement.clientWidth)
    );
  }

  function scrollListener() {
    const playerSection = document.querySelector("#player");
    const playerIsVisible = isElementInvisible(playerSection);

    if (playerIsVisible && isValidVideo() && !videoHasEnded()) {
      moveVideoToCorner();
    } else {
      restoreVideoPosition();
    }
  }

  document.addEventListener("yt-navigate-finish", () => {
    const isVideoPage = location.pathname === "/watch";
    if (isVideoPage) return document.addEventListener("scroll", scrollListener);
    document.removeEventListener("scroll", scrollListener);
    removeFixedContainer();
  });
})();