如何检测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
process
function将改变页面。
请注意,指定的元素类和结构将在未来发生变化。
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>"); }
我们load
的postProcess
函数只会在网站打开时运行一次。 加载完所有脚本之后,将其用于页面的一次性处理。
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