/**
* 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);
}