您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
隐藏所有 Shorts/短视频,不支持旧浏览器。添加了开关功能记忆功能和可选图标显示。
当前为
// ==UserScript== // @name YouTube No-Shorts // @name:zh-CN YouTube 油管去除短视频 // @name:zh-TW YouTube 油管去除短视频 // @namespace http://tampermonkey.net/ // @version 1.3 // @description Hide all Shorts/Short Videos, older browsers are not supported. Added toggle function, memory function and optional icon display. // @description:zh-CN 隐藏所有 Shorts/短视频,不支持旧浏览器。添加了开关功能记忆功能和可选图标显示。 // @description:zh-TW 隐藏所有 Shorts/短视频,不支持旧浏览器。添加了开关功能记忆功能和可选图标显示。 // @author dogchild // @match https://www.youtube.com/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @run-at document-start // @license MIT // ==/UserScript== (function () { "use strict"; // 调试模式开关,设为false可减少日志输出 const DEBUG = false; // 调试日志函数 function debugLog(message) { if (DEBUG) console.log(`[Anti-Shorts] ${message}`); } // 检测浏览器语言并返回相应的菜单命令文本 function getMenuCommandTexts() { const browserLang = navigator.language || ''; debugLog(`检测到浏览器语言: ${browserLang}`); const isChinese = browserLang.startsWith('zh'); return isChinese ? { enableIcon: "启动图标", disableIcon: "禁用图标" } : { enableIcon: "Show icon", disableIcon: "Hide icon" }; } // 获取菜单命令文本 const menuTexts = getMenuCommandTexts(); // 检查油猴选项是否启用 const enableAntiShorts = GM_getValue("enableAntiShorts", true); // 如果选项关闭,直接应用CSS隐藏shorts并不显示按钮 if (!enableAntiShorts) { debugLog("油猴选项已关闭,默认隐藏所有Shorts"); // 立即应用CSS规则 const style = document.createElement("style"); style.id = "__anti_shorts_css_forced"; style.textContent = ` ytd-rich-grid-media:has(a[href*="/shorts/"]), ytd-video-renderer:has(a[href*="/shorts/"]), ytd-grid-video-renderer:has(a[href*="/shorts/"]), ytd-rich-item-renderer:has(a[href*="/shorts/"]), ytd-compact-video-renderer:has(a[href*="/shorts/"]), ytd-playlist-video-renderer:has(a[href*="/shorts/"]), ytd-rich-grid-row:has(a[href*="/shorts/"]), grid-shelf-view-model:has(ytm-shorts-lockup-view-model), grid-shelf-view-model:has(ytm-shorts-lockup-view-model-v2), ytd-reel-shelf-renderer, ytd-rich-shelf-renderer[is-shorts], ytd-shelf-renderer { display: none !important; } `; // 使用更早的插入方式 if (document.head) { document.head.appendChild(style); } else { // 如果head还不存在,等待它可用 const observer = new MutationObserver(() => { if (document.head) { document.head.appendChild(style); observer.disconnect(); } }); observer.observe(document, { childList: true, subtree: true }); } // 注册(不可用)菜单命令,允许用户重新启用图标 GM_registerMenuCommand(menuTexts.enableIcon, () => { GM_setValue("enableAntiShorts", true); location.reload(); }); return; // 不继续执行其余代码 } // CSS规则,用于隐藏Shorts const cssHas = ` ytd-rich-grid-media:has(a[href*="/shorts/"]), ytd-video-renderer:has(a[href*="/shorts/"]), ytd-grid-video-renderer:has(a[href*="/shorts/"]), ytd-rich-item-renderer:has(a[href*="/shorts/"]), ytd-compact-video-renderer:has(a[href*="/shorts/"]), ytd-playlist-video-renderer:has(a[href*="/shorts/"]), ytd-rich-grid-row:has(a[href*="/shorts/"]), grid-shelf-view-model:has(ytm-shorts-lockup-view-model), grid-shelf-view-model:has(ytm-shorts-lockup-view-model-v2), ytd-reel-shelf-renderer, ytd-rich-shelf-renderer[is-shorts], ytd-shelf-renderer { display: none !important; } `; // 创建样式元素 const styleElement = document.createElement("style"); styleElement.id = "__anti_shorts_css"; styleElement.textContent = cssHas; // 按钮样式和通知样式(合并到一个样式元素中) const uiStyleElement = document.createElement("style"); uiStyleElement.textContent = ` #anti-shorts-toggle { margin-left: 6px; padding: 0 8px; height: 28px; border-radius: 14px; border: 1px solid transparent; background-color: transparent; font-size: 13px; font-weight: 500; cursor: pointer; display: flex; align-items: center; transition: all 0.2s; white-space: nowrap; min-width: 85px; justify-content: center; color: var(--yt-spec-text-primary); } #anti-shorts-toggle:hover { background-color: var(--yt-spec-badge-chip-background-hover); } #anti-shorts-toggle.on { background-color: transparent; color: var(--yt-spec-text-primary); } #anti-shorts-toggle.on:hover { background-color: var(--yt-spec-badge-chip-background-hover); } .anti-shorts-notification { position: fixed; bottom: 20px; right: 20px; background-color: rgba(0, 0, 0, 0.8); color: white; padding: 12px 20px; border-radius: 8px; font-size: 14px; z-index: 9999; opacity: 0; transition: opacity 0.3s; } .anti-shorts-notification.show { opacity: 1; } `; // 缓存和状态管理 const state = { button: null, notification: null, settings: {}, lastUrl: location.href, buttonCheckInterval: null, spaObserver: null, domObserver: null, pageType: null, isInitialized: false }; // 等待head元素可用 function waitForHead(callback) { if (document.head) { callback(); } else { const observer = new MutationObserver(() => { if (document.head) { observer.disconnect(); callback(); } }); observer.observe(document, { childList: true, subtree: true }); } } // 初始化样式 waitForHead(() => { document.head.appendChild(uiStyleElement); }); // 注册(不可用)菜单命令,允许用户禁用图标 GM_registerMenuCommand(menuTexts.disableIcon, () => { GM_setValue("enableAntiShorts", false); location.reload(); }); // 显示通知(复用通知元素) function showNotification(message) { // 如果通知已存在,先移除 if (state.notification) { state.notification.classList.remove('show'); setTimeout(() => { if (state.notification && state.notification.parentNode) { state.notification.parentNode.removeChild(state.notification); state.notification = null; } }, 300); } // 创建新通知 state.notification = document.createElement('div'); state.notification.className = 'anti-shorts-notification'; state.notification.textContent = message; document.body.appendChild(state.notification); // 显示通知 requestAnimationFrame(() => { if (state.notification) { state.notification.classList.add('show'); } }); // 3秒后隐藏通知 setTimeout(() => { if (state.notification) { state.notification.classList.remove('show'); setTimeout(() => { if (state.notification && state.notification.parentNode) { state.notification.parentNode.removeChild(state.notification); state.notification = null; } }, 300); } }, 3000); } // 检测当前页面类型(缓存结果) function getPageType() { if (state.pageType) return state.pageType; const path = window.location.pathname; const search = window.location.search; if (path === "/" || path === "/feed/subscriptions") { state.pageType = "home"; } else if (path === "/results" || search.includes("search_query")) { state.pageType = "search"; } else { state.pageType = "other"; } return state.pageType; } // 从localStorage获取设置,使用缓存减少读取 function getHideShortsSetting(pageType) { // 如果缓存中有设置,直接返回 if (state.settings[pageType] !== undefined) { return state.settings[pageType]; } const key = `hideShorts_${pageType}`; const storedValue = localStorage.getItem(key); // 如果没有存储过值,默认为false(显示Shorts,即off状态) if (storedValue === null) { debugLog(`首次访问${pageType}页面,默认显示Shorts (off状态)`); state.settings[pageType] = false; return false; } // 解析存储的值并缓存 const hideShorts = storedValue === "true"; state.settings[pageType] = hideShorts; debugLog(`从记忆中读取${pageType}页面设置: ${hideShorts ? '隐藏' : '显示'} Shorts`); return hideShorts; } // 保存设置到localStorage并更新缓存 function saveHideShortsSetting(pageType, hide) { const key = `hideShorts_${pageType}`; localStorage.setItem(key, hide); state.settings[pageType] = hide; // 更新缓存 debugLog(`已保存${pageType}页面设置: ${hide ? '隐藏' : '显示'} Shorts`); // 显示保存成功的通知 const pageTypeName = pageType === "home" ? "主页" : "搜索页"; showNotification(`已保存设置:${pageTypeName} Shorts ${hide ? '已关闭' : '已开启'}`); } // 应用或移除CSS规则 function applyShortsSetting() { const pageType = getPageType(); const hideShorts = getHideShortsSetting(pageType); if (hideShorts) { if (!document.getElementById("__anti_shorts_css")) { document.documentElement.appendChild(styleElement); debugLog(`已应用CSS规则,${pageType}页面Shorts已隐藏`); } } else { const existingStyle = document.getElementById("__anti_shorts_css"); if (existingStyle) { existingStyle.remove(); debugLog(`已移除CSS规则,${pageType}页面Shorts已显示`); } } // 更新按钮文本 updateButtonText(); } // 更新按钮文本和样式 function updateButtonText() { // 使用缓存的按钮元素 const button = state.button || document.getElementById("anti-shorts-toggle"); if (button) { state.button = button; // 缓存按钮元素 const pageType = getPageType(); const hideShorts = getHideShortsSetting(pageType); // 统一使用"shorts: on/off"格式 const buttonText = hideShorts ? "shorts: off" : "shorts: on"; button.textContent = buttonText; // 根据状态添加或移除on类 button.classList.toggle("on", hideShorts); } } // 创建开关按钮 function createToggleButton() { const button = document.createElement("button"); button.id = "anti-shorts-toggle"; // 设置初始文本 const pageType = getPageType(); const hideShorts = getHideShortsSetting(pageType); const buttonText = hideShorts ? "shorts: off" : "shorts: on"; button.textContent = buttonText; button.classList.toggle("on", hideShorts); button.addEventListener("click", () => { const pageType = getPageType(); const hideShorts = getHideShortsSetting(pageType); saveHideShortsSetting(pageType, !hideShorts); applyShortsSetting(); }); debugLog(`已创建控制按钮,初始文本: ${buttonText}`); return button; } // 查找并添加按钮到YouTube顶栏 function addButtonToHeader() { // 如果按钮已存在,直接返回 if (document.getElementById("anti-shorts-toggle")) { return true; } // 尝试多种可能的选择器,按优先级排序 const possibleSelectors = [ "#end", "#buttons", "ytd-masthead #end", "ytd-masthead #buttons" ]; for (const selector of possibleSelectors) { const header = document.querySelector(selector); if (header) { const button = createToggleButton(); header.appendChild(button); state.button = button; // 缓存按钮元素 debugLog(`已添加控制按钮到YouTube顶栏 (${selector})`); return true; } } return false; } // 清理资源 function cleanup() { if (state.buttonCheckInterval) { clearInterval(state.buttonCheckInterval); state.buttonCheckInterval = null; } if (state.spaObserver) { state.spaObserver.disconnect(); state.spaObserver = null; } if (state.domObserver) { state.domObserver.disconnect(); state.domObserver = null; } } // 处理页面导航 function handleNavigation() { // 重置页面类型缓存 state.pageType = null; // 应用设置 applyShortsSetting(); // 检查按钮是否存在,如果不存在则重新添加 if (!document.getElementById("anti-shorts-toggle")) { debugLog("导航后按钮不存在,尝试重新添加"); addButtonToHeader(); } } // 初始化 function init() { // 防止重复初始化 if (state.isInitialized) return; state.isInitialized = true; debugLog("开始初始化"); debugLog(`使用浏览器语言: ${navigator.language}`); // 应用初始设置 applyShortsSetting(); // 尝试添加按钮 let buttonAdded = addButtonToHeader(); // 如果按钮未添加成功,观察DOM变化 if (!buttonAdded) { debugLog("按钮未添加成功,将观察DOM变化"); state.domObserver = new MutationObserver(() => { if (!document.getElementById("anti-shorts-toggle") && addButtonToHeader()) { debugLog("通过DOM观察成功添加按钮"); state.domObserver.disconnect(); state.domObserver = null; } }); // 只观察body的子元素变化,而不是整个子树 state.domObserver.observe(document.body, { childList: true }); // 30秒后停止观察 setTimeout(() => { if (state.domObserver) { state.domObserver.disconnect(); state.domObserver = null; if (!document.getElementById("anti-shorts-toggle")) { debugLog("30秒内未找到合适位置添加按钮"); } } }, 30000); } // 监听URL变化,以便在页面导航时更新设置 window.addEventListener("popstate", handleNavigation); // 监听YouTube的SPA导航 state.spaObserver = new MutationObserver(() => { const url = location.href; if (url !== state.lastUrl) { state.lastUrl = url; debugLog("检测到YouTube SPA导航,更新设置"); // 使用requestAnimationFrame确保DOM已更新 requestAnimationFrame(handleNavigation); } }); // 只观察documentElement的子元素变化,减少观察范围 state.spaObserver.observe(document.documentElement, { childList: true, subtree: false }); // 减少按钮检查频率,从5秒改为10秒 state.buttonCheckInterval = setInterval(() => { const button = document.getElementById("anti-shorts-toggle"); if (button && (!button.textContent || button.textContent.trim() === "")) { debugLog("检测到按钮文本为空,更新"); updateButtonText(); } }, 10000); // 页面卸载时清理资源 window.addEventListener("beforeunload", cleanup); debugLog("初始化完成,记忆功能已启用"); } // 确保DOM加载完成后初始化 if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init); } else { init(); } debugLog("现代浏览器模式已启用 (CSS :has())"); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址