/** * Filebrowser + Upload fuer VideoKonverter */ // === Filebrowser === let fbCurrentPath = "/mnt"; let fbSelectedFiles = new Set(); let fbSelectedDirs = new Set(); function openFileBrowser() { document.getElementById("filebrowser-overlay").style.display = "flex"; fbSelectedFiles.clear(); fbSelectedDirs.clear(); fbNavigate("/mnt"); } function closeFileBrowser() { document.getElementById("filebrowser-overlay").style.display = "none"; } function closeBrowserOnOverlay(e) { if (e.target === e.currentTarget) closeFileBrowser(); } async function fbNavigate(path) { fbCurrentPath = path; fbSelectedFiles.clear(); fbSelectedDirs.clear(); updateFbSelection(); const content = document.getElementById("fb-content"); content.innerHTML = '
Lade...
'; try { const resp = await fetch("/api/browse?path=" + encodeURIComponent(path)); const data = await resp.json(); if (!resp.ok) { content.innerHTML = `
${data.error}
`; return; } renderBreadcrumb(data.path); renderBrowser(data); } catch (e) { content.innerHTML = '
Verbindungsfehler
'; } } function renderBreadcrumb(path) { const bc = document.getElementById("fb-breadcrumb"); const parts = path.split("/").filter(Boolean); let html = '/mnt'; let current = ""; for (const part of parts) { current += "/" + part; if (current === "/mnt") continue; html += ` / `; html += `${part}`; } bc.innerHTML = html; } function renderBrowser(data) { const content = document.getElementById("fb-content"); let html = ""; // "Nach oben" Link if (data.parent) { html += `
..
`; } // Ordner for (const dir of data.dirs) { const badge = dir.video_count > 0 ? `${dir.video_count} Videos` : ""; html += `
📁 ${dir.name} ${badge}
`; } // Dateien for (const file of data.files) { html += `
🎥 ${file.name} ${file.size_human}
`; } if (data.dirs.length === 0 && data.files.length === 0) { html = '
Keine Videodateien in diesem Ordner
'; } content.innerHTML = html; } function fbToggleFile(path, checked) { if (checked) fbSelectedFiles.add(path); else fbSelectedFiles.delete(path); updateFbSelection(); } function fbToggleDir(path, checked) { if (checked) fbSelectedDirs.add(path); else fbSelectedDirs.delete(path); updateFbSelection(); } function fbSelectAll() { const checks = document.querySelectorAll("#fb-content input[type=checkbox]"); const allChecked = Array.from(checks).every(c => c.checked); checks.forEach(c => { c.checked = !allChecked; c.dispatchEvent(new Event("change")); }); } function updateFbSelection() { const count = fbSelectedFiles.size + fbSelectedDirs.size; document.getElementById("fb-selected-count").textContent = `${count} ausgewaehlt`; document.getElementById("fb-convert").disabled = count === 0; } async function fbConvertSelected() { const paths = [...fbSelectedFiles, ...fbSelectedDirs]; if (paths.length === 0) return; document.getElementById("fb-convert").disabled = true; document.getElementById("fb-convert").textContent = "Wird gesendet..."; try { const resp = await fetch("/api/convert", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({files: paths}), }); const data = await resp.json(); showToast(data.message, "success"); closeFileBrowser(); } catch (e) { showToast("Fehler beim Senden", "error"); } finally { document.getElementById("fb-convert").disabled = false; document.getElementById("fb-convert").textContent = "Konvertieren"; } } // === Upload === let uploadFiles = []; function openUpload() { document.getElementById("upload-overlay").style.display = "flex"; uploadFiles = []; document.getElementById("upload-list").innerHTML = ""; document.getElementById("upload-progress").style.display = "none"; document.getElementById("upload-start").disabled = true; document.getElementById("upload-input").value = ""; } function closeUpload() { document.getElementById("upload-overlay").style.display = "none"; } function closeUploadOnOverlay(e) { if (e.target === e.currentTarget) closeUpload(); } function handleDragOver(e) { e.preventDefault(); e.currentTarget.classList.add("drag-over"); } function handleDragLeave(e) { e.currentTarget.classList.remove("drag-over"); } function handleDrop(e) { e.preventDefault(); e.currentTarget.classList.remove("drag-over"); addFiles(e.dataTransfer.files); } function handleFileSelect(e) { addFiles(e.target.files); } function addFiles(fileList) { for (const file of fileList) { if (!uploadFiles.some(f => f.name === file.name && f.size === file.size)) { uploadFiles.push(file); } } renderUploadList(); } function removeUploadFile(index) { uploadFiles.splice(index, 1); renderUploadList(); } function renderUploadList() { const list = document.getElementById("upload-list"); if (uploadFiles.length === 0) { list.innerHTML = ""; document.getElementById("upload-start").disabled = true; return; } let html = ""; uploadFiles.forEach((file, i) => { const size = file.size < 1024 * 1024 ? (file.size / 1024).toFixed(0) + " KiB" : file.size < 1024 * 1024 * 1024 ? (file.size / (1024 * 1024)).toFixed(1) + " MiB" : (file.size / (1024 * 1024 * 1024)).toFixed(2) + " GiB"; html += `
${file.name} ${size}
`; }); list.innerHTML = html; document.getElementById("upload-start").disabled = false; } async function startUpload() { if (uploadFiles.length === 0) return; const btn = document.getElementById("upload-start"); btn.disabled = true; btn.textContent = "Wird hochgeladen..."; const progress = document.getElementById("upload-progress"); const bar = document.getElementById("upload-bar"); const status = document.getElementById("upload-status"); progress.style.display = "block"; const formData = new FormData(); uploadFiles.forEach(f => formData.append("files", f)); try { const xhr = new XMLHttpRequest(); xhr.open("POST", "/api/upload"); xhr.upload.onprogress = (e) => { if (e.lengthComputable) { const pct = (e.loaded / e.total) * 100; bar.style.width = pct + "%"; const loaded = (e.loaded / (1024 * 1024)).toFixed(1); const total = (e.total / (1024 * 1024)).toFixed(1); status.textContent = `${loaded} / ${total} MiB (${pct.toFixed(0)}%)`; } }; const result = await new Promise((resolve, reject) => { xhr.onload = () => { if (xhr.status === 200) resolve(JSON.parse(xhr.responseText)); else reject(JSON.parse(xhr.responseText)); }; xhr.onerror = () => reject({error: "Netzwerkfehler"}); xhr.send(formData); }); showToast(result.message, "success"); closeUpload(); } catch (e) { showToast(e.error || "Upload fehlgeschlagen", "error"); btn.disabled = false; btn.textContent = "Hochladen & Konvertieren"; } } // === Toast === function showToast(message, type) { const container = document.getElementById("toast-container"); if (!container) return; const toast = document.createElement("div"); toast.className = `toast ${type}`; toast.textContent = message; container.appendChild(toast); setTimeout(() => toast.remove(), 3000); }