|
<!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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |