我正在开发一个铬扩展名,它使用contentscript.js文件中youtube页面中的ytplayer对象。在过去,ytplayer对象每次导航到一个新的youtube视频时都会更新。到目前为止,我已经看不到它的更新了。
如何复制
您将看到ytplayer在导航到第二个视频后不会更新。我的扩展使用这个对象。问题是,在导航到另一个视频后,该对象已失效。当我在每次视频导航之后提取ytplayer对象时,我会显示错误的数据,因为ytplayer总是来自第一个视频。
问题。
发布于 2019-02-10 06:41:49
Youtube是一个现代化的网站,它只使用来自服务器的部分数据来更新页面。这意味着只有一个完整的页面加载,在此期间,ytplayer是在内联<script>标记中构建的。这也意味着您的内容脚本只运行一次。
所提出的解决方案是通过在open中重写XHR page context方法来拦截站点的网络通信,以获得新的ytplayer对象。
manifest.json:
"content_scripts": [{
"run_at": "document_start",
"matches": ["https://www.youtube.com/*"],
"js": ["content.js"]
}]content.js:
const token = chrome.runtime.id + ':' + performance.now() + ':' + Math.random();
window.addEventListener(token, e => {
console.log('gotPlayerArgs', e.detail);
chrome.runtime.sendMessage({
action: 'gotPlayerArgs',
data: e.detail,
});
});
const script = document.createElement('script');
script.textContent = '(' + (token => {
const origOpen = XMLHttpRequest.prototype.open;
const dispatch = data => window.dispatchEvent(new CustomEvent(token, {detail: data}));
const onLoad = e => {
const json = e.target.response;
const player = (Array.isArray(json) && json.find(_ => _.player) || {}).player || {};
dispatch(player.args);
};
// get the initial config
try {
dispatch(window.ytplayer.config.args);
} catch (e) {}
// intercept the subsequent config queries
XMLHttpRequest.prototype.open = function (method, url) {
if (url.startsWith('https://www.youtube.com/watch?')) {
this.addEventListener('load', onLoad);
}
return origOpen.apply(this, arguments);
};
}) + `)("${token}")`;
document.documentElement.appendChild(script);
script.remove();还有一个警告仍然存在:(1)如果您的扩展被更新/重新加载或禁用/重新启用,而(2) youtube页面不是第一个导航,那么初始的config对象将是错误的。要解决这个问题,您可以将视频的id (从URL中提取)与配置(例如“loaderUrl”属性)中的id进行比较,如果它不匹配,只需通过get_video_info端点获得args,这很容易解析(由&拆分,然后使用decodeURIComponent):'https://www.youtube.com/get_video_info?video_id=' + id + '&hl=en_US&html5=1&el=embedded':
https://stackoverflow.com/questions/54610750
复制相似问题