如何用JavaScript实现Chrome视频下载器扩展?
Hey there! Congrats on diving into your first Chrome extension project—video downloaders are super handy, so this is a great starting point. Let’s break down how to build something similar to Video Downloader Plus, step by step, with practical code examples.
1. Set Up Your Manifest File (manifest.json)
This is the backbone of your extension, defining permissions, UI elements, and core behavior. We’ll use Manifest V3 (the current standard for Chrome extensions):
{ "manifest_version": 3, "name": "My Video Grabber", "version": "1.0", "description": "Download videos from any web page with a single click", "permissions": ["activeTab", "scripting", "downloads"], "action": { "default_popup": "popup.html", "default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }, "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" }, "content_scripts": [ { "matches": ["<all_urls>"], "js": ["content.js"], "run_at": "document_idle" } ] }
activeTablets you access the user’s current open tab.scriptingallows you to inject JavaScript into web pages.downloadsgives you access to Chrome’s download API (bypasses some CORS issues).- The
content_scriptensures our code runs on every page to detect videos.
2. Detect Videos on the Page
First, we’ll create a function to scan the page for <video> elements and extract their source URLs. Add this to content.js:
function getVideoSources() { const videoSources = []; const videos = document.querySelectorAll('video'); videos.forEach(video => { // Grab direct video src if (video.src && video.src.startsWith('http')) { videoSources.push({ url: video.src, title: document.title, type: video.type || 'video/mp4' }); } // Also check <source> child elements (common for multi-quality videos) const sourceTags = video.querySelectorAll('source'); sourceTags.forEach(tag => { if (tag.src && tag.src.startsWith('http')) { videoSources.push({ url: tag.src, title: document.title, type: tag.type || 'video/mp4' }); } }); }); // Remove duplicate URLs return [...new Map(videoSources.map(item => [item.url, item])).values()]; }
3. Add a Floating Download Button (Like Video Downloader Plus)
Video Downloader Plus shows a floating button when videos are detected—let’s replicate that. Add this to content.js:
function createFloatingBtn() { const btn = document.createElement('button'); btn.textContent = '📥 Download Video'; btn.dataset.videoDownloadBtn = true; btn.style.cssText = ` position: fixed; bottom: 20px; right: 20px; padding: 12px 16px; background: #ff4444; color: white; border: none; border-radius: 4px; cursor: pointer; z-index: 99999; font-size: 14px; font-weight: 500; `; btn.addEventListener('click', () => { const sources = getVideoSources(); if (sources.length === 0) { alert('No downloadable videos found on this page!'); return; } // Use Chrome's download API to avoid CORS issues sources.forEach((source, index) => { const fileExt = source.type.split('/')[1] || 'mp4'; const fileName = `${source.title.replace(/[<>:"/\\|?*]/g, '_')}_${index + 1}.${fileExt}`; chrome.runtime.sendMessage({ action: 'downloadVideo', url: source.url, filename: fileName }); }); }); document.body.appendChild(btn); } // Watch for videos appearing on the page (even if loaded dynamically) const observer = new MutationObserver(() => { const hasVideo = document.querySelector('video') !== null; const existingBtn = document.querySelector('[data-video-download-btn]'); if (hasVideo && !existingBtn) { createFloatingBtn(); } else if (!hasVideo && existingBtn) { existingBtn.remove(); } }); observer.observe(document.body, { childList: true, subtree: true });
4. Handle Downloads with a Background Script
We need a background script to listen for download requests and use Chrome’s downloads API. Create a background.js file and add it to your manifest:
// Add this to manifest.json "background": { "service_worker": "background.js" }
Then in background.js:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'downloadVideo') { chrome.downloads.download({ url: request.url, filename: request.filename, conflictAction: 'uniquify' // Adds a number if filename exists }, (downloadId) => { if (chrome.runtime.lastError) { console.error('Download failed:', chrome.runtime.lastError); } }); } });
5. Add a Popup UI (Optional)
If you want users to access download options via the extension icon, create popup.html:
<!DOCTYPE html> <html> <head> <style> body { width: 250px; padding: 16px; font-family: Arial, sans-serif; } #downloadBtn { width: 100%; padding: 8px; background: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; } #options { margin-top: 12px; } </style> </head> <body> <button id="downloadBtn">Find Videos on Page</button> <div id="options"></div> <script src="popup.js"></script> </body> </html>
And popup.js:
document.getElementById('downloadBtn').addEventListener('click', async () => { const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true }); chrome.scripting.executeScript({ target: { tabId: activeTab.id }, function: getVideoSources }, (results) => { const optionsDiv = document.getElementById('options'); optionsDiv.innerHTML = ''; if (!results[0].result.length) { optionsDiv.textContent = 'No videos found.'; return; } results[0].result.forEach((source, index) => { const link = document.createElement('div'); link.style.padding = '8px 0'; link.style.borderBottom = '1px solid #eee'; const btn = document.createElement('button'); btn.textContent = `Download Video ${index + 1}`; btn.style.width = '100%'; btn.style.padding = '6px'; btn.style.background = '#4CAF50'; btn.style.color = 'white'; btn.style.border = 'none'; btn.style.borderRadius = '4px'; btn.style.cursor = 'pointer'; btn.addEventListener('click', () => { const fileExt = source.type.split('/')[1] || 'mp4'; const fileName = `${source.title.replace(/[<>:"/\\|?*]/g, '_')}_${index + 1}.${fileExt}`; chrome.runtime.sendMessage({ action: 'downloadVideo', url: source.url, filename: fileName }); window.close(); }); link.appendChild(btn); optionsDiv.appendChild(link); }); }); });
Key Notes to Keep in Mind
- CORS Bypass: Using
chrome.downloads.download()instead of regular<a>tags avoids most cross-origin download errors. - Dynamic Content: The mutation observer ensures we detect videos loaded after the initial page load (like in single-page apps).
- Copyright Disclaimer: Add a note in your extension description that users should only download videos they have rights to—this protects you legally.
- Advanced Cases: For streaming videos (like YouTube’s HLS/DASH), you’ll need to capture network requests with the
webRequestpermission, but that’s more complex. Start with the basics first!
内容的提问来源于stack exchange,提问作者iLiA




