您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Maximizes YouTube's video player to fill the entire browser viewport and fixes a few minor annoyances
- // ==UserScript==
- // @name YouTube Cinema Mode
- // @description Maximizes YouTube's video player to fill the entire browser viewport and fixes a few minor annoyances
- // @license MIT
- // @author Rotem Dan <rotemdan@gmail.com>
- // @match https://www.youtube.com/*
- // @version 0.2.4
- // @run-at document-start
- // @grant none
- // @require https://code.jquery.com/jquery-2.1.4.min.js
- // @namespace https://github.com/rotemdan
- // @homepageURL https://github.com/rotemdan/YouTubeCinemaMode
- // ==/UserScript==
- ////////////////////////////////////////////////////////////////
- // Main Operations
- ////////////////////////////////////////////////////////////////
- // Detect the type of YouTube page loaded
- var isWatchPage = location.href.indexOf("https://www.youtube.com/watch?") === 0;
- // Start or install operation handlers
- onDocumentStart();
- $(document).on("ready", onDocumentEnd);
- $(window).on("load", onWindowLoad);
- // Operations that are run as early as possible during page load
- function onDocumentStart() {
- installUnsafewindowPolyfill();
- disableSPF();
- if (isWatchPage) {
- disableMatchMedia();
- installFullSizePlayerStylesheet();
- }
- }
- // Operations that run when DOMContentLoaded event is fired
- function onDocumentEnd() {
- if (isWatchPage) {
- installTopBarAutohide();
- expandVideoDescription();
- installPlayerAutoFocus();
- installPlayerKeyboardShortcutExtensions();
- installPlaylistRepositioner();
- }
- installPlayerAutoPause();
- }
- // Operations that run when window is loaded (after YouTube scripts are run)
- function onWindowLoad() {
- if (isWatchPage) {
- setTimeout(switchPlayerToTheaterMode, 2000);
- }
- }
- ////////////////////////////////////////////////////////////////
- // Methods
- ////////////////////////////////////////////////////////////////
- // Ensure unsafeWindow object is available both in Firefox and Chrome
- function installUnsafewindowPolyfill() {
- if (typeof unsafeWindow === 'undefined') {
- if (typeof XPCNativeWrapper === 'function' && typeof XPCNativeWrapper.unwrap === 'function')
- unsafeWindow = XPCNativeWrapper.unwrap(window);
- else if (window.wrappedJSObject)
- unsafeWindow = window.wrappedJSObject;
- }
- }
- // Disable SPF (Structured Page Fragments), which prevents properly attaching to page load events when navigation occurs
- // Will also disable the red loading bar.
- function disableSPF() {
- if (unsafeWindow._spf_state && unsafeWindow._spf_state.config) {
- unsafeWindow._spf_state.config['navigate-limit'] = 0;
- unsafeWindow._spf_state.config['navigate-part-received-callback'] = function (targetUrl) { location.href = targetUrl; }
- }
- setTimeout(disableSPF, 50);
- }
- // Disable matchMedia - allow proper resizing of the video player and its contents.
- function disableMatchMedia() {
- window.matchMedia = undefined;
- }
- // Add full-size player page stylesheet (works correctly only when the player is in "theater" mode).
- function installFullSizePlayerStylesheet() {
- var runningInChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
- var styleSheet =
- "<style type='text/css'>\n" +
- "body { overflow-x: hidden !important; }\n" +
- "#masthead-positioner-height-offset { display: none }\n" +
- "#masthead-positioner { visibility: hidden; opacity: 0; transition: opacity 0.2s ease-in-out; }\n" +
- ".player-width { width: 100% !important; margin: 0px !important; left: 0px !important; right: 0px !important; }\n" +
- ".player-height { height: 100vh !important; }\n" +
- ":focus { outline: 0; }\n";
- //if (!runningInChrome)
- styleSheet += "body { overflow-y: scroll !important; }\n";
- styleSheet += "</style>\n";
- $("head").append(styleSheet);
- }
- // Switch player to theater mode if in default mode.
- function switchPlayerToTheaterMode() {
- if ($("div#page").hasClass("watch-non-stage-mode"))
- $("button.ytp-size-button, div.ytp-size-toggle-large").click();
- }
- // Automatically shows/hides the top bar based on different properties of the view.
- function installTopBarAutohide() {
- var topBar = getTopBar();
- var videoPlayer = getVideoPlayer();
- var videoPlayerElement = videoPlayer[0];
- function topBarIsVisible() {
- return topBar.css("visibility") === "visible";
- }
- function showTopBar() {
- topBar.css("visibility", "visible");
- topBar.css("opacity", "1");
- }
- function hideTopBar() {
- topBar.css("opacity", "0");
- topBar.css("visibility", "hidden");
- }
- function toggleTopBar() {
- if (topBarIsVisible())
- hideTopBar();
- else
- showTopBar();
- }
- function getScrollTop() {
- return $(document).scrollTop();
- }
- function onPageScroll() {
- if (getScrollTop() > 0)
- showTopBar();
- else
- hideTopBar();
- }
- var searchInput = $("input#masthead-search-term");
- function onKeyDown(e) {
- if (e.which === 27) { // Handle escape key
- if (getScrollTop() === 0) {
- toggleTopBar();
- if (topBarIsVisible())
- setTimeout(function () { searchInput.focus() }, 200);
- e.stopPropagation();
- }
- }
- }
- searchInput.on("keydown", onKeyDown);
- $(document).on("keydown", onKeyDown);
- $(document).on("scroll", onPageScroll);
- }
- // Continuously auto-focus the player when some conditions are met.
- function installPlayerAutoFocus() {
- function autoFocusIfNeeded() {
- var topbarVisibility = getTopBar().css("visibility");
- if (topbarVisibility !== undefined) {
- if (topbarVisibility === "hidden") {
- $(".html5-video-player").focus();
- }
- //else if ($(".html5-video-player").is(":focus") && $(document).scrollTop() > 0)
- //{
- // $(".html5-video-player").blur();
- //}
- }
- setTimeout(autoFocusIfNeeded, 20);
- }
- autoFocusIfNeeded();
- }
- function installPlayerKeyboardShortcutExtensions() {
- // Install keyboard shortcut extensions
- function onPlayerKeyDown(e) {
- if ($(".html5-video-player").is(":focus")) {
- if (e.ctrlKey) {
- if (e.which === 37) { // Handle ctl + left key
- var previousButton = $("a.ytp-prev-button, div.ytp-button-prev")[0];
- if (previousButton)
- previousButton.click();
- }
- else if (e.which === 39) { // Handle ctl + right key
- var nextButton = $("a.ytp-next-button, div.ytp-button-next")[0]
- if (nextButton)
- nextButton.click();
- }
- }
- }
- }
- $(document).on("keydown", onPlayerKeyDown);
- $(".html5-video-player").on("keydown", function (e) {
- if (e.which === 38 || e.which === 40) {
- console.log("up or down");
- e.stopPropagation();
- }
- });
- }
- // Expands video description
- function expandVideoDescription() {
- $("#action-panel-details").removeClass("yt-uix-expander-collapsed");
- }
- // Correct the positioning of the playlist on window resize.
- function installPlaylistRepositioner() {
- $("#watch-appbar-playlist").removeClass("player-height");
- function onResize() {
- var playlistContainer = $("#watch-appbar-playlist");
- if (playlistContainer.length === 0)
- return;
- var playlistOffset = playlistContainer.offset();
- playlistOffset.top = $("#watch-header").offset().top;
- playlistContainer.offset(playlistOffset);
- }
- onResize();
- $(window).resize(onResize);
- }
- // Pauses playing videos in other tabs when a video play event is detected (works in both watch and channel page videos)
- function installPlayerAutoPause() {
- var videoPlayer = getVideoPlayer();
- if (videoPlayer.length === 0) {
- //console.log("Player not found, retrying in 100ms..");
- setTimeout(installPlayerAutoPause, 100);
- return;
- }
- var videoPlayerElement = videoPlayer.get(0);
- // Generate a random script instance ID
- var instanceID = Math.random().toString();
- function onVideoPlay() {
- localStorage["YouTubeCinemaMode_PlayingInstanceID"] = instanceID;
- function pauseWhenAnotherPlayerStartsPlaying() {
- if (localStorage["YouTubeCinemaMode_PlayingInstanceID"] !== instanceID)
- videoPlayerElement.pause();
- else
- setTimeout(pauseWhenAnotherPlayerStartsPlaying, 10);
- }
- pauseWhenAnotherPlayerStartsPlaying();
- }
- // If video isn't paused on startup, fire the handler immediately
- if (!videoPlayerElement.paused)
- onVideoPlay();
- // Add event handler for the "play" event.
- videoPlayer.on("play", onVideoPlay);
- }
- // Get the video player element
- function getVideoPlayer() {
- // Note: the channel page has another hidden video except the main one (if it exists). The hidden video doesn't have an "src" attribute.
- return $('video.html5-main-video').filter(function (index) { return $(this).attr("src") !== undefined });
- }
- // Get the top bar element
- function getTopBar() {
- return $("#masthead-positioner");
- }