Make Facebook Reel: Video Controls
当前为
// ==UserScript==
// @name Facebook Reel: Video Controls
// @namespace UserScript
// @match https://www.facebook.com/*
// @version 0.2.8
// @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", "");
}
}
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');
for (const s of document.querySelectorAll("[frvc-video-layer-container], [frvc-cursor-passthrough], [frvc-div-might-empty]")) {
s.removeAttribute("frvc-video-layer-container");
}
// 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);
})();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址