Ответ 1
Сайт Youtube не перезагружает страницы при навигации, он заменяет состояние истории.
Сценарии расширения содержимого не повторно вводятся при изменении URL-адреса без перезагрузки страницы. Естественно, когда вы перезагружаете страницу вручную, выполняется скрипт содержимого.
Существует несколько способов обнаружения переходов страниц на сайте Youtube:
- использование фонового скрипта страницы: API webNavigation, API вкладок
- использование сценария содержимого: событие
transitionend
для индикатора выполнения на страницах с видео -
используя скрипт контента и специфичное для сайта событие, запускаемое при видеонавигации:
Запустите
getEventListeners(window)
в консоли devtools и проверьте вывод.yt-navigate-start - это то, что нам нужно.
Обратите внимание, что старый дизайн YouTube все еще показан в некоторых случаях с использованием событияspfdone
manifest.json:
{
"name": "YouTube Playlist Length",
"version": "0.0.1",
"manifest_version": 2,
"description": ".............",
"content_scripts": [{
"matches": [ "*://*.youtube.com/*" ],
"js": [ "content.js" ],
"run_at": "document_start"
}]
}
Обратите внимание, что когда мы загружаем скрипт контента в document_start
он заставляет нашего слушателя DOMContentLoaded
запускаться немного раньше по сравнению с поведением по умолчанию, когда скрипты контента вводятся незначительно после DOMContentLoaded
. С document_start
скрипт контента запускается, когда в body
документа ничего нет и даже нет элемента head
. Присоединить слушателя к document
можно, однако, точно так же.
content.js:
window.addEventListener("spfdone", process); // old youtube design
window.addEventListener("yt-navigate-start", process); // new youtube design
document.addEventListener("DOMContentLoaded", process); // one-time early processing
window.addEventListener("load", postProcess); // one-time late postprocessing
Функция process
изменит страницу.
Обратите внимание, что указанные классы элементов и структура изменится в будущем.
function process() {
if (location.pathname != "/playlist") {
return;
}
var seconds = [].reduce.call(
document.getElementsByClassName("timestamp"),
function(sum, ts) {
var minsec = ts.textContent.split(":");
return sum + minsec[0]*60 + minsec[1]*1;
},
0
);
if (!seconds) {
console.warn("Got no timestamps. Empty playlist?");
return;
}
var timeHMS = new Date(seconds * 1000).toUTCString().split(" ")[4]
.replace(/^[0:]+/, ""); // trim leading zeroes
document.querySelector(".pl-header-details")
.insertAdjacentHTML("beforeend", "<li>Length: " + timeHMS + "</li>");
}
Функция postProcess
которую мы прикрепили при load
будет запускаться только один раз при открытии сайта. Используйте его для однократной обработки страницы после загрузки всех ее скриптов.