Skip to content

Instantly share code, notes, and snippets.

@coryvirok
Created January 18, 2025 03:52
Show Gist options
  • Save coryvirok/40e610f12d0fdd23cc074d7e08e4be80 to your computer and use it in GitHub Desktop.
Save coryvirok/40e610f12d0fdd23cc074d7e08e4be80 to your computer and use it in GitHub Desktop.
Download embedded videos in your browser (even blob: sources)
function addDownloadButtonsToVideos() {
const addButton = (video) => {
// Check if a download button already exists for this video
if (video.parentElement.querySelector('.download-button')) return;
// Create the download button
const button = document.createElement('button');
button.textContent = 'Download';
button.className = 'download-button';
Object.assign(button.style, {
position: 'absolute',
top: '10px',
right: '10px',
zIndex: 10000,
backgroundColor: '#007bff',
color: '#fff',
border: 'none',
padding: '5px 10px',
cursor: 'pointer',
borderRadius: '5px',
});
// Set up the download functionality
button.addEventListener('click', async () => {
try {
const videoSrc = video.currentSrc || video.src;
if (videoSrc.startsWith('blob:')) {
// Extract data from the video element
const mimeType = video.getAttribute('type') || 'video/mp4';
const chunks = [];
const stream = video.captureStream();
const recorder = new MediaRecorder(stream, { mimeType });
recorder.ondataavailable = (e) => chunks.push(e.data);
recorder.onstop = () => {
const blob = new Blob(chunks, { type: mimeType });
const objectUrl = URL.createObjectURL(blob);
// Trigger download
const a = document.createElement('a');
a.href = objectUrl;
a.download = 'video.mp4';
a.click();
URL.revokeObjectURL(objectUrl); // Clean up the object URL
};
recorder.start();
setTimeout(() => recorder.stop(), video.duration * 1000); // Record until video ends
} else if (videoSrc) {
// Handle regular URLs
const a = document.createElement('a');
a.href = videoSrc;
a.download = 'video.mp4';
a.click();
} else {
alert('No video source found!');
}
} catch (err) {
console.error('Error downloading video:', err);
alert('Failed to download the video.');
}
});
// Add the button to the video's parent element
const parent = video.parentElement;
parent.style.position = 'relative';
parent.appendChild(button);
};
// Add buttons to existing videos
document.querySelectorAll('video').forEach(addButton);
// Observe the DOM for new video elements
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.tagName === 'VIDEO') {
addButton(node);
} else if (node.querySelectorAll) {
node.querySelectorAll('video').forEach(addButton);
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
}
// Call the function
addDownloadButtonsToVideos();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment