如何用JavaScript将YouTube缩略图保存到硬盘?脚本问题求助
YouTube缩略图保存脚本问题解决
问题场景
编写Violentmonkey用户脚本实现YouTube频道缩略图本地保存时遇到跨域问题:
- Firefox中虽能保存缩略图,但会自动打开图片页面,无法停留在当前YouTube页面
- Chromium浏览器直接抛出「已被CORS策略阻止」的错误
需求是直接复用浏览器已下载的缩略图以节省流量,若油猴脚本无法实现,可采用WebExtension方案。
问题根源
- 原脚本通过
fetch/XHR重新请求ytimg.com域名的缩略图,触发浏览器CORS安全限制,因为ytimg的响应头未允许youtube.com跨域读取资源 - 直接使用
<a>标签加download属性下载跨域资源时,Firefox会默认打开资源而非触发下载,这是浏览器的跨域安全行为
解决方案
方案一:优化Violentmonkey脚本(复用已加载的图片)
通过Canvas将页面已加载的img元素转为Blob,绕开CORS限制,同时实现无跳转下载:
// ==UserScript== // @name 保存YouTube频道缩略图 // @namespace Violentmonkey Scripts // @match https://www.youtube.com/* // @grant none // @version 1.1 // @author - // @description 直接复用浏览器已加载的缩略图,无跳转保存到本地 // ==/UserScript== "use strict"; function saveBlob(blob, filename) { const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = filename; link.style.display = 'none'; document.body.appendChild(link); // 添加preventDefault阻止可能的跳转 const clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true }); link.dispatchEvent(clickEvent); document.body.removeChild(link); // 释放URL对象 setTimeout(() => URL.revokeObjectURL(link.href), 100); } function downloadThumbnail(imgEl, filename) { if (!imgEl || !filename) return; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // 设置canvas尺寸与图片一致 canvas.width = imgEl.naturalWidth || imgEl.width; canvas.height = imgEl.naturalHeight || imgEl.height; // 将图片绘制到canvas ctx.drawImage(imgEl, 0, 0); // 导出为Blob并保存 canvas.toBlob((blob) => { if (blob) saveBlob(blob, filename); }, 'image/webp'); } function forElement(el) { const imgEl = el.querySelector('ytd-thumbnail img'); if (!imgEl) return; // 提取视频标题作为文件名(可选) const title = el.querySelector('#video-title').textContent.trim().replace(/[\\/:*?"<>|]/g, '_'); const filename = `${title}.webp`; downloadThumbnail(imgEl, filename); } function start() { let testButton = document.querySelector("button#test"); if (!testButton) { document.querySelector('ytd-masthead div#container div#end').insertAdjacentHTML( 'afterbegin', '<button id="test" style="padding: 8px 12px; margin-right: 8px; cursor: pointer;">保存缩略图</button>' ); testButton = document.querySelector("button#test"); } testButton.onclick = function() { const firstVideoEl = document.querySelectorAll("div#content.ytd-rich-item-renderer")[0]; if (firstVideoEl) forElement(firstVideoEl); }; } // 监听页面动态加载(YouTube是单页应用) new MutationObserver(start).observe(document.body, { childList: true, subtree: true }); start();
方案二:WebExtension实现(更稳定)
如果需要批量下载或更可靠的行为,可开发WebExtension,利用浏览器的downloads API直接下载跨域资源:
- 在
manifest.json中声明权限:
{ "manifest_version": 3, "name": "YouTube缩略图下载器", "version": "1.0", "permissions": ["downloads"], "content_scripts": [ { "matches": ["https://www.youtube.com/*"], "js": ["content.js"] } ] }
content.js中触发下载:
// 给视频元素添加下载按钮(示例逻辑) function addDownloadButtons() { document.querySelectorAll("div#content.ytd-rich-item-renderer").forEach(el => { if (el.querySelector('.thumb-download-btn')) return; const btn = document.createElement('button'); btn.textContent = "存缩略图"; btn.classList.add('thumb-download-btn'); btn.style.cssText = 'margin: 8px; padding: 4px; cursor: pointer;'; btn.onclick = () => { const imgUrl = el.querySelector('ytd-thumbnail img').src; const title = el.querySelector('#video-title').textContent.trim().replace(/[\\/:*?"<>|]/g, '_'); // 发送消息给后台脚本调用downloads API chrome.runtime.sendMessage({ url: imgUrl, filename: `${title}.webp` }); }; el.appendChild(btn); }); } // 监听页面变化 new MutationObserver(addDownloadButtons).observe(document.body, { childList: true, subtree: true }); addDownloadButtons();
- 后台脚本
background.js:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.url && request.filename) { chrome.downloads.download({ url: request.url, filename: `YouTube缩略图/${request.filename}`, conflictAction: 'uniquify' }); } });
内容的提问来源于stack exchange,提问作者aiyo4930aiyo
相关产品推荐
相关产品推荐

