# 🌐 API REST - Documentation complĂšte **Date**: 2025-01-27 **Version**: 0.2.0 **Base URL**: `http://localhost:8082` --- ## Vue d'ensemble L'API REST du stream-server permet de: - Soumettre des fichiers audio pour transcodage - RĂ©cupĂ©rer l'Ă©tat des jobs - Servir les fichiers HLS gĂ©nĂ©rĂ©s --- ## Endpoints ### POST `/v1/stream/transcode` Soumet un fichier audio pour transcodage en HLS. **Request**: - **Method**: `POST` - **Content-Type**: `multipart/form-data` - **Body**: - `file` (required): Fichier audio (WAV, MP3, FLAC, etc.) - `codec` (optional): Codec cible (`aac`, `mp3`, `opus`, `flac`) - `bitrate` (optional): Bitrate en bps (ex: `192000`) - `quality_profile` (optional): Profil (`hi_res`, `high`, `medium`, `low`) - `priority` (optional): PrioritĂ© (`urgent`, `normal`, `background`) **Response** (200 OK): ```json { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "queued", "message": "Job submitted successfully" } ``` **Erreurs**: - `400 Bad Request`: Fichier manquant ou invalide - `500 Internal Server Error`: Erreur serveur **Exemple cURL**: ```bash curl -X POST http://localhost:8082/v1/stream/transcode \ -F "file=@audio.wav" \ -F "quality_profile=high" \ -F "priority=normal" ``` **Exemple JavaScript**: ```javascript const formData = new FormData(); formData.append('file', audioFile); formData.append('quality_profile', 'high'); const response = await fetch('http://localhost:8082/v1/stream/transcode', { method: 'POST', body: formData }); const { job_id, status } = await response.json(); ``` --- ### GET `/v1/stream/job/{id}` RĂ©cupĂšre l'Ă©tat d'un job de transcodage. **Request**: - **Method**: `GET` - **Path Parameter**: `id` (UUID du job) **Response** (200 OK): ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "track_id": "my_track", "status": "processing", "progress": 45.5, "created_at": "SystemTime { tv_sec: 1737979200, tv_nsec: 0 }", "started_at": "Some(SystemTime { tv_sec: 1737979205, tv_nsec: 0 })", "completed_at": null, "error": null } ``` **Statuts possibles**: - `"Pending"`: Job en attente dans la queue - `"Processing"`: Job en cours de traitement - `"Completed"`: Job terminĂ© avec succĂšs - `"Failed(String)"`: Job Ă©chouĂ© (le message d'erreur est dans `error`) - `"Cancelled"`: Job annulĂ© **Erreurs**: - `404 Not Found`: Job introuvable **Exemple cURL**: ```bash curl http://localhost:8082/v1/stream/job/550e8400-e29b-41d4-a716-446655440000 ``` **Exemple JavaScript**: ```javascript const response = await fetch(`http://localhost:8082/v1/stream/job/${jobId}`); const status = await response.json(); if (status.status === 'Completed') { console.log('Job terminĂ©!'); } else if (status.status.startsWith('Failed')) { console.error('Erreur:', status.error); } ``` --- ### GET `/v1/stream/hls/{job_id}/index.m3u8` Sert le manifest HLS pour un job terminĂ©. **Request**: - **Method**: `GET` - **Path Parameter**: `job_id` (UUID du job) - **Headers**: Aucun requis **Response** (200 OK): - **Content-Type**: `application/vnd.apple.mpegurl` - **Body**: Contenu du fichier `index.m3u8` **Exemple de contenu**: ```m3u8 #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:6 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:6.0, segment_00001.ts #EXTINF:6.0, segment_00002.ts #EXTINF:6.0, segment_00003.ts #EXT-X-ENDLIST ``` **Erreurs**: - `404 Not Found`: Job introuvable ou manifest non gĂ©nĂ©rĂ© - `400 Bad Request`: Job non terminĂ© **Exemple cURL**: ```bash curl http://localhost:8082/v1/stream/hls/550e8400-e29b-41d4-a716-446655440000/index.m3u8 ``` **Exemple JavaScript**: ```javascript const manifestUrl = `http://localhost:8082/v1/stream/hls/${jobId}/index.m3u8`; // Utiliser avec hls.js import Hls from 'hls.js'; const hls = new Hls(); hls.loadSource(manifestUrl); hls.attachMedia(audioElement); ``` --- ### GET `/v1/stream/hls/{job_id}/{segment}` Sert un segment HLS (.ts). **Request**: - **Method**: `GET` - **Path Parameters**: - `job_id`: UUID du job - `segment`: Nom du segment (ex: `segment_00001.ts`) **Response** (200 OK): - **Content-Type**: `video/mp2t` - **Body**: Contenu binaire du segment **Erreurs**: - `404 Not Found`: Segment introuvable **Exemple cURL**: ```bash curl http://localhost:8082/v1/stream/hls/550e8400-e29b-41d4-a716-446655440000/segment_00001.ts \ --output segment_00001.ts ``` **Note**: GĂ©nĂ©ralement appelĂ© automatiquement par le player HLS lors du parsing du manifest. --- ## Workflow complet ### 1. Soumettre un job ```javascript const formData = new FormData(); formData.append('file', audioFile); formData.append('quality_profile', 'high'); const submitResponse = await fetch('http://localhost:8082/v1/stream/transcode', { method: 'POST', body: formData }); const { job_id } = await submitResponse.json(); console.log('Job soumis:', job_id); ``` ### 2. Poller l'Ă©tat ```javascript async function pollJobStatus(jobId) { while (true) { const response = await fetch(`http://localhost:8082/v1/stream/job/${jobId}`); const status = await response.json(); console.log(`Statut: ${status.status}, Progression: ${status.progress}%`); if (status.status === 'Completed') { return status; } else if (status.status.startsWith('Failed')) { throw new Error(status.error); } // Attendre 2 secondes avant le prochain poll await new Promise(resolve => setTimeout(resolve, 2000)); } } const completedJob = await pollJobStatus(jobId); ``` ### 3. Charger le manifest HLS ```javascript const manifestUrl = `http://localhost:8082/v1/stream/hls/${jobId}/index.m3u8`; // Avec hls.js import Hls from 'hls.js'; if (Hls.isSupported()) { const hls = new Hls(); hls.loadSource(manifestUrl); hls.attachMedia(audioElement); hls.on(Hls.Events.MANIFEST_PARSED, () => { console.log('Manifest chargĂ©, prĂȘt Ă  jouer'); audioElement.play(); }); } else if (audioElement.canPlayType('application/vnd.apple.mpegurl')) { // Support natif (Safari) audioElement.src = manifestUrl; audioElement.addEventListener('loadedmetadata', () => { audioElement.play(); }); } ``` --- ## Codes d'erreur ### 400 Bad Request - Fichier manquant dans la requĂȘte - Format de fichier invalide - ParamĂštres invalides ### 404 Not Found - Job introuvable - Manifest HLS introuvable - Segment introuvable ### 500 Internal Server Error - Erreur serveur interne - Échec de soumission du job - Erreur de traitement --- ## Rate limiting Actuellement non implĂ©mentĂ© (P0). À ajouter en P1. --- ## Authentification Actuellement non requise (P0). À ajouter en P1 avec JWT. --- ## CORS CORS configurĂ© pour: - `http://localhost:5176` (Vite dev) - `http://localhost:3000` (React dev) Configurable via variable d'environnement `ALLOWED_ORIGINS`. --- ## Exemples complets ### Python ```python import requests import time import uuid # 1. Soumettre un job with open('audio.wav', 'rb') as f: response = requests.post( 'http://localhost:8082/v1/stream/transcode', files={'file': f}, data={'quality_profile': 'high'} ) job_id = response.json()['job_id'] # 2. Poller l'Ă©tat while True: response = requests.get(f'http://localhost:8082/v1/stream/job/{job_id}') status = response.json() print(f"Statut: {status['status']}, Progression: {status['progress']}%") if status['status'] == 'Completed': break elif status['status'].startswith('Failed'): raise Exception(status['error']) time.sleep(2) # 3. URL du manifest manifest_url = f'http://localhost:8082/v1/stream/hls/{job_id}/index.m3u8' print(f"Manifest HLS: {manifest_url}") ``` ### Node.js ```javascript const FormData = require('form-data'); const fs = require('fs'); const fetch = require('node-fetch'); async function transcodeAudio(filePath) { // 1. Soumettre const form = new FormData(); form.append('file', fs.createReadStream(filePath)); form.append('quality_profile', 'high'); const submitRes = await fetch('http://localhost:8082/v1/stream/transcode', { method: 'POST', body: form }); const { job_id } = await submitRes.json(); // 2. Poller while (true) { const statusRes = await fetch(`http://localhost:8082/v1/stream/job/${job_id}`); const status = await statusRes.json(); if (status.status === 'Completed') { return `http://localhost:8082/v1/stream/hls/${job_id}/index.m3u8`; } else if (status.status.startsWith('Failed')) { throw new Error(status.error); } await new Promise(resolve => setTimeout(resolve, 2000)); } } // Usage transcodeAudio('./audio.wav') .then(manifestUrl => console.log('Manifest:', manifestUrl)) .catch(console.error); ``` --- ## Changelog ### v0.2.0 (2025-01-27) - ✅ Ajout endpoints `/v1/stream/transcode` - ✅ Ajout endpoint `/v1/stream/job/{id}` - ✅ Ajout endpoints HLS `/v1/stream/hls/{job_id}/...` - ✅ Support multipart/form-data pour upload - ✅ Gestion des erreurs et statuts --- **Prochaine Ă©tape**: Voir `STREAM_PIPELINE.md` pour l'architecture interne.