Aggiunge docs/ARCHITECTURE.md con topologia rete, edge nginx, flussi HLS/replay e monitoraggio ops; allinea i documenti esistenti. Co-authored-by: Cursor <cursoragent@cursor.com>
5.9 KiB
Modulo Replay — Match Live TV
Panoramica
Al termine di ogni diretta Premium, MediaMTX registra i segmenti. Sidekiq unisce i segmenti, genera thumbnail, carica su Garage (S3-compatible) e attiva i servizi di notifica, statistiche e (opzionale) republicazione YouTube.
Piani e retention
| Piano | Registrazione | Retention | Download MP4 | YouTube VOD |
|---|---|---|---|---|
| Free | No | — | No | No |
| Premium Light | Sì | 30 giorni | Sì | No |
| Premium Full | Sì | 90 giorni | Sì | Sì (auto se diretta YouTube) |
Funzionalità implementate
1. Registrazione automatica
Pipeline: Sessions::Stop → FinalizeSession → UploadJob → storage.
MediaMTX registra solo mentre il telefono pubblica (RTMP connesso). In pausa o con sola slate alwaysAvailable la registrazione è disattivata, così il replay non contiene minuti di schermo «Trasmissione in pausa».
2. Retention e purge
Recordings::PurgeExpiredJob / rails recordings:purge_expired
3. Archivio Replay
- Web:
/clubs/:id/replays(gestione società) - Pubblico:
/replaycon filtro società/squadra - App mobile: nessuna UI replay (gestione solo da sito web)
4. Riproduzione
- Player MP4:
/replay/:id+ stream/replay/:id/stream - Delivery: Rails verifica accesso → redirect 302 a
/media/...(edge → Garage). Puma non proxya il file. - Contatore visualizzazioni su ogni play (
view_count)
5. Visibilità
- Pubblico (
public): compare in/replay, indicizzabile, YouTubepublic - Privato (
unlisted): non in catalogo pubblico, accessibile solo con link diretto,noindex, YouTubeunlisted
Modificabile dall’archivio società (/clubs/:id/replays). Il cambio privacy sincronizza automaticamente il VOD YouTube se presente (Recordings::SyncYoutubePrivacyJob).
6. Eliminazione anticipata
Recordings::Delete — elimina video YouTube collegato, oggetti S3/Garage (MP4 + thumbnail) e soft-delete DB.
Stesso comportamento alla scadenza retention (PurgeExpiredJob alle 03:00).
7. Dashboard KPI
Replay disponibili, in scadenza (7 gg), spazio occupato, visualizzazioni totali.
8. Miglioramenti Premium
| Feature | Descrizione |
|---|---|
| Email replay pronto | A owner e membri società quando status → ready |
| Email scadenza | 7 giorni prima di expires_at (rails recordings:expiry_warnings) |
| Thumbnail | Frame ffmpeg, URL /replay/:id/thumbnail |
| Download MP4 | Premium, link presigned 15 min o /replay/:id/download |
| Statistiche views | view_count su ogni replay |
| metadata JSONB | source_platform, auto_publish_youtube, ai: {} per estensioni |
| YouTube VOD | Premium Full: upload automatico se diretta era su YouTube; manuale da archivio |
Storage
REPLAY_STORAGE_ENDPOINT=http://garage:3900
REPLAY_STORAGE_BUCKET=matchlivetv-replays
REPLAY_STORAGE_ACCESS_KEY_ID=...
REPLAY_STORAGE_SECRET_ACCESS_KEY=...
REPLAY_DOWNLOAD_URL_TTL_SECONDS=900
Senza endpoint S3: storage locale /recordings/replays/.
Dev locale con Garage
cd infra
docker compose up -d # include garage
bash scripts/setup_garage_replays.sh # layout, bucket, chiave → .env
docker compose up -d rails sidekiq
# Verifica pipeline (segmento finto → Garage)
docker compose exec -T rails bundle exec rails replay:e2e_garage
Produzione (/opt/matchlivetv)
cd infra
bash scripts/setup_garage_production.sh # garage.prod.toml, bucket, chiavi → .env
# Rails/Sidekiq usano REPLAY_STORAGE_ENDPOINT=http://garage:3900 (rete Docker)
Credenziali in .env: non compilarle a mano in .env.example. Lo script scrive in infra/.env:
REPLAY_STORAGE_ACCESS_KEY_ID= Key ID Garage (es.GK...)REPLAY_STORAGE_SECRET_ACCESS_KEY= Secret mostrato una sola volta alla creazione chiave
Cron (produzione)
Installazione sul server:
cd /opt/matchlivetv/infra
bash scripts/install_production_cron.sh
Job attivi (utente eminux):
| Orario | Task |
|---|---|
| 03:00 | recordings:purge_expired — elimina replay scaduti (DB + Garage) |
| 08:00 | recordings:expiry_warnings — email avviso scadenza (7 gg) |
Log: ${MATCHLIVETV_VIDEOS_ROOT}/log/cron-replay.log (es. /media/videos/matchlivetv/log/cron-replay.log)
Capacità Garage
All’installazione, setup_garage_production.sh assegna ~(disco libero − 20 GB) al nodo.
Per ridimensionare dopo:
bash scripts/garage_set_capacity.sh 85G # oppure senza argomento: calcolo automatico
Piattaforme live e replay
| Origine diretta | Copia Garage/S3 | Player sito /replay/:id |
YouTube VOD |
|---|---|---|---|
matchlivetv |
Sì (Premium) | MP4 via redirect /media/ → Garage |
Manuale (Premium Full) |
youtube |
Sì (Premium) | MP4 via redirect /media/ → Garage |
Auto se Premium Full + diretta YouTube |
Se il file S3 non è disponibile ma esiste youtube_video_id, la pagina replay mostra embed YouTube.
Retention e abbonamento
expires_atviene impostato alla fine diretta: 30 giorni (Premium Light), 90 giorni (Premium Full)expires_atnon cambia al cambio piano successivo- Nuove registrazioni richiedono abbonamento attivo (
can_create_recordings?) - Archivio esistente resta accessibile fino a
expires_atanche se l’abbonamento scade (can_access_recordings?)
API mobile
GET /teams/:id/recordings— lista con thumbnail, views, download_enabledGET /recordings/:id/download— URL download temporaneoPOST /recordings/:id/publish_youtube— coda republicazione YouTube
Estensioni future (metadata.ai)
Campo metadata["ai"] predisposto per:
- highlight automatici
- trascrizioni
- articoli generati
- clip / Shorts
Esempio aggiornamento via API:
{ "recording": { "metadata": { "ai": { "transcript_status": "queued" } } } } }