# d4rk_media Eigener Medien-Dienst für alle FiveM-Ressourcen: Dateien annehmen, ablegen, ausliefern, in einem Dashboard verwalten. **Ein Container**, SQLite, Dateien auf einer Platte. Läuft unter **https://fivemanage.d4rkst3r.de** — Dashboard und API an der Wurzel, Dateien unter `/f/`. ``` vehicles/adder.webp → https://fivemanage.d4rkst3r.de/f/vehicles/adder.webp ``` **Der Pfad ist der Schlüssel.** `vehicles/adder.webp` bleibt `vehicles/adder.webp`, damit die Vorlage in einem Skript schlicht `{model}.webp` lauten kann. Die Adressen stehen nirgends in der Datenbank — sie werden bei jeder Antwort aus `PUBLIC_URL` gebaut. Ein Umzug auf einen anderen Namen ist eine geänderte Variable, kein Datenbankeingriff. | | | |---|---| | **Anleitung für Skripte** | [Wiki](https://git.d4rkst3r.de/D4rkst3r/d4rk_media/wiki) — Quelle ist `docs/` | | **Stand und Reihenfolge** | `ROADMAP.md` | | **Arbeitsweise** | `CLAUDE.md` — prüfen statt raten | --- ## Starten ```bash cp .env.example .env # PUBLIC_URL und ADMIN_PASSWORD ausfüllen docker compose up -d --build ``` Das war es. Ein Container, ein Volume, kein zweiter Dienst. **In Portainer:** Stacks → Add stack → Repository, `Compose path: docker-compose.yml`. Die Werte kommen als Stack-Variablen. > **`Compose path` nimmt genau EINE Datei.** Ergänzungen werden stillschweigend > übergangen — alle Container gesund, alles 502. Das hat beim Vorgänger einen > Nachmittag gekostet. ### An der Oberfläche arbeiten ```bash npm --prefix server/ui install npm --prefix server/ui run dev ``` Läuft auf `localhost:5173` und leitet `/api` und `/f` an den Container weiter. Dass das Sitzungs-Cookie dabei ankommt, liegt an einer Ausnahme: es trägt `Secure`, und ein Browser nimmt so eines über `http` **nur auf localhost** an. --- ## Was der Dienst kann **Hochladen** — über die Skript-API mit Token (drei Rumpfformen: multipart, Base64, rohe Bytes) oder aus dem Dashboard per Ziehen und Ablegen. Bilder, Videos, Ton, PDF. Ein **ZIP wird ausgepackt** statt abgelegt, und die Ordner darin bleiben erhalten — 3670 Bilder einzeln ins Fenster zu ziehen ist keine Bedienung. **Ausliefern** — mit ETag, `304`, Bereichsanfragen und `nosniff`. Vorschaubilder werden beim Upload erzeugt (320 px WebP): aus 7,5 MB je Galerieseite werden 766 KB. **Sparen, ohne Adressen zu ändern** — neben jedem PNG und JPEG liegt eine WebP-Fassung, ausgeliefert unter *derselben* Adresse je nach `Accept` des Aufrufers. Nachgemessen über den ganzen Bestand: **199 MB → 33 MB**, das sind 83 %. Für Lua ändert sich nichts — es schickt kein `Accept: image/webp` und bekommt weiterhin das Original. **Zurückholen** — Gelöschtes liegt 30 Tage im Papierkorb, danach räumt der Dienst selbst auf. Die Datei ist dann nur nicht mehr öffentlich, nicht weg. **Zählen** — wie oft eine Datei geholt wurde und wann zuletzt. Beantwortet die Frage, die ein Aufbewahrungsbericht sonst nicht beantworten kann: *braucht das noch jemand?* **Verwalten** — Galerie mit Ordnerbaum, Suche, Filter nach Medienart, Sortierung, Mehrfachauswahl, Verschieben, Löschen. **Ansehen ohne neuen Tab** — Bild, Video, Ton, PDF und alles Lesbare: Markdown wird gesetzt, `.lua` und `.json` eingefärbt, CSV als Tabelle, alles andere mit Zeilennummern. Video und Ton mit gemerkter Lautstärke und „weiter zum nächsten Stück"; Leertaste hält an, die Pfeile springen fünf Sekunden, mit Umschalt wechseln sie die Datei. Markdown wird **ohne Bibliothek** dargestellt, und das ist kein Geiz: der übliche Weg endet bei `dangerouslySetInnerHTML`, und die Sicherheit hängt dann an einer Filterliste. Hier entsteht nie eine HTML-Zeichenkette — der Text wird zu React-Knoten, ein `