如何检测Youtube上的页面导航并在页面呈现之前修改HTML? [英] How to detect page navigation on Youtube and modify HTML before page is rendered?
问题描述
我正在制作一个简单的Chrome扩展程序,将YouTube播放列表中每个视频的长度加起来,并在页面中插入总长度。我已经成功了,但是我的脚本只在刷新页面后才起作用,但在站点导航时不起作用。这不是很方便。
是否可以在浏览器中呈现之前检测Youtube上的页面导航并将HTML插入到页面中添加的内容会立即显示,不会有任何延迟,并且不需要刷新页面?
示例链接:
yt-navigate-start 是我们需要的。在某些情况下仍会显示YouTube设计使用 spfdone
事件
$ b manifest.json :
{
name:YouTube Playlist Length,
version:0.0.1,
manifest_version:2,
description:.............,
content_scripts:[{
与 :[*://*.youtube.com/*],
js:[content.js],
run_at:document_start
}]
}
请注意,当我们将内容脚本加载到 document_start
与内容脚本稍后注入时的默认行为相比,它会使我们的 DOMContentLoaded
侦听器稍微运行一些。 DOMContentLoaded
。使用 document_start
时,内容脚本在文档 body
中甚至没有 head
元素。将侦听器添加到文档
是可能的,但也是一样的。
content.js strong>:
window.addEventListener(spfdone,process); //旧的youtube设计
window.addEventListener(yt-navigate-start,process); //新的youtube设计
document.addEventListener(DOMContentLoaded,process); //一次性提前处理
window.addEventListener(load,postProcess); //一次性后期处理
进程
函数将改变页面。
注意,指定的元素类和结构将在未来发生变化。
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:] + /, ); //修剪前导零
document.querySelector(。pl-header-details)
.insertAdjacentHTML(beforeend,< li>长度:+ timeHMS +< / li> );
postProcess
函数我们附加在 load
上的附件只会在网站打开时运行一次。在加载所有脚本后,将其用于一次性页面处理。
I'm making a simple Chrome extension to add up the length of each video in a YouTube playlist and insert the total length in the page. I've succeeded at that, but my script only works after refreshing a page but not when the site is navigated. That's not very convenient though.
Is it possible to detect page navigation on Youtube and insert HTML into the page before it's rendered in the browser so that the added content is shown immediately without any delay and no page refresh is required?
Example link: https://www.youtube.com/playlist?list=PL_8APVyhfhpdgMJ3J80YQxWBMUhbwXw8B
P.S. My question is not the same as Modify elements immediately after they are displayed (not after page completely loads) in greasemonkey script? because I've tried MutationObserver and the problem is the same - a refresh is needed to show changes to the web page:
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 site doesn't reload pages on navigation, it replaces the history state.
The extension's content scripts aren't reinjected when URL changes without a page being reloaded. Naturally when you reload a page manually the content script is executed.
There are several methods to detect page transitions on Youtube site:
- using a background page script: webNavigation API, tabs API
- using a content script:
transitionend
event for the progress meter on video pages using a content script and a site-specific event triggered on video navigation:
Run
getEventListeners(window)
in devtools console and inspect the output.yt-navigate-start is what we need.
Note, the old youtube design still shown in some cases usesspfdone
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"
}]
}
Note, when we load the content script at document_start
it will make our DOMContentLoaded
listener run slightly sooner compared to the default behavior when content scripts are injected slightly after DOMContentLoaded
. With document_start
the content script runs when there's nothing in the document body
and even no head
element. Attaching a listener to document
is possible, though, just the same.
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
The process
function will alter the page.
Note, the specified element classes and structure will change in the future.
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>");
}
The postProcess
function that we attached on load
will run only one time when the site is opened. Use it for one-time processing of the page after all of its scripts are loaded.
这篇关于如何检测Youtube上的页面导航并在页面呈现之前修改HTML?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!