您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Make theater mode fill the entire page view with a hidden navbar and auto theater mode
当前为
// ==UserScript== // @name Youtube Fullpage Theater // @version 1.2.0 // @description Make theater mode fill the entire page view with a hidden navbar and auto theater mode // @run-at document-body // @match https://www.youtube.com/* // @exclude https://*.youtube.com/live_chat* // @exclude https://*.youtube.com/embed* // @exclude https://*.youtube.com/tv* // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @grant GM.getValue // @grant GM.setValue // @grant GM.addStyle // @author Fznhq // @namespace https://github.com/fznhq // @homepageURL https://github.com/fznhq/userscript-collection // @license GNU GPLv3 // ==/UserScript== // Icons provided by https://iconmonstr.com/ (async function () { "use strict"; /** @type {Window} */ const win = unsafeWindow; /** @type {HTMLHtmlElement} */ const html = document.documentElement; /** @type {HTMLBodyElement} */ const body = document.body; /** * Options must be changed via popup menu, * just press (v) to open the menu */ const options = { auto_theater_mode: { icon: `<svg width="24" height="24" fill-rule="evenodd" clip-rule="evenodd"><path d="M24 22h-24v-20h24v20zm-1-19h-22v18h22v-18zm-4 7h-1v-3.241l-11.241 11.241h3.241v1h-5v-5h1v3.241l11.241-11.241h-3.241v-1h5v5z"/></svg>`, label: "Auto Open Theater", value: false, // fallback value }, hide_scrollbar: { icon: `<svg width="24" height="24" viewBox="0 0 24 24"><path d="M14 12c0 1.104-.896 2-2 2s-2-.896-2-2 .896-2 2-2 2 .896 2 2zm-3-3.858c.321-.083.653-.142 1-.142s.679.059 1 .142v-2.142h4l-5-6-5 6h4v2.142zm2 7.716c-.321.083-.653.142-1 .142s-.679-.059-1-.142v2.142h-4l5 6 5-6h-4v-2.142z"/></svg>`, label: "Theater Hide Scrollbar", value: true, // fallback value onUpdate: (attr, value) => html.toggleAttribute(attr, value), }, close_theater_with_esc: { icon: `<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 24 24"><path d="m21 3.998c0-.478-.379-1-1-1h-16c-.62 0-1 .519-1 1v16c0 .621.52 1 1 1h16c.478 0 1-.379 1-1zm-16.5.5h15v15h-15zm7.491 6.432 2.717-2.718c.146-.146.338-.219.53-.219.404 0 .751.325.751.75 0 .193-.073.384-.22.531l-2.717 2.717 2.728 2.728c.147.147.22.339.22.531 0 .427-.349.75-.75.75-.192 0-.385-.073-.531-.219l-2.728-2.728-2.728 2.728c-.147.146-.339.219-.531.219-.401 0-.75-.323-.75-.75 0-.192.073-.384.22-.531l2.728-2.728-2.722-2.722c-.146-.147-.219-.338-.219-.531 0-.425.346-.749.75-.749.192 0 .384.073.53.219z" fill-rule="nonzero"/></svg>`, label: "Close Theater with Esc", value: true, // fallback value }, }; function saveOption(name, value) { options[name].value = value; GM.setValue(name, value); return value; } if (GM.getValue && GM.setValue) { for (const name in options) { const saved_option = await GM.getValue(name); if (saved_option === undefined) { saveOption(name, options[name].value); } else { options[name].value = saved_option; } } } const popup = { container: document.createElement("div"), menu: (() => { const menu = document.createElement("div"); menu.className = "ytc-menu ytp-panel-menu"; for (const name in options) { const container = document.createElement("div"); container.innerHTML = /*html*/ ` <div class="ytp-menuitem" aria-checked=${options[name].value}> <div class="ytp-menuitem-icon">${options[name].icon}</div> <div class="ytp-menuitem-label">${options[name].label}</div> <div class="ytp-menuitem-content"> <div class="ytp-menuitem-toggle-checkbox"></div> </div> </div> `; const item = container.firstElementChild; item.addEventListener("click", () => { const newValue = saveOption(name, !options[name].value); item.ariaChecked = newValue; if (options[name].onUpdate) { options[name].onUpdate(attr.no_scroll, newValue); } }); menu.append(item); } return menu; })(), }; popup.container.className = "ytc-popup-container"; popup.container.append(popup.menu); popup.container.addEventListener("click", (ev) => { if (!popup.menu.contains(ev.target)) { popup.container.remove(); } }); window.addEventListener("keydown", (ev) => { if (ev.key.toLowerCase() == "v" && !isActiveEditable()) { if (document.contains(popup.container)) { popup.container.remove(); } else { body.append(popup.container); } } else if (ev.key == "Escape" && document.contains(popup.container)) { popup.container.remove(); } }); /** * @param {string} query * @returns {() => HTMLElement | null} */ function $(query) { let cache; return () => cache || (cache = document.querySelector(query)); } GM.addStyle(/*css*/ ` html[theater][no-scroll], html[theater][no-scroll] body { scrollbar-width: none !important; } html[theater][no-scroll]::-webkit-scrollbar, html[theater][no-scroll] body::-webkit-scrollbar { display: none !important; } html[masthead-hidden] ytd-watch-flexy[fixed-panels] #chat { top: 0 !important; } html[theater] ytd-player .ytp-paid-content-overlay, html[theater] ytd-player .iv-branding, html[theater] ytd-player .ytp-ce-element, html[theater] ytd-player .ytp-chrome-top, html[theater] ytd-player .ytp-suggested-action { display: none !important; } html[theater][masthead-hidden] #masthead-container { transform: translateY(-100%) !important; } html[theater] #page-manager { margin: 0 !important; } html[theater] #full-bleed-container, html[theater] #player-full-bleed-container { height: 100vh !important; max-height: none !important; } .ytc-popup-container { position: fixed; inset: 0; z-index: 9000; background: rgba(0, 0, 0, .5); display: flex; align-items: center; justify-content: center; } .ytc-menu.ytp-panel-menu { background: #000; width: 400px; font-size: 120%; padding: 10px; } .ytc-menu svg { fill: #eee; } `); const element = { watch: $("ytd-watch-flexy, ytd-watch-grid"), // ytd-watch-grid == trash search: $("input#search"), }; const attr = { video_id: "video-id", role: "role", theater: "theater", fullscreen: "fullscreen", hidden_header: "masthead-hidden", no_scroll: "no-scroll", }; const keyToggleTheater = new KeyboardEvent("keydown", { key: "t", code: "KeyT", which: 84, keyCode: 84, bubbles: true, cancelable: true, view: win, }); /** * @param {MutationCallback} callback * @param {Node} target * @param {MutationObserverInit | undefined} options * @returns */ function observer(callback, target, options) { const mutation = new MutationObserver(callback); mutation.observe(target, options || { subtree: true, childList: true }); return mutation; } function isTheater() { const elem = element.watch(); return ( elem.getAttribute(attr.role) == "main" && !elem.hasAttribute(attr.fullscreen) && elem.hasAttribute(attr.theater) ); } function isActiveEditable() { /** @type {HTMLElement} */ const active = document.activeElement; return ( active.tagName == "TEXTAREA" || active.tagName == "INPUT" || active.contentEditable == "true" ); } function toggleHeader() { if (document.activeElement != element.search()) { html.toggleAttribute(attr.hidden_header, !win.scrollY); } } function toggleTheater() { document.dispatchEvent(keyToggleTheater); } /** * @param {KeyboardEvent} event */ function onEscapePress(event) { if (event.key != "Escape" || document.contains(popup.container)) { return; } if (options.close_theater_with_esc.value) { toggleTheater(); } else { const input = element.search(); if (document.activeElement != input) { html.removeAttribute(attr.hidden_header); setTimeout(() => input.focus(), 1); } else if (!win.scrollY) { html.setAttribute(attr.hidden_header, ""); input.blur(); } } } /** * @param {MutationRecord[]} mutations */ function openTheater(mutations) { const attrs = [attr.role, attr.video_id]; const elem = element.watch(); if ( options.auto_theater_mode.value && mutations.some((m) => attrs.includes(m.attributeName)) && !elem.hasAttribute(attr.theater) && !elem.hasAttribute(attr.fullscreen) ) { setTimeout(toggleTheater, 1); } } function setAttribute(theater, header, scroll) { html.toggleAttribute(attr.theater, theater); html.toggleAttribute(attr.hidden_header, header); html.toggleAttribute(attr.no_scroll, scroll); } function setListener(action) { element.search()[action]("blur", toggleHeader); win[action]("scroll", toggleHeader); win[action]("keydown", onEscapePress, true); } function watchTheaterMode() { const state = isTheater(); if (state && !html.hasAttribute(attr.theater)) { setAttribute(true, true, options.hide_scrollbar.value); setListener("addEventListener"); } else if (!state && html.hasAttribute(attr.theater)) { setAttribute(false, false, false); setListener("removeEventListener"); } } observer((_, observe) => { const elem = element.watch(); if (!elem) return; observer( (mutations) => { watchTheaterMode(); openTheater(mutations); }, elem, { attributes: true } ); observe.disconnect(); }, body); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址