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

IT技术 javascript google-chrome google-chrome-extension
2021-01-22 02:50:31

我正在制作一个简单的 Chrome 扩展程序,以将 YouTube 播放列表中每个视频的长度相加,并将总长度插入页面中。我已经成功了,但是我的脚本仅在刷新页面后才有效,而在浏览网站时无效。不过这不是很方便。

是否可以在 YouTube 上检测页面导航并将 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});
2个回答

YouTube 网站不会在导航时重新加载页面,它会替换历史状态

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

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

  • 使用后台页面脚本:webNavigation API , tabs API

  • 使用内容脚本:视频页面上进度表的transitionend事件

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

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

    在此处输入图片说明

    在这种情况下,我们需要yt-navigate-start

    笔记:

    • 对于其他任务,我们可能需要yt-navigate-finish
    • 旧的 youtube 设计正在使用spfdone事件

清单.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"
  }]
}

注意:该matches键包含整个 youtube.com 域,以便在用户首次打开 youtube 主页然后导航到观看页面时运行内容脚本。

内容.js

document.addEventListener('yt-navigate-start', process);

if (document.body) process();
else document.addEventListener('DOMContentLoaded', process);

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>');
}
你确定他们使用pushState几天前我因为一个问题快速浏览了一下(顺便说一句,我会发现它回到 VTC 作为这个人的骗局),但是为了在这些方法上包含一个事件发射器而覆盖history.pushStatehistory.replaceState,根本没有用,即使我在页面加载之前确实覆盖了。
2021-03-11 02:50:31
此解决方案工作正常,但不幸的是仅适用于 YouTube 旧设计。
2021-03-20 02:50:31
yt-navigate-start网站上有一个新事件向某些用户显示。另外,我稍微概括了答案以解释如何找到实际事件。
2021-03-31 02:50:31
@Kaiido,是的,他们只是使用 hack 通过 iframe 恢复原始 API 绑定:puu.sh/wRIZg/6a3ad30828.png
2021-04-03 02:50:31
作为参考,这里有一个后台脚本方法的例子:stackoverflow.com/a/21071357/72321
2021-04-05 02:50:31

2017年答案:

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

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

这对于旧的 Youtube

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

代码来自我编写的 2 个脚本,称为
“Youtube 字幕下载器”和“Youtube 自动字幕下载器”。

他们都工作,我测试过。

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

值得注意的,现有答案涵盖了此信息(尽管它使用了yt-navigate-start
2021-03-24 02:50:31
是的,这个不讲原理,直接给出代码,我觉得这个答案还是有一定value的,所以还是保留这个答案。:D 谢谢你提到它@Xan
2021-03-24 02:50:31