您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Make Facebook Reel: Video Controls
// ==UserScript== // @name Facebook Reel: Video Controls // @namespace UserScript // @match https://www.facebook.com/* // @version 0.2.10 // @license MIT // @author CY Fung // @description Make Facebook Reel: Video Controls // @run-at document-start // @grant none // @unwrap // ==/UserScript== (() => { const resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { if (entry.contentRect.height > 0) { document.documentElement.style.setProperty('--frvc-reel-control-height', entry.contentRect.height + 'px'); } } }); let addCSS = () => { if (addCSS.done) return; addCSS.done = true; document.head.appendChild(document.createElement('style')).textContent = ` [frvc-div-might-empty]:empty { display: none; } [frvc-cursor-passthrough] { pointer-events: none; } [frvc-cursor-passthrough] [role], [frvc-cursor-passthrough] [tabindex] { pointer-events: initial; } [frvc-mutual-layer]:hover [frvc-video-button-layer]{ z-index: 9999; opacity: initial !important; transition-duration: 0 !important; } [frvc-mutual-layer]:hover [frvc-video-button-layer] .x10l6tqk { z-index: 9999; } `; }; const setVideoTargetStyles = (videoTarget) => { Object.assign(videoTarget.style, { 'position': 'relative', 'zIndex': 999, 'pointerEvents': 'all', 'height': 'calc(100% - var(--frvc-reel-control-height))' }); }; const mutualLayer = (a, b) => { let c = a, d = b; if (!a || !b) return null; while (c || d) { if (c && c.contains(b)) { return c; } else if (d && d.contains(a)) { return d; } if (c) c = c.parentElement; if (d) d = d.parentElement; } return document.body; } const forceShowButtons = (layer) => { const buttons = layer.querySelectorAll('div[aria-label][role="button"][tabindex][class]'); const floatingLayer = [...new Set([...buttons].map((btn) => btn.closest("div.x1jha2h7")))].filter(e => !!e); if (floatingLayer.length === 0) return; layer.setAttribute("frvc-mutual-layer", ""); for (const s of floatingLayer) { s.setAttribute("frvc-video-button-layer", ""); } } const attributeRemoves = (list) => { for (const m of list) { for (const s of document.querySelectorAll(`[${m}]`)) { s.removeAttribute(m); } } } document.addEventListener('play', (evt) => { const videoTarget = (evt || 0).target; if (videoTarget instanceof HTMLVideoElement) { { const fid = videoTarget.getAttribute("frvc-video-id"); if (fid) { const layer = document.querySelector(`[frvc-layer-id="${fid}"]`); if (!layer) { videoTarget.removeAttribute("frvc-video-id"); } else if (!layer.contains(videoTarget)) { videoTarget.removeAttribute("frvc-video-id"); layer.removeAttribute("frvc-layer-id"); } else { return; } } } // if (videoTarget.hasAttribute('controls')) return; if (location.href.indexOf('reel') < 0) return; const debugInfo = {}; Promise.resolve(debugInfo).then(console.debug); const videoLayerContainer = videoTarget.closest('div[class][role="button"][tabindex], div[role="main"]'); if (!videoLayerContainer) return; debugInfo.videoLayerContainer = videoLayerContainer; videoTarget.setAttribute('controls', ''); addCSS(); const fid = `f${Math.floor(Math.random() * 1e8 + 1e8).toString(36)}`; videoTarget.setAttribute("frvc-video-id", fid); setTimeout(() => { if (!videoTarget.hasAttribute("controls") || videoTarget.getAttribute("frvc-video-id") !== fid) return; document.documentElement.style.removeProperty('--frvc-reel-control-height'); attributeRemoves(["frvc-video-layer-container", "frvc-cursor-passthrough", "frvc-div-might-empty", "frvc-mutual-layer"]); // position: absolute; top:0; do not contains videoTarget videoLayerContainer.setAttribute("frvc-video-layer-container", ""); let floatingLayer = [...videoLayerContainer.querySelectorAll('.x10l6tqk.x13vifvy:not(.x1m3v4wt)')].filter(elm => !elm.contains(videoTarget)); debugInfo.floatingLayer = floatingLayer; const clickable = videoLayerContainer.querySelectorAll('a[role="link"][href]'); debugInfo.clickable = clickable; const clickableHolder = [...new Set([...clickable].map(e => { // looking for clickableHolder inside floatingLayer do { if (floatingLayer.includes(e.parentNode)) return e; } while ((e = e.parentNode) instanceof HTMLElement); return null; }))].filter(e => !!e).map(e => { const f = (e) => { const { firstElementChild, lastElementChild } = e; if (firstElementChild === lastElementChild) return f(firstElementChild); const validChildren = [...e.children].filter(e => e.firstElementChild !== null); if (validChildren.length === 1) return f(validChildren[0]); return e; } return f(e); }); debugInfo.clickableHolder = clickableHolder; if (clickableHolder.length === 0) return; for (const s of clickableHolder) { let e = s; while (e && e.nodeType === 1 && !e.hasAttribute("frvc-video-layer-container")) { if (floatingLayer.includes(e)) { Object.assign(e.style, { 'pointerEvents': 'none' }); e.setAttribute('frvc-cursor-passthrough', ""); } e = e.parentNode; } const clickable = s.querySelectorAll('a[role="link"][href]'); for (const s of clickable) { Object.assign(s.style, { 'pointerEvents': 'initial' }); } } const videoElmBRect = videoTarget.getBoundingClientRect(); let effctiveHolder = null; for (const s of clickableHolder) { if (effctiveHolder === null) { const clickableHolderBRect = s.getBoundingClientRect(); const conditions = { bottom: Math.abs(clickableHolderBRect.bottom - videoElmBRect.bottom) < 48, top: clickableHolderBRect.top + 1 > videoElmBRect.top, left: Math.abs(clickableHolderBRect.left - videoElmBRect.left) < 5, right: Math.abs(clickableHolderBRect.right - videoElmBRect.right) < 5 } console.debug(conditions); if (conditions.bottom && conditions.top && conditions.left && conditions.right) { effctiveHolder = s; } } Object.assign(s.style, { 'pointerEvents': 'initial', 'height': 'auto', 'boxSizing': 'border-box', 'paddingTop': '16px' }); } debugInfo.effctiveHolder = effctiveHolder; if (effctiveHolder) { addCSS(); for (const s of effctiveHolder.querySelectorAll('div[class]:empty')) { s.setAttribute('frvc-div-might-empty', ""); } resizeObserver.disconnect(); resizeObserver.observe(effctiveHolder); setVideoTargetStyles(videoTarget); const layer = mutualLayer(videoTarget, effctiveHolder); forceShowButtons(layer); for (const s of document.querySelectorAll("[frvc-video-id], [frvc-layer-id]")) { s.removeAttribute("frvc-video-id"); s.removeAttribute("frvc-layer-id"); } videoTarget.setAttribute("frvc-video-id", fid); layer.setAttribute("frvc-layer-id", fid); } }, 1); } }, true); })();