【发布时间】:2018-07-09 11:29:12
【问题描述】:
我正在为 Greasemonkey 创建一个用户脚本,用于在 YouTube 的 cmets 附近显示其他内容。我希望它同时支持 Classic 模式和 New Look(基于 Polymer,可以在 https://www.youtube.com/new 激活),并且我已经实现了我想要的大部分功能。
但我最近发现的一个主要问题与看似复杂的 YouTube 机制有关,涉及以下过程:
-
(1) 从缓存中加载第一批 cmets。
-
(2) 从缓存中加载更多批次的 cmets。
为了处理每条评论,我使用waitForKeyElements 来捕捉它们。
当我不离开当前页面时,这很有效。但是,当我在同一页面上打开不同的视频时,或者当我打开任何其他 YouTube 页面然后按返回时,内容会中断。
导航后,应该由脚本处理的 cmets 显示为已处理。当然,这就是 YouTube 的免重新加载设计的工作原理。
在某些时候,我能够让脚本识别导航事件yt-navigate-finish - 这解决了问题 (1)。但另一个问题 (2) 仍然存在 - 新批次的 cmets 出现缓存并被重新插入和重新填充。这是我找不到解决方案的地方。
为了演示这个问题,我创建了一个小的 Greasemonkey 脚本 (MCVE):
// ==UserScript==
// @name TEST2
// @include https://*youtube.com/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// @grant none
// @run-at document-start
// ==/UserScript==
waitForKeyElements('#main .style-scope ytd-comment-renderer', ParseItemTest);
function ParseItemTest(jNode) {
var aNode = $(jNode).find("#author-text")[0];
var newspan = document.createElement('span');
newspan.innerHTML = ' <font color="red">===</font> ' + $(aNode).find("span.style-scope.ytd-comment-renderer").html();
$(aNode).append(newspan);
}
function waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector) {
var targetNodes, btargetsFound;
if (typeof iframeSelector == "undefined") targetNodes = $(selectorTxt);
else targetNodes = $(iframeSelector).contents().find(selectorTxt);
if (targetNodes && targetNodes.length > 0) {
btargetsFound = true;
targetNodes.each(function() {
var jThis = $(this);
var alreadyFound = jThis.data('alreadyFound') || false;
if (!alreadyFound) {
var cancelFound = actionFunction(jThis);
if (cancelFound) btargetsFound = false;
else jThis.data('alreadyFound', true);
}
});
} else {
btargetsFound = false;
}
var controlObj = waitForKeyElements.controlObj || {};
var controlKey = selectorTxt.replace(/[^\w]/g, "_");
var timeControl = controlObj[controlKey];
if (btargetsFound && bWaitOnce && timeControl) {
clearInterval(timeControl);
delete controlObj[controlKey];
} else {
if (!timeControl) {
timeControl = setInterval(function() {
waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector);
}, 300);
controlObj[controlKey] = timeControl;
}
}
waitForKeyElements.controlObj = controlObj;
}
激活此脚本,启用 YouTube 的新外观并使用 cmets 转到任何视频。让他们加载,注意每个评论是如何添加用户名的,例如
爱丽丝 === 爱丽丝
约翰 === 约翰
格蕾丝 === 格蕾丝
打开任何其他页面并按返回后,您将看到以下内容:
爱丽丝 === 格蕾丝
约翰 === 约翰
格蕾丝 === 爱丽丝
在您转到另一个视频页面并检查 cmets 后,您会看到:
简 === 格蕾丝
多萝西 === 约翰
布拉德 === 爱丽丝
我希望这足以解释问题。我只需要抓住 YouTube 用新数据填充现有评论元素的时刻,然后用新数据再次解析它们。
【问题讨论】:
标签: javascript jquery youtube greasemonkey tampermonkey