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

我正在制作一个简单的Chrome扩展程序,将YouTube播放列表中每个video的长度相加,然后在页面中插入总长度。 我已经成功了,但是我的脚本只在刷新页面后才起作用,但是在导航站点时不起作用。 虽然这不是很方便。

是否有可能在Youtube上检测到页面导航,并在浏览器中呈现HTML之前将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}); 

Youtube网站不会重新加载导航页面,它会取代历史状态 。

当URL更改而没有重新加载页面时,扩展的内容脚本不会重新注入。 当然,当你手动重新加载页面时,内容脚本被执行。

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

  • 使用后台页面脚本: webNavigation API , 选项卡API
  • 使用video页面上的进度表的内容脚本: transitionend事件
  • 使用video导航上触发的内容脚本和特定于站点的事件:

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

    在这里输入图像描述

    yt-navigate-start是我们需要的。
    请注意,旧的YouTubedevise仍然显示在某些情况下使用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 

processfunction将改变页面。
请注意,指定的元素类和结构将在未来发生变化。

 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>"); } 

我们loadpostProcess函数只会在网站打开时运行一次。 加载完所有脚本之后,将其用于页面的一次性处理。

2017答复:

我用这个新的材料devise版本Youtube

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

这是旧的Youtube

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

代码来自我写的2个脚本调用
“Youtube subtitle downloader”和“Youtube auto subtitle downloader”。

他们两个都工作,我testing了。

如果你对我的脚本感兴趣,想知道更多的细节:
https://github.com/1c7/Youtube-Auto-Subtitle-Download