Jeder kennt es: Tausende Fotos auf verschiedenen Festplatten, eine Synology im Keller, Backups in der Cloud — und die einzige Suchfunktion ist manuelles Durchklicken. „Welche Fotos habe ich von der Sardinien-Reise 2019?" erfordert eine halbe Stunde Ordnernavigation und gute Erinnerung an die Dateistruktur.
Mein Archiv bestand aus 15 Ordnern, verteilt auf drei NAS-Volumes, gewachsen über 15 Jahre. Kameras von Canon über GoPro bis Insta360. Formate von JPEG über RAW bis zu 360°-Videos. Keine einheitlichen Dateinamen, keine Tags, keine Suche.
Mein Ziel: Eine App, die das gesamte Archiv als digitales Leuchtpult darstellt — durchsuchbar nach Ort, Zeit, Kamera, Inhalt und Personen. Offline-fähig. Auf dem iPad. Das Ergebnis nach drei Wochen:
Die Pipeline — 11 Stufen im Überblick
Die Pipeline verwandelt eine unstrukturierte Festplatte in eine durchsuchbare Datenbank. Jede Stufe ist eigenständig — du kannst nach Stufe 2 aufhören und hast bereits ein brauchbares Archiv. Oder du gehst bis Stufe 11.
Dateisystem-Scan & Metadaten Pflicht
Rekursiver Walk, EXIF-Extraktion, Video-Metadaten → SQLite-Datenbank
Kleine Thumbnails (96 + 176 px) Pflicht
Grid-Ansicht und Leuchtpult — parallel zur Indexierung
Große Vorschauen (800 px) Optional
Detail-Ansicht und Input für KI-Beschreibungen
Abgeleitete Tiers (80 + 360 px) Optional
Extra-klein und mittel, kaskadiert aus vorhandenen Tiers
Video-Filmstrips Optional
Sprite-Grids: alle 30s ein Frame, max 30, 800 px, 5 Spalten
KI-Bildbeschreibungen GPU
Vision-LLM beschreibt jedes Bild als strukturiertes JSON
Filmstrip-Beschreibungen GPU
Frame-für-Frame und Gesamtbild, mit Reverse Geocoding
Embeddings GPU
Text (BGE-M3, 1024-dim) + Bild (SigLIP2, 768-dim) für semantische Suche
Gesichtserkennung GPU
Detection → ArcFace Embedding → DBSCAN Clustering (nur auf Originalen!)
Import in PostgreSQL Optional
SQLite → Postgres mit PostGIS für räumliche Suche
Pack & Deploy auf iPad Optional
267.000 Thumbnails → 1 SQLite-DB → 103× schnellerer Transfer
Das Herzstück: Was die Metadatenerfassung wirklich tut
Stufe 1 klingt unspektakulär — „Dateien scannen und EXIF lesen". Aber sie ist der Grund, warum alles andere funktioniert. Ohne saubere Metadaten gibt es keine GPS-Karte, keine Zeitachse, keine Kamerafilter, keine Event-Erkennung. Jede spätere Funktion in ArchivBlick baut auf dem auf, was in diesen ersten 12 Stunden Indexierung passiert.
Hier ist, was das Skript reindex_all.py aus jeder einzelnen Datei herausholt — und warum:
Aus jedem Bild: EXIF-Daten
Aus jedem Video: ffprobe-Metadaten
Warum jedes Feld zählt — der Datenfluss in ArchivBlick
Jedes Metadatenfeld ermöglicht eine konkrete Funktion in der App. Ohne die Felder fehlt die Funktion:
| Metadatenfeld | Ermöglicht in ArchivBlick |
|---|---|
datum + jahr | Zeitachse, Jahresfilter, Event-Erkennung (Zeitlücke > 4h = neues Event → 834 erkannte Events) |
gps_lat + gps_lon | GPS-Weltkarte (Leaflet/MapKit), Umkreissuche, Event-Erkennung (GPS-Distanz > 50 km = neues Event) |
kamera + kamera_make | Kamera-Filter („nur GoPro"), Statistik-View (45 erkannte Kameramodelle), Filmstrip-Filter |
aufloesung | Qualitäts-Badge (4K/1080p/720p), Entscheidung ob Gesichtserkennung sinnvoll ist |
dauer_sek | Video-Länge im Viewer, Filmstrip-Frame-Berechnung (min(dauer/30 + 1, 30)) |
groesse_bytes | Speicherplatz-Statistik, Duplikaterkennung (gleiche Größe + gleicher Hash = Duplikat) |
extension + mimetype | Typ-Filter (Bild/Video/Audio/RAW), Icon-Auswahl, Thumbnail-Strategie (Bild: Pillow, Video: ffmpeg) |
pfad + archiv | Ordner-Navigation (Sidebar-Tree), Archiv-Zuordnung, Duplikat-Check (archiv+pfad = unique) |
quickxor_hash | SharePoint-Abgleich (99,91% Match-Rate), Datenintegritäts-Prüfung über Systeme hinweg |
llava_beschreibung | Volltextsuche („Sonnenuntergang am Strand"), Basis für Text-Embeddings |
Die Datenbank: Was am Ende drinsteht
Nach dem Scan liegt alles in einer einzigen SQLite-Datei: multimedia_index.db. Die Tabelle dateien hat 20 Spalten und 151.636 Zeilen. Jede Zeile ist eine Mediendatei. Jede Spalte ist ein Metadatenfeld, das eine Funktion in der App ermöglicht.
Thumbnails: Vier Größen, ein System
Nicht jede Ansicht braucht dasselbe Bild. Die Grid-Ansicht mit 200 Bildern pro Seite braucht winzige Vorschauen. Die Detail-Ansicht braucht 800 Pixel. Und ein Vision-LLM braucht mindestens 800 Pixel, um etwas Sinnvolles zu erkennen. Deshalb gibt es vier Tiers:
| Tier | Pixel | Zweck | Quelle |
|---|---|---|---|
xs | 80 px | Kompakte Listen | Abgeleitet von sm |
sm | 96 px | iPad-Grid (Leuchtpult) | Direkt aus Original |
md | 176 / 360 px | Web-Viewer, mittlere Ansicht | Direkt oder von lg |
lg | 800 px | Detail-Ansicht, KI-Input | Direkt aus Original |
Alle Thumbnails werden als JPEG gespeichert (Qualität 80%, LANCZOS-Resampling) und über ein Sharding-System in Ordner aufgeteilt: datei_id // 1000 ergibt den Ordnernamen. So enthält jeder Ordner maximal ~1.000 Dateien.
Video-Filmstrips: 30 Frames erzählen die Geschichte
Ein einzelnes Thumbnail sagt wenig über ein 15-minütiges Video. Ein Filmstrip — 30 Frames in einem Sprite-Grid — erzählt die ganze Geschichte auf einen Blick. Im Web-Viewer kann man per Hover über den Filmstrip scrubben und sieht sofort, was in welcher Minute passiert.
Für jedes Video extrahiert filmstrip_gen_nas.py mit 6 parallelen ffmpeg-Prozessen:
- Alle 30 Sekunden ein Frame, maximal 30 Frames
- Jeder Frame 800 px breit (Höhe proportional)
- Zusammenbau als 5-Spalten Sprite-Grid (hstack → vstack)
- Dazu ein JSON mit Metadaten: Hash, Pfad, Dauer, GPS, Grid-Layout
Insta360-Sonderfall: 360°-Kameras speichern zwei Fisheye-Linsen in einer Datei. Für Filmstrips gibt es die Variante Dual-Lens (Front oben, Back unten, je 400 px) — sie zeigt beide Perspektiven gleichzeitig, ohne aufwendiges Stitching.
KI-Beschreibungen: Drei Wege zum Ziel
Metadaten beantworten „Wo?" und „Womit?" — aber nicht „Was?". Dafür braucht es ein Vision-LLM, das jedes Bild in Sprache übersetzt. Danach findet die Suche nach „Sonnenuntergang am Strand" die richtigen 47 Bilder aus 151.000.
Eigener Mac
Ollama + LLaVA / Qwen
- + Kostenlos
- + Daten bleiben lokal
- − ~5 Sek/Bild
- − 6 Tage für 131k Bilder
GPU-Server
vLLM + Qwen 32B AWQ
- + Strukturiertes JSON
- + ~2,5 Sek/Bild
- − ~80 €/Woche
- − Setup-Aufwand
Cloud-API
Claude Batch / Gemini Flash
- + Kein Server nötig
- + Höchste Qualität
- − Daten gehen in die Cloud
- − ~5–15 €/100k Bilder
Die aktuelle Pipeline erzeugt strukturiertes JSON mit 11 Feldern — von der Kurzbeschreibung über erkannte Objekte und Personen bis zu Stimmung, Farben und erkanntem Text im Bild.
Gesichtserkennung: Auflösung schlägt Algorithmus
Die überraschendste Erkenntnis des ganzen Projekts:
Die Pipeline ist dreistufig: Detection (Gesichter finden via Vision-LLM), Embedding (512-dimensionaler Fingerabdruck via InsightFace/ArcFace), Clustering (automatische Gruppierung via DBSCAN). Die Benennung passiert über einen iCloud-Trick: Apple Photos hat 28 Personen bereits benannt — per Positionsvergleich werden die Cluster automatisch zugeordnet.
Am Ende: 4,6 GB statt 1,6 TB
Alle Daten werden in drei SQLite-Datenbanken gepackt — keine losen Dateien. 267.000 einzelne JPEGs per Finder: 60 Minuten. Eine SQLite-DB: 35 Sekunden. Faktor 103.
Drei Ausbaustufen — was du wirklich brauchst
Minimal
Durchsuchbar nach Datum, Kamera, GPS, Ordner. Kleine Thumbnails. ~12 Stunden, kostenlos.
Komfortabel
Plus 800-px-Vorschauen, Filmstrips, abgestufte Tiers. iPad-ready. +1–2 Tage, kostenlos.
Vollausbau
KI-Beschreibungen, semantische Suche, Gesichtserkennung. +1–3 Wochen, 0–240 €.
Lessons Learned
- Auflösung schlägt Algorithmus — Der Unterschied zwischen dem besten und zweitbesten Gesichtserkennungs-Modell: 0,2%. Zwischen Thumbnail und Original: 89 Prozentpunkte.
- GPU auf dem NAS bringt nichts — ffmpeg-Thumbnail-Extraktion ist I/O-gebunden, nicht rechengebunden. Spare dir die VAAPI-Konfiguration.
- Lokale KI ist praxistauglich — 25.000 Bildbeschreibungen pro Tag auf einem Mac mini. Eine Woche für das ganze Archiv, ohne Cloud-Kosten.
- SQLite-Packing schlägt Dateisysteme — 267.000 Dateien: 60 Minuten. Eine SQLite-DB: 35 Sekunden. Faktor 103.
- Metadaten sind nicht Beiwerk — sie sind die App — Ohne GPS keine Karte, ohne Datum keine Timeline, ohne Kameramodell kein Filter. Die 12 Stunden Indexierung erzeugen die Grundlage für alles.
Die beste Archiv-Software ist die, die man tatsächlich benutzt. Meine Fotos lagen 15 Jahre verteilt auf drei NAS-Volumes. Jetzt sind sie in einer App, die in 35 Sekunden auf dem iPad landet.