// ==UserScript==
// @name YT Downloader
// @namespace http://tampermonkey.net/
// @version 2024-6-16.3
// @description Youtube MP3 and MP4 downloader
// @author LeonelM
// @match https://www.youtube.com/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const stylesCss = `
<style>
/* For Chrome or Safari */
progress::-webkit-progress-bar {
background-color: #ff0000;
;
}
.content_collapsible_colors {
display: none;
overflow: hidden;
background-color: #3f3f3f;
}
progress::-webkit-progress-value {
background-color: #06d406;
}
.clasic-mode-short svg{
background-color: #272727;
padding: 13px;
border-radius: 50%;
margin-bottom: 10px;
color: #fff;
cursor: pointer;
}
.clasic-mode-short svg:hover{
background-color: #252525
}
/* For Firefox */
progress {
background-color: #ff0000;
border: none;
}
progress::-moz-progress-bar {
background-color: #06d406;
}
.barralikes {
display: flex;
justify-content: center;
align-items: center;
}
</style>
<meta http-equiv="Expires" content="0">
<meta http-equiv="Last-Modified" content="0">
<meta http-equiv="Cache-Control" content="no-cache, mustrevalidate">
<meta http-equiv="Pragma" content="no-cache">
<style>
.mdcm:hover {
cursor: pointer;
background-color: #6b6b6b;
}
.hidden {
display: none;
}
.mdcm {
font-size: 10px;
background-color: #595959;
border: none;
color: #fbf4f4 !important;
padding: 3px 0;
margin-left: 10px;
width: 70px;
border-radius: 10px;
}
.btn_download {
font-size: 1.2rem;
padding: 3px;
color: #fff;
border-radius: 5px;
background-color: #ec3203;
}
#subscribe-button>ytd-subscribe-button-renderer>yt-button-shape>button:hover {
zoom: 0.9;
}
.containerButtons {
position: relative;
display: flex;
justify-content: center;
flex-wrap: wrap;
align-items: center;
user-select: none;
border-radius: 20px;
margin: 0 auto;
padding: 4px;
}
.containerButtons button,
input {
display: flex;
flex-direction: column-reverse;
margin: 0 5px;
align-items: center;
cursor: pointer;
border-radius: 10px;
}
.containerButtons h1,
h2 {
user-select: none;
}
#MDCM {
animation: mdcm 10s infinite alternate;
position: relative;
transition: 4s;
}
.containerButtons button .containerButtons button svg {
width: 50px;
height: 40px;
}
.content_collapsible_colors {
position: relative;
width: 400px;
margin: auto;
padding: 10px;
border-radius: 20px;
}
.content_collapsible_colors h2 {
color: #fff !important;
}
.content_collapsible_colors div{
display: flex;
justify-content: space-between;
align-items: center;
}
.colors_buttons_collpases {
opacity: 0;
position: absolute;
height: 24px;
bottom: 0;
top: 0;
left: 10%;
margin-left: 2px;
width: 40px;
}
#eyes {
opacity: 0;
position: absolute;
height: 24px;
bottom: 0;
top: 0;
width: 24px;
}
/* width */
::-webkit-scrollbar {
width: 4px;
height: 10px;
}
/* Track */
::-webkit-scrollbar-track {
background: ##d5d5d5;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #000;
}
.containerall {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.container .botoncalidades {
margin: 3px 2px;
width: 24.6%;
}
.botoncalidades:first-child {
background-color: #0af;
}
.botoncalidades:last-child {
background-color: red;
width: 100px;
}
.selectcalidades,
.botoncalidades,
.selectcalidadesaudio {
width: 50%;
height: 27.8px;
background-color: #fff;
color: #000;
font-size: 25px;
text-align: center;
border: none;
font-size: 20px;
margin: 2px 2px;
}
.botoncalidades {
width: 70px;
height: 30px;
background-color: rgb(4, 156, 22);
border: 0px solid #000;
color: #fff;
font-size: 20px;
border-radius: 10px;
margin: 2px 2px;
}
.botoncalidades:hover,
.bntcontainer:hover {
cursor: pointer;
}
.ocultarframe,
.ocultarframeaudio {
display: none;
}
.progress-button:hover {
background-color: #000;
}
.progress-button {
display: inline-block;
font-size: 1em;
color: #fff;
text-decoration: none;
line-height: 1;
overflow: hidden;
position: relative;
text-align: center;
width: 100%;
height: 100%;
box-shadow: 0 1px 1px #ccc;
border-radius: 2px;
cursor: pointer;
background-color: #000;
}
#downloadButton:hover .progress-button {
filter: brightness(95%);
}
.progress-button.in-progress,
.progress-button.finished {
color: red;
}
.progress-button.in-progress:after,
.progress-button.finished:after {
position: absolute;
z-index: 2;
width: 100%;
height: 100%;
text-align: center;
top: 0;
padding-top: inherit;
color: #fff;
left: 0;
}
.progress-button.in-progress:after {
content: attr(data-loading);
}
.progress-button.finished:after {
content: attr(data-finished);
}
.progress-button .tz-bar {
background-color: #f00;
height: 3px;
bottom: 0;
left: 0;
width: 0;
position: absolute;
z-index: 1;
border-radius: 0 0 2px 2px;
-webkit-transition: width 0.5s, height 0.5s;
-moz-transition: width 0.5s, height 0.5s;
transition: width 0.5s, height 0.5s;
}
.progress-button .tz-bar.background-horizontal {
height: 100%;
border-radius: 2px;
}
.progress-button .tz-bar.background-vertical {
height: 0;
top: 0;
width: 100%;
border-radius: 2px;
}
.buttonTitle {
font-size: 0.5em;
margin-top: 4px;
}
#containerbutton {
height: 100px;
text-align: center;
}
#containerbutton:before {
content: '';
display: inline-block;
vertical-align: middle;
height: 100%;
}
#percentageText {
width: 95%;
display: inline-block;
position: relative;
vertical-align: middle;
z-index: 3;
}
.headerbutton {
position: fixed;
top: 0;
z-index: 1;
width: 100%;
background-color: #f1f1f1;
}
.progress-containerbutton {
width: 99%;
height: 20px;
background: #3e3e3c;
}
.progress-bar {
height: 20px;
background: #f00;
width: 0%;
}
.grecaptcha-badge {
visibility: hidden;
}
button {
margin: 0;
padding: 0;
}
.newVideoTest:hover{
background-color: rgba(80,80,80,0.8)
}
button:hover {
color: #ec3203;
}
.newText{
font-size: 118%;
font-weight: 500;
display: flex;
}
.newText span{
margin-right: 40px;
}
.botones_div {
background-color: transparent;
border: none;
color: #FFFFFF;
}
#downloadButton:hover{
background-color: #32644b
}
</style>
`;
const menuBotones = `
<style>
${stylesCss}
</style>
<div class="ytp-popup ytp-settings-menu leotest leoaudiotest" data-layer="6" id="ytp-id-18" style="width: 397px; height: 177px;">
<!-- Panel for Audio Quality -->
<div class="ytp-panel" style="width: 397px; height: 177px;">
<span style="padding-left:20px;font-size: large;font-weight: 900;align-content: center;und;und;flex-wrap: wrap;display: flex;reverse;justify-content: space-between;flex-direction: row;align-items: center;">Download Audio
<button title="Close" type="button" class="btn3 botones_div" style="
left: auto;
padding-left: 20px;
position: relative;
">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-x" width="30" height="48" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
<path d="M10 10l4 4m0 -4l-4 4"></path>
</svg>
</button>
</span>
<div class="ytp-panel-menu" role="menu" style="height: 177px;">
<div class="newVideoTest" aria-haspopup="true" value="8k" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText">
<span>FLAC UHQ </span>
<button id="downloadButtonflac" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( 'flac','downloadButtonflac')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="8k" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText">
<span>WAV UHQ </span>
<button id="downloadButtonwav" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( 'wav','downloadButtonwav')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true"value="4k" role="menuitem" tabindex="1" style="padding-left:20px">
<div class="newText"> <span>MP3</span>
<button id="downloadButtonmp3" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( 'mp3','downloadButtonmp3')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="1080" role="menuitem" tabindex="2" style="padding-left:20px">
<div class="newText"> <span>M4A </span>
<button id="downloadButtonm4a" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( 'm4a','downloadButtonm4a')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="720" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText"> <span>AAC </span>
<button id="downloadButtonaac" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( 'aac','downloadButtonaac')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="480" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText"> <span>OPUS </span>
<button id="downloadButtonopus" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( 'opus','downloadButtonopus')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="360" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText"> <span> OGG </span>
<button id="downloadButtonogg" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( 'ogg','downloadButtonogg')">
Click to Download
</button>
</div>
</div>
</div>
</div>
</div>
<div class="ytp-popup ytp-settings-menu leotest leovideotest" data-layer="6" id="ytp-id-18" style="width: 397px; height: 177px;">
<!-- Panel for Video Quality -->
<div class="ytp-panel" style="width: 397px; height: 177px;">
<span style="padding-left:20px;font-size: large;font-weight: 900;align-content: center;und;und;flex-wrap: wrap;display: flex;reverse;justify-content: space-between;flex-direction: row;align-items: center;">Download Video
<button title="Close" type="button" class="btn3 botones_div" style="
left: auto;
padding-left: 20px;
position: relative;
">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-x" width="30" height="48" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
<path d="M10 10l4 4m0 -4l-4 4"></path>
</svg>
</button>
</span>
<div class="ytp-panel-menu" role="menu" style="height: 177px;">
<div class="newVideoTest" aria-haspopup="true" value="8k" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText">
<span>4320p 8K WEBM </span>
<button id="downloadButton8k" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( '8k','downloadButton8k')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true"value="4k" role="menuitem" tabindex="1" style="padding-left:20px">
<div class="newText"> <span> 2160p 4K WEBM </span>
<button id="downloadButton4k" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( '4k','downloadButton4k')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="1080" role="menuitem" tabindex="2" style="padding-left:20px">
<div class="newText"> <span>1080p </span>
<button id="downloadButton1080" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( '1080','downloadButton1080')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="720" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText"> <span>720p HD Mp4 </span>
<button id="downloadButton720" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( '720','downloadButton720')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="480" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText"> <span>480p Mp4 </span>
<button id="downloadButton480" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( '480','downloadButton480')">
Click to Download
</button>
</div>
</div>
<div class="newVideoTest" aria-haspopup="true" value="360" role="menuitem" tabindex="0" style="padding-left:20px">
<div class="newText"> <span> 360p Mp4 </span>
<button id="downloadButton360" style="place-content:center;margin-left: auto;height:100%;top: 8px;width:45%;padding: 9px;background-color:#2986cc;color: white;border: none;display: flex;border-radius: 5px;position: relative;" onclick="initiateDownload( '360','downloadButton360')">
Click to Download
</button>
</div>
</div>
</div>
</div>
</div>
</div>
`;
// HTML de los botones
const downloadMp4Mp3 = `
<button title="Download MP4" type="button" class="btn1 botones_div">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-file-download"
width="30" height="48" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"></path>
<path d="M12 17v-6"></path>
<path d="M9.5 14.5l2.5 2.5l2.5 -2.5"></path>
</svg>
</button>
<button title="Download MP3" type="button" class="btn2 botones_div">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-file-music" width="30"
height="48" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"></path>
<path d="M11 16m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
<path d="M12 16l0 -5l2 1"></path>
</svg>
</button>
`;
let currentVideoUrl = window.location.href;
let currentFunction = "";
let firstBoot = true;
function removeButtons(){
let existingMenuBotones = document.querySelector('.leoaudiotest');
let existingMenuBotones2 = document.querySelector('.leovideotest');
let existingMenuBotones3 = document.querySelector('.btn1');
let existingMenuBotones4 = document.querySelector('.btn2');
if (existingMenuBotones) {
existingMenuBotones.remove();
}
if (existingMenuBotones2) {
existingMenuBotones2.remove();
}
if (existingMenuBotones3) {
existingMenuBotones3.remove();
}
if (existingMenuBotones4) {
existingMenuBotones4.remove();
}
}
function cargarScript(){
currentVideoUrl = window.location.href;
currentFunction = "";
const rightControlsDiv = document.querySelector('.ytp-right-controls');
// Remover botones existentes si ya están presentes
removeButtons();
// Inserta los botones dentro del div
if (rightControlsDiv) {
rightControlsDiv.insertAdjacentHTML('beforebegin', menuBotones);
rightControlsDiv.insertAdjacentHTML('beforebegin', downloadMp4Mp3);
}
// Inserta el CSS en el head del documento
const existingStyleSheet = document.querySelector('#custom-style-sheet');
if (existingStyleSheet) {
existingStyleSheet.remove();
}
const styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.id = 'custom-style-sheet';
styleSheet.innerText = stylesCss;
document.head.appendChild(styleSheet);
const leoaudiotest = document.querySelector('.leoaudiotest');
const leovideotest = document.querySelector('.leovideotest');
const btn1mp4 = document.querySelector('.btn1');
const btn2mp3 = document.querySelector('.btn2');
const btn3cancel = document.querySelectorAll('.btn3');
leovideotest.style.display = 'none';
leoaudiotest.style.display = 'none';
for (let i = 0; i < btn3cancel.length; i++) {
if (btn3cancel[i]) {
btn3cancel[i].onclick = () => {
leovideotest.style.display = 'none';
leoaudiotest.style.display = 'none';
};
}
}
if (btn1mp4) {
btn1mp4.onclick = () => {
leovideotest.style.display = '';
leoaudiotest.style.display = 'none';
};
}
if (btn2mp3) {
btn2mp3.onclick = () => {
leovideotest.style.display = 'none';
leoaudiotest.style.display = '';
};
}
}
window.initiateDownload = function(format, buttonID) {
console.log("id:" + buttonID);
const button = document.getElementById(buttonID);
const url = window.location.href;
currentFunction = format;
// Check if the video URL has changed
if (url !== currentVideoUrl) {
resetButton(buttonID, currentFunction);
currentVideoUrl = url;
}
button.innerHTML = 'Preparing...';
button.style.backgroundColor = '#53c9ff';
fetch("https://loader.to/ajax/download.php?url=" + encodeURIComponent(currentVideoUrl) + "&format=" + format + "&start=1&end=1")
.then(response => {
if (!response.ok) {
return response.text().then(text => { throw new Error('Network response was not ok: ' + text); });
}
return response.json();
})
.then(data => {
if (data && data.success) {
window.checkProgress(data.id, data.download_url, buttonID);
} else {
alert('Failed to initiate download.');
button.innerHTML = 'Failed';
button.style.backgroundColor = '#BF4B4B';
}
})
.catch(error => {
alert('An error occurred while trying to download the video: ' + error.message);
button.innerHTML = 'Error';
button.style.backgroundColor = '#BF4B4B';
console.error('Error:', error);
});
}
window.checkProgress = function(id, downloadUrl, buttonID) {
const button = document.getElementById(buttonID);
fetch("https://loader.to/ajax/progress.php?id=" + id)
.then(response => {
if (!response.ok) {
return response.text().then(text => { throw new Error('Network response was not ok: ' + text); });
}
return response.json();
})
.then(data => {
if (data && data.download_url) {
button.innerHTML = 'Download Now!';
button.style.backgroundColor = '#64c896';
button.onclick = function() {
window.open(data.download_url, '_blank');
resetButton(buttonID, currentFunction); // Reiniciar el botón después de la descarga
};
} else {
setTimeout(function() {
window.checkProgress(id, downloadUrl, buttonID);
}, 750);
}
})
.catch(error => {
alert('An error occurred while checking download progress: ' + error.message);
console.error('Error:', error);
});
};
function resetButton(buttonID, prevFormat) {
const button = document.getElementById(buttonID);
button.innerHTML = 'Download again';
button.style.backgroundColor = '#64c896'; // Restablecer color original
}
// Function to handle URL changes
function handleUrlChange() {
if (window.location.href !== currentVideoUrl) {
currentVideoUrl = window.location.href;
console.log("url changed");
removeButtons();
setTimeout(cargarScript, 2000);
}
}
// Observe changes in the video URL
const observer = new MutationObserver(handleUrlChange);
observer.observe(document.body, { childList: true, subtree: true });
window.addEventListener('popstate', handleUrlChange);
if (firstBoot){
setTimeout(cargarScript, 2000);
firstBoot = false;
}
})();