Facebook Reel: Video Controls

Make Facebook Reel: Video Controls

目前为 2025-03-21 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Facebook Reel: Video Controls
  3. // @namespace UserScript
  4. // @match https://www.facebook.com/*
  5. // @version 0.2.0
  6. // @license MIT
  7. // @author CY Fung
  8. // @description Make Facebook Reel: Video Controls
  9. // @run-at document-start
  10. // @grant none
  11. // @unwrap
  12. // ==/UserScript==
  13.  
  14. (() => {
  15.  
  16. const resizeObserver = new ResizeObserver((entries) => {
  17. for (const entry of entries) {
  18. if (entry.contentRect.height > 0) {
  19. document.documentElement.style.setProperty('--frvc-reel-control-height', entry.contentRect.height + 'px');
  20. }
  21. }
  22. });
  23.  
  24. let addCSS = () => {
  25. if (addCSS.done) return;
  26. addCSS.done = true;
  27. document.head.appendChild(document.createElement('style')).textContent = `
  28. .frvc-div-might-empty:empty {
  29. display: none;
  30. }
  31. .frvc-cursor-passthrough {
  32. pointer-events: none;
  33. }
  34. .frvc-cursor-passthrough [role], .frvc-cursor-passthrough [tabindex] {
  35. pointer-events: initial;
  36. }
  37. `
  38.  
  39. }
  40.  
  41. document.addEventListener('play', (evt) => {
  42. const target = (evt || 0).target;
  43.  
  44. if (target instanceof HTMLVideoElement) {
  45.  
  46. if (target.hasAttribute('controls')) return;
  47. if (location.href.indexOf('reel') < 0) return;
  48.  
  49. let buttonLayer = target.closest('div[class][role="button"][tabindex]');
  50. if (!buttonLayer) return;
  51.  
  52.  
  53. target.setAttribute('controls', '');
  54. addCSS();
  55.  
  56.  
  57. setTimeout(() => {
  58.  
  59.  
  60. Object.assign(target.style, {
  61. 'position': 'relative',
  62. 'zIndex': 999,
  63. 'pointerEvents': 'all',
  64. 'height': 'calc(100% - var(--frvc-reel-control-height))'
  65. });
  66.  
  67. let arr = [...buttonLayer.querySelectorAll('.x10l6tqk.x13vifvy:not(.x1m3v4wt)')].filter(elm => !elm.contains(target));
  68.  
  69.  
  70. const clickable = buttonLayer.querySelectorAll('a[role="link"][href]');
  71. const clickableHolder = [...new Set([...clickable].map(e => {
  72. do {
  73. if (arr.includes(e.parentNode)) return e;
  74. } while ((e = e.parentNode) instanceof HTMLElement);
  75. return null;
  76. }))].filter(e => !!e);
  77.  
  78. for (const s of arr) {
  79.  
  80. Object.assign(s.style, {
  81. 'pointerEvents': 'none'
  82. });
  83. s.classList.add('frvc-cursor-passthrough')
  84.  
  85. }
  86.  
  87. for (const s of clickable) {
  88.  
  89. Object.assign(s.style, {
  90. 'pointerEvents': 'initial'
  91. });
  92. }
  93.  
  94. const videoElmBRect = target.getBoundingClientRect();
  95. let p = null;
  96. for (const s of clickableHolder) {
  97.  
  98. const clickableHolderBRect = s.getBoundingClientRect();
  99. if (p === null && clickableHolderBRect.bottom === clickableHolderBRect.bottom && clickableHolderBRect.top > videoElmBRect.top && clickableHolderBRect.left === clickableHolderBRect.left && clickableHolderBRect.right === clickableHolderBRect.right) {
  100. p = s;
  101.  
  102. }
  103.  
  104.  
  105. Object.assign(s.style, {
  106. 'pointerEvents': 'initial',
  107. 'height': 'auto',
  108. 'boxSizing': 'border-box',
  109. 'paddingTop': '16px'
  110. });
  111. }
  112.  
  113. if (p) {
  114. addCSS();
  115. for (const s of p.querySelectorAll('div[class]:empty')) {
  116. s.classList.add('frvc-div-might-empty');
  117. }
  118. resizeObserver.disconnect();
  119. resizeObserver.observe(p);
  120. }
  121.  
  122. }, 1)
  123.  
  124. }
  125.  
  126. }, true);
  127.  
  128. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址