Skip to content

Commit 81abcc5

Browse files
committed
fix: resolve web active download rendering, style cookies selector and custom confirmations
1 parent 185049c commit 81abcc5

4 files changed

Lines changed: 164 additions & 28 deletions

File tree

src/services/download_manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import time
33
from queue import Queue, Empty
44
from datetime import datetime
5+
import uuid
56

67
from src.modules.core import VideoDownloadTask, Config
78
from src.services.workers import DownloadWorker
@@ -184,7 +185,7 @@ def start_download(self, task: VideoDownloadTask):
184185
config.get("format", "mp4"),
185186
config.get("language", "es")
186187
)
187-
worker_id = f"{task.url}_{time.time()}"
188+
worker_id = f"worker_{uuid.uuid4().hex}"
188189

189190
task.state = "descargando"
190191
task.start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

src/web/static/app.js

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ function updateUI(state) {
186186
</div>
187187
188188
<!-- Progress Bar -->
189-
<div class="w-full h-2 bg-slate-955/40 rounded-full overflow-hidden mb-3">
189+
<div class="w-full h-2 bg-slate-950/40 rounded-full overflow-hidden mb-3">
190190
<div id="${workerId}-bar" class="h-full progress-fill" style="width: ${percent}%"></div>
191191
</div>
192192
@@ -211,7 +211,7 @@ function updateUI(state) {
211211

212212
function createPendingCard(task, index) {
213213
const card = document.createElement('div');
214-
card.className = 'glass-card p-4 download-card border-l-4 border-l-purple-500/40 bg-slate-955/10 animate-slide-in';
214+
card.className = 'glass-card p-4 download-card border-l-4 border-l-purple-500/40 bg-slate-950/10 animate-slide-in';
215215

216216
card.innerHTML = `
217217
<div class="flex items-center justify-between gap-4">
@@ -239,7 +239,7 @@ function createPendingCard(task, index) {
239239
}
240240

241241
async function cancelActiveWorker(workerId) {
242-
if (!confirm('¿Cancelar esta descarga?')) return;
242+
if (!await showConfirm('¿Cancelar Descarga?', '¿Estás seguro de que deseas cancelar esta descarga activa?', 'warning')) return;
243243
try {
244244
const response = await fetch(`/api/downloads/${encodeURIComponent(workerId)}/cancel`, { method: 'POST' });
245245
const res = await response.json();
@@ -257,7 +257,7 @@ async function cancelActiveWorker(workerId) {
257257
}
258258

259259
async function removePendingTask(url) {
260-
if (!confirm('¿Eliminar esta tarea de la cola?')) return;
260+
if (!await showConfirm('¿Quitar de la Cola?', '¿Estás seguro de que deseas eliminar esta tarea de la cola de pendientes?', 'warning')) return;
261261
try {
262262
const response = await fetch('/api/downloads/remove-pending', {
263263
method: 'POST',
@@ -457,7 +457,7 @@ async function togglePauseQueue() {
457457
}
458458

459459
async function cancelAllDownloads() {
460-
if (!confirm('¿Estás seguro de que quieres cancelar todas las descargas activas?')) return;
460+
if (!await showConfirm('¿Cancelar Todo?', '¿Estás seguro de que deseas cancelar todas las descargas activas?', 'error')) return;
461461
try {
462462
const response = await fetch('/api/downloads/cancel', { method: 'POST' });
463463
const res = await response.json();
@@ -488,7 +488,7 @@ async function clearHistory() {
488488
}
489489

490490
async function clearQueue() {
491-
if (!confirm('¿Cancelar todas las descargas activas y vaciar la cola de pendientes?')) return;
491+
if (!await showConfirm('¿Limpiar Lista?', '¿Cancelar todas las descargas activas y vaciar la cola de pendientes?', 'error')) return;
492492
try {
493493
const response = await fetch('/api/downloads/clear-queue', { method: 'POST' });
494494
const res = await response.json();
@@ -800,6 +800,52 @@ async function saveSettings() {
800800
}
801801
}
802802

803+
// Custom Confirmation Modal Logic
804+
let confirmPromiseResolve = null;
805+
806+
function showConfirm(title, message, iconType = 'warning') {
807+
const modal = document.getElementById('confirm-modal');
808+
const titleEl = document.getElementById('confirm-modal-title');
809+
const messageEl = document.getElementById('confirm-modal-message');
810+
const iconEl = document.getElementById('confirm-modal-icon');
811+
const iconBg = document.getElementById('confirm-modal-icon-bg');
812+
813+
titleEl.textContent = title;
814+
messageEl.textContent = message;
815+
816+
// Icon and colors
817+
iconBg.className = 'w-10 h-10 rounded-xl flex items-center justify-center shrink-0 border';
818+
if (iconType === 'error') {
819+
iconBg.classList.add('bg-rose-500/20', 'border-rose-500/30', 'text-rose-400');
820+
iconEl.className = 'fa-solid fa-ban text-lg';
821+
} else if (iconType === 'info') {
822+
iconBg.classList.add('bg-blue-500/20', 'border-blue-500/30', 'text-blue-400');
823+
iconEl.className = 'fa-solid fa-circle-info text-lg';
824+
} else { // warning
825+
iconBg.classList.add('bg-amber-500/20', 'border-amber-500/30', 'text-amber-400');
826+
iconEl.className = 'fa-solid fa-triangle-exclamation text-lg';
827+
}
828+
829+
modal.classList.add('modal-active');
830+
831+
return new Promise((resolve) => {
832+
confirmPromiseResolve = resolve;
833+
});
834+
}
835+
836+
function handleConfirmResult(value) {
837+
const modal = document.getElementById('confirm-modal');
838+
modal.classList.remove('modal-active');
839+
if (confirmPromiseResolve) {
840+
confirmPromiseResolve(value);
841+
confirmPromiseResolve = null;
842+
}
843+
}
844+
845+
function closeConfirmModal() {
846+
handleConfirmResult(false);
847+
}
848+
803849
// Fetch logs and output to terminal log box
804850
async function fetchLogs() {
805851
const terminal = document.getElementById('terminal-logs');
@@ -826,6 +872,42 @@ window.addEventListener('DOMContentLoaded', () => {
826872
connectWebSocket();
827873
updateCookiesStatus();
828874

875+
// Setup confirm modal action listener
876+
const btnConfirmOk = document.getElementById('btn-confirm-ok');
877+
if (btnConfirmOk) {
878+
btnConfirmOk.addEventListener('click', () => handleConfirmResult(true));
879+
}
880+
881+
// Setup Drag & Drop Cookie Upload Zone
882+
const dropZone = document.getElementById('cookie-drop-zone');
883+
if (dropZone) {
884+
['dragenter', 'dragover'].forEach(eventName => {
885+
dropZone.addEventListener(eventName, (e) => {
886+
e.preventDefault();
887+
e.stopPropagation();
888+
dropZone.classList.add('dragover');
889+
}, false);
890+
});
891+
892+
['dragleave', 'drop'].forEach(eventName => {
893+
dropZone.addEventListener(eventName, (e) => {
894+
e.preventDefault();
895+
e.stopPropagation();
896+
dropZone.classList.remove('dragover');
897+
}, false);
898+
});
899+
900+
dropZone.addEventListener('drop', (e) => {
901+
const dt = e.dataTransfer;
902+
const files = dt.files;
903+
if (files && files.length > 0) {
904+
const fileInput = document.getElementById('cookie-file-input');
905+
fileInput.files = files; // Assign files to input
906+
uploadCookieFile(); // Trigger upload
907+
}
908+
}, false);
909+
}
910+
829911
// Fetch logs every 5 seconds
830912
fetchLogs();
831913
setInterval(fetchLogs, 5000);

src/web/static/index.html

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -227,26 +227,43 @@ <h2 class="text-lg font-bold font-outfit text-white mb-4 flex items-center gap-2
227227
</select>
228228
</div>
229229
</div>
230-
<div>
231-
<label class="block text-xs font-semibold text-slate-400 uppercase tracking-wider mb-2">Cookies de Navegador (Bypass Bot)</label>
232-
<select id="setting-cookies"
233-
class="w-full px-3 py-2.5 bg-slate-900/50 border border-white/10 rounded-lg text-xs focus:outline-none focus:border-violet-500 transition-all text-white font-medium cursor-pointer">
234-
<option value="none">Ninguno (None)</option>
235-
<option value="chrome">Chrome</option>
236-
<option value="firefox">Firefox</option>
237-
<option value="edge">Edge</option>
238-
<option value="brave">Brave</option>
239-
<option value="opera">Opera</option>
240-
</select>
241-
</div>
242-
<div>
243-
<label class="block text-xs font-semibold text-slate-400 uppercase tracking-wider mb-2">Archivo de Cookies Local (cookies.txt / cookies.json)</label>
244-
<div class="flex items-center gap-3">
245-
<label class="px-3 py-2 bg-slate-800 hover:bg-slate-700 text-xs font-semibold rounded-lg border border-white/10 cursor-pointer text-white transition-all flex items-center gap-1.5">
246-
<i class="fa-solid fa-file-import"></i> Seleccionar archivo...
230+
<!-- Cookies / Bot Bypass section styled beautifully -->
231+
<div class="p-4 rounded-2xl bg-violet-950/10 border border-violet-500/20 space-y-4">
232+
<div class="flex items-center gap-2">
233+
<div class="w-6 h-6 rounded-lg bg-violet-600/20 border border-violet-500/30 flex items-center justify-center text-violet-400">
234+
<i class="fa-solid fa-cookie-bite text-xs"></i>
235+
</div>
236+
<h3 class="text-xs font-bold text-white uppercase tracking-wider">Bypass de Bot (Cookies)</h3>
237+
</div>
238+
239+
<div>
240+
<label class="block text-[10px] font-semibold text-slate-400 uppercase tracking-wider mb-1.5">Cookies de Navegador</label>
241+
<div class="relative">
242+
<select id="setting-cookies"
243+
class="w-full px-3 py-2 bg-slate-900/50 border border-white/10 rounded-lg text-xs focus:outline-none focus:border-violet-500 transition-all text-white font-medium cursor-pointer appearance-none">
244+
<option value="none">Ninguno (None)</option>
245+
<option value="chrome">Chrome</option>
246+
<option value="firefox">Firefox</option>
247+
<option value="edge">Edge</option>
248+
<option value="brave">Brave</option>
249+
<option value="opera">Opera</option>
250+
</select>
251+
<span class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none text-slate-400 text-[10px]">
252+
<i class="fa-solid fa-chevron-down"></i>
253+
</span>
254+
</div>
255+
</div>
256+
257+
<div>
258+
<label class="block text-[10px] font-semibold text-slate-400 uppercase tracking-wider mb-1.5">Archivo de Cookies Local (cookies.txt / cookies.json)</label>
259+
<!-- Drag and Drop Cookie Upload Zone -->
260+
<div id="cookie-drop-zone" class="border border-dashed border-violet-500/30 rounded-xl p-4 bg-slate-900/20 hover:bg-slate-900/40 hover:border-violet-500/60 transition-all duration-300 flex flex-col items-center justify-center gap-2 cursor-pointer">
261+
<i id="cookie-upload-icon" class="fa-solid fa-cloud-arrow-up text-xl text-violet-400"></i>
262+
<span class="text-xs font-semibold text-slate-200 text-center">Importar cookies.txt / cookies.json</span>
263+
<span class="text-[9px] text-slate-500 text-center">Arrastra el archivo aquí o haz clic para buscar</span>
264+
<span id="cookie-file-status" class="text-[10px] text-slate-400 font-semibold mt-1">Cargando estado...</span>
247265
<input type="file" id="cookie-file-input" class="hidden" accept=".json,.txt" onchange="uploadCookieFile()">
248-
</label>
249-
<span id="cookie-file-status" class="text-xs text-slate-400 font-medium">Cargando estado...</span>
266+
</div>
250267
</div>
251268
</div>
252269
<div class="flex items-center justify-between pt-2">
@@ -393,7 +410,32 @@ <h3 class="text-sm font-bold text-white font-outfit">Nueva Carpeta</h3>
393410
</div>
394411
</div>
395412

413+
<!-- Custom Confirmation Modal -->
414+
<div id="confirm-modal" class="fixed inset-0 z-50 flex items-center justify-center bg-black/75 backdrop-blur-md opacity-0 pointer-events-none transition-all duration-300">
415+
<div class="glass-card w-full max-w-sm mx-4 p-6 border border-white/10 bg-[#0c0f1d]/95 shadow-2xl space-y-4 transform scale-95 transition-transform duration-300">
416+
<div class="flex items-start gap-4">
417+
<div id="confirm-modal-icon-bg" class="w-10 h-10 rounded-xl bg-amber-500/20 border border-amber-500/30 flex items-center justify-center text-amber-400 shrink-0">
418+
<i id="confirm-modal-icon" class="fa-solid fa-triangle-exclamation text-lg"></i>
419+
</div>
420+
<div class="space-y-1">
421+
<h3 id="confirm-modal-title" class="text-md font-bold text-white font-outfit">Confirmar Acción</h3>
422+
<p id="confirm-modal-message" class="text-xs text-slate-300 leading-relaxed"></p>
423+
</div>
424+
</div>
425+
<div class="flex items-center justify-end gap-3 pt-2">
426+
<button id="btn-confirm-cancel" onclick="closeConfirmModal();"
427+
class="px-4 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 text-xs font-semibold text-slate-300 transition-all active:scale-95">
428+
Cancelar
429+
</button>
430+
<button id="btn-confirm-ok"
431+
class="px-4 py-2 rounded-lg bg-gradient-to-r from-violet-600 to-fuchsia-600 hover:from-violet-500 hover:to-fuchsia-500 text-xs font-semibold text-white transition-all active:scale-95">
432+
Confirmar
433+
</button>
434+
</div>
435+
</div>
436+
</div>
437+
396438
<!-- Web App JS Logic -->
397-
<script src="app.js"></script>
439+
<script src="app.js" defer></script>
398440
</body>
399441
</html>

src/web/static/style.css

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,18 @@ input:focus, select:focus {
210210
}
211211

212212
/* Modal default scaling transition */
213-
#folder-browser-modal > div, #new-folder-modal > div {
213+
#folder-browser-modal > div, #new-folder-modal > div, #confirm-modal > div {
214214
transform: scale(0.95);
215215
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
216216
}
217+
218+
/* Cookie Upload Drag and Drop Zone styling */
219+
#cookie-drop-zone {
220+
transition: all 0.3s ease;
221+
}
222+
223+
#cookie-drop-zone.dragover {
224+
border-color: var(--neon-purple) !important;
225+
background: rgba(168, 85, 247, 0.08) !important;
226+
box-shadow: 0 0 15px rgba(168, 85, 247, 0.15) !important;
227+
}

0 commit comments

Comments
 (0)