Youtube - это современный сайт, который обновляет страницу только частично, используя данные с сервера.Это означает, что есть только одна полная загрузка страницы, во время которой ytplayer
состоит из встроенного тега <script>
.Это также означает, что ваш скрипт контента запускается только один раз.
Предлагаемое решение - перехватить сетевое взаимодействие сайта, переопределив метод XHR open
в контексте страницы , чтобы получить новый ytplayer.object.
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 не является первой навигацией, первоначальный объект конфигурации будет неправильным.Чтобы это исправить, вы можете сравнить идентификатор видео (извлечь его из URL) с идентификатором внутри конфигурации (например, свойством «loaderUrl»), и, если он не совпадает, просто получить аргументы через конечную точку get_video_info, котораялегко анализировать (разделить на &
, затем на =
, затем использовать decodeURIComponent): 'https://www.youtube.com/get_video_info?video_id=' + id + '&hl=en_US&html5=1&el=embedded'