initial aubox skeleton: web-UI, kirin DLOAD, firmware library
- FastAPI Web-UI auf 127.0.0.1:8080 mit Geräte-Live-Erkennung, sandboxed File-Browser, Firmware-Library (SQLite + Auto-Identifikation) - Huawei update.app Parser: extrahiert Hardware-ID, Section-Layout, BOOT/SYSTEM-Vorhandensein direkt aus den Headern - Kirin Download-Mode: hisi-idt-Protokoll-Implementation gegen pyusb - USB-Erkennung für Huawei (DLOAD/Fastboot-D), Google, MediaTek, Qualcomm EDL - Huawei-P10-Lite-Workflow (eRecovery + Testpoint-DLOAD-Pfade) - Docker-Compose mit USB-Passthrough (Major 189) für Re-Enumeration - udev-Regeln + Setup-Script für Debian/Ubuntu/Pi-OS Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// Live-Refresh für Container mit data-refresh="<url>" und data-interval="<ms>"
|
||||
function startAutoRefresh() {
|
||||
document.querySelectorAll("[data-refresh]").forEach((el) => {
|
||||
const url = el.dataset.refresh;
|
||||
const interval = parseInt(el.dataset.interval || "2000", 10);
|
||||
const tick = async () => {
|
||||
try {
|
||||
const r = await fetch(url, { headers: { "Accept": "text/html" } });
|
||||
if (r.ok) el.innerHTML = await r.text();
|
||||
} catch (e) { /* netzkurz weg, nicht weiter schlimm */ }
|
||||
};
|
||||
tick();
|
||||
setInterval(tick, interval);
|
||||
});
|
||||
}
|
||||
|
||||
// Forms mit data-action posten und Antwort in data-target rendern
|
||||
function wireScanForms() {
|
||||
document.querySelectorAll("form[data-action]").forEach((form) => {
|
||||
form.addEventListener("submit", async (ev) => {
|
||||
ev.preventDefault();
|
||||
const btn = form.querySelector("button[type=submit]");
|
||||
const target = document.querySelector(form.dataset.target);
|
||||
btn.disabled = true;
|
||||
if (target) target.textContent = "läuft…";
|
||||
try {
|
||||
const r = await fetch(form.dataset.action, { method: "POST" });
|
||||
const j = await r.json().catch(() => null);
|
||||
if (target) {
|
||||
if (j) {
|
||||
target.textContent = `gescannt: ${j.scanned} · neu: ${j.added} · aktualisiert: ${j.updated} · entfernt: ${j.removed}`;
|
||||
} else {
|
||||
target.textContent = r.ok ? "fertig" : "Fehler";
|
||||
}
|
||||
}
|
||||
// Seite neu laden, damit die Tabelle die neuen Einträge zeigt
|
||||
if (r.ok) setTimeout(() => location.reload(), 800);
|
||||
} catch (e) {
|
||||
if (target) target.textContent = "Fehler: " + e;
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
startAutoRefresh();
|
||||
wireScanForms();
|
||||
});
|
||||
@@ -0,0 +1,136 @@
|
||||
:root {
|
||||
--bg: #1c1f24;
|
||||
--bg-card: #262a31;
|
||||
--fg: #e6e6e6;
|
||||
--muted: #8a8f98;
|
||||
--accent: #6cb4ff;
|
||||
--accent-hover: #8fc8ff;
|
||||
--border: #353a44;
|
||||
--ok: #7adf7a;
|
||||
--warn: #ffb86c;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
header {
|
||||
background: var(--bg-card);
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 1rem 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
header h1 { margin: 0; font-size: 1.4rem; }
|
||||
header h1 a { color: var(--fg); text-decoration: none; }
|
||||
|
||||
nav { display: flex; gap: 1.5rem; }
|
||||
nav a { color: var(--muted); text-decoration: none; font-weight: 500; }
|
||||
nav a:hover { color: var(--accent); }
|
||||
|
||||
main { max-width: 1200px; margin: 0 auto; padding: 2rem; }
|
||||
|
||||
footer {
|
||||
text-align: center; padding: 2rem; color: var(--muted);
|
||||
border-top: 1px solid var(--border); margin-top: 4rem;
|
||||
}
|
||||
|
||||
a { color: var(--accent); }
|
||||
a:hover { color: var(--accent-hover); }
|
||||
|
||||
code, pre {
|
||||
font-family: "JetBrains Mono", Menlo, Consolas, monospace;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
pre {
|
||||
background: var(--bg-card);
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
code { background: var(--bg-card); padding: 0.1em 0.4em; border-radius: 3px; }
|
||||
|
||||
.cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 1rem;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
.card h2 { margin-top: 0; font-size: 1rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
.card .big { font-size: 2.5rem; font-weight: 700; margin: 0.5rem 0; }
|
||||
|
||||
.info { margin-top: 3rem; }
|
||||
.info ul { list-style: none; padding: 0; }
|
||||
.info li { margin: 0.5rem 0; }
|
||||
|
||||
table.grid {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: var(--bg-card);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
table.grid th, table.grid td {
|
||||
text-align: left;
|
||||
padding: 0.75rem 1rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
table.grid th { background: rgba(255,255,255,0.04); font-weight: 600; }
|
||||
table.grid tbody tr:last-child td { border-bottom: none; }
|
||||
table.grid tbody tr:hover { background: rgba(255,255,255,0.03); }
|
||||
|
||||
table.kv { border-collapse: collapse; }
|
||||
table.kv th { text-align: left; padding: 0.5rem 1rem 0.5rem 0; color: var(--muted); font-weight: 500; }
|
||||
table.kv td { padding: 0.5rem 0; }
|
||||
|
||||
button {
|
||||
background: var(--accent);
|
||||
color: #0d1117;
|
||||
border: 0;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
button:hover { background: var(--accent-hover); }
|
||||
button:disabled { opacity: 0.5; cursor: wait; }
|
||||
|
||||
.empty {
|
||||
background: var(--bg-card);
|
||||
border: 1px dashed var(--border);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
color: var(--muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.muted { color: var(--muted); }
|
||||
|
||||
.crumbs {
|
||||
background: var(--bg-card);
|
||||
padding: 0.6rem 1rem;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 1rem;
|
||||
border: 1px solid var(--border);
|
||||
font-family: "JetBrains Mono", Menlo, monospace;
|
||||
}
|
||||
.crumbs a { color: var(--fg); text-decoration: none; }
|
||||
.crumbs a:hover { color: var(--accent); }
|
||||
|
||||
#scan-result { margin-left: 1rem; color: var(--muted); }
|
||||
Reference in New Issue
Block a user