mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 18:34:13 +00:00
docs: add YouTube thumbnail download design document
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2d4f43e780
commit
5aef72f72b
1 changed files with 96 additions and 0 deletions
96
docs/plans/2026-02-14-youtube-thumbnail-download-design.md
Normal file
96
docs/plans/2026-02-14-youtube-thumbnail-download-design.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# YouTube Thumbnail Download — Design
|
||||
|
||||
**Datum:** 14.02.2026
|
||||
**Status:** Approved
|
||||
|
||||
## Ziel
|
||||
|
||||
Automatischer Download von YouTube-Video-Thumbnails und Kanalbildern als Payload Media, damit diese offline verfügbar sind und von Payload's Sharp-Pipeline optimiert werden.
|
||||
|
||||
## Scope
|
||||
|
||||
- **Video-Thumbnails:** Auto-Download bei Sync + Bulk-Import für bestehende Einträge
|
||||
- **Kanalbilder:** Profilbilder und Banner beim Channel-Sync
|
||||
- **Nicht im Scope:** Kommentar-Autor-Avatare (bleiben als externe URLs)
|
||||
|
||||
## Qualität
|
||||
|
||||
- YouTube-Thumbnails: `hqdefault` (480x360)
|
||||
- Payload generiert daraus automatisch alle responsive Sizes (thumbnail, small, medium, etc.)
|
||||
|
||||
## Architektur: Inline beim Sync
|
||||
|
||||
Download direkt im Sync-Flow integriert, kein separater Queue-Job.
|
||||
|
||||
### 1. Kern-Utility: `downloadAndUploadImage()`
|
||||
|
||||
**Datei:** `src/lib/utils/media-download.ts`
|
||||
|
||||
```typescript
|
||||
interface DownloadOptions {
|
||||
url: string
|
||||
filename: string
|
||||
alt?: string
|
||||
tenantId?: number
|
||||
}
|
||||
|
||||
async function downloadAndUploadImage(
|
||||
payload: Payload,
|
||||
options: DownloadOptions
|
||||
): Promise<number | null>
|
||||
```
|
||||
|
||||
- Lädt Bild von URL herunter
|
||||
- Erstellt Payload Media-Dokument (mit Tenant-Zuordnung)
|
||||
- Sharp-Pipeline generiert alle 11 responsive Sizes automatisch
|
||||
- Duplikat-Erkennung: Prüft ob Media mit gleichem Dateinamen + Tenant existiert
|
||||
- Fehler → `null` (kein harter Fehler, Sync läuft weiter)
|
||||
|
||||
### 2. Integration in YouTube-Sync
|
||||
|
||||
**YouTubeContent** (beim Erstellen/Updaten):
|
||||
- Wenn `thumbnail`-Feld leer → Download von `https://img.youtube.com/vi/{videoId}/hqdefault.jpg`
|
||||
- Media-ID in `thumbnail`-Feld speichern
|
||||
- Manuell hochgeladene Thumbnails werden nie überschrieben
|
||||
|
||||
**YouTubeChannels** (beim Channel-Sync):
|
||||
- Profilbild und Banner aus YouTube API herunterladen (falls Felder leer)
|
||||
- In entsprechende Media-Felder speichern
|
||||
|
||||
### 3. Bulk-Import Endpoint
|
||||
|
||||
**Route:** `POST /api/youtube/thumbnails/bulk`
|
||||
**Auth:** Super-Admin erforderlich
|
||||
|
||||
- Findet alle `YouTubeContent`-Einträge ohne Thumbnail
|
||||
- Downloadet sequentiell mit 500ms Delay (Rate-Limit-Schutz)
|
||||
- Response: `{ processed, downloaded, skipped, errors }`
|
||||
- Optional: `?dryRun=true`
|
||||
|
||||
### 4. Fehlerbehandlung
|
||||
|
||||
| Aspekt | Verhalten |
|
||||
|--------|-----------|
|
||||
| Rate-Limiting | 500ms Delay zwischen Downloads (Bulk) |
|
||||
| Timeout | 10s pro Download |
|
||||
| Retry | Kein Retry (YouTube CDN zuverlässig) |
|
||||
| 404/Fehler | `null` zurückgeben, Sync fortsetzen |
|
||||
| Duplikate | Existierendes Media zurückgeben |
|
||||
| Manuelle Uploads | Nie überschreiben |
|
||||
| Logging | Console.log (nicht AuditLogs) |
|
||||
|
||||
## Betroffene Dateien
|
||||
|
||||
### Neu
|
||||
- `src/lib/utils/media-download.ts` — Kern-Utility
|
||||
- `src/app/(payload)/api/youtube/thumbnails/bulk/route.ts` — Bulk-Endpoint
|
||||
|
||||
### Modifiziert
|
||||
- YouTube-Sync-Services — Thumbnail-Download nach Content-Erstellung
|
||||
- YouTubeChannels-Sync — Kanalbild-Download nach Channel-Update
|
||||
|
||||
## Nicht-Ziele
|
||||
|
||||
- Keine Kommentar-Avatare herunterladen
|
||||
- Kein Queue-basierter Download
|
||||
- Keine automatische Aktualisierung bestehender Thumbnails
|
||||
Loading…
Reference in a new issue