Aggiunge modulo Replay, Garage dev e YouTube a livello società.
Pipeline registrazione/upload con storage S3, archivio web e app, proxy replay per il browser, OAuth YouTube sulla pagina club (Premium Full) e footer legale. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -16,7 +16,7 @@ Percorso per il **responsabile trasmissione** invitato via email: accede in app
|
||||
| Premium Full, canale collegato | Canale **della società** |
|
||||
| Premium Full, canale non collegato | **Match Live TV** (default, come Light) |
|
||||
|
||||
Il collegamento del canale società è **opzionale** su Full: si fa dal sito (dettaglio squadra) o in futuro da app; finché non c’è OAuth, l’app trasmette sul canale piattaforma.
|
||||
Il collegamento del canale società è **opzionale** su Full: si fa dal sito (pagina società → sezione YouTube Live) o in futuro da app; finché non c’è OAuth, l’app trasmette sul canale piattaforma.
|
||||
|
||||
## 1. Invito
|
||||
|
||||
@@ -31,7 +31,7 @@ API: `GET /api/v1/invitations/:token`, `POST /api/v1/invitations/:token/accept`
|
||||
|
||||
Solo se la società vuole il **proprio** canale invece di Match Live TV:
|
||||
|
||||
1. Sul sito: dettaglio squadra → **Collega il tuo canale YouTube**
|
||||
1. Sul sito: pagina società (`/clubs/:id`) → **Collega il canale YouTube della società**
|
||||
2. Oppure (se abilitato) OAuth da app al tocco YouTube quando non c’è ancora canale piattaforma
|
||||
|
||||
## 3. Scegli la partita
|
||||
|
||||
105
docs/REPLAY_MODULE.md
Normal file
105
docs/REPLAY_MODULE.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# 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.
|
||||
|
||||
### 2. Retention e purge
|
||||
`Recordings::PurgeExpiredJob` / `rails recordings:purge_expired`
|
||||
|
||||
### 3. Archivio Replay
|
||||
- Web: `/clubs/:id/replays` (gestione società)
|
||||
- Pubblico: `/replay` con filtro società/squadra
|
||||
- App: schermata Replay
|
||||
|
||||
### 4. Riproduzione
|
||||
- Player MP4: `/replay/:id` + stream `/replay/:id/stream`
|
||||
- Contatore visualizzazioni su ogni play (`view_count`)
|
||||
|
||||
### 5. Visibilità
|
||||
Pubblico / Privato (unlisted), modificabile dall’admin società.
|
||||
|
||||
### 6. Eliminazione anticipata
|
||||
`Recordings::Delete` — DB + video + thumbnail su storage.
|
||||
|
||||
### 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
|
||||
|
||||
```env
|
||||
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
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
**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 consigliati (produzione)
|
||||
|
||||
```cron
|
||||
0 3 * * * cd /opt/matchlivetv/infra && docker compose exec -T rails bundle exec rails recordings:purge_expired
|
||||
0 8 * * * cd /opt/matchlivetv/infra && docker compose exec -T rails bundle exec rails recordings:expiry_warnings
|
||||
```
|
||||
|
||||
## API mobile
|
||||
|
||||
- `GET /teams/:id/recordings` — lista con thumbnail, views, download_enabled
|
||||
- `GET /recordings/:id/download` — URL download temporaneo
|
||||
- `POST /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:
|
||||
```json
|
||||
{ "recording": { "metadata": { "ai": { "transcript_status": "queued" } } } } }
|
||||
```
|
||||
@@ -76,7 +76,7 @@ YOUTUBE_MOCK_STREAM_KEY=mock-stream-key
|
||||
|
||||
## 5. Verifica
|
||||
|
||||
- Premium Full: dopo collegamento, `GET /api/v1/teams/:id` → `youtube_connected: true`, `youtube_selectable: true`
|
||||
- Premium Full: collegamento OAuth dalla pagina società (`/clubs/:id`); credenziali uniche per club. Dopo collegamento, `GET /api/v1/teams/:id` → `youtube_connected: true`, `youtube_selectable: true`
|
||||
- Premium Light: con `YOUTUBE_PLATFORM_REFRESH_TOKEN` → `youtube_selectable: true` anche senza OAuth squadra
|
||||
- Avvia diretta YouTube da app → in admin session compare broadcast ID → link YouTube Studio
|
||||
|
||||
|
||||
Reference in New Issue
Block a user