Files
xtremflow/docs/archive/RECORDING_MIGRATION_GUIDE.md
T
MichaelandClaude Fable 5 60d3f42901 feat: security hardening, streaming overhaul, design polish, tests
Security:
- Replace unsalted SHA-256 password hashing with bcrypt (lazy rehash on login)
- Add authenticated /api/xtream-api gateway: Xtream credentials are injected
  server-side and never sent to the frontend; /api/playlists no longer
  returns passwords
- Redact credentials from all logs (login body, proxy/FFmpeg/scheduler URLs)
- Add auth to recordings, EPG, season-passes and streaming routes
  (HttpOnly session cookie for hls.js; loopback bypass for local FFmpeg)
- Lock player postMessage to same-origin in both directions
- Vendor and pin hls.js 1.6.7 / mpegts.js 1.7.3 (drop CDN @latest)
- Fix rate limiter (client IP was never resolved), add login rate limit,
  restrict CORS, add CSP Report-Only, block private-IP SSRF targets,
  fix path traversal in recording log retrieval, chmod 777 -> 770
- Remove dead HiveService (seeded admin/admin into IndexedDB with SHA-256)
- Fix authMiddleware not populating 'user' context (getPlaylist ignored the
  logged-in user; admin purge always returned 403)

Streaming:
- New FfmpegSessionManager: process registry, idle reaper (4 min live /
  15 min VOD), orphan cleanup at startup, clean SIGTERM shutdown,
  fast-fail with stderr instead of 30 s timeout
- Quality selection (source/high/medium/low) for live and VOD; source mode
  streams with -c:v copy (zero transcoding); selector wired into the player
- Concurrent recordings (MAX_CONCURRENT_RECORDINGS, default 2); conflicts
  retry on the next tick instead of silently failing
- Lower live latency (HLS window 20 -> 10 segments, liveSync 10 -> 3)
- Fix recording log lookup (.mp4 vs .mkv mismatch)

Design:
- Replace hardcoded colors with AppColors tokens (12 files)
- web/theme.css syncs HTML players with the Flutter palette
- DPAD/keyboard navigation (arrow-key focus, player shortcuts)
- Tooltips on player icon buttons, Semantics on content cards
- Remove 7 dead widgets broken since the Stitch merge

Quality:
- bin/test/: 21 unit tests (bcrypt, redaction, traversal, SSRF, recording
  conflicts) plus a quality-selector widget test
- GitHub Actions CI (analyze + test + build web)
- Archive stale status docs into docs/archive/

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:07:18 +02:00

6.8 KiB

🚀 Guide d'Intégration - Nouveau Système d'Enregistrement

⚠️ BACKUP D'ABORD!

# Sauvegarder avant de modifier
git add .
git commit -m "backup: before recording system upgrade"

🔄 Étapes de Migration

ÉTAPE 1️⃣: Supprimer les anciens fichiers

# Ancien système (à supprimer):
rm bin/services/recording_scheduler.dart
rm bin/api/recordings_api.dart
rm bin/api/season_passes_api.dart
rm lib/features/iptv/widgets/recording_modal.dart
rm lib/features/iptv/widgets/recordings_tab.dart

Les nouveaux fichiers:

  • bin/services/simple_recorder.dart ✅
  • bin/api/simple_recording_api.dart ✅
  • lib/features/iptv/widgets/simple_recording_widget.dart ✅

ÉTAPE 2️⃣: Mettre à jour bin/server.dart

AVANT:

// ❌ OLD
import 'services/recording_scheduler.dart';
import 'api/recordings_api.dart';

// Dans main()
final recordingScheduler = RecordingScheduler(db);
recordingScheduler.start();

// Injecter la config playlist
Future<void> _injectPlaylistToScheduler() async {
  // ... 30+ lignes de code compliqué
}
Future.delayed(const Duration(seconds: 5), _injectPlaylistToScheduler);

// Routes
router.post('/api/recordings', recordingsApi.handlePost);
router.get('/api/recordings', recordingsApi.handleGetAll);
router.delete('/api/recordings/<id>', (req, id) => recordingsApi.handleDelete(req, id));
// ... plus d'endpoints compliqués

APRÈS:

// ✅ NEW
import 'services/simple_recorder.dart';
import 'api/simple_recording_api.dart';

// Dans main()
final recorder = SimpleRecorder(db);
await recorder.init();

// Vérifier les enregistrements programmés toutes les minutes
Timer.periodic(Duration(minutes: 1), (_) => recorder.checkScheduled());

// Cleanup automatique toutes les 6 heures (garde 20 derniers)
Timer.periodic(Duration(hours: 6), (_) => recorder.cleanupOld(keepCount: 20));

// Routes
final recordingApi = SimpleRecordingApi(db, recorder);
router.mount('/api/record/', recordingApi.router);

ÉTAPE 3️⃣: Mettre à jour la base de données (optionnel mais recommandé)

Les tables ne changent pas - les anciens enregistrements restent valides. Mais vous pouvez nettoyer:

-- Nettoyer les season passes (plus utilisés)
DELETE FROM season_passes;

-- Supprimer les anciens enregistrements failed/orphaned
DELETE FROM tv_recordings WHERE status = 'failed' AND updated_at < datetime('now', '-1 week');

ÉTAPE 4️⃣: Remplacer l'UI quelque part

AVANT (compliqué):

// ❌ Ancien widget avec 3 onglets, modal complexe, state compliqué
RecordingsTab(playlist: playlist)
// + 250 lignes de code pour recording_modal.dart

APRÈS (simple):

// ✅ Nouveau widget - 3 lignes pour afficher
ElevatedButton(
  onPressed: () => SimpleRecordingWidget.show(context, channel, streamUrl),
  child: const Text('Record'),
)

Ou dans une liste de chaînes:

// Ajouter le bouton dans votre Channel card
Card(
  child: ListTile(
    title: Text(channel.name),
    trailing: IconButton(
      icon: const Icon(Icons.fiber_manual_record),
      onPressed: () {
        SimpleRecordingWidget.show(
          context,
          channel,
          '/api/live/${channel.streamId}.ts',
        );
      },
    ),
  ),
)

ÉTAPE 5️⃣: Compiler et tester

# Flutter
flutter pub get
flutter run -d chrome

# Docker
docker-compose build
docker-compose up

✅ Vérification Post-Migration

1. API Testing

# 1. Record NOW
curl -X POST http://localhost:8089/api/record/now \
  -H 'Content-Type: application/json' \
  -d '{
    "channel_id": "1001",
    "stream_url": "http://localhost:8089/api/live/1001.ts",
    "title": "Test Channel",
    "duration_minutes": 2
  }'

✅ Expected: {"status": "recording", "id": "xxx", "message": "Recording started!"}

# 2. See active
curl http://localhost:8089/api/record/active

✅ Expected: {"active": [...], "count": 1}

# 3. Stop it
curl -X POST http://localhost:8089/api/record/stop/1001

✅ Expected: {"status": "stopped", "message": "Recording stopped!"}

# 4. List all
curl http://localhost:8089/api/record/list

✅ Expected: {"total": 1, "recordings": [...]}

2. UI Testing

  • Click a channel
  • Click "Record"
  • Select "1 hour"
  • ✅ Should say "Recording started!"
  • Check files in /app/recordings/
  • File should exist: channelname_20260326T123456.mkv

3. Schedule Testing

  • Click channel
  • Click "Schedule for Later"
  • Set time 2 minutes in future
  • Set duration 1 minute
  • Click "SCHEDULE"
  • Wait 2+ minutes
  • Check if file appears in /app/recordings/
  • ✅ Auto-started!

🔍 Troubleshooting

Problem: "No recordings showing"

# Check if directory exists
ls -la /app/recordings/

# If not, create it
mkdir -p /app/recordings
chmod 777 /app/recordings

Problem: "FFmpeg not found"

# Check if FFmpeg installed
which ffmpeg

# If not, install it
apt-get install ffmpeg

# Or in Docker, it's already there

Problem: "API returns "Already recording""

# Channel is already being recorded
# Either wait for it to finish or use /api/record/stop/<channelId>
curl -X POST http://localhost:8089/api/record/stop/1001

Problem: "Recording starts but creates empty file"

# Stream URL is probably wrong
# Test the stream manually:
ffmpeg -i "http://localhost:8089/api/live/1001.ts" -t 10 test.mkv

# If that fails, the stream URL is bad

📊 Avant/Après Checklist

Feature Before After Notes
Record NOW ✅ Works ✅ Works Simpler code
Record Later ✅ Works ✅ Works Uses simple scheduling
Stop Recording ✅ Works ✅ Works One endpoint
File Storage ✅ Works ✅ Works Same directory
Status History ✅ Works ✅ Works Same DB
Season Passes ✅ Works ❌ Removed Not needed! (just use Schedule)
Logs ✅ Works ⚠️ Minimal Simpler error tracking
Cleanup ✅ Works ✅ Works Auto every 6h

🎯 Quick Summary

A faire:

  1. ✅ Delete old files (3 files)
  2. ✅ Replace server.dart (5 lines)
  3. ✅ Update UI (1-2 buttons)
  4. ✅ Test APIs (5 calls)
  5. ✅ Deploy

Temps total: 30 minutes ⚡

Résultat:

  • Système 10x plus simple
  • Même fonctionnalité
  • Code cleaner
  • Maintenance easier

🆘 Besoin de support?

Si ça ne marche pas:

  1. Check /app/logs for errors
  2. Run curl http://localhost:8089/api/record/list to verify API
  3. Make sure FFmpeg is installed: ffmpeg -version
  4. Check /app/recordings/ exists and writable

Questions?

  • API endpoints: See SIMPLE_RECORDING.md
  • Code structure: See simple_recorder.dart (260 lines, very documented)
  • UI usage: See simple_recording_widget.dart (shows all options)

✨ Migration complete! Your recording system is now 10x simpler! ✨