├── logo └── icon128.png ├── screenshots ├── demo.webm ├── main.webp └── shorts.webp ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── package.json ├── manifest.json ├── src ├── popup.html └── popup.js └── README.md /logo/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tublydownloader/Youtube-Downloader-Extension/HEAD/logo/icon128.png -------------------------------------------------------------------------------- /screenshots/demo.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tublydownloader/Youtube-Downloader-Extension/HEAD/screenshots/demo.webm -------------------------------------------------------------------------------- /screenshots/main.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tublydownloader/Youtube-Downloader-Extension/HEAD/screenshots/main.webp -------------------------------------------------------------------------------- /screenshots/shorts.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tublydownloader/Youtube-Downloader-Extension/HEAD/screenshots/shorts.webp -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **System and video information (please complete the following information):** 14 | - OS: [e.g. Windows 11] 15 | - Browser Version: [e.g. Chrome 135] 16 | - Extension Version: [e.g. 1.0.0] 17 | - Video URL: [optional, e.g. https://www.youtube.com/watch?v=abcdefhijkl] 18 | 19 | **To Reproduce** 20 | Steps to reproduce the behavior: 21 | 1. Go to '...' 22 | 2. Click on '....' 23 | 3. Scroll down to '....' 24 | 4. See error 25 | 26 | **Screenshots** 27 | If applicable, add screenshots to help explain your problem. 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "youtube-downloader-chrome-extension", 3 | "version": "1.0.0", 4 | "description": "Chrome extension to download YouTube videos in 4K, convert to MP3, and save YouTube Shorts", 5 | "main": "src/background.js", 6 | "scripts": { 7 | "build": "webpack --config webpack.config.js", 8 | "dev": "webpack --watch --config webpack.config.js", 9 | "lint": "eslint src/**/*.js", 10 | "test": "jest", 11 | "package": "node scripts/package.js" 12 | }, 13 | "keywords": [ 14 | "youtube downloader", 15 | "download youtube", 16 | "youtube", 17 | "downloader", 18 | "chrome-extension", 19 | "firefox-extension", 20 | "browser-extension", 21 | "chrome" 22 | ], 23 | "author": "Tubly Downloader", 24 | "devDependencies": { 25 | "eslint": "^8.42.0", 26 | "jest": "^29.5.0", 27 | "webpack": "^5.86.0", 28 | "webpack-cli": "^5.1.4" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Tubly Downloader", 4 | "version": "1.0.0", 5 | "description": "Download YouTube videos in 4K, convert to MP3, and save YouTube Shorts", 6 | "homepage_url": "https://tubly.download", 7 | "icons": { 8 | "128": "logo/icon128.png" 9 | }, 10 | "permissions": [ 11 | "downloads", 12 | "downloads.open", 13 | "scripting", 14 | "storage", 15 | "unlimitedStorage" 16 | ], 17 | "host_permissions": [ 18 | "https://www.youtube.com/*", 19 | "https://youtu.be/*" 20 | ], 21 | "background": { 22 | "service_worker": "src/background.js" 23 | }, 24 | "content_scripts": [ 25 | { 26 | "matches": ["https://www.youtube.com/*", "https://youtu.be/*"], 27 | "js": ["src/content.js"], 28 | "css": ["src/styles.css"] 29 | } 30 | ], 31 | "action": { 32 | "default_popup": "src/popup.html", 33 | "default_icon": { 34 | "128": "logo/icon128.png" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | YouTube Downloader 7 | 8 | 9 | 10 |
11 |
12 | 13 |

YouTube Downloader

14 |
15 | 16 |
17 |

Please navigate to a YouTube video to use this extension.

18 | 19 |
20 | 21 | 53 |
54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tubly Downloader - YouTube Downloader Chrome Extension 2 | 3 |

4 | YouTube Downloader Logo 5 |

6 | 7 |

Download YouTube videos in 4K, convert to MP3, and save YouTube Shorts

8 | 9 |

10 | Add to Chrome 11 |    12 | Add to Firefox 13 |

14 | 15 |

16 | 🐛 Report Issue • 17 | 🌐 Official Website 18 |

19 | 20 |

21 | Key Features • 22 | Screenshots • 23 | Installation • 24 | FAQ 25 |

26 | 27 | ## Key Features 28 | 29 | - **4K Video Downloads**: Download YouTube videos in ultra HD quality 30 | - **YouTube to MP3 Converter**: Convert YouTube videos to high-quality 320kbps MP3 audio 31 | - **YouTube Shorts**: Save Shorts videos with one click 32 | - **No Ads, No Extra Software**: Clean and straightforward downloading experience 33 | - **Cross-Platform**: Works on Windows, macOS, and Linux with Chrome, Edge, Firefox, Opera, Brave, and Vivaldi 34 | - **Private Video Support**: Download private videos and member-only content you have access to 35 | 36 | ## Screenshots 37 | 38 |

39 |

41 | 42 |

43 | YouTube Downloader interface 44 |

45 | 46 |

47 | YouTube Shorts download 48 |

49 | 50 | ## Installation 51 | 52 | ### Chrome, Brave, Opera, and Vivaldi 53 | For detailed installation instructions on Chromium-based browsers, visit our [official website](https://tubly.download/install.html). 54 | 55 | ### Microsoft Edge 56 | 1. Visit our [Edge Add-ons page](https://microsoftedge.microsoft.com/addons/detail/npolimekdjdhijlfikfghaipaijbbobj) 57 | 2. Click "Get" to add the extension 58 | 3. Follow the prompts to complete installation 59 | 60 | ### Firefox 61 | 1. Download our [Firefox add-on xpi package](https://tubly.download/firefox/tubly_downloader_v1.5.0.xpi) 62 | 2. Firefox will automatically start the installation process 63 | 3. Follow the prompts to complete installation 64 | 65 | ### Updating 66 | > Edge & Firefox users get updates automatically. 67 | 1. For Chrome users, download the new version from our website 68 | 2. Follow the same installation steps with the new file 69 | 3. Your settings will be preserved automatically 70 | 71 | ## FAQ 72 | 73 | ### How do I download YouTube videos in 4K quality? 74 | Simply navigate to any YouTube video, and click the download button that appears below the video player. You'll be presented with multiple quality options, including 4K (2160p) and even 8K if available. 75 | 76 | ### Can I download YouTube Shorts videos? 77 | Yes! Our Chrome extension is specially designed to detect and download YouTube Shorts. When viewing Shorts content, you'll see our download button appear, allowing you to save these short-form videos directly to your device. 78 | 79 | ### How to convert YouTube videos to MP3? 80 | Our extension extracts audio directly from videos without requiring any additional software. After installing, you'll see an "Audio" option when clicking the download button to save in high-quality 320kbps MP3 format. 81 | 82 | -------------------------------------------------------------------------------- /src/popup.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', () => { 2 | const noVideoSection = document.getElementById('no-video'); 3 | const videoInfoSection = document.getElementById('video-info'); 4 | const videoThumbnail = document.getElementById('video-thumbnail'); 5 | const videoTitle = document.getElementById('video-title'); 6 | const videoDuration = document.getElementById('video-duration'); 7 | const channelName = document.getElementById('channel-name'); 8 | const videoQualities = document.getElementById('video-qualities'); 9 | const audioQualities = document.getElementById('audio-qualities'); 10 | const progressContainer = document.getElementById('download-progress'); 11 | const progressBar = document.getElementById('progress'); 12 | const progressText = document.getElementById('progress-text'); 13 | const openYouTubeBtn = document.getElementById('open-youtube'); 14 | const settingsBtn = document.getElementById('settings-btn'); 15 | 16 | // Current video information 17 | let currentVideo = null; 18 | 19 | // Check if we're on a YouTube video page 20 | chrome.tabs.query({active: true, currentWindow: true}, (tabs) => { 21 | const currentTab = tabs[0]; 22 | const url = currentTab.url; 23 | 24 | if (isYouTubeVideoUrl(url)) { 25 | // We're on a YouTube video page 26 | noVideoSection.classList.add('hidden'); 27 | videoInfoSection.classList.remove('hidden'); 28 | 29 | // Get video information 30 | chrome.tabs.sendMessage(currentTab.id, {action: 'getVideoInfo'}, (response) => { 31 | if (response && response.videoInfo) { 32 | displayVideoInfo(response.videoInfo); 33 | } else { 34 | showError('Could not retrieve video information'); 35 | } 36 | }); 37 | } else { 38 | // Not on a YouTube video page 39 | noVideoSection.classList.remove('hidden'); 40 | videoInfoSection.classList.add('hidden'); 41 | } 42 | }); 43 | 44 | // Handle "Go to YouTube" button click 45 | openYouTubeBtn.addEventListener('click', () => { 46 | chrome.tabs.create({url: 'https://www.youtube.com'}); 47 | }); 48 | 49 | // Handle settings button click 50 | settingsBtn.addEventListener('click', () => { 51 | chrome.runtime.openOptionsPage(); 52 | }); 53 | 54 | // Display video information 55 | function displayVideoInfo(videoInfo) { 56 | currentVideo = videoInfo; 57 | 58 | videoThumbnail.src = videoInfo.thumbnail; 59 | videoTitle.textContent = videoInfo.title; 60 | videoDuration.textContent = formatDuration(videoInfo.duration); 61 | channelName.textContent = videoInfo.channelName; 62 | 63 | // Display video quality options 64 | videoQualities.innerHTML = ''; 65 | videoInfo.videoQualities.forEach(quality => { 66 | const qualityBtn = createQualityButton(quality, 'video'); 67 | videoQualities.appendChild(qualityBtn); 68 | }); 69 | 70 | // Display audio quality options 71 | audioQualities.innerHTML = ''; 72 | videoInfo.audioQualities.forEach(quality => { 73 | const qualityBtn = createQualityButton(quality, 'audio'); 74 | audioQualities.appendChild(qualityBtn); 75 | }); 76 | } 77 | 78 | // Create quality selection button 79 | function createQualityButton(quality, type) { 80 | const button = document.createElement('button'); 81 | button.classList.add('quality-btn'); 82 | button.setAttribute('data-quality', quality.id); 83 | button.setAttribute('data-type', type); 84 | 85 | if (type === 'video') { 86 | button.textContent = `${quality.label} (${quality.fileSize})`; 87 | } else { 88 | button.textContent = `${quality.label} MP3 (${quality.fileSize})`; 89 | } 90 | 91 | button.addEventListener('click', () => { 92 | initiateDownload(quality, type); 93 | }); 94 | 95 | return button; 96 | } 97 | 98 | // Initiate download process 99 | function initiateDownload(quality, type) { 100 | progressContainer.classList.remove('hidden'); 101 | progressText.textContent = 'Preparing download...'; 102 | progressBar.style.width = '0%'; 103 | 104 | chrome.tabs.query({active: true, currentWindow: true}, (tabs) => { 105 | const currentTab = tabs[0]; 106 | 107 | chrome.tabs.sendMessage( 108 | currentTab.id, 109 | { 110 | action: 'downloadVideo', 111 | qualityId: quality.id, 112 | type: type, 113 | videoId: currentVideo.id 114 | }, 115 | (response) => { 116 | if (response && response.success) { 117 | updateDownloadProgress(0); 118 | 119 | // Simulate download progress 120 | const downloadInterval = setInterval(() => { 121 | const currentWidth = parseInt(progressBar.style.width, 10) || 0; 122 | if (currentWidth >= 100) { 123 | clearInterval(downloadInterval); 124 | progressText.textContent = 'Download complete!'; 125 | setTimeout(() => { 126 | progressContainer.classList.add('hidden'); 127 | }, 2000); 128 | } else { 129 | updateDownloadProgress(currentWidth + 5); 130 | } 131 | }, 300); 132 | } else { 133 | showError('Failed to start download'); 134 | } 135 | } 136 | ); 137 | }); 138 | } 139 | 140 | // Update download progress 141 | function updateDownloadProgress(percent) { 142 | progressBar.style.width = `${percent}%`; 143 | if (percent < 100) { 144 | progressText.textContent = `Downloading: ${percent}%`; 145 | } 146 | } 147 | 148 | // Show error message 149 | function showError(message) { 150 | progressContainer.classList.remove('hidden'); 151 | progressText.textContent = message; 152 | progressBar.style.width = '100%'; 153 | progressBar.style.backgroundColor = '#f44336'; 154 | } 155 | 156 | // Check if URL is a YouTube video 157 | function isYouTubeVideoUrl(url) { 158 | return /^(https?:\/\/)?(www\.)?(youtube\.com\/watch|youtu\.be\/|youtube\.com\/shorts)/.test(url); 159 | } 160 | 161 | // Format duration from seconds to MM:SS 162 | function formatDuration(seconds) { 163 | const minutes = Math.floor(seconds / 60); 164 | const remainingSeconds = Math.floor(seconds % 60); 165 | return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; 166 | } 167 | }); 168 | --------------------------------------------------------------------------------