ytdl / index.html
vbvbot9117's picture
Upload index.html
11b4853 verified
raw
history blame
5.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YouTube Audio Downloader</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<div class="max-w-2xl mx-auto">
<h1 class="text-3xl font-bold text-center mb-8 text-gray-800">YouTube Audio Downloader</h1>
<!-- Input Form -->
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
<div class="mb-4">
<input type="text" id="youtubeUrl" placeholder="Paste YouTube URL here"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<button onclick="getVideoInfo()"
class="w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 transition duration-200">
Get Video Info
</button>
</div>
<!-- Video Info Section -->
<div id="videoInfo" class="hidden bg-white rounded-lg shadow-md p-6 mb-6">
<div id="videoDetails" class="mb-4">
<div id="thumbnailContainer" class="mb-4"></div>
<h2 id="videoTitle" class="text-xl font-semibold mb-2"></h2>
<p id="channelName" class="text-gray-600"></p>
<p id="duration" class="text-gray-600"></p>
</div>
<button onclick="downloadAudio()"
class="w-full bg-green-500 text-white py-2 px-4 rounded-lg hover:bg-green-600 transition duration-200">
Download Audio
</button>
</div>
<!-- Loading Indicator -->
<div id="loading" class="hidden">
<div class="flex justify-center items-center">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
</div>
</div>
<!-- Error Message -->
<div id="errorMessage" class="hidden bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4">
</div>
</div>
</div>
<script>
function showLoading() {
$('#loading').removeClass('hidden');
}
function hideLoading() {
$('#loading').addClass('hidden');
}
function showError(message) {
$('#errorMessage').text(message).removeClass('hidden');
setTimeout(() => {
$('#errorMessage').addClass('hidden');
}, 5000);
}
function formatDuration(seconds) {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
}
function getVideoInfo() {
const url = $('#youtubeUrl').val().trim();
if (!url) {
showError('Please enter a YouTube URL');
return;
}
showLoading();
$('#videoInfo').addClass('hidden');
$.ajax({
url: '/get-info',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ url: url }),
success: function(response) {
$('#thumbnailContainer').html(`
<img src="${response.thumbnail}" alt="Video thumbnail" class="w-full rounded-lg">
`);
$('#videoTitle').text(response.title);
$('#channelName').text(`Channel: ${response.channel}`);
$('#duration').text(`Duration: ${formatDuration(response.duration)}`);
$('#videoInfo').removeClass('hidden');
hideLoading();
},
error: function(xhr) {
showError(xhr.responseJSON?.error || 'Failed to get video information');
hideLoading();
}
});
}
function downloadAudio() {
const url = $('#youtubeUrl').val().trim();
if (!url) {
showError('Please enter a YouTube URL');
return;
}
showLoading();
$.ajax({
url: '/download',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ url: url }),
xhrFields: {
responseType: 'blob'
},
success: function(response) {
const blob = new Blob([response], { type: 'audio/mp3' });
const downloadUrl = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = downloadUrl;
a.download = $('#videoTitle').text() + '.mp3';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(downloadUrl);
hideLoading();
},
error: function(xhr) {
showError('Failed to download audio');
hideLoading();
}
});
}
</script>
</body>
</html>