描述:
我正在开发一个浏览器扩展,其唯一目的是调整 Facebook 页面上视频的播放速度。该扩展在其他网站上运行完美,但是,当我尝试专门在 Facebook 上实现它时遇到了障碍。
问题:
当我将扩展应用到 Facebook 视频时,速度调整似乎没有生效。
我的代码:
popup.html:
<!DOCTYPE html>
<html>
<head>
<title>Fb Video Speed Control</title>
</head>
<body>
<h2>Facebook Video Speed Control</h2>
<form id="speedForm">
<label for="speed">Playback Speed:</label>
<input type="number" id="speed" step="0.1" min="0.1" max="5" value="1">
<button type="submit">Apply</button>
</form>
<script src="popup.js"></script>
</body>
</html>
manifest.json:
{
"manifest_version": 3,
"name": "Fb Video Speed Control",
"version": "1.0",
"description": "Adjust Facebook video playback speed",
"permissions": ["activeTab", "storage"],
"icons": {
"48": "icon.png"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"48": "icon.png"
}
},
"content_scripts": [
{
"matches": ["*://*.facebook.com/*"],
"js": ["content.js"]
}
]
}
popup.js:
document.addEventListener("DOMContentLoaded", function() {
console.log("Popup DOMContentLoaded event fired.");
const form = document.getElementById("speedForm");
const speedInput = document.getElementById("speed");
form.addEventListener("submit", function(event) {
event.preventDefault();
const selectedSpeed = parseFloat(speedInput.value);
console.log("Submit button clicked. Selected speed:", selectedSpeed);
chrome.storage.local.set({ playbackSpeed: selectedSpeed }, function() {
console.log("Playback speed set to:", selectedSpeed);
});
});
});
内容.js :
console.log("Content script is running.");
chrome.storage.local.get(["playbackSpeed"], function(result) {
const playbackSpeed = result.playbackSpeed || 1;
console.log("Playback speed retrieved:", playbackSpeed);
const videos = document.getElementsByTagName("video");
for (let i = 0; i < videos.length; i++) {
videos[i].playbackRate = playbackSpeed;
console.log("Video", i, "playback speed set to:", playbackSpeed);
}
});
要求:
我正在寻求有关如何排查和解决此特定问题的建议。如果有人有创建与 Facebook 环境交互的浏览器扩展的经验,我们将非常感谢您的见解和指导。
谢谢您的帮助!
问题是像 facebook 这样的现代 SPA 网站(single-page application)会动态生成页面内容,而从服务器加载的初始内容只是一个带有页眉/页脚的空模板。你的 content.js 运行在这个空页面上,没有找到任何视频,然后他们的脚本根据新的网络请求异步生成内容。
最轻量级的解决方案就是监听
play
事件:
const STORAGE = chrome.storage.sync; // `sync` is preferable for small settings
const KEY = 'playbackSpeed';
const ignored = new WeakSet();
let speed, speedPromise;
addEventListener('play', async e => {
if (e.target.tagName === 'VIDEO' && !ignored.has(e.target)) {
ignored.add(e.target);
e.target.playbackRate = speed || await (
speedPromise || (speedPromise = STORAGE.get(KEY).then(r => (speed = r[KEY])))
);
}
}, true); // IMPORTANT! The `play` event doesn't bubble, so we listen in the first phase
chrome.storage.onChanged.addListener(changes => {
const ch = changes[KEY];
if (ch) {
speed = ch.newValue;
for (const el of document.getElementsByTagName('video')) {
el.playbackRate = speed;
}
}
});
另一个解决方案是MutationObserver,您可以使用它来检测正在添加的视频元素,但这很浪费,因为并非所有视频元素都会被播放。