historypoint / templates /index.html
devusman's picture
feat: deployment
6ade7fe
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Video Downloader</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Helvetica, Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f4f7f6;
}
.container {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 500px;
text-align: center;
}
h1 {
margin-bottom: 1.5rem;
color: #333;
}
#download-form {
display: flex;
flex-direction: column;
gap: 1rem;
}
#url {
padding: 0.75rem;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
}
button {
padding: 0.75rem;
border: none;
border-radius: 4px;
background-color: #007bff;
color: white;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s;
}
button:hover {
background-color: #0056b3;
}
button:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
.message {
margin-top: 1rem;
padding: 0.75rem;
border-radius: 4px;
display: none;
}
.message.info {
display: block;
background-color: #e2f3ff;
color: #005f9e;
}
.message.success {
display: block;
background-color: #d4edda;
color: #155724;
}
.message.error {
display: block;
background-color: #f8d7da;
color: #721c24;
}
#progress {
display: none;
margin-top: 1rem;
}
#progress-bar {
width: 100%;
height: 20px;
}
#percent {
text-align: center;
margin-top: 0.5rem;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h1>Video Downloader</h1>
<form id="download-form">
<input
type="text"
id="url"
name="url"
placeholder="Enter video URL"
required
/>
<button type="submit" id="download-btn">Download</button>
</form>
<div id="progress">
<progress id="progress-bar" value="0" max="100"></progress>
<div id="percent">0%</div>
</div>
<div id="message" class="message"></div>
</div>
<script>
document
.getElementById("download-form")
.addEventListener("submit", function (event) {
event.preventDefault();
const form = event.target;
const url = form.elements.url.value;
const messageDiv = document.getElementById("message");
const progressDiv = document.getElementById("progress");
const progressBar = document.getElementById("progress-bar");
const percentSpan = document.getElementById("percent");
const downloadBtn = document.getElementById("download-btn");
// Reset
messageDiv.style.display = "none";
progressDiv.style.display = "none";
downloadBtn.disabled = true;
// Start
messageDiv.textContent = "Starting download...";
messageDiv.className = "message info";
messageDiv.style.display = "block";
progressDiv.style.display = "block";
progressBar.value = 0;
percentSpan.textContent = "0%";
const formData = new FormData();
formData.append("url", url);
const postXhr = new XMLHttpRequest();
postXhr.open("POST", "/download", true);
postXhr.addEventListener("load", function () {
if (postXhr.status === 200) {
try {
const data = JSON.parse(postXhr.responseText);
const taskId = data.task_id;
messageDiv.textContent = "Downloading video...";
messageDiv.className = "message info";
let polling = true;
function poll() {
if (!polling) return;
const getXhr = new XMLHttpRequest();
getXhr.open("GET", `/progress/${taskId}`, true);
getXhr.addEventListener("load", function () {
if (getXhr.status === 200) {
try {
const task = JSON.parse(getXhr.responseText);
const percent = task.progress || 0;
progressBar.value = percent;
percentSpan.textContent = Math.round(percent) + "%";
if (task.done) {
polling = false;
progressDiv.style.display = "none";
if (task.error) {
messageDiv.textContent = task.error;
messageDiv.className = "message error";
} else {
messageDiv.textContent =
"Download completed successfully!";
messageDiv.className = "message success";
const filename =
task.filename || "downloaded_video.mp4";
const link = document.createElement("a");
link.href = `/file/${taskId}`;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
downloadBtn.disabled = false;
} else {
setTimeout(poll, 500);
}
} catch (e) {
// Parse error
polling = false;
messageDiv.textContent =
"Error parsing progress update.";
messageDiv.className = "message error";
downloadBtn.disabled = false;
}
} else {
// Poll error, retry
setTimeout(poll, 1000);
}
});
getXhr.addEventListener("error", function () {
polling = false;
messageDiv.textContent =
"Network error while checking progress.";
messageDiv.className = "message error";
downloadBtn.disabled = false;
});
getXhr.send();
}
poll();
} catch (e) {
messageDiv.textContent = "Error starting download.";
messageDiv.className = "message error";
downloadBtn.disabled = false;
}
} else {
let errorMsg = `Error: ${postXhr.statusText}`;
try {
const errorData = JSON.parse(postXhr.responseText);
errorMsg = `Error: ${errorData.error}`;
} catch (e) {
// Ignore
}
messageDiv.textContent = errorMsg;
messageDiv.className = "message error";
progressDiv.style.display = "none";
downloadBtn.disabled = false;
}
});
postXhr.addEventListener("error", function () {
messageDiv.textContent =
"An unexpected error occurred: Network issue";
messageDiv.className = "message error";
progressDiv.style.display = "none";
downloadBtn.disabled = false;
});
postXhr.send(formData);
});
</script>
</body>
</html>