// ==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';
}
}
})();