Как обнаружить навигацию по страницам на Youtube и изменить HTML перед отображением страницы?

Я делаю простое расширение для Chrome, чтобы добавить длину каждого видео в плейлист YouTube и указать общую длину на странице. Мне это удалось, но мой скрипт работает только после обновления страницы, но не при переходе по сайту. Это не очень удобно, хотя.

Можно ли обнаружить навигацию по страницам на Youtube и вставить HTML-код на страницу до ее отображения в браузере, чтобы добавленное содержимое отображалось немедленно без каких-либо задержек и не требовалось обновление страницы?

Пример ссылки: https://www.youtube.com/playlist?list=PL_8APVyhfhpdgMJ3J80YQxWBMUhbwXw8B

PS Мой вопрос не совпадает с изменением элементов сразу после их отображения (не после полной загрузки страницы) в скрипте greasemonkey? потому что я пробовал MutationObserver и проблема та же - требуется обновление для отображения изменений на веб-странице:

var observer = new MutationObserver(function(mutations) {
    for (var i=0; i<mutations.length; i++) {
        var mutationAddedNodes = mutations[i].addedNodes;
        for (var j=0; j<mutationAddedNodes.length; j++) {
            var node = mutationAddedNodes[j];
            if (node.classList && node.classList.contains("timestamp")) {
                var videoLength = node.firstElementChild.innerText;
                observer.disconnect();    

                var lengthNode = document.createElement("li");
                var lengthNodeText = document.createTextNode(videoLength);
                lengthNode.appendChild(lengthNodeText);
                document.getElementsByClassName("pl-header-details")[0].appendChild(lengthNode);

                return;
            }
        }
    }
});
observer.observe(document, {childList: true, subtree: true});

2 ответа

Решение

Сайт 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 будет работать только один раз, когда сайт открыт. Используйте его для одноразовой обработки страницы после загрузки всех ее скриптов.

Ответ 2017 года:

Я использую это для новой версии Material Design Youtube

body.addEventListener("yt-navigate-finish", function(event) {
    // code here
});

и это для старого Youtube

window.addEventListener("spfdone", function(e) {
    // code here
});

код пришел из 2 сценария я написал вызов
"Youtube загрузчик субтитров" и "Youtube автоматический загрузчик субтитров".

оба они работают, я проверял.

если вы заинтересованы в моем сценарии и хотите узнать более подробно:
https://github.com/1c7/Youtube-Auto-Subtitle-Download

Другие вопросы по тегам