您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
禁止Sora探索页面的视频自动缓存和播放。仅当鼠标悬停在视频上时才加载并播放,移开则停止。已修复SPA页面切换导致@exclude失效的问题。
// ==UserScript== // @name Sora - 视频悬停播放 (Hover to Play) // @namespace http://tampermonkey.net/ // @version 1.3.1 // @description 禁止Sora探索页面的视频自动缓存和播放。仅当鼠标悬停在视频上时才加载并播放,移开则停止。已修复SPA页面切换导致@exclude失效的问题。 // @author Your Name // @match https://sora.chatgpt.com/* // @exclude https://sora.chatgpt.com/p/* // @exclude https://sora.chatgpt.com/d/* // @grant none // @run-at document-idle // ==/UserScript== (function() { 'use strict'; console.log('Sora Hover-to-Play 脚本 v1.3 已启动'); // --- 新增:检查当前是否为详情页 --- // 这个函数会贯穿整个脚本,用于判断是否应该执行核心逻辑 function isDetailPage() { return window.location.pathname.startsWith('/p/') || window.location.pathname.startsWith('/d/'); } function processVideo(video) { // 在处理任何视频前,先检查页面路径 if (isDetailPage()) { return; // 如果是详情页,则不执行任何操作 } // 如果视频已经被处理过,就跳过 if (video.dataset.hoverPlayReady) { return; } const container = video.closest('div.group'); if (!container) { console.warn('未找到视频的悬停目标:', video); return; } container.classList.remove('animate-pulse', 'bg-secondary/20'); if (video.src) { video.dataset.originalSrc = video.src; video.removeAttribute('src'); } video.preload = 'none'; video.muted = true; container.addEventListener('mouseenter', () => { // 悬停时再次检查,确保万无一失 if (isDetailPage()) return; if (video.dataset.originalSrc && !video.getAttribute('src')) { video.src = video.dataset.originalSrc; video.play().catch(e => { // 忽略浏览器可能报出的播放中断错误 }); } }); container.addEventListener('mouseleave', () => { video.pause(); video.removeAttribute('src'); video.load(); }); video.dataset.hoverPlayReady = 'true'; } function initAllVideos() { // 初始化时检查 if (isDetailPage()) { return; } document.querySelectorAll('video[poster]').forEach(processVideo); } const observer = new MutationObserver((mutations) => { // --- 修改:在监听到DOM变化时,首先检查URL --- // 这是处理SPA导航的关键 if (isDetailPage()) { return; // 如果是详情页,忽略所有DOM变化 } mutations.forEach((mutation) => { if (mutation.addedNodes) { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { if (node.matches('video[poster]')) { processVideo(node); } node.querySelectorAll('video[poster]').forEach(processVideo); } }); } }); }); observer.observe(document.body, { childList: true, subtree: true }); // 页面加载完成后,先执行一次 initAllVideos(); // 保留 @exclude 规则也是有好处的,它可以防止在直接通过URL访问详情页时,脚本被注入。 // 我们将 @match 范围扩大到 `https://sora.chatgpt.com/*`,这样脚本在网站的任何地方都会被注入, // 然后依靠内部的 isDetailPage() 函数来决定是否执行功能。 })();