// ==UserScript== // @name Youtube Video Downloader // @namespace http://tampermonkey.net/ // @author fb // @version 1.0 // @description Simple Youtube Video Downloader // @match https://www.youtube.com/watch* // @grant GM_xmlhttpRequest // @connect p.oceansaver.in // @license GPL-3.0-or-later // @run-at document-end // @downloadURL none // ==/UserScript== (function() { 'use strict'; let animInterval = null; let originalText = ''; const observer = new MutationObserver((mutations, obs) => { const actionsInner = document.querySelector('#actions-inner'); if (!actionsInner) return; obs.disconnect(); injectUI(actionsInner); }); observer.observe(document.body, { childList: true, subtree: true }); function injectUI(container) { if (document.getElementById('download-button')) return; const wrapper = document.createElement('div'); wrapper.style.display = 'flex'; wrapper.style.alignItems = 'center'; wrapper.style.marginBottom = "2px"; const select = document.createElement('select'); select.id = 'format'; select.className = 'doc'; select.style.marginRight = '8px'; select.innerHTML = ` `; const btn = document.createElement('button'); btn.id = 'download-button'; btn.textContent = 'Download'; btn.style.cursor = 'pointer'; btn.className = 'style-scope ytd-button-renderer'; btn.addEventListener('click', startDownload); wrapper.appendChild(select); wrapper.appendChild(btn); container.insertAdjacentElement('afterbegin', wrapper); } function startDownload() { const btn = document.getElementById('download-button'); if (!btn) return; const fmt = document.getElementById('format').value; const videoUrl = encodeURIComponent(window.location.href); const initUrl = `https://p.oceansaver.in/ajax/download.php?format=${fmt}&url=${videoUrl}`; startButtonAnimation(btn); GM_xmlhttpRequest({ method: 'GET', url: initUrl, responseType: 'json', onload(res) { const data = res.response; if (!data || !data.success) { stopButtonAnimation(); alert('❌ Failed to initialize download'); return; } pollProgress(data.progress_url); }, onerror() { stopButtonAnimation(); alert('❌ Network error while starting download'); } }); } function pollProgress(progressUrl) { const intervalId = setInterval(() => { GM_xmlhttpRequest({ method: 'GET', url: progressUrl, responseType: 'json', onload(res) { const p = res.response; if (!p) { clearInterval(intervalId); stopButtonAnimation(); return; } if (p.success) { clearInterval(intervalId); triggerFileDownload(p.download_url); stopButtonAnimation(); } else { console.log(`Download progress: ${p.progress || 'unknown'}`); } }, onerror() { console.error('Error polling download progress'); clearInterval(intervalId); stopButtonAnimation(); } }); }, 1500); } function triggerFileDownload(url) { const a = document.createElement('a'); a.href = url; a.download = ''; document.body.appendChild(a); a.click(); document.body.removeChild(a); } function startButtonAnimation(btn) { originalText = btn.textContent; btn.disabled = true; let dots = 0; animInterval = setInterval(() => { dots = (dots + 1) % 4; btn.textContent = 'Downloading' + '.'.repeat(dots); }, 500); } function stopButtonAnimation() { const btn = document.getElementById('download-button'); if (animInterval) { clearInterval(animInterval); animInterval = null; } if (btn) { btn.disabled = false; btn.textContent = originalText || 'Download'; } } })();