You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展仅在刷新YouTube页面后生效问题求助

问题描述

我为学习制作了一款Chrome扩展,功能是捕获多帧YouTube画面并合并(效果示例:多帧合并效果)。但该扩展仅在刷新页面后才能正常工作。我对JavaScript不太熟悉,推测扩展在页面跳转后被卸载,刷新YouTube页面时能看到加载状态。

以下是扩展的代码文件:

manifest.json

{"name": "some text that not on english","description": "some text that not on english","version": "0.1","manifest_version": 3,"action": {"default_popup": "popup.html","default_icon": {"16": "/icons/icons8-capture-16.png","32": "/icons/icons8-capture-32.png","48": "/icons/icons8-capture-48.png","128": "/icons/icons8-capture-128.png"}},"content_scripts":[{"js": ["contentscript.js" ],"matches":["https://www.youtube.com/watch*"],"run_at": "document_end"}],"permissions" : ["storage", "activeTab", "scripting","tabs"],"host_permissions": ["*://*/"],"icons": {"16": "/icons/icons8-capture-16.png","32": "/icons/icons8-capture-32.png","48": "/icons/icons8-capture-48.png","128": "/icons/icons8-capture-128.png"}}
document.addEventListener('DOMContentLoaded', function () {var captureButton = document.getElementById('capture');var saveButton = document.getElementById('save');
    captureButton.addEventListener('click', function () {chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {chrome.tabs.sendMessage(tabs[0].id, { action: 'capture' });});});
    saveButton.addEventListener('click', function () {chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {chrome.tabs.sendMessage(tabs[0].id, { action: 'save' });});});
});

contentscript.js

let k=0;let obj=[];var image = 0;let imageheight = 0;let imagewidth = 0 ;
function picture(){let canvas=document.createElement("canvas"),video=document.querySelector("video"),ctx=canvas.getContext("2d");canvas.width=parseInt(video.offsetWidth),canvas.height=parseInt(video.offsetHeight),ctx.drawImage(video,0,0,canvas.width,canvas.height);imageheight = canvas.height;imagewidth = canvas.width;var base64ImageData1=canvas.toDataURL("image/webp");return base64ImageData1;}
function Imagepic(){var image = new Image();image.src=picture();obj[k] = image;k++;}
function mergepic(){let canvas=document.createElement("canvas"),video=document.querySelector("video"),ctx=canvas.getContext("2d");let canvas3=document.createElement("canvas"),video3=document.querySelector("video"),ctx3=canvas3.getContext("2d");canvas3.width=parseInt(video3.offsetWidth),canvas3.height=parseInt(video3.offsetHeight*k);for (var i=0; i<obj.length; i++){console.log("a");ctx3.drawImage(obj[i],0,imageheight*i);}var base64ImageData=canvas3.toDataURL("image/webp"),o = new Date(0),p = new Date(video3.currentTime*1000),filename="📷Capture_"+new URL(document.location.href).searchParams.get("v")+"_"+document.title+"@"+new Date(p.getTime()-o.getTime()).toISOString().split("T")[1].split("Z")[0]+"\.webp",a=document.createElement("a");a.download=filename,a.href=base64ImageData,a.click();obj=[];k=0;}
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {if (request.action === 'capture') {Imagepic();} else if (request.action === 'save') {mergepic();}});
解决方案

问题出在YouTube是单页应用(SPA),页面内导航(比如从首页进视频页、视频间跳转)不会触发页面刷新,而你的content script仅在页面首次加载(刷新)时注入,跳转后扩展就失效了。

1. 更新manifest.json

添加background服务工作者,调整权限和注入逻辑:

{
  "name": "非英文名称",
  "description": "非英文描述",
  "version": "0.1",
  "manifest_version": 3,
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "/icons/icons8-capture-16.png",
      "32": "/icons/icons8-capture-32.png",
      "48": "/icons/icons8-capture-48.png",
      "128": "/icons/icons8-capture-128.png"
    }
  },
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage", "activeTab", "scripting", "tabs"],
  "host_permissions": ["*://*.youtube.com/*"],
  "icons": {
    "16": "/icons/icons8-capture-16.png",
    "32": "/icons/icons8-capture-32.png",
    "48": "/icons/icons8-capture-48.png",
    "128": "/icons/icons8-capture-128.png"
  }
}

2. 创建background.js

监听页面导航,动态注入content script:

chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
  if (tab.url?.includes('youtube.com/watch') && changeInfo.status === 'complete') {
    try {
      // 检查脚本是否已注入
      const [{result}] = await chrome.scripting.executeScript({
        target: {tabId},
        func: () => typeof chrome.runtime.onMessage.hasListener === 'function'
      });
      if (!result) {
        await chrome.scripting.executeScript({
          target: {tabId},
          files: ['contentscript.js']
        });
      }
    } catch (err) {
      console.error('注入脚本失败:', err);
    }
  }
});

3. 优化contentscript.js

避免重复注册监听器,修复图片加载问题:

let k = 0;
let obj = [];
let imageheight = 0;
let imagewidth = 0;

function picture() {
  const video = document.querySelector("video");
  if (!video) return '';
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  canvas.width = parseInt(video.offsetWidth);
  canvas.height = parseInt(video.offsetHeight);
  ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
  imageheight = canvas.height;
  imagewidth = canvas.width;
  return canvas.toDataURL("image/webp");
}

function Imagepic() {
  const imageSrc = picture();
  if (!imageSrc) return;
  const image = new Image();
  image.src = imageSrc;
  obj[k] = image;
  k++;
}

function mergepic() {
  const video = document.querySelector("video");
  if (!video || obj.length === 0) return;
  const canvas3 = document.createElement("canvas");
  const ctx3 = canvas3.getContext("2d");
  canvas3.width = parseInt(video.offsetWidth);
  canvas3.height = parseInt(video.offsetHeight * k);
  
  // 等待所有图片加载完成再绘制
  Promise.all(obj.map(img => new Promise(resolve => img.onload = resolve)))
    .then(() => {
      for (let i = 0; i < obj.length; i++) {
        ctx3.drawImage(obj[i], 0, imageheight * i);
      }
      const base64ImageData = canvas3.toDataURL("image/webp");
      const videoTime = new Date(video.currentTime * 1000);
      const filename = `📷Capture_${new URL(document.location.href).searchParams.get("v")}_${document.title}@${videoTime.toISOString().split("T")[1].split("Z")[0]}.webp`;
      const a = document.createElement("a");
      a.download = filename;
      a.href = base64ImageData;
      a.click();
      obj = [];
      k = 0;
    });
}

// 避免重复注册消息监听器
if (!chrome.runtime.onMessage.hasListeners()) {
  chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action === 'capture') {
      Imagepic();
    } else if (request.action === 'save') {
      mergepic();
    }
  });
}

效果说明

  • 动态注入:每次进入YouTube视频页(包括SPA跳转)都会自动注入content script,无需刷新页面。
  • 监听器去重:防止重复注册导致多次执行逻辑。
  • 图片加载优化:合并时等待所有捕获的图片加载完成,避免绘制空白内容。

内容的提问来源于stack exchange,提问作者banalena

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:47:32