You need to enable JavaScript to run this app. 开发Chrome扩展实现YouTube视频描述含Licence关键词告警:检测失效、误扫旧页面问题排查
优惠活动
大模型
产品
解决方案
定价
更多

开发Chrome扩展实现YouTube视频描述含Licence关键词告警:检测失效、误扫旧页面问题排查

问题核心根因

你碰到的两个异常(持续检测到上一页内容、扩展偶发失效)根本不是YouTube API适配的问题,是三个实现细节没踩中单页应用(SPA)的特性:

  • YouTube是纯单页应用,webNavigation.onHistoryStateUpdated的触发时机远早于视频描述区DOM渲染完成,此时发消息给内容脚本,读到的全是上一个视频的残留DOM
  • 现有匹配逻辑是全页面扫XPath找「Licence」,没有限定到视频描述区域,很容易把其他位置的同关键词误判,碰到懒加载的描述区时还会因为节点没加载返回错误结果
  • 消息通信的时序没有兜底,一旦内容脚本没注入完成、或者sendResponse时机不对,就会触发通信失败,表现为偶发不工作
    你之前想靠YouTube API判断播放状态的思路完全没必要,纯靠原生DOM监听+合适的触发时机就能实现功能,不用调用任何外部接口。
优化落地方案
  • 把核心检测逻辑从“background发消息等内容脚本返回结果”改成“内容脚本自主监听路由变化、DOM更新时机,触发后自主完成检测+告警”,彻底绕开消息通信的时序问题
  • 检测范围从全页面缩小到YouTube固定的视频描述区容器,从根源上减少误判
  • 加防抖、去重逻辑,避免DOM频繁更新时重复检测、同一个视频反复弹告警
  • 注入时机调整为页面空闲阶段再加载内容脚本,减少注入太早导致的DOM读取错误
改完的可运行代码

contentscript.js

// 存储已告警过的视频ID,避免重复弹窗
let lastAlertedVideoId = null;
// 防抖定时器
let checkDebounceTimer = null;

// 核心检测逻辑
function runKeywordCheck() {
    // 锁定YouTube视频描述区的固定容器
    const descArea = document.querySelector('#description-inline-expander, ytd-text-inline-expander');
    if (!descArea) return;

    // 提取当前视频ID
    const currentVideoId = new URL(location.href).searchParams.get('v');
    // 已经检测告警过的视频直接跳过
    if (currentVideoId === lastAlertedVideoId) return;

    // 在描述区范围内匹配关键词
    const isLicenceExist = descArea.textContent.includes('Licence');
    if (isLicenceExist) {
        lastAlertedVideoId = currentVideoId;
        alert("检测到视频描述区包含「Licence」关键词");
    }
}

// 防抖处理:避免DOM频繁变动时重复触发检测
function debouncedRunCheck() {
    clearTimeout(checkDebounceTimer);
    checkDebounceTimer = setTimeout(runKeywordCheck, 300);
}

// 监听页面初次加载
window.addEventListener('load', debouncedRunCheck);
// 监听YouTube自身的导航完成事件(比原生popstate触发时机更准)
window.addEventListener('yt-navigate-finish', debouncedRunCheck);
// 监听DOM变化:等懒加载的描述区内容渲染完成再触发检测
const domObserver = new MutationObserver(debouncedRunCheck);
domObserver.observe(document.body, {
    childList: true,
    subtree: true,
    attributes: false,
    characterData: false
});

background.js

简化成只做路由变更的通知,不再处理检测的返回值,避免alert脱离页面上下文:

// 监听YouTube站点的历史状态变更
chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
    // 只给YouTube视频页发通知,其他页面不处理
    if (details.url.includes('youtube.com/watch')) {
        chrome.tabs.sendMessage(details.tabId, {message: "pageChange"});
    }
});

manifest.json

缩小内容脚本的匹配范围,调整注入时机,减少性能消耗:

{
    "manifest_version": 2,
    "name": "Licence关键词告警",
    "version": "1.0",
    "permissions": [
        "tabs",
        "webNavigation",
        "activeTab"
    ],
    "content_scripts": [{
        "matches": ["*://*.youtube.com/*"],
        "js": ["contentscript.js"],
        "run_at": "document_idle"
    }],
    "background": {
        "scripts": ["background.js"]
    }
}
调整后的效果说明
  • 原来的时序问题:把检测逻辑放到内容脚本里,结合YouTube官方的yt-navigate-finish导航完成事件、MutationObserver监听DOM更新,等描述区真正渲染出内容之后再读,完全不会拿到上一页的残留DOM
  • 原来的偶发失效:不再依赖跨进程的消息返回做检测,内容脚本自主判断DOM状态,不会出现消息丢失、sendResponse时机不对的问题,检测稳定性会高很多
  • 原来的误判问题:只在描述区容器里找关键词,不会把页面其他位置的同关键词当成触发条件,检测精度足够
  • 原来的重复告警:加了视频ID的状态记录,同个视频只弹一次告警,切到新视频再重新判断

内容的提问来源于stack exchange,提问作者Vojtěch Fíla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 01:06:05