Update templates/index.html
Browse files- templates/index.html +105 -65
templates/index.html
CHANGED
|
@@ -3,89 +3,129 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
-
<title>
|
| 7 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
</head>
|
| 9 |
-
<body
|
| 10 |
-
<div class="
|
| 11 |
-
<h1
|
| 12 |
-
<
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
placeholder="https://downloadwella.com/...">
|
| 18 |
-
</div>
|
| 19 |
-
<button type="submit" id="submitBtn"
|
| 20 |
-
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
| 21 |
-
Start Process
|
| 22 |
-
</button>
|
| 23 |
</form>
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
<
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
</div>
|
| 29 |
</div>
|
| 30 |
</div>
|
| 31 |
|
| 32 |
<script>
|
| 33 |
-
const
|
| 34 |
-
const
|
| 35 |
-
const
|
| 36 |
-
const
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
if (
|
| 42 |
-
statusList.appendChild(p);
|
| 43 |
-
statusDiv.classList.remove('hidden');
|
| 44 |
-
}
|
| 45 |
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
const url = document.getElementById('url').value;
|
| 49 |
-
|
| 50 |
-
submitBtn.disabled = true;
|
| 51 |
-
submitBtn.classList.add('opacity-50', 'cursor-not-allowed');
|
| 52 |
-
statusList.innerHTML = '';
|
| 53 |
-
addStatus('Initiating process...');
|
| 54 |
|
| 55 |
try {
|
| 56 |
-
const response = await fetch('/
|
| 57 |
method: 'POST',
|
| 58 |
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
| 59 |
-
body:
|
| 60 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
addStatus(data.message, data.error);
|
| 76 |
-
} catch (e) {
|
| 77 |
-
// Not JSON, skip
|
| 78 |
-
}
|
| 79 |
-
}
|
| 80 |
-
}
|
| 81 |
}
|
|
|
|
|
|
|
| 82 |
} catch (error) {
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
submitBtn.disabled = false;
|
| 86 |
-
submitBtn.classList.remove('opacity-50', 'cursor-not-allowed');
|
| 87 |
}
|
| 88 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
</script>
|
| 90 |
</body>
|
| 91 |
</html>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Downloadwella to Hugging Face Frame Extractor</title>
|
| 7 |
+
<style>
|
| 8 |
+
body { font-family: sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; }
|
| 9 |
+
.container { max-width: 800px; margin: auto; background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
| 10 |
+
h1 { color: #0056b3; }
|
| 11 |
+
form { margin-top: 20px; display: flex; flex-direction: column; gap: 10px; }
|
| 12 |
+
input[type="text"] { padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; }
|
| 13 |
+
button { padding: 10px 15px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }
|
| 14 |
+
button:hover { background-color: #0056b3; }
|
| 15 |
+
.status-box { background-color: #e9ecef; border: 1px solid #ced4da; padding: 15px; border-radius: 4px; margin-top: 20px; }
|
| 16 |
+
.log-entry { margin-bottom: 5px; border-bottom: 1px dotted #ccc; padding-bottom: 3px; }
|
| 17 |
+
.error { color: red; font-weight: bold; }
|
| 18 |
+
.success { color: green; font-weight: bold; }
|
| 19 |
+
</style>
|
| 20 |
</head>
|
| 21 |
+
<body>
|
| 22 |
+
<div class="container">
|
| 23 |
+
<h1>Downloadwella to Hugging Face Frame Extractor</h1>
|
| 24 |
+
<p>Enter a Downloadwella URL to download the video, extract frames, and upload them as a zip to Hugging Face.</p>
|
| 25 |
+
|
| 26 |
+
<form id="processForm">
|
| 27 |
+
<input type="text" id="videoUrl" name="video_url" placeholder="Enter Downloadwella URL (e.g., https://downloadwella.com/some-video-id)" required>
|
| 28 |
+
<button type="submit">Start Processing</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
</form>
|
| 30 |
+
|
| 31 |
+
<div class="status-box">
|
| 32 |
+
<h2>Processing Status</h2>
|
| 33 |
+
<p><strong>Is Running:</strong> <span id="isRunning">{{ status.is_running }}</span></p>
|
| 34 |
+
<p><strong>Current Action:</strong> <span id="currentAction">{{ status.current_action }}</span></p>
|
| 35 |
+
<p><strong>Last Processed URL:</strong> <span id="lastProcessedUrl">{{ status.last_processed_url if status.last_processed_url else 'N/A' }}</span></p>
|
| 36 |
+
<p><strong>Processed Count:</strong> <span id="processedCount">{{ status.processed_count }}</span></p>
|
| 37 |
+
<h3>Logs:</h3>
|
| 38 |
+
<div id="logs" style="max-height: 300px; overflow-y: scroll; background-color: #fff; padding: 10px; border-radius: 4px;">
|
| 39 |
+
{% for log in status.logs %}
|
| 40 |
+
<div class="log-entry">{{ log }}</div>
|
| 41 |
+
{% endfor %}
|
| 42 |
</div>
|
| 43 |
</div>
|
| 44 |
</div>
|
| 45 |
|
| 46 |
<script>
|
| 47 |
+
const processForm = document.getElementById('processForm');
|
| 48 |
+
const videoUrlInput = document.getElementById('videoUrl');
|
| 49 |
+
const isRunningSpan = document.getElementById('isRunning');
|
| 50 |
+
const currentActionSpan = document.getElementById('currentAction');
|
| 51 |
+
const lastProcessedUrlSpan = document.getElementById('lastProcessedUrl');
|
| 52 |
+
const processedCountSpan = document.getElementById('processedCount');
|
| 53 |
+
const logsDiv = document.getElementById('logs');
|
| 54 |
|
| 55 |
+
processForm.addEventListener('submit', async (event) => {
|
| 56 |
+
event.preventDefault();
|
| 57 |
+
const videoUrl = videoUrlInput.value;
|
| 58 |
+
if (!videoUrl) return;
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
+
logsDiv.innerHTML = ''; // Clear previous logs
|
| 61 |
+
addLog('Initiating processing...');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
try {
|
| 64 |
+
const response = await fetch('/start', {
|
| 65 |
method: 'POST',
|
| 66 |
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
| 67 |
+
body: `video_url=${encodeURIComponent(videoUrl)}`
|
| 68 |
});
|
| 69 |
+
const data = await response.json();
|
| 70 |
+
addLog(data.message);
|
| 71 |
+
if (data.message === "Processor started") {
|
| 72 |
+
// Start polling for status updates
|
| 73 |
+
pollStatus();
|
| 74 |
+
}
|
| 75 |
+
} catch (error) {
|
| 76 |
+
addLog(`Error starting process: ${error}`, true);
|
| 77 |
+
}
|
| 78 |
+
});
|
| 79 |
|
| 80 |
+
async function fetchStatus() {
|
| 81 |
+
try {
|
| 82 |
+
const response = await fetch('/stats');
|
| 83 |
+
const status = await response.json();
|
| 84 |
+
isRunningSpan.textContent = status.is_running;
|
| 85 |
+
currentActionSpan.textContent = status.current_action;
|
| 86 |
+
lastProcessedUrlSpan.textContent = status.last_processed_url || 'N/A';
|
| 87 |
+
processedCountSpan.textContent = status.processed_count;
|
| 88 |
+
|
| 89 |
+
// Only update logs if there are new entries or status changed
|
| 90 |
+
if (status.logs.length !== logsDiv.children.length) {
|
| 91 |
+
logsDiv.innerHTML = '';
|
| 92 |
+
status.logs.forEach(log => addLog(log));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
}
|
| 94 |
+
|
| 95 |
+
return status.is_running;
|
| 96 |
} catch (error) {
|
| 97 |
+
addLog(`Error fetching status: ${error}`, true);
|
| 98 |
+
return false;
|
|
|
|
|
|
|
| 99 |
}
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
function addLog(message, isError = false) {
|
| 103 |
+
const logEntry = document.createElement('div');
|
| 104 |
+
logEntry.classList.add('log-entry');
|
| 105 |
+
if (isError) {
|
| 106 |
+
logEntry.classList.add('error');
|
| 107 |
+
}
|
| 108 |
+
logEntry.textContent = message;
|
| 109 |
+
logsDiv.appendChild(logEntry);
|
| 110 |
+
logsDiv.scrollTop = logsDiv.scrollHeight; // Auto-scroll to bottom
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
let pollingInterval;
|
| 114 |
+
function pollStatus() {
|
| 115 |
+
if (pollingInterval) clearInterval(pollingInterval);
|
| 116 |
+
pollingInterval = setInterval(async () => {
|
| 117 |
+
const running = await fetchStatus();
|
| 118 |
+
if (!running && currentActionSpan.textContent !== "Idle" && currentActionSpan.textContent !== "Error") {
|
| 119 |
+
addLog("Processing finished or stopped.");
|
| 120 |
+
clearInterval(pollingInterval);
|
| 121 |
+
}
|
| 122 |
+
}, 3000); // Poll every 3 seconds
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
// Initial status fetch on page load
|
| 126 |
+
fetchStatus();
|
| 127 |
+
pollStatus(); // Start polling immediately
|
| 128 |
+
|
| 129 |
</script>
|
| 130 |
</body>
|
| 131 |
</html>
|