您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Make theater mode fill the entire page view with a hidden navbar and auto theater mode (Support new UI)
当前为
// ==UserScript== // @name Youtube Fullpage Theater // @version 1.8.0 // @description Make theater mode fill the entire page view with a hidden navbar and auto theater mode (Support new UI) // @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 unsafeWindow // @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; /** * @param {string} attributes * @returns {SVGSVGElement} */ function makeIcon(attributes) { const create = (tagName) => document.createElementNS("http://www.w3.org/2000/svg", tagName); let icon = create("svg"); for (const name in attributes) { const element = create(name); const attribute = attributes[name]; for (const key in attribute) { element.setAttributeNS(null, key, attribute[key]); } if (name == "svg") icon = element; else icon.append(element); } return icon; } /** * Options must be changed via popup menu, * just press (v) to open the menu */ const options = { auto_theater_mode: { icon: makeIcon({ svg: { "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", }, }), label: "Auto Open Theater", value: false, // fallback value }, hide_scrollbar: { icon: makeIcon({ 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", }, }), label: "Theater Hide Scrollbar", value: true, // fallback value onUpdate() { if (html.hasAttribute(attr.theater)) { html.toggleAttribute( attr.no_scroll, options.hide_scrollbar.value ); win.dispatchEvent(new Event("resize")); } }, }, close_theater_with_esc: { icon: makeIcon({ svg: { "clip-rule": "evenodd", "fill-rule": "evenodd", "stroke-linejoin": "round", "stroke-miterlimit": 2, }, 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", }, }), label: "Close Theater With Esc", value: true, // fallback value }, hide_card: { icon: makeIcon({ path: { d: "M22 6v16H6V6h16zm2-2H4v20h20V4zM0 0v20h2V2h18V0H0zm14.007 11.225C10.853 11.225 9 13.822 9 13.822s2.015 2.953 5.007 2.953c3.222 0 4.993-2.953 4.993-2.953s-1.788-2.597-4.993-2.597zm.042 4.717a1.942 1.942 0 1 1 .002-3.884 1.942 1.942 0 0 1-.002 3.884zM15.141 14a1.092 1.092 0 1 1-2.184 0l.02-.211a.68.68 0 0 0 .875-.863l.197-.019c.603 0 1.092.489 1.092 1.093z", }, }), label: "Hide Card Outside Theater Mode", value: false, // fallback value onUpdate() { if (!html.hasAttribute(attr.theater)) { html.toggleAttribute( attr.hide_card, options.hide_card.value ); } }, }, show_header_near: { icon: makeIcon({ path: { d: "M5 4.27 15.476 13H8.934L5 18.117V4.27zM3 0v24l6.919-9H21L3 0z", }, }), label: "Show Header When Mouse is Near", value: false, // fallback value }, }; /** * @param {string} name * @param {boolean} value * @returns {boolean} */ function saveOption(name, value) { GM.setValue(name, value); return (options[name].value = value); } 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; } } /** * @param {string} className * @returns {HTMLDivElement} */ function createDIV(className) { const element = document.createElement("div"); element.className = className || ""; return element; } const popup = { show: false, menu: (() => { const container = createDIV("ytc-popup-container"); const menu = createDIV("ytc-menu ytp-panel-menu"); for (const name in options) { const option = options[name], menuItem = createDIV("ytp-menuitem"), icon = createDIV("ytp-menuitem-icon"), label = createDIV("ytp-menuitem-label"), content = createDIV("ytp-menuitem-content"), checkbox = createDIV("ytp-menuitem-toggle-checkbox"); menuItem.setAttribute("aria-checked", option.value); icon.append(option.icon); label.textContent = option.label; content.append(checkbox); menuItem.append(icon, label, content); menuItem.addEventListener("click", () => { menuItem.setAttribute( "aria-checked", saveOption(name, !option.value) ); if (option.onUpdate) option.onUpdate(); }); menu.append(menuItem); } container.append(menu); win.addEventListener("click", (ev) => { if (popup.show && !menu.contains(ev.target)) popup.show = !!container.remove(); }); return container; })(), }; win.addEventListener("keydown", (ev) => { const isV = ev.key.toLowerCase() == "v" || ev.code == "KeyV"; if ( (isV && !ev.ctrlKey && !isActiveEditable()) || (ev.code == "Escape" && popup.show) ) { if (popup.show) popup.menu.remove(); else body.append(popup.menu); popup.show = !popup.show; } }); /** * @param {string} query * @returns {() => HTMLElement | null} */ function $(query) { let cache; return () => cache || (cache = document.querySelector(query)); } /** * @param {string} css */ function addStyle(css) { const style = document.createElement("style"); style.textContent = css; document.head.append(style); } let style = /*css*/ ` html[no-scroll], html[no-scroll] body { scrollbar-width: none !important; } html[no-scroll]::-webkit-scrollbar, html[no-scroll] body::-webkit-scrollbar { display: none !important; } html[masthead-hidden] ytd-watch-flexy[fixed-panels] #chat { top: 0 !important; } html[hide-card] ytd-player .ytp-paid-content-overlay, html[hide-card] ytd-player .iv-branding, html[hide-card] ytd-player .ytp-ce-element, html[hide-card] ytd-player .ytp-chrome-top, html[hide-card] 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] #content #page-manager ytd-watch-flexy #full-bleed-container, html[theater] #content #page-manager ytd-watch-grid #player-full-bleed-container { height: 100vh; min-height: auto; max-height: none; } .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 customAttr = { hidden_header: "masthead-hidden", no_scroll: "no-scroll", hide_card: "hide-card", }; for (const key in customAttr) { const oldAttr = new RegExp("\\[" + customAttr[key], "g"); const uniqueKey = Math.random().toString(36).slice(2); customAttr[key] = customAttr[key] + `-${uniqueKey}`; style = style.replace(oldAttr, "[" + customAttr[key]); } addStyle(style); const attr = { video_id: "video-id", role: "role", theater: "theater", fullscreen: "fullscreen", ...customAttr, }; const element = { watch: $("ytd-watch-flexy, ytd-watch-grid"), // ytd-watch-grid == trash search: $("input#search"), }; 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; } let theater = false; /** * @returns {boolean} */ function isTheater() { const watch = element.watch(); return (theater = watch.getAttribute(attr.role) == "main" && !watch.hasAttribute(attr.fullscreen) && watch.hasAttribute(attr.theater)); } /** * @returns {boolean} */ function isActiveEditable() { /** @type {HTMLElement} */ const active = document.activeElement; return ( active.tagName == "TEXTAREA" || active.tagName == "INPUT" || active.contentEditable == "true" ); } /** * @param {boolean} state * @param {boolean} skipActive */ function toggleHeader(state, skipActive) { if ( theater && (skipActive || document.activeElement != element.search()) ) { const scroll = !options.show_header_near.value && win.scrollY; html.toggleAttribute(attr.hidden_header, !(state || scroll)); } } let showHeaderTimer = 0; /** * @param {MouseEvent} ev */ function mouseShowHeader(ev) { if (options.show_header_near.value && theater) { const state = ev.clientY < 300; if (state) { clearTimeout(showHeaderTimer); showHeaderTimer = setTimeout(() => toggleHeader(false), 1500); } toggleHeader(!popup.show && state); } } function toggleTheater() { document.dispatchEvent(keyToggleTheater); } /** * @param {KeyboardEvent} ev */ function onEscapePress(ev) { if (ev.code != "Escape" || !theater || popup.show) return; if (options.close_theater_with_esc.value) { toggleTheater(); } else { const input = element.search(); if (document.activeElement != input) { setTimeout(() => input.focus(), 1); } else { setTimeout(() => input.blur(), 1); } } } /** * @param {MutationRecord[]} mutations */ function autoOpenTheater(mutations) { const attrs = [attr.role, attr.video_id]; const watch = element.watch(); if ( options.auto_theater_mode.value && !watch.hasAttribute(attr.theater) && !watch.hasAttribute(attr.fullscreen) && mutations.some((m) => attrs.includes(m.attributeName)) ) { setTimeout(toggleTheater, 1); } } function registerEventListener() { element.search().addEventListener("focus", () => { setTimeout(() => toggleHeader(true, true), 1); }); element.search().addEventListener("blur", () => { setTimeout(() => toggleHeader(false), 1); }); win.addEventListener("scroll", () => toggleHeader()); win.addEventListener("mousemove", mouseShowHeader); win.addEventListener("keydown", onEscapePress, true); } function applyTheaterMode() { const state = isTheater(); const hasTheater = html.hasAttribute(attr.theater); if ((state && !hasTheater) || (!state && hasTheater)) { html.toggleAttribute(attr.theater, state); html.toggleAttribute(attr.hidden_header, state); html.toggleAttribute( attr.no_scroll, state && options.hide_scrollbar.value ); html.toggleAttribute( attr.hide_card, state || options.hide_card.value ); } } observer((_, observe) => { const watch = element.watch(); if (!watch) return; observer( (mutations) => { applyTheaterMode(); autoOpenTheater(mutations); }, watch, { attributes: true } ); registerEventListener(); observe.disconnect(); }, body); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址