Chrome扩展调用YouTube movie_player方法返回undefined问题咨询
别急,不用急着上YouTube API v3——这个问题根本不是API的事儿,是Chrome扩展内容脚本的隔离环境在搞鬼!
你在浏览器控制台直接跑代码能成功,是因为控制台的代码运行在页面的主世界(Main World)里,能直接访问YouTube页面加载的所有全局变量和对象,包括那个movie_player实例。但内容脚本是运行在一个隔离的沙盒环境里的:它和页面主世界的DOM是共享的,但主世界的JavaScript变量、函数、对象,内容脚本完全访问不到——所以你在内容脚本里拿到的document.getElementById("movie_player")只是个DOM元素壳子,它身上的getDuration()方法是主世界JS挂载的,内容脚本根本看不到这个方法,自然返回undefined。
不用YouTube API v3的解决办法
你完全不需要用YouTube API v3,那个API主要是给开发者做视频搜索、获取视频元数据、在自己网站嵌入视频用的,和你在YouTube页面上直接操作现有播放器的场景不搭。这里给你两个靠谱的方案:
方案1:向页面主世界注入脚本
把获取时长的代码包装成<script>标签插入页面DOM,让它在主世界运行,再通过自定义事件把结果传回内容脚本:
// 内容脚本里的代码 function getVideoDuration() { const script = document.createElement('script'); script.textContent = ` const video = document.getElementById("movie_player"); const duration = video.getDuration(); // 把结果通过自定义事件传给内容脚本 window.dispatchEvent(new CustomEvent('ytDurationReady', { detail: duration })); `; document.head.appendChild(script); script.remove(); } // 监听主世界发来的时长结果 window.addEventListener('ytDurationReady', (e) => { console.log('视频时长:', e.detail); }); // 绑定按钮点击事件 yourButton.addEventListener('click', getVideoDuration);
方案2:用Chrome脚本执行API(Manifest V3推荐)
如果用的是Manifest V3,直接用chrome.scripting.executeScript指定在主世界运行代码,还能直接拿到返回值:
// 内容脚本里的按钮点击逻辑 yourButton.addEventListener('click', async () => { const currentTab = await chrome.tabs.getCurrent(); const [result] = await chrome.scripting.executeScript({ target: { tabId: currentTab.id }, world: 'MAIN', // 关键:指定在主世界执行代码 func: () => { const video = document.getElementById("movie_player"); return video.getDuration(); } }); console.log('视频时长:', result.result); });
要是你还在用Manifest V2,换成chrome.tabs.executeScript就行,逻辑类似,只是API参数略有差异。
额外提醒
记得要等YouTube播放器完全加载完成再执行代码,不然即使在主世界也可能拿不到有效值。可以通过轮询检查movie_player.getDuration()是否大于0,或者监听YouTube的onYouTubePlayerReady事件来确保播放器就绪。
内容的提问来源于stack exchange,提问作者warmSnowyMorning

