let selectedProduct = null; let selectedDevice = null; let catalogItems = []; let libraryIds = new Set(); // Produkt-IDs die schon lokal (dauerhaft) vorhanden sind let mode = "stick"; // "stick" | "download" const versionSelect = document.getElementById("versionSelect"); const versionDetail = document.getElementById("versionDetail"); const catalogStatus = document.getElementById("catalogStatus"); const deviceSection = document.getElementById("deviceSection"); const deviceList = document.getElementById("deviceList"); const confirmPath = document.getElementById("confirmPath"); const stickConfirm = document.getElementById("stickConfirm"); const downloadHint = document.getElementById("downloadHint"); const step3Title = document.getElementById("step3Title"); const startBtn = document.getElementById("startBtn"); const progressCard = document.getElementById("progressCard"); const progressFill = document.getElementById("progressFill"); const progressPhase = document.getElementById("progressPhase"); const logEl = document.getElementById("log"); const libraryStatus = document.getElementById("libraryStatus"); const modeStickBtn = document.getElementById("modeStick"); const modeDownloadBtn = document.getElementById("modeDownload"); function fmtSize(bytes) { if (!bytes) return "?"; const gb = bytes / 1e9; return gb >= 1 ? gb.toFixed(1) + " GB" : (bytes / 1e6).toFixed(0) + " MB"; } function setMode(next) { mode = next; modeStickBtn.classList.toggle("active", mode === "stick"); modeDownloadBtn.classList.toggle("active", mode === "download"); deviceSection.style.display = mode === "stick" ? "" : "none"; stickConfirm.style.display = mode === "stick" ? "" : "none"; downloadHint.style.display = mode === "download" ? "" : "none"; step3Title.textContent = mode === "stick" ? "3. Bestaetigen & Schreiben" : "3. Herunterladen"; startBtn.textContent = mode === "stick" ? "Stick erstellen" : "Image herunterladen"; updateStartEnabled(); } modeStickBtn.addEventListener("click", () => setMode("stick")); modeDownloadBtn.addEventListener("click", () => setMode("download")); async function loadLibrary() { const res = await fetch("/api/library"); const data = await res.json(); libraryIds = new Set((data.items || []).map((it) => it.id)); const count = (data.items || []).length; const size = fmtSize(data.total_bytes || 0); libraryStatus.textContent = count ? `${count} Installer bereits dauerhaft lokal vorhanden -- ${size} in ./downloads/library/` : "Noch keine Installer dauerhaft lokal gespeichert."; renderVersionOptions(); } function renderVersionOptions() { versionSelect.innerHTML = ""; for (const item of catalogItems) { const opt = document.createElement("option"); opt.value = item.id; const modeTag = item.mode === "recovery" ? " [experimentell]" : ""; const offlineTag = libraryIds.has(item.id) ? " -- bereits offline vorhanden" : ""; opt.textContent = `${item.title} ${item.version} - ${fmtSize(item.size_bytes)}${modeTag}${offlineTag}`; versionSelect.appendChild(opt); } } async function loadVersions() { catalogStatus.textContent = "Lade Apple-Katalog..."; const res = await fetch("/api/versions"); const data = await res.json(); catalogItems = data.items || []; if (data.loading) { catalogStatus.textContent = "Katalog wird noch geladen, gleich nochmal versuchen..."; setTimeout(loadVersions, 3000); return; } if (data.error) { catalogStatus.textContent = "Fehler beim Laden: " + data.error; return; } catalogStatus.textContent = `${catalogItems.length} macOS-Installer gefunden (Katalog: ${data.catalog_url ? data.catalog_url.split("/").pop() : "?"})`; renderVersionOptions(); } versionSelect.addEventListener("change", () => { selectedProduct = catalogItems.find((i) => i.id === versionSelect.value) || null; if (selectedProduct) { const modeText = selectedProduct.mode === "recovery" ? "Big Sur+ Pfad: experimentell, Extraktion kann fehlschlagen." : "Klassischer dd-Pfad: robust und gut getestet."; const offlineText = libraryIds.has(selectedProduct.id) ? " | bereits offline vorhanden, kein erneuter Download noetig." : ""; versionDetail.textContent = `${selectedProduct.title} ${selectedProduct.version} | ${fmtSize(selectedProduct.size_bytes)} | ${modeText}${offlineText}`; } updateStartEnabled(); }); async function loadDevices() { deviceList.innerHTML = "