Files
MatchLiveTv/docs/REPLAY_MODULE.md
T
eminuxandCursor 05ef56c56d Aggiunge replay YouTube temporaneo, pull registrazioni dai CPX e snapshot ingest in admin.
Così overflow Hetzner e VOD YouTube restano in archivio dopo lo spegnimento del nodo, e la colonna ingest non si svuota.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 13:01:41 +02:00

5.4 KiB
Raw Blame History

Modulo Replay — Match Live TV

Panoramica

Al termine di ogni diretta Premium, MediaMTX registra i segmenti. Sidekiq unisce i segmenti, genera thumbnail e carica su Garage (S3-compatible).

  • Live MatchLiveTV (HLS): copia permanente (policy retained) con retention del piano.
  • Live YouTube: copia temporanea di sicurezza (policy temporary, default 48h), poi player YouTube in archivio. Niente re-upload automatico del MP4 su YouTube.

Piani e retention

Piano Registrazione Retention archivio MLTV Download MP4 YouTube
Free No No No
Premium Light 30 giorni (expires_at) Sì (solo se file MLTV) No
Premium Full 90 giorni (expires_at) se HLS; nessuna scadenza archivio se YouTube (expires_at nil) Sì solo con file Garage Live → VOD nativo; verify collega youtube_video_id

Storage policy (Recordings::StoragePolicy)

if youtube_destination?     → temporary
elsif can_create_recordings? → retained
else                         → none
Policy Prefisso storage expires_at (archivio) temp_expires_at
temporary temporary_replays/... nil now + YOUTUBE_TEMP_REPLAY_RETENTION_HOURS (2472, default 48)
retained teams/... piano recording_days nil
none

Archivio logico vs storage fisico

Dopo cleanup della copia temp, la partita resta in archivio MatchLiveTV. Cambia solo la sorgente:

replay_source Player File Garage permanente
youtube embed / link YouTube no (MP4 temp già eliminato)
matchlivetv player MP4 proprietario
none non playable

available_in_archive? = ready e (YouTube URL/youtube_video_id oppure storage_key).

Clear/purge temporary: solo oggetti S3 video; mai soft-delete; mai azzerare youtube_video_id / metadata / score. Thumbnail preferibilmente conservata.

Flusso YouTube

Stop → StoragePolicy(temporary) → Finalize (expires_at nil, temp_expires_at)
  → Upload temporary_replays/... → ready
  → VerifyYoutubeReplayJob (backoff)
      → ok: youtube_video_id + youtube_verified_at → ClearTemporaryMediaJob
      → fail fino a max attempts: aspetta safety net
  → PurgeTemporaryMediaJob (cron): a temp_expires_at elimina file + log se non verificato

Funzionalità implementate

1. Registrazione automatica

Pipeline: Sessions::StopFinalizeSessionUploadJob → storage → PostProcessJob.

MediaMTX registra solo mentre il telefono pubblica (RTMP connesso).

2. Retention e purge

  • Retained: Recordings::PurgeExpiredJob / rails recordings:purge_expired (soft-delete + S3 + YouTube se collegato)
  • Temporary: rails recordings:purge_temporary (solo storage)

3. Archivio Replay

  • Web: /clubs/:id/replays (gestione società)
  • Pubblico: /replay con filtro società/squadra
  • Stessa UX listing per YouTube e MLTV (differisce solo il player)

4. Riproduzione

  • YouTube: embed su /replay/:id
  • MLTV: MP4 via /replay/:id/stream → redirect /media/... → Garage
  • Contatore visualizzazioni su ogni play (view_count)

5. Visibilità

Pubblico / privato (unlisted) come prima. Sync privacy YouTube se youtube_video_id presente.

6. Eliminazione anticipata

Recordings::Delete manuale — resta distruttiva sul record (distinta dal cleanup temporary automatico).

78. KPI, email, thumbnail, download, views — invariati dove applicabili.

Config ENV

YOUTUBE_TEMP_REPLAY_RETENTION_HOURS=48
YOUTUBE_REPLAY_VERIFY_MAX_ATTEMPTS=12
YOUTUBE_REPLAY_VERIFY_BASE_INTERVAL_SECS=300
YOUTUBE_REPLAY_VERIFY_GRACE_SECS=120

REPLAY_STORAGE_ENDPOINT=http://garage:3900
REPLAY_STORAGE_BUCKET=matchlivetv-replays
...

Valori letti da MatchLiveTv (config/initializers/match_live_tv.rb).

Storage Garage

Senza endpoint S3: storage locale /recordings/replays/.

Dev / produzione Garage

Vedi script infra/scripts/setup_garage_*.sh come in precedenza.

Cron (produzione)

cd /opt/matchlivetv/infra
bash scripts/install_production_cron.sh
Orario Task
03:00 recordings:purge_expired — replay retained scaduti
03:30 recordings:purge_temporary — copie temp YouTube scadute
08:00 recordings:expiry_warnings — email avviso scadenza (7 gg)

Audit duplicati storici

rails recordings:audit_youtube_duplicates   # dry-run di default

Nessun cleanup automatico dei vecchi MP4 YouTube già in Garage.

API

  • GET /teams/:id/recordings — include replay_source, youtube_watch_url, playback_url (null se youtube-only), download_enabled solo con storage_key
  • GET /recordings/:id/download — richiede file Garage
  • POST /recordings/:id/publish_youtube — solo MatchLiveTV-only con file (non per live già YouTube)

Colonne DB (migration)

  • storage_policy (default retained)
  • temp_expires_at, youtube_verified_at, local_media_purged_at

Rischi

  • VOD YouTube in ritardo oltre retention temp → safety net elimina file; archivio resta se id collegato; altrimenti anomaly log.
  • Thumb: se manca storage, poster YouTube da metadata / default.
  • Record storici restano storage_policy=retained.