Initial upload: iptv-android-tv-hermes
This commit is contained in:
@@ -0,0 +1,486 @@
|
||||
# iMedia TV+ / Xtream Google TV Player (Hermes Edition)
|
||||
## Spécifications, architecture et guide du projet
|
||||
|
||||
**Projet :** Lecteur IPTV Xtream pour Google TV / Android TV
|
||||
**Package Android :** `ma.tkgraph.xtreamtv`
|
||||
**Plateforme cible :** Google TV / Android TV
|
||||
**Langage :** Kotlin
|
||||
**Interface :** Jetpack Compose / Compose TV
|
||||
**Lecteur vidéo :** AndroidX Media3 ExoPlayer
|
||||
**API IPTV :** Xtream Codes compatible
|
||||
**Date du document :** 11/06/2026
|
||||
**Version :** 2.0 (Hermes)
|
||||
|
||||
---
|
||||
|
||||
## 1. Objectif du projet
|
||||
|
||||
Développer une application Google TV complète pour lire des contenus IPTV depuis un serveur Xtream, en mettant l'accent sur :
|
||||
|
||||
- **Qualité logicielle** : tests, architecture propre, sécurité
|
||||
- **Expérience utilisateur** : navigation fluide, télécommande, réactivité
|
||||
- **Résilience** : gestion d'erreur, cache, fallbacks gracieux
|
||||
- **Maintenabilité** : documentation, historique, conventions
|
||||
|
||||
Fonctionnalités couvertes :
|
||||
- Connexion à un serveur Xtream + mémorisation sécurisée des identifiants
|
||||
- Lecture Live TV avec EPG court
|
||||
- Guide TV global + Replay / Catch-up TV
|
||||
- VOD et Séries avec catalogues complets
|
||||
- Favoris persistants (Live, VOD, Séries)
|
||||
- Chaîne épinglée au démarrage
|
||||
- Navigation complète à la télécommande Google TV
|
||||
- Support multilingue (français, anglais, arabe)
|
||||
- Cache local EPG pour performances
|
||||
|
||||
---
|
||||
|
||||
## 2. Architecture
|
||||
|
||||
### 2.1. Diagramme de flux
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph UI ["Couche UI (Compose TV)"]
|
||||
Login[LoginScreen]
|
||||
Home[HomeScreen]
|
||||
Player[PlayerScreen]
|
||||
Guide[ProgramGuideScreen]
|
||||
Replay[ReplayGuideScreen]
|
||||
Vod[VodScreen]
|
||||
Series[SeriesScreen]
|
||||
end
|
||||
|
||||
subgraph ViewModel ["Couche ViewModel"]
|
||||
VM_Home[HomeViewModel]
|
||||
VM_Player[PlayerViewModel]
|
||||
VM_Vod[VodViewModel]
|
||||
VM_Series[SeriesViewModel]
|
||||
end
|
||||
|
||||
subgraph Repository ["Couche Repository"]
|
||||
Repo_Auth[AuthRepository]
|
||||
Repo_Live[LiveRepository]
|
||||
Repo_Vod[VodRepository]
|
||||
Repo_Series[SeriesRepository]
|
||||
Repo_Epg[EpgRepository]
|
||||
end
|
||||
|
||||
subgraph Data ["Couche Data"]
|
||||
API[XtreamApi<br/>Retrofit]
|
||||
Cache[EpgCache<br/>Room / SQLite]
|
||||
Storage[ConfigStorage<br/>EncryptedSharedPreferences]
|
||||
end
|
||||
|
||||
subgraph External ["Externe"]
|
||||
Xtream[Xtream Server]
|
||||
end
|
||||
|
||||
Login --> VM_Home
|
||||
Home --> VM_Home
|
||||
Player --> VM_Player
|
||||
Guide --> VM_Player
|
||||
Replay --> VM_Player
|
||||
Vod --> VM_Vod
|
||||
Series --> VM_Series
|
||||
|
||||
VM_Home --> Repo_Auth
|
||||
VM_Home --> Repo_Live
|
||||
VM_Home --> Repo_Epg
|
||||
VM_Player --> Repo_Live
|
||||
VM_Player --> Repo_Epg
|
||||
VM_Vod --> Repo_Vod
|
||||
VM_Series --> Repo_Series
|
||||
|
||||
Repo_Auth --> Storage
|
||||
Repo_Live --> API
|
||||
Repo_Vod --> API
|
||||
Repo_Series --> API
|
||||
Repo_Epg --> API
|
||||
Repo_Epg --> Cache
|
||||
|
||||
API --> Xtream
|
||||
Storage -.->|Fallback| API
|
||||
```
|
||||
|
||||
### 2.2. Flux de navigation
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Splash[Splash<br/>iMedia TV+] --> Login[LoginScreen]
|
||||
Login --> Home[HomeScreen]
|
||||
|
||||
Home -->|Live TV| LiveList[Liste Chaînes]
|
||||
Home -->|Guide TV| GuideScreen[Guide TV Global]
|
||||
Home -->|VOD| VodScreen[Catalogue VOD]
|
||||
Home -->|Séries| SeriesScreen[Catalogue Séries]
|
||||
|
||||
LiveList --> Player[PlayerScreen]
|
||||
GuideScreen --> Player
|
||||
ReplayGuide --> Player
|
||||
VodScreen --> Player
|
||||
SeriesScreen --> Player
|
||||
|
||||
Player -->|Retour 1| Overlay
|
||||
Player -->|Retour 2| PreviousScreen
|
||||
|
||||
Home -->|Retour| ConfirmQuit{Confirmer?}
|
||||
```
|
||||
|
||||
### 2.3. Structure des dossiers
|
||||
|
||||
```
|
||||
app/
|
||||
└── src/
|
||||
├── main/
|
||||
│ ├── AndroidManifest.xml
|
||||
│ ├── java/ma/tkgraph/xtreamtv/
|
||||
│ │ ├── MainActivity.kt
|
||||
│ │ ├── data/
|
||||
│ │ │ ├── model/ ← DTOs Xtream
|
||||
│ │ │ ├── network/ ← Retrofit API + interceptors
|
||||
│ │ │ ├── repository/ ← Live, VOD, Series, EPG, Auth
|
||||
│ │ │ └── storage/ ← EncryptedSharedPreferences
|
||||
│ │ ├── ui/
|
||||
│ │ │ ├── components/ ← ChannelLogo, CategoryRow, etc.
|
||||
│ │ │ ├── screens/ ← Login, Home, Player, Guide, etc.
|
||||
│ │ │ └── theme/ ← Thème Material 3
|
||||
│ │ └── util/ ← UrlBuilder, CategorySort, Extensions
|
||||
│ └── res/
|
||||
│ ├── drawable/ ← launch_background.xml
|
||||
│ ├── drawable-nodpi/ ← iMedia TV+ splash PNG
|
||||
│ ├── mipmap-*/ ← icône app
|
||||
│ ├── values/ ← strings.xml (default = EN)
|
||||
│ ├── values-fr/ ← strings.xml (français)
|
||||
│ └── values-ar/ ← strings.xml (العربية)
|
||||
├── test/ ← Tests unitaires (JUnit + MockK)
|
||||
└── androidTest/ ← Tests UI (Compose Test)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Stack technique détaillée
|
||||
|
||||
| Couche | Technologie | Justification |
|
||||
|--------|-------------|---------------|
|
||||
| Langage | Kotlin 2.x | Moderne, sûr, natif Android |
|
||||
| UI | Jetpack Compose + Compose TV (1.7+) | Déclaratif, natif TV |
|
||||
| Lecteur | AndroidX Media3 ExoPlayer 1.5+ | Standard Google, HLS/DASH/MP4 |
|
||||
| Réseau | Retrofit 2.11+ / OkHttp 4.12+ | Robuste, interceptable |
|
||||
| Images | Coil 3.x | Asynchrone, cache, fallback |
|
||||
| Cache EPG | Room 2.7+ (SQLite) | Performant, requêtes typées |
|
||||
| Stockage | EncryptedSharedPreferences + AES-256 | Sécurité des credentials |
|
||||
| Tests unitaires | JUnit 5 / MockK / Turbine | Kotlin-friendly, Flow test |
|
||||
| Tests UI | Compose UI Test + Espresso | Automatisation UI TV |
|
||||
| Logging | Timber | Structuré, tags, crash |
|
||||
| Crash reporting | Firebase Crashlytics | Monitoring production |
|
||||
|
||||
---
|
||||
|
||||
## 4. Environnement de développement
|
||||
|
||||
| Composant | Valeur |
|
||||
|-----------|--------|
|
||||
| OS de développement | Windows 11 |
|
||||
| IDE | Android Studio (Ladybug+) |
|
||||
| Terminal | PowerShell |
|
||||
| Appareil cible | Google TV / Android TV 12+ (API 31+) |
|
||||
| Connexion | ADB Wi-Fi ou USB |
|
||||
| JDK | OpenJDK 21 (via Android Studio) |
|
||||
| SDK Android | API 36, Build-Tools 36.x |
|
||||
| Gradle | 9.1+ (wrapper) |
|
||||
|
||||
### 4.1. Variables d'environnement
|
||||
|
||||
```powershell
|
||||
$env:JAVA_HOME = "D:\Program Files\Android\Android Studio\jbr"
|
||||
$env:ANDROID_HOME = "$env:LOCALAPPDATA\Android\Sdk"
|
||||
$env:Path = "$env:JAVA_HOME\bin;$env:ANDROID_HOME\platform-tools;$env:ANDROID_HOME\cmdline-tools\latest\bin;D:\Tools\Gradle\gradle-9.1.0\bin;$env:Path"
|
||||
```
|
||||
|
||||
### 4.2. Compilation
|
||||
|
||||
```powershell
|
||||
cd "D:\07-Logiciels\12-IPTV Andoid TV HERMES"
|
||||
.\gradlew.bat clean --no-daemon
|
||||
.\gradlew.bat :app:assembleDebug --no-daemon
|
||||
```
|
||||
|
||||
APK générée : `app\build\outputs\apk\debug\app-debug.apk`
|
||||
|
||||
---
|
||||
|
||||
## 5. Sécurité
|
||||
|
||||
### 5.1. Stockage des identifiants
|
||||
|
||||
**Problème de la v1 :** identifiants stockés en clair dans `SharedPreferences`.
|
||||
|
||||
**Solution Hermes :** `EncryptedSharedPreferences` avec AES-256 GCM.
|
||||
|
||||
```kotlin
|
||||
// data/storage/SecureStorage.kt
|
||||
val masterKey = MasterKey.Builder(context)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build()
|
||||
|
||||
val prefs = EncryptedSharedPreferences.create(
|
||||
context,
|
||||
"imedia_secure_prefs",
|
||||
masterKey,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
```
|
||||
|
||||
### 5.2. Règles de sécurité
|
||||
|
||||
- Aucun log contenant `username`, `password` ou `server_url`
|
||||
- Timeout réseau configuré (15s connect, 30s read)
|
||||
- Validation côté client avant envoi : URL bien formée, champs non vides
|
||||
- Pas de stockage en cache HTTP des credentials
|
||||
- OkHttp interceptor pour masquer les auth dans les logs debug
|
||||
- Préparation au HTTPS (certificats, SSR)
|
||||
|
||||
---
|
||||
|
||||
## 6. Gestion d'erreurs
|
||||
|
||||
### 6.1. Stratégie générale
|
||||
|
||||
| Scénario | Comportement | Message utilisateur |
|
||||
|----------|-------------|---------------------|
|
||||
| Réseau indisponible | Toast + fallback cache EPG | "Connexion impossible. Vérifiez votre réseau." |
|
||||
| Timeout API (15s) | Retry 1x, puis message | "Le serveur ne répond pas. Réessayez." |
|
||||
| Auth échouée | Effacer champs, focus sur login | "Identifiants incorrects ou serveur invalide." |
|
||||
| Flux vidéo mort | 503 overlay, retour menu | "Flux indisponible pour cette chaîne." |
|
||||
| EPG vide | Afficher "Aucun programme" | "Aucun programme trouvé pour cette chaîne." |
|
||||
| Données corrompues | Fallback valeurs par défaut | "Des données sont manquantes — certains affichages peuvent être incomplets." |
|
||||
|
||||
### 6.2. État UI avec sealed class
|
||||
|
||||
```kotlin
|
||||
sealed class UiState<out T> {
|
||||
object Idle : UiState<Nothing>()
|
||||
object Loading : UiState<Nothing>()
|
||||
data class Success<T>(val data: T) : UiState<T>()
|
||||
data class Error(val message: String, val retry: Boolean = true) : UiState<Nothing>()
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3. Intercepteur réseau
|
||||
|
||||
```kotlin
|
||||
class ErrorInterceptor : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
return try {
|
||||
val response = chain.proceed(request)
|
||||
if (!response.isSuccessful) {
|
||||
throw XtreamHttpException(response.code, response.message)
|
||||
}
|
||||
response
|
||||
} catch (e: SocketTimeoutException) {
|
||||
throw XtreamTimeoutException("Le serveur Xtream est injoignable")
|
||||
} catch (e: UnknownHostException) {
|
||||
throw XtreamNetworkException("Aucune connexion réseau")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Cache EPG
|
||||
|
||||
### 7.1. Problème
|
||||
|
||||
Le guide TV global peut nécessiter des centaines d'appels API (1 par chaîne). Sans cache, l'écran est inutilisable.
|
||||
|
||||
### 7.2. Solution : Room (SQLite)
|
||||
|
||||
```kotlin
|
||||
@Entity(tableName = "epg_cache")
|
||||
data class EpgCacheEntry(
|
||||
@PrimaryKey val id: Long,
|
||||
val streamId: Int,
|
||||
val channelName: String,
|
||||
val title: String,
|
||||
val description: String?,
|
||||
val startTimestamp: Long,
|
||||
val endTimestamp: Long,
|
||||
val cachedAt: Long = System.currentTimeMillis()
|
||||
)
|
||||
```
|
||||
|
||||
### 7.3. Politique de cache
|
||||
|
||||
| Type | Durée | Invalidation |
|
||||
|------|-------|-------------|
|
||||
| EPG court (live) | 2 minutes | Rafraîchi au scroll |
|
||||
| EPG complet (guide) | 15 minutes | Pull-to-refresh manuel |
|
||||
| Catégories | 1 heure | Au lancement |
|
||||
| Listes chaînes | 5 minutes | Changement de catégorie |
|
||||
|
||||
### 7.4. Flux EPG
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Ouvre Guide TV] --> B{Cache valide?}
|
||||
B -->|Oui < 15min| C[Afficher depuis Room]
|
||||
B -->|Non| D[Requête API par chaîne]
|
||||
D --> E[Stocker dans Room]
|
||||
E --> C
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Tests
|
||||
|
||||
### 8.1. Tests unitaires (JUnit 5 + MockK)
|
||||
|
||||
| Fichier | Test | Ce qu'on vérifie |
|
||||
|---------|------|------------------|
|
||||
| `AuthRepositoryTest.kt` | Connexion valide/invalide | Repository retourne `Success` ou `Error` |
|
||||
| `AuthRepositoryTest.kt` | Timeout réseau | Erreur lisible, pas de crash |
|
||||
| `EpgRepositoryTest.kt` | Cache hit/miss | Appel API si cache expiré, sinon données locales |
|
||||
| `CategorySortUtilsTest.kt` | Tri FR/AR/autres | Ordre exact des catégories |
|
||||
| `XtreamUrlBuilderTest.kt` | URLs Live/VOD/Series | Format correct de chaque URL |
|
||||
| `SecureStorageTest.kt` | Lecture/écriture chiffrée | Données diffférentes en clair vs stocké |
|
||||
| `PlayerViewModelTest.kt` | Zapping gauche/droite | Chaîne suivante/précédente correcte |
|
||||
| `FavoritesRepositoryTest.kt` | Ajout/suppression favoris | Persistance après redémarrage |
|
||||
|
||||
### 8.2. Tests UI (Compose UI Test)
|
||||
|
||||
| Fichier | Test |
|
||||
|---------|------|
|
||||
| `LoginScreenTest.kt` | Remplissage formulaire → bouton actif |
|
||||
| `LoginScreenTest.kt` | Erreur → message d'erreur affiché |
|
||||
| `HomeScreenTest.kt` | Navigation entre catégories OK |
|
||||
| `HomeScreenTest.kt` | Favori accessible via télécommande |
|
||||
| `PlayerScreenTest.kt` | Overlay disparaît après 3s |
|
||||
|
||||
### 8.3. Lancer les tests
|
||||
|
||||
```powershell
|
||||
# Tests unitaires uniquement
|
||||
.\gradlew.bat test --no-daemon
|
||||
|
||||
# Tests UI (appareil/émulateur connecté)
|
||||
.\gradlew.bat connectedAndroidTest --no-daemon
|
||||
|
||||
# Les deux
|
||||
.\gradlew.bat test connectedAndroidTest --no-daemon
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Internationalisation (i18n)
|
||||
|
||||
### 9.1. Langues supportées
|
||||
|
||||
| Langue | Dossier | Statut |
|
||||
|--------|---------|--------|
|
||||
| Anglais (défaut) | `values/` | ✅ Prévu |
|
||||
| Français | `values-fr/` | ✅ Prévu |
|
||||
| Arabe | `values-ar/` | ✅ Prévu (RTL) |
|
||||
|
||||
### 9.2. Exemple
|
||||
|
||||
```xml
|
||||
<!-- values/strings.xml -->
|
||||
<string name="app_name">iMedia TV+</string>
|
||||
<string name="live_tv">Live TV</string>
|
||||
<string name="connect">Connect</string>
|
||||
<string name="network_error">Connection lost. Check your network.</string>
|
||||
|
||||
<!-- values-fr/strings.xml -->
|
||||
<string name="app_name">iMedia TV+</string>
|
||||
<string name="live_tv">Direct TV</string>
|
||||
<string name="connect">Connexion</string>
|
||||
<string name="network_error">Connexion perdue. Vérifiez votre réseau.</string>
|
||||
|
||||
<!-- values-ar/strings.xml -->
|
||||
<string name="app_name">iMedia TV+</string>
|
||||
<string name="live_tv">البث المباشر</string>
|
||||
<string name="connect">اتصال</string>
|
||||
<string name="network_error">انقطع الاتصال. تحقق من شبكتك.</string>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Logging et Monitoring
|
||||
|
||||
### 10.1. Timber
|
||||
|
||||
```kotlin
|
||||
// Application.kt
|
||||
class XtreamApplication : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
} else {
|
||||
Timber.plant(CrashReportingTree())
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Règles :
|
||||
- `Timber.d` / `Timber.i` pour debug et infos
|
||||
- `Timber.w` pour anomalies non bloquantes
|
||||
- `Timber.e` pour erreurs utilisateur
|
||||
- **Jamais** de log de credentials, tokens, ou données sensibles
|
||||
|
||||
### 10.2. Crash reporting
|
||||
|
||||
Firebase Crashlytics est prévu pour la version release :
|
||||
- Rapports de crash automatiques
|
||||
- Logs non-sensibles attachés aux rapports
|
||||
- Clés custom : écran actif, dernier état réseau
|
||||
|
||||
---
|
||||
|
||||
## 11. Roadmap
|
||||
|
||||
### Phase 1 — Fondations (immédiat)
|
||||
- [x] Structure du projet
|
||||
- [x] Stack technique définie
|
||||
- [ ] Connexion Xtream + SecureStorage
|
||||
- [ ] Live TV avec Media3
|
||||
|
||||
### Phase 2 — Fonctionnalités cœur
|
||||
- [ ] Catégories + Favoris Live
|
||||
- [ ] EPG court + Replay
|
||||
- [ ] Guide TV global
|
||||
- [ ] VOD + Séries
|
||||
|
||||
### Phase 3 — Qualité
|
||||
- [ ] Tests unitaires (couverture > 70%)
|
||||
- [ ] Cache EPG (Room)
|
||||
- [ ] Gestion d'erreur complète
|
||||
- [ ] i18n (FR, EN, AR)
|
||||
|
||||
### Phase 4 — Production
|
||||
- [ ] Signing + ProGuard
|
||||
- [ ] Firebase Crashlytics
|
||||
- [ ] Bannière Android TV + icônes finales
|
||||
- [ ] Politique de confidentialité
|
||||
- [ ] Publication Play Store
|
||||
|
||||
---
|
||||
|
||||
## 12. Conclusion
|
||||
|
||||
Cette version Hermes reprend l'excellente base de la v1 et y ajoute :
|
||||
|
||||
1. **🔐 Sécurité** : chiffrement AES-256 des credentials
|
||||
2. **📦 Cache EPG** : Room SQLite pour des performances réelles
|
||||
3. **🧪 Tests** : stratégie complète (unitaire + UI)
|
||||
4. **🌍 i18n** : support FR/EN/AR
|
||||
5. **📋 Gestion d'erreur** : sealed class + intercepteurs + messages lisibles
|
||||
6. **📊 Monitoring** : Timber + Crashlytics
|
||||
7. **📐 Architecture** : flux documentés en Mermaid
|
||||
|
||||
Le logiciel fonctionnait déjà en v1. Cette version le rend fiable, sécurisé et prêt pour la production.
|
||||
Reference in New Issue
Block a user