您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
91pinse 视频宽屏
// ==UserScript== // @name 91pinse-优化 // @namespace https://sleazyfork.org/zh-CN/users/1461640-%E6%98%9F%E5%AE%BF%E8%80%81%E9%AD%94 // @version 0.1.1 // @description 91pinse 视频宽屏 // @match https://91pinse.com/* // @match https://fplayer.cc/* // @match https://*.fplayer.cc/* // @icon https://www.google.com/s2/favicons?sz=64&domain=91pinse.com // @license MIT // @grant none // @run-at document-start // ==/UserScript== (function () { 'use strict'; // ======= 广告/弹窗拦截 ======= const blockedAdHosts = ['tsyndicate.com', 'rmhfrtnd.com', 'pemsrv.com']; // 点击视频区域时短时间内屏蔽弹窗 let suppressPopupUntil = 0; function armPopupShield(durationMs) { const duration = typeof durationMs === 'number' ? durationMs : 1500; const until = Date.now() + duration; suppressPopupUntil = Math.max(suppressPopupUntil, until); } function isShieldActive() { return Date.now() < suppressPopupUntil; } function isInsideVideoArea(target) { try { if (!target) return false; if (target.closest && target.closest('video, #videoIframe, .video-container')) return true; return false; } catch (_) { return false; } } // 在护盾生效期间,禁止脚本触发强制导航(assign/replace/reload) (function patchLocationNavigation() { try { const LocProto = window.Location && window.Location.prototype; if (!LocProto) return; const originalAssign = LocProto.assign; const originalReplace = LocProto.replace; const originalReload = LocProto.reload; if (originalAssign) { LocProto.assign = function (url) { if (isShieldActive()) { try { console.log('[91pinse-优化] 护盾生效,拦截 assign:', url); } catch (_) {} return; } return originalAssign.call(this, url); }; } if (originalReplace) { LocProto.replace = function (url) { if (isShieldActive()) { try { console.log('[91pinse-优化] 护盾生效,拦截 replace:', url); } catch (_) {} return; } return originalReplace.call(this, url); }; } if (originalReload) { LocProto.reload = function () { if (isShieldActive()) { try { console.log('[91pinse-优化] 护盾生效,拦截 reload'); } catch (_) {} return; } return originalReload.call(this); }; } } catch (_) {} })(); // 强制启用原生右键菜单(视频区域) function stripContextMenuAttribute(root) { try { const scope = (root || document).querySelectorAll('[oncontextmenu]'); scope.forEach(function (el) { try { el.oncontextmenu = null; el.removeAttribute('oncontextmenu'); } catch (_) {} }); } catch (_) {} } function enableContextMenuInDoc(doc) { try { doc.addEventListener('contextmenu', function (e) { try { // 仅在视频区域或包含视频的容器中放开右键 const target = e.target; const inVideo = target && (target.tagName === 'VIDEO' || (target.closest && target.closest('video, .video-container, .plyr, .plyr__video-wrapper'))); if (inVideo) { e.stopImmediatePropagation(); e.stopPropagation(); } } catch (_) {} }, true); const removeInline = function (root) { try { const scope = (root || doc).querySelectorAll('[oncontextmenu], .plyr__poster'); scope.forEach(function (el) { try { el.oncontextmenu = null; el.removeAttribute('oncontextmenu'); } catch (_) {} }); } catch (_) {} }; removeInline(doc); // 观察 iframe 内部变化,持续移除 oncontextmenu const obs = new doc.defaultView.MutationObserver(function (mutations) { mutations.forEach(function (m) { if (m.type === 'childList') { m.addedNodes.forEach(function (n) { if (n.nodeType === 1) removeInline(n); }); } else if (m.type === 'attributes' && (m.attributeName === 'oncontextmenu' || m.attributeName === 'style')) { try { m.target.oncontextmenu = null; m.target.removeAttribute('oncontextmenu'); } catch (_) {} } }); }); obs.observe(doc.documentElement || doc, { childList: true, subtree: true, attributes: true, attributeFilter: ['oncontextmenu','style'] }); } catch (_) {} } function tryHookSameOriginIframe(iframe) { try { const cw = iframe && iframe.contentWindow; const cd = cw && cw.document; if (!cd) return; // 在同源或明确为 fplayer 域时尝试放开右键 const origin = cw.location.origin; if (origin === window.location.origin || /(^https?:\/\/)?([\w-]+\.)?fplayer\.cc$/i.test(origin)) { enableContextMenuInDoc(cd); } } catch (_) { // 跨域无法处理 } } // 在捕获阶段阻止站点脚本接管右键,但不阻止默认行为,从而保留浏览器菜单 document.addEventListener('contextmenu', function (e) { try { // 全局右键:启动护盾,阻断冒泡,减少站点监听器触发的弹窗/刷新 armPopupShield(1600); e.stopImmediatePropagation(); e.stopPropagation(); // 不调用 preventDefault,确保浏览器显示自带菜单 } catch (_) {} }, true); function isBlockedAdUrl(url) { try { const u = new URL(url, window.location.href); return blockedAdHosts.some(function (host) { return u.hostname === host || u.hostname.endsWith('.' + host); }); } catch (e) { return false; } } // ======= 91pinse: 优先使用 HD ======= function isPinseDomain() { try { return /(^|\.)91pinse\.com$/i.test(window.location.hostname); } catch (_) { return false; } } function extractVideoIdFromPath(pathname) { try { const mHD = pathname.match(/^\/vhd\/(\d+)/); if (mHD) return { id: mHD[1], isHD: true }; const mSD = pathname.match(/^\/v\/(\d+)/); if (mSD) return { id: mSD[1], isHD: false }; return null; } catch (_) { return null; } } function buildPinseUrl(isHD, id) { return isHD ? `/vhd/${id}` : `/v/${id}`; } // 基于页面“是否存在 HD 标记/链接”来判断是否应走 HD,而不是发请求探测 function elementHasHdText(el) { try { if (!el) return false; const text = (el.textContent || '').trim(); return text === 'HD' || text === 'Hd' || text === 'hd' || /\bHD\b/i.test(text); } catch (_) { return false; } } function hasHdMarkerIn(container) { try { if (!container) return false; // 仅识别右上角的 HD 徽标,避免把时长等误判 const hdBadges = container.querySelectorAll('.absolute.top-1.right-1, .absolute[class*="top-1"][class*="right-1"], .bg-primary-600'); for (let i = 0; i < hdBadges.length; i++) { if (elementHasHdText(hdBadges[i])) return true; } // 也可能作为按钮或链接出现 const anchors = container.querySelectorAll('a'); for (let i = 0; i < anchors.length; i++) { if (elementHasHdText(anchors[i]) || /Switch\s+to\s+HD/i.test((anchors[i].textContent||''))) return true; } return false; } catch (_) { return false; } } function hasHdForId(id, scope) { try { const root = scope || document; if (root.querySelector(`a[href="/vhd/${id}"]`)) return true; return hasHdMarkerIn(root); } catch (_) { return false; } } async function preferHDOnPage() { if (!isPinseDomain()) return; const info = extractVideoIdFromPath(window.location.pathname); if (!info || info.isHD) return; // 仅在页面存在明确的 HD 入口/标记时才切换 const pageHasHd = hasHdForId(info.id, document) || !!document.querySelector('.absolute.top-1.right-1, .absolute[class*="top-1"][class*="right-1"], a:contains("Switch to HD")'); if (!pageHasHd) return; const hdUrl = buildPinseUrl(true, info.id); console.log('[91pinse-优化] 自动切换到 HD:', hdUrl); window.location.replace(hdUrl); } function upgradeLinksToHD(root) { if (!isPinseDomain()) return; const scope = (root || document).querySelectorAll('a[href^="/v/"]:not([data-hd-upgraded])'); scope.forEach(function (a) { try { const m = a.getAttribute('href').match(/^\/v\/(\d+)/); if (!m) return; const id = m[1]; const sdHref = a.getAttribute('href'); const hdHref = `/vhd/${id}`; // 仅当“该卡片”内存在 HD 标记/链接时才升级;否则如已被误升级则回退 const card = a.closest('.group, [id^="preview_"], .rounded, .shadow, .card, .overflow-hidden, .relative') || a.parentElement; const shouldUpgrade = hasHdForId(id, card); if (shouldUpgrade) { a.dataset.hdUpgraded = '1'; a.dataset.sdHref = sdHref; a.setAttribute('href', hdHref); } else { // 若之前被误升级,恢复 sd const prevSd = a.dataset.sdHref; if (prevSd && a.getAttribute('href') === hdHref) { a.setAttribute('href', prevSd); } delete a.dataset.hdUpgraded; } } catch (_) {} }); } function installPreferHdClickHandler() { if (!isPinseDomain()) return; document.addEventListener('click', async function (event) { try { if (event.defaultPrevented) return; if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return; let anchor = event.target && event.target.closest ? event.target.closest('a') : null; if (!anchor) return; const href = anchor.getAttribute('href') || ''; const m = href.match(/^\/v\/(\d+)/); if (!m) return; const id = m[1]; // 仅当附近确实有 HD 标记/链接时,才替换为 HD const card = anchor.closest('.group, [id^="preview_"], .rounded, .shadow, .card, .overflow-hidden, .relative') || anchor.parentElement; if (!hasHdForId(id, card)) return; const hdUrl = `/vhd/${id}`; if (href === hdUrl) return; event.preventDefault(); window.location.href = hdUrl; } catch (_) {} }, true); } // 移除/禁用指向广告域名的 iframe,以防止其在自身上下文内弹窗 function shouldRemoveIframe(iframe) { try { const src = iframe.getAttribute('src') || ''; if (!src) return false; return isBlockedAdUrl(src); } catch (_) { return false; } } function sanitizeIframes(root) { const frames = (root || document).querySelectorAll('iframe'); frames.forEach(function (frame) { try { if (shouldRemoveIframe(frame)) { console.log('[91pinse-优化] 已移除广告 iframe:', frame.src); frame.remove(); return; } // 降权可能触发弹窗的 iframe:尽量禁止其响应点击 if (!frame.__pinseLocked) { frame.style.pointerEvents = 'auto'; // 对可疑域名关闭指针事件,避免在其内部触发“基于用户手势”的弹窗 if (frame.src && isBlockedAdUrl(frame.src)) { frame.style.pointerEvents = 'none'; frame.__pinseLocked = true; } } } catch (_) {} }); } (function patchWindowOpen() { const originalOpen = window.open; window.open = function () { try { let url = arguments[0]; if (url && typeof url !== 'string') { try { url = String(url); } catch (_) {} } // 直接拦截已知广告域名 if (typeof url === 'string' && isBlockedAdUrl(url)) { console.log('[91pinse-优化] 已拦截弹窗:', url); return null; } // 某些站点先打开 about:blank 再在新窗口内跳转,这里在 91pinse 域名内一并拦截 if ((url === '' || url === 'about:blank' || url === undefined) && window.location.hostname.endsWith('91pinse.com')) { const target = arguments[1]; if (target === '_blank' || !target) { console.log('[91pinse-优化] 已拦截空白弹窗'); return null; } } // 若当前处于“弹窗护盾”时间窗内,仅允许同源窗口 if (isShieldActive()) { try { const u = new URL(typeof url === 'string' ? url : '', window.location.href); const sameOrigin = u.origin === window.location.origin; if (!sameOrigin) { console.log('[91pinse-优化] 护盾生效,已拦截跨域弹窗:', url || '(empty)'); return null; } } catch (_) { console.log('[91pinse-优化] 护盾生效,已拦截无法解析的弹窗'); return null; } } } catch (e) {} return originalOpen.apply(this, arguments); }; try { if (window.top && window.top !== window) window.top.open = window.open; } catch (_) {} try { if (window.parent && window.parent !== window) window.parent.open = window.open; } catch (_) {} })(); // 捕获阶段拦截到指向广告域名的 <a> 点击 function interceptAnchorEvent(event) { try { let anchor = null; const path = event.composedPath ? event.composedPath() : []; for (let i = 0; i < path.length; i++) { const node = path[i]; if (node && node.tagName === 'A') { anchor = node; break; } } if (!anchor && event.target && event.target.closest) { anchor = event.target.closest('a'); } // 列表页点击/右键同源链接时,先开启护盾,防止随后触发的跨域弹窗 if (anchor && anchor.href) { try { const u = new URL(anchor.href, window.location.href); if (u.origin === window.location.origin) { armPopupShield(1600); } } catch (_) {} } if (anchor && anchor.href && isBlockedAdUrl(anchor.href)) { event.preventDefault(); event.stopImmediatePropagation(); console.log('[91pinse-优化] 已阻止跳转到广告域名:', anchor.href); } } catch (e) {} } ['click', 'mousedown', 'mouseup', 'pointerdown', 'auxclick', 'contextmenu', 'touchstart'].forEach(function (evt) { document.addEventListener(evt, interceptAnchorEvent, true); }); // 在视频区域的任意按键或点击都会激活护盾(包括右键) ['mousedown', 'pointerdown', 'click', 'auxclick', 'contextmenu'].forEach(function (evt) { document.addEventListener( evt, function (e) { try { // 在视频区域或链接点击前,启动护盾 if (isInsideVideoArea(e.target)) armPopupShield(1600); // 右键/中键在任何位置也启动护盾 if (evt === 'contextmenu' || (e.button && e.button !== 0)) armPopupShield(1600); } catch (_) {} }, true ); }); const currentDomain = window.location.hostname; const config = { selectors: { videoContainer: '.video-container', videoIframe: '#videoIframe', mainGrid: '.grid.grid-cols-1.lg\\:grid-cols-3.gap-6', mainCol: '.lg\\:col-span-2' }, applyStyles: function () { const mainGrid = document.querySelector( '.grid.grid-cols-1.lg\\:grid-cols-3.gap-6' ); const mainCol = document.querySelector('.lg\\:col-span-2'); if (mainGrid) { mainGrid.classList.remove('grid-cols-1', 'lg:grid-cols-3'); mainGrid.classList.add('grid-cols-1'); mainGrid.style.maxWidth = '100%'; } if (mainCol) { mainCol.classList.remove('lg:col-span-2'); mainCol.style.width = '100%'; mainCol.style.maxWidth = '100%'; } }, cssRules: ` .video-container { width: 100% !important; max-width: 100% !important; margin: 0 auto !important; background-color: #000 !important; } /* 去除 plyr 覆盖层影响右键 */ .plyr__poster { pointer-events: none !important; } .plyr__controls[hidden], .plyr__controls[style*="display: none"] { display: none !important; } .pinse-open-player-btn { position: absolute; top: 10px; right: 10px; z-index: 9999; padding: 6px 10px; font-size: 12px; border-radius: 6px; background: rgba(0,0,0,0.6); color: #fff; border: 1px solid rgba(255,255,255,0.2); cursor: pointer; user-select: none; text-decoration: none; } .pinse-open-player-btn:hover { background: rgba(0,0,0,0.75); } #videoIframe, .aspect-video { display: block !important; width: 100% !important; height: auto !important; } .grid.grid-cols-1 { width: 100% !important; max-width: 100% !important; } .text-xl.md\\:text-2xl.font-bold.p-4 { text-align: center !important; } .grid.grid-cols-2.md\\:grid-cols-3.gap-4 { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)) !important; } @media (min-width: 1400px) { .video-container { max-width: 85% !important; } .lg\\:col-span-2 { margin: 0 auto !important; max-width: 85% !important; } } body { background-color: #121212 !important; } .bg-base-100 { background-color: #1a1a1a !important; } .shadow-lg { box-shadow: 0 4px 6px rgba(0,0,0,0.2) !important; } ` }; function setWideScreenMode() { const videoContainer = document.querySelector(config.selectors.videoContainer); const videoElement = document.querySelector(config.selectors.videoElement) || document.querySelector(config.selectors.videoIframe); if (!videoContainer && !videoElement) { console.log(`${currentDomain}宽屏模式: 未找到视频元素`); return; } if (config.applyStyles) { config.applyStyles(); } if (videoContainer) { const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const targetAspect = 16 / 9; let containerWidth = viewportWidth; let containerMaxWidth = viewportWidth; let containerMaxHeight = Math.floor(viewportHeight * 0.9); if (viewportWidth >= 1400) { containerMaxWidth = Math.floor(viewportWidth * 0.9); } // 计算在可用高度内能容纳的最大宽度 const widthByHeight = Math.floor(containerMaxHeight * targetAspect); containerWidth = Math.min(containerMaxWidth, widthByHeight); videoContainer.style.width = containerWidth + 'px'; videoContainer.style.maxWidth = containerWidth + 'px'; videoContainer.style.margin = '0 auto'; videoContainer.style.position = 'relative'; } if (videoElement) { const aspectRatio = 16 / 9; videoElement.style.width = '100%'; videoElement.style.height = 'auto'; videoElement.style.maxHeight = '90vh'; videoElement.removeAttribute('style'); // 重新设置关键样式,避免行内样式与 CSS 冲突 videoElement.style.width = '100%'; videoElement.style.height = 'auto'; videoElement.style.maxHeight = '90vh'; } ensureOpenPlayerButton(); console.log(`${currentDomain}宽屏模式: 已启用宽屏模式`); } function setupResizeListener() { let resizeRaf = null; window.addEventListener('resize', function () { if (resizeRaf) cancelAnimationFrame(resizeRaf); resizeRaf = requestAnimationFrame(function () { setWideScreenMode(); }); }); } function addStyles() { const styleSheet = document.createElement('style'); styleSheet.textContent = config.cssRules; document.head.appendChild(styleSheet); } // 去除内联 style 中的强制宽高/比例,避免与适配冲突 function normalizeInlineStyles() { try { const iframe = document.querySelector('#videoIframe'); if (iframe) { iframe.style.removeProperty('max-height'); iframe.style.removeProperty('aspect-ratio'); iframe.style.removeProperty('height'); iframe.style.removeProperty('width'); } const container = document.querySelector('.video-container'); if (container) { container.style.removeProperty('max-width'); container.style.removeProperty('width'); } } catch (_) {} } // 在同域播放器中提供“在新标签页打开播放器”按钮,方便用户用原生界面右键 function ensureOpenPlayerButton() { try { const container = document.querySelector(config.selectors.videoContainer); const iframe = document.querySelector(config.selectors.videoIframe); if (!container || !iframe) return; if (iframe.src && new URL(iframe.src, location.href).origin !== location.origin) return; // 仅处理同源 let btn = container.querySelector('.pinse-open-player-btn'); if (!btn) { btn = document.createElement('a'); btn.className = 'pinse-open-player-btn'; btn.textContent = '在新标签页打开播放器'; btn.target = '_blank'; container.appendChild(btn); } btn.href = iframe.src || location.href; } catch (_) {} } function init() { addStyles(); sanitizeIframes(document); stripContextMenuAttribute(document); // 尝试对同源 iframe 也启用右键 try { document.querySelectorAll('iframe').forEach(function (f) { tryHookSameOriginIframe(f); }); } catch (_) {} // 列表链接与详情页优先 HD upgradeLinksToHD(document); preferHDOnPage(); installPreferHdClickHandler(); const delay = 200; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function () { setTimeout(function () { setWideScreenMode(); setupResizeListener(); }, delay); }); } else { setTimeout(function () { setWideScreenMode(); setupResizeListener(); }, delay); } document.addEventListener( 'load', function (e) { if (e.target.tagName === 'VIDEO' || e.target.tagName === 'IFRAME') { setWideScreenMode(); } }, true ); window.addEventListener('load', function () { setWideScreenMode(); }); const observer = new MutationObserver(function (mutations) { let shouldUpdate = false; mutations.forEach(function (mutation) { if (mutation.addedNodes.length > 0) { shouldUpdate = true; mutation.addedNodes.forEach(function (node) { try { if (node.nodeType === 1) { if (node.tagName === 'IFRAME') { sanitizeIframes(node.parentNode || document); tryHookSameOriginIframe(node); } else if (node.querySelectorAll) { sanitizeIframes(node); stripContextMenuAttribute(node); // 针对新增的同源 iframe try { node.querySelectorAll('iframe').forEach(function (f) { tryHookSameOriginIframe(f); }); } catch (_) {} // 新增节点里同样升级视频链接 upgradeLinksToHD(node); } } } catch (_) {} }); } }); if (shouldUpdate) { setWideScreenMode(); } }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['src','style'] }); console.log(`${currentDomain}宽屏模式: 已启用`); } init(); })();