Javascript 如何检测YouTube上的页面导航并无缝修改其外观?

Javascript 如何检测YouTube上的页面导航并无缝修改其外观?,javascript,google-chrome,google-chrome-extension,Javascript,Google Chrome,Google Chrome Extension,我正在制作一个简单的Chrome扩展,将YouTube播放列表中每个视频的长度相加,并将总长度插入页面。我已经成功地做到了这一点,但我的脚本只有在刷新页面后才能工作,而在导航站点时却无法工作。不过那不是很方便 是否可以检测YouTube上的页面导航,并在页面在浏览器中呈现之前将HTML插入该页面,以便立即显示添加的内容,而不需要任何延迟,也不需要刷新页面 示例链接: 另外,我的问题与其他问题不同,因为我尝试了MutationObserver,问题是相同的-需要刷新以显示对网页的更改: var o

我正在制作一个简单的Chrome扩展,将YouTube播放列表中每个视频的长度相加,并将总长度插入页面。我已经成功地做到了这一点,但我的脚本只有在刷新页面后才能工作,而在导航站点时却无法工作。不过那不是很方便

是否可以检测YouTube上的页面导航,并在页面在浏览器中呈现之前将HTML插入该页面,以便立即显示添加的内容,而不需要任何延迟,也不需要刷新页面

示例链接:

另外,我的问题与其他问题不同,因为我尝试了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});
var observer=新的突变观察者(函数(突变){

对于(var i=0;iYouTube站点,它不会在导航上重新加载页面,而是替换了

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

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

  • 使用后台页面脚本:

  • 使用内容脚本:用于视频页面上的进度计

  • 使用内容脚本和视频导航触发的特定于站点的事件:

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

    yt导航开始是我们在这种情况下需要的

    注:

    • 对于其他任务,我们可能需要导航完成
    • youtube的旧设计正在使用

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.addEventListener('yt-navigate-start', process);

if (document.body) process();
else document.addEventListener('DOMContentLoaded', process);
注意:
匹配
键包含整个youtube.com域,因此当用户首先打开youtube主页,然后导航到监视页面时,内容脚本将运行

content.js

{
  "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.addEventListener('yt-navigate-start', process);

if (document.body) process();
else document.addEventListener('DOMContentLoaded', process);
过程
功能将改变页面。
请注意,指定的元素类和结构将在将来更改

function process() {
  if (!location.pathname.startsWith('/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>');
}
函数过程(){
如果(!location.pathname.startsWith('/playlist')){
返回;
}
var seconds=[].reduce.call(
document.getElementsByClassName('timestamp'),
函数(和,ts){
var minsec=ts.textContent.split(“:”);
返回和+minsec[0]*60+minsec[1]*1;
},
0,
);
如果(!秒){
console.warn('没有时间戳。播放列表为空?');
返回;
}
var timeHMS=新日期(秒*1000).toutString().split(“”)[4]
.replace(//^[0://,'');//修剪前导零
document.querySelector(“.pl头详细信息”)
.insertAdjacentHTML('beforeend','
  • 长度:'+timeHMS+'
  • ); }
    2017答案:

    我将此用于新材料设计版本Youtube

    body.addEventListener("yt-navigate-finish", function(event) {
        // code here
    });
    
    这是给老Youtube的

    window.addEventListener("spfdone", function(e) {
        // code here
    });
    
    代码来自我编写的2个脚本调用
    “Youtube字幕下载器”和“Youtube自动字幕下载器”

    我测试了一下,它们都能工作

    如果您对我的脚本感兴趣并想了解更多详细信息:

    Hmm,我试过了,但没有达到我的目的。在加载每个视频的时间戳时,我要插入组合视频长度的页面部分已经加载,因此我遇到了同样的问题,页面需要刷新以显示注入的HTML。更新了我的问题,因为它被标记为重复。只是尝试了t不,这没有解决问题。仍然需要刷新。感谢您迄今为止的帮助。以下是脚本,底部还有清单:作为参考,下面是一个背景脚本方法的示例:此解决方案工作正常,但不幸的是仅适用于YouTube旧设计。有一个新的
    yt导航开始
    事件在展示给一些用户的网站上。另外,我稍微概括了一下答案,解释了如何找到实际事件。你确定他们使用了
    pushState
    ?几天前,因为一个问题,我快速浏览了一下(顺便说一句,我会发现它是VTC的翻版),但为了在这些方法中包含事件发射器而覆盖
    history.pushState
    history.replaceState
    ,根本不起作用,即使我在加载页面之前重写了它。@kaido,是的,他们只是通过iframe使用hack来恢复原始API绑定:注意,这些信息是红色的现有答案(虽然它使用了
    yt导航开始
    )是的,这一个没有谈到原则,但给出了正确的代码,我认为这个答案仍然有一些价值,所以我仍然会保留这个答案。:D谢谢你提到它@Xan