如何检测Youtube上的页面导航并在呈现页面之前修改HTML?

时间:2015-12-03 22:42:52

标签: javascript google-chrome google-chrome-extension

我正在制作一个简单的Chrome扩展程序,以在YouTube播放列表中添加每个视频的长度,并在页面中插入总长度。我已经成功了,但我的脚本仅在刷新页面后才起作用,但在网站导航时却不起作用。但这不太方便。

是否可以在浏览器中呈现之前检测Youtube上的页面导航并将HTML插入页面,以便立即显示添加的内容而不会有任何延迟并且不需要刷新页面?< / p>

示例链接:https://www.youtube.com/playlist?list=PL_8APVyhfhpdgMJ3J80YQxWBMUhbwXw8B

P.S。我的问题与Modify elements immediately after they are displayed (not after page completely loads) in greasemonkey script?不一样,因为我尝试过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 个答案:

答案 0 :(得分:18)

Youtube网站不会在导航时重新加载页面,而是取代history state

在没有重新加载页面的情况下更改URL时,不会重新注入扩展程序的内容脚本。当然,当您手动重新加载页面时,将执行内容脚本。

有几种方法可以检测Youtube网站上的页面转换:

  • 使用背景页脚本:webNavigation APItabs API
  • 使用内容脚本:transitionend event用于视频页面上的进度表
  • 使用内容脚本和在视频导航中触发的特定于网站的事件:

    在devtools控制台中运行getEventListeners(window)并检查输出。

    enter image description here

    我们需要

    yt-navigate-start 请注意,在某些情况下仍会显示旧的YouTube设计使用spfdone event

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侦听器稍早运行一下{1}}。使用DOMContentLoaded时,如果文档document_start中没有任何内容,甚至没有body元素,则会运行内容脚本。但是,将听众附加到head也是可能的。

content.js

document

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功能只会在网站打开时运行一次。在加载所有脚本后,将其用于页面的一次性处理。

答案 1 :(得分:10)

2017回答:

我将它用于新的Material Design版本Youtube

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

和旧的Youtube

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

代码来自我编写的2个脚本 &#34; Youtube字幕下载&#34;和&#34; Youtube自动字幕下载器&#34;。

这两个都有效,我测试了。

如果您对我的剧本感兴趣并想了解更多细节:
https://github.com/1c7/Youtube-Auto-Subtitle-Download