Initial upload: iptv-android-tv-hermes

This commit is contained in:
Abderrahim-Mouhcine
2026-08-16 19:57:53 +01:00
commit 534d462553
222 changed files with 22516 additions and 0 deletions
+486
View File
@@ -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.