|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<title>Audio Downloader</title> |
|
<style> |
|
body { |
|
background-color: #121212; |
|
color: #e0e0e0; |
|
font-family: 'Segoe UI', Tahoma, Verdana, sans-serif; |
|
margin: 0; |
|
padding: 20px; |
|
} |
|
|
|
h1 { |
|
color: #59a459; |
|
font-size: 2em; |
|
margin-bottom: 20px; |
|
display: none; |
|
} |
|
|
|
#downloadForm { |
|
display: flex; |
|
flex-direction: column; |
|
flex-wrap: wrap; |
|
align-content: center; |
|
justify-content: center; |
|
align-items: center; |
|
} |
|
|
|
form { |
|
background-color: #1f1f1f; |
|
border-radius: 8px; |
|
padding: 20px; |
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); |
|
} |
|
|
|
div.codec { |
|
display: none; |
|
} |
|
|
|
label { |
|
font-size: 1.1em; |
|
margin-bottom: 8px; |
|
} |
|
|
|
label[for="youtube_url"] { |
|
display: none |
|
} |
|
|
|
input[type="text"] { |
|
width: 40%; |
|
padding: 10px; |
|
margin-bottom: 20px; |
|
border: 1px solid #3c3c3c; |
|
border-radius: 4px; |
|
background-color: #2c2c2c; |
|
color: #e0e0e0; |
|
} |
|
|
|
input[type="radio"] { |
|
margin-right: 8px; |
|
} |
|
|
|
input[type="radio"] + label { |
|
margin-right: 20px; |
|
font-size: 1em; |
|
} |
|
|
|
button { |
|
margin-top: 20px; |
|
width: 40%; |
|
background-color: #86e598; |
|
color: #121212; |
|
border: none; |
|
padding: 10px 20px; |
|
border-radius: 4px; |
|
font-size: 1.1em; |
|
cursor: pointer; |
|
transition: background-color 0.3s; |
|
} |
|
|
|
button:hover { |
|
background-color: #58cc4d; |
|
} |
|
|
|
#status { |
|
margin-top: 20px; |
|
font-size: 1.1em; |
|
} |
|
|
|
a { |
|
color: #03da84; |
|
text-decoration: none; |
|
transition: color 0.3s; |
|
} |
|
|
|
a:hover { |
|
color: #0ef758; |
|
} |
|
|
|
audio { |
|
margin-top: 10px; |
|
width: 100%; |
|
} |
|
</style> |
|
<script> |
|
function pollTaskStatus(task_id) { |
|
fetch(`/download_status/${task_id}`) |
|
.then(response => response.json()) |
|
.then(data => { |
|
document.getElementById('status').innerText = data.status; |
|
if (data.status === 'готово') { |
|
data.files.forEach(file => { |
|
const p = document.createElement('p'); |
|
const a = document.createElement('a'); |
|
a.href = `/play/${file}`; |
|
a.innerText = file; |
|
p.innerText = 'File: '; |
|
p.appendChild(a); |
|
document.body.appendChild(p); |
|
const audio = document.createElement('audio'); |
|
audio.controls = true; |
|
const source = document.createElement('source'); |
|
source.src = `/play/${file}`; |
|
source.type = 'audio/mpeg'; |
|
audio.appendChild(source); |
|
document.body.appendChild(audio); |
|
}); |
|
} else { |
|
setTimeout(() => pollTaskStatus(task_id), 1000); |
|
} |
|
}); |
|
} |
|
|
|
function startDownload() { |
|
const form = document.getElementById('downloadForm'); |
|
const formData = new FormData(form); |
|
fetch('/download', { |
|
method: 'POST', |
|
body: formData |
|
}) |
|
.then(response => response.json()) |
|
.then(data => { |
|
document.getElementById('status').innerText = 'Starting download...'; |
|
pollTaskStatus(data.task_id); |
|
}); |
|
} |
|
</script> |
|
</head> |
|
<body> |
|
<h1>получить минимальную звуковую дорожку с YouTube</h1> |
|
<form id="downloadForm"> |
|
<label for="youtube_url">ссылка на видео:</label> |
|
<input type="text" id="youtube_url" name="youtube_url" placeholder="ссылка на видео" required> |
|
<br> |
|
<div id="status"></div> |
|
<div class="codec"> |
|
<label for="codec">кодек:</label> |
|
<input type="radio" id="opus" name="codec" value="opus" checked> |
|
<label for="opus">Opus</label> |
|
<input type="radio" id="usac" name="codec" value="usac"> |
|
<label for="usac">USAC</label> |
|
<input type="radio" id="both" name="codec" value="both"> |
|
<label for="both">Both</label> |
|
</div> |
|
<br> |
|
<button type="button" onclick="startDownload()">Download</button> |
|
</form> |
|
</body> |
|
</html> |