init specs
f89a2b8 added
spec/init-plan.md +348 -0 | new file mode 100644 | ||
| @@ -0,0 +1,348 @@ | ||
| 1 | +# RSS Podcast Downloader - Plan de Développement | |
| 2 | + | |
| 3 | +## 1. Vue d'ensemble du Projet | |
| 4 | + | |
| 5 | +### 1.1 Description | |
| 6 | +Application de bureau en Rust utilisant le framework **egui** pour télécharger automatiquement des épisodes de podcasts à partir de flux RSS. L'application permet à l'utilisateur de gérer plusieurs flux, de synchroniser les nouveaux épisodes et de les télécharger dans des dossiers dédiés. | |
| 7 | + | |
| 8 | +### 1.2 Fonctionnalités Principales | |
| 9 | +- Ajout/suppression/édition de flux RSS | |
| 10 | +- Synchronisation manuelle des flux | |
| 11 | +- Téléchargement des nouveaux épisodes | |
| 12 | +- Stockage local de la configuration | |
| 13 | +- Interface graphique intuitive avec egui | |
| 14 | + | |
| 15 | +--- | |
| 16 | + | |
| 17 | +## 2. Stack Technique | |
| 18 | + | |
| 19 | +| Composant | Technologie | Rôle | | |
| 20 | +|-----------|-------------|------| | |
| 21 | +| Langage | Rust (edition 2021) | Langage principal | | |
| 22 | +| UI | egui 0.24+ | Framework d'interface graphique | | |
| 23 | +| Parsing RSS | rss (crate) | Lecture des flux RSS/Atom | | |
| 24 | +| HTTP | reqwest | Requêtes HTTP pour téléchargements | | |
| 25 | +| Async | tokio | Gestion asynchrone | | |
| 26 | +| Sérialisation | serde + serde_json | Sauvegarde/restauration des flux | | |
| 27 | +| Date/Heure | chrono | Gestion des timestamps | | |
| 28 | +| Fichiers | std::fs + std::path | Gestion du système de fichiers | | |
| 29 | +| Logging | log + env_logger | Journalisation | | |
| 30 | + | |
| 31 | +--- | |
| 32 | + | |
| 33 | +## 3. Architecture du Projet | |
| 34 | + | |
| 35 | +### 3.1 Structure des Fichiers | |
| 36 | + | |
| 37 | +``` | |
| 38 | +rss-podcast-dl-egui/ | |
| 39 | +├── Cargo.toml # Dépendances et métadonnées | |
| 40 | +├── src/ | |
| 41 | +│ ├── main.rs # Point d'entrée de l'application | |
| 42 | +│ ├── app.rs # Structure principale de l'application egui | |
| 43 | +│ ├── config/ | |
| 44 | +│ │ ├── mod.rs # Module de configuration | |
| 45 | +│ │ ├── feed.rs # Modèle Feed (flux RSS) | |
| 46 | +│ │ └── storage.rs # Sauvegarde/chargement des flux | |
| 47 | +│ ├── rss/ | |
| 48 | +│ │ ├── mod.rs # Module de gestion des flux RSS | |
| 49 | +│ │ ├── parser.rs # Parsing des flux | |
| 50 | +│ │ └── downloader.rs # Téléchargement des épisodes | |
| 51 | +│ └── ui/ | |
| 52 | +│ ├── mod.rs # Module UI | |
| 53 | +│ ├── home.rs # Écran d'accueil | |
| 54 | +│ ├── feed_list.rs # Liste des flux | |
| 55 | +│ └── add_feed.rs # Dialogue d'ajout de flux | |
| 56 | +├── spec/ | |
| 57 | +│ └── init-plan.md # Ce document | |
| 58 | +└── assets/ | |
| 59 | + └── icon.png # Icône de l'application (optionnel) | |
| 60 | +``` | |
| 61 | + | |
| 62 | +### 3.2 Modèles de Données | |
| 63 | + | |
| 64 | +#### 3.2.1 Feed (Flux RSS) | |
| 65 | +```rust | |
| 66 | +#[derive(Debug, Clone, Serialize, Deserialize)] | |
| 67 | +pub struct Feed { | |
| 68 | + pub id: String, // UUID unique | |
| 69 | + pub url: String, // URL du flux RSS | |
| 70 | + pub name: String, // Nom du podcast (extraite du RSS ou personnalisé) | |
| 71 | + pub download_path: PathBuf, // Chemin de téléchargement | |
| 72 | + pub last_checked: Option<DateTime<Utc>>, // Dernière vérification | |
| 73 | + pub last_episode_date: Option<DateTime<Utc>>, // Date du dernier épisode | |
| 74 | + pub enabled: bool, // Actif/désactivé | |
| 75 | +} | |
| 76 | +``` | |
| 77 | + | |
| 78 | +#### 3.2.2 Episode | |
| 79 | +```rust | |
| 80 | +#[derive(Debug, Clone)] | |
| 81 | +pub struct Episode { | |
| 82 | + pub id: String, // UUID ou guid | |
| 83 | + pub title: String, | |
| 84 | + pub description: Option<String>, | |
| 85 | + pub pub_date: DateTime<Utc>, | |
| 86 | + pub audio_url: String, | |
| 87 | + pub audio_filename: String, | |
| 88 | + pub downloaded: bool, | |
| 89 | + pub file_size: Option<u64>, | |
| 90 | +} | |
| 91 | +``` | |
| 92 | + | |
| 93 | +#### 3.2.3 AppState | |
| 94 | +```rust | |
| 95 | +pub struct AppState { | |
| 96 | + pub feeds: Vec<Feed>, | |
| 97 | + pub current_feed: Option<usize>, // Index du feed sélectionné | |
| 98 | + pub show_add_feed_dialog: bool, | |
| 99 | + pub sync_in_progress: bool, | |
| 100 | + pub download_progress: HashMap<String, f32>, // feed_id -> progression 0.0-1.0 | |
| 101 | + pub error_message: Option<String>, | |
| 102 | + pub info_message: Option<String>, | |
| 103 | +} | |
| 104 | +``` | |
| 105 | + | |
| 106 | +--- | |
| 107 | + | |
| 108 | +## 4. Phases de Développement | |
| 109 | + | |
| 110 | +### 4.1 Phase 1 : Initialisation du Projet (Durée : 1 jour) | |
| 111 | + | |
| 112 | +**Objectif** : Créer la structure de base du projet Rust avec egui. | |
| 113 | + | |
| 114 | +| Tâche | Priorité | Description | Livrable | | |
| 115 | +|-------|----------|-------------|----------| | |
| 116 | +| 1.1 | High | Créer le projet Rust avec Cargo | `Cargo.toml` | | |
| 117 | +| 1.2 | High | Ajouter les dépendances de base | `Cargo.toml` configuré | | |
| 118 | +| 1.3 | High | Créer la structure de dossiers | Arboorescence complète | | |
| 119 | +| 1.4 | Medium | Configurer le logging | Logging fonctionnel | | |
| 120 | +| 1.5 | Medium | Vérifier la compilation de base | Projet compilable | | |
| 121 | + | |
| 122 | +**Dépendances Cargo.toml** : | |
| 123 | +```toml | |
| 124 | +[package] | |
| 125 | +name = "rss-podcast-dl-egui" | |
| 126 | +version = "0.1.0" | |
| 127 | +edition = "2021" | |
| 128 | + | |
| 129 | +[dependencies] | |
| 130 | +egui = "0.24" | |
| 131 | +eframe = "0.24" | |
| 132 | +serde = { version = "1.0", features = ["derive"] } | |
| 133 | +serde_json = "1.0" | |
| 134 | +reqwest = { version = "0.11", features = ["json"] } | |
| 135 | +tokio = { version = "1.0", features = ["full"] } | |
| 136 | +rss = "2.0" | |
| 137 | +chrono = { version = "0.4", features = ["serde"] } | |
| 138 | +log = "0.4" | |
| 139 | +env_logger = "0.10" | |
| 140 | +uuid = { version = "1.0", features = ["v4", "serde"] } | |
| 141 | +``` | |
| 142 | + | |
| 143 | +--- | |
| 144 | + | |
| 145 | +### 4.2 Phase 2 : Modèles et Stockage (Durée : 2 jours) | |
| 146 | + | |
| 147 | +**Objectif** : Implémenter les modèles de données et la persistance. | |
| 148 | + | |
| 149 | +| Tâche | Priorité | Description | Livrable | | |
| 150 | +|-------|----------|-------------|----------| | |
| 151 | +| 2.1 | High | Créer le module `config/feed.rs` | Modèle `Feed` | | |
| 152 | +| 2.2 | High | Créer le module `config/storage.rs` | Fonctions de sauvegarde/chargement | | |
| 153 | +| 2.3 | High | Implémenter la sérialisation/désérialisation | JSON compatible | | |
| 154 | +| 2.4 | Medium | Ajouter la validation des URLs | Vérification format URL | | |
| 155 | +| 2.5 | Medium | Créer le fichier de configuration par défaut | `~/.config/rss-podcast-dl/config.json` | | |
| 156 | + | |
| 157 | +**Fonctions clés à implémenter** : | |
| 158 | +```rust | |
| 159 | +// storage.rs | |
| 160 | +pub fn save_feeds(feeds: &[Feed], config_path: &Path) -> Result<(), StorageError> | |
| 161 | +pub fn load_feeds(config_path: &Path) -> Result<Vec<Feed>, StorageError> | |
| 162 | +pub fn get_config_path() -> PathBuf | |
| 163 | +``` | |
| 164 | + | |
| 165 | +--- | |
| 166 | + | |
| 167 | +### 4.3 Phase 3 : Parsing RSS et Téléchargement (Durée : 3 jours) | |
| 168 | + | |
| 169 | +**Objectif** : Implémenter la récupération et le parsing des flux, ainsi que le téléchargement. | |
| 170 | + | |
| 171 | +| Tâche | Priorité | Description | Livrable | | |
| 172 | +|-------|----------|-------------|----------| | |
| 173 | +| 3.1 | High | Créer `rss/parser.rs` | Parsing des flux RSS/Atom | | |
| 174 | +| 3.2 | High | Extraire les épisodes d'un flux | Liste d'épisodes | | |
| 175 | +| 3.3 | High | Créer `rss/downloader.rs` | Téléchargement des fichiers audio | | |
| 176 | +| 3.4 | High | Implémenter la détection des nouveaux épisodes | Comparaison par date | | |
| 177 | +| 3.5 | Medium | Gérer les erreurs de réseau | Retry et timeout | | |
| 178 | +| 3.6 | Medium | Afficher la progression du téléchargement | Callback de progression | | |
| 179 | + | |
| 180 | +**Fonctions clés** : | |
| 181 | +```rust | |
| 182 | +// parser.rs | |
| 183 | +pub async fn fetch_feed(url: &str) -> Result<RssFeed, ParserError> | |
| 184 | +pub fn extract_episodes(feed: &RssFeed) -> Vec<Episode> | |
| 185 | + | |
| 186 | +// downloader.rs | |
| 187 | +pub async fn download_episode( | |
| 188 | + episode: &Episode, | |
| 189 | + download_path: &Path, | |
| 190 | + progress_callback: Box<dyn Fn(f32) + Send + Sync>, | |
| 191 | +) -> Result<PathBuf, DownloadError> | |
| 192 | +``` | |
| 193 | + | |
| 194 | +--- | |
| 195 | + | |
| 196 | +### 4.4 Phase 4 : Interface Utilisateur (Durée : 4 jours) | |
| 197 | + | |
| 198 | +**Objectif** : Créer l'interface graphique complète avec egui. | |
| 199 | + | |
| 200 | +| Tâche | Priorité | Description | Livrable | | |
| 201 | +|-------|----------|-------------|----------| | |
| 202 | +| 4.1 | High | Créer la structure de base de l'app egui | `app.rs` + `main.rs` | | |
| 203 | +| 4.2 | High | Implémenter l'écran d'accueil | `ui/home.rs` | | |
| 204 | +| 4.3 | High | Créer la liste des flux avec actions | `ui/feed_list.rs` | | |
| 205 | +| 4.4 | High | Implémenter le dialogue d'ajout de flux | `ui/add_feed.rs` | | |
| 206 | +| 4.5 | Medium | Ajouter les boutons d'action (Ajouter, Synchroniser) | Boutons fonctionnels | | |
| 207 | +| 4.6 | Medium | Afficher les messages d'erreur/info | Notifications UI | | |
| 208 | +| 4.7 | Medium | Ajouter une barre de progression | Visual feedback | | |
| 209 | +| 4.8 | Low | Personnaliser le thème egui | Thème cohérent | | |
| 210 | + | |
| 211 | +**Structure UI** : | |
| 212 | +``` | |
| 213 | ++------------------------------------------+ | |
| 214 | +| RSS Podcast Downloader [⚙️] | | |
| 215 | ++------------------------------------------+ | |
| 216 | +| | | |
| 217 | +| +----------------------+ | | |
| 218 | +| | [+ Ajouter un flux] | | | |
| 219 | +| +----------------------+ | | |
| 220 | +| | | |
| 221 | +| +----------------------+ | | |
| 222 | +| | [🔄 Synchroniser] | | | |
| 223 | +| +----------------------+ | | |
| 224 | +| | | |
| 225 | +| Liste des flux configurés : | | |
| 226 | +| +------------------------------------+ | | |
| 227 | +| | 🎙️ Le Podcast #1 | | | |
| 228 | +| | URL: https://... | | | |
| 229 | +| | Dossier: ~/podcasts/lepodcast | | | |
| 230 | +| | [✏️] [🗑️] [🔄] | | | |
| 231 | +| +------------------------------------+ | | |
| 232 | +| | 🎙️ Tech News | | | |
| 233 | +| | URL: https://... | | | |
| 234 | +| | Dossier: ~/podcasts/tech | | | |
| 235 | +| | [✏️] [🗑️] [🔄] | | | |
| 236 | +| +------------------------------------+ | | |
| 237 | +| | | |
| 238 | +| Statut: Prêt | | | |
| 239 | ++------------------------------------------+ | |
| 240 | +``` | |
| 241 | + | |
| 242 | +--- | |
| 243 | + | |
| 244 | +### 4.5 Phase 5 : Synchronisation (Durée : 2 jours) | |
| 245 | + | |
| 246 | +**Objectif** : Implémenter la logique de synchronisation complète. | |
| 247 | + | |
| 248 | +| Tâche | Priorité | Description | Livrable | | |
| 249 | +|-------|----------|-------------|----------| | |
| 250 | +| 5.1 | High | Implémenter la synchronisation d'un flux | Vérification des nouveaux épisodes | | |
| 251 | +| 5.2 | High | Synchroniser tous les flux | Boucle sur tous les flux | | |
| 252 | +| 5.3 | High | Mettre à jour le `last_checked` | Persistance de l'état | | |
| 253 | +| 5.4 | Medium | Gérer les conflits de noms de fichiers | Nom unique | | |
| 254 | +| 5.5 | Medium | Ajouter un bouton "Tout synchroniser" | Action globale | | |
| 255 | +| 5.6 | Low | Synchronisation automatique (optionnelle) | Minuterie | | |
| 256 | + | |
| 257 | +**Logique de synchronisation** : | |
| 258 | +``` | |
| 259 | +1. Pour chaque flux activé : | |
| 260 | + a. Récupérer le flux RSS | |
| 261 | + b. Extraire les épisodes | |
| 262 | + c. Comparer avec last_episode_date | |
| 263 | + d. Télécharger les nouveaux épisodes | |
| 264 | + e. Mettre à jour last_checked et last_episode_date | |
| 265 | +``` | |
| 266 | + | |
| 267 | +--- | |
| 268 | + | |
| 269 | +### 4.6 Phase 6 : Intégration et Tests (Durée : 2 jours) | |
| 270 | + | |
| 271 | +**Objectif** : Intégrer tous les composants et tester l'application. | |
| 272 | + | |
| 273 | +| Tâche | Priorité | Description | Livrable | | |
| 274 | +|-------|----------|-------------|----------| | |
| 275 | +| 6.1 | High | Connecter UI ↔ Logique métier | Événements gérés | | |
| 276 | +| 6.2 | High | Tester l'ajout de flux | Flux persisté | | |
| 277 | +| 6.3 | High | Tester la synchronisation | Épisodes téléchargés | | |
| 278 | +| 6.4 | High | Tester la suppression de flux | Flux supprimé | | |
| 279 | +| 6.5 | Medium | Gérer les erreurs gracefully | Pas de crash | | |
| 280 | +| 6.6 | Medium | Optimiser les performances | Réactivité UI | | |
| 281 | +| 6.7 | Low | Ajouter des logs détaillés | Debug facilitée | | |
| 282 | + | |
| 283 | +--- | |
| 284 | + | |
| 285 | +### 4.7 Phase 7 : Finalisation (Durée : 1 jour) | |
| 286 | + | |
| 287 | +**Objectif** : Préparer l'application pour la distribution. | |
| 288 | + | |
| 289 | +| Tâche | Priorité | Description | Livrable | | |
| 290 | +|-------|----------|-------------|----------| | |
| 291 | +| 7.1 | Medium | Ajouter une icône | `assets/icon.png` | | |
| 292 | +| 7.2 | Medium | Configurer le nom et version | `Cargo.toml` | | |
| 293 | +| 7.3 | Medium | Créer un README | Documentation | | |
| 294 | +| 7.4 | Low | Builder pour Windows/Linux | Binaires | | |
| 295 | +| 7.5 | Low | Nettoyer le code | Code propre | | |
| 296 | + | |
| 297 | +--- | |
| 298 | + | |
| 299 | +## 5. Calendrier Global | |
| 300 | + | |
| 301 | +| Phase | Durée | Dates Estimées | Statut | | |
| 302 | +|-------|-------|----------------|--------| | |
| 303 | +| Phase 1 | 1 jour | J1 | ⬜ | | |
| 304 | +| Phase 2 | 2 jours | J2-J3 | ⬜ | | |
| 305 | +| Phase 3 | 3 jours | J4-J6 | ⬜ | | |
| 306 | +| Phase 4 | 4 jours | J7-J10 | ⬜ | | |
| 307 | +| Phase 5 | 2 jours | J11-J12 | ⬜ | | |
| 308 | +| Phase 6 | 2 jours | J13-J14 | ⬜ | | |
| 309 | +| Phase 7 | 1 jour | J15 | ⬜ | | |
| 310 | +| **Total** | **15 jours** | | | | |
| 311 | + | |
| 312 | +--- | |
| 313 | + | |
| 314 | +## 6. Points d'Attention | |
| 315 | + | |
| 316 | +### 6.1 Risques Identifiés | |
| 317 | + | |
| 318 | +| Risque | Probabilité | Impact | Mitigation | | |
| 319 | +|--------|-------------|--------|------------| | |
| 320 | +| Problème de compatibilité avec egui 0.24 | Moyenne | Élevé | Vérifier la documentation et exemples | | |
| 321 | +| Parsing de flux RSS non-standards | Élevée | Moyen | Utiliser la crate `rss` robuste | | |
| 322 | +| Gestion des chemins Windows/Linux | Moyenne | Moyen | Utiliser `PathBuf` et `std::path` | | |
| 323 | +| Performance avec beaucoup de flux | Faible | Moyen | Async/await + tokio | | |
| 324 | + | |
| 325 | +### 6.2 Contraintes Techniques | |
| 326 | +- L'application doit fonctionner sans serveur (standalone) | |
| 327 | +- Les flux doivent être stockés localement dans un fichier unique | |
| 328 | +- L'interface doit rester réactive pendant les téléchargements | |
| 329 | +- Les téléchargements doivent être asynchrones | |
| 330 | + | |
| 331 | +### 6.3 Hypothèses | |
| 332 | +- Les flux RSS suivent les standards RSS 2.0 ou Atom | |
| 333 | +- Les URLs des épisodes pointent vers des fichiers audio (MP3, M4A, etc.) | |
| 334 | +- L'utilisateur a les permissions d'écriture dans les dossiers de téléchargement | |
| 335 | +- L'application sera utilisée sur Windows et Linux | |
| 336 | + | |
| 337 | +--- | |
| 338 | + | |
| 339 | +## 7. Prochaines Étapes | |
| 340 | + | |
| 341 | +1. **Valider ce plan** avec les parties prenantes | |
| 342 | +2. **Créer le projet Rust** avec la structure initiale | |
| 343 | +3. **Commencer par la Phase 1** : Initialisation du projet | |
| 344 | +4. **Configurer l'environnement** de développement | |
| 345 | + | |
| 346 | +--- | |
| 347 | + | |
| 348 | +*Document généré le 03/07/2026 - Version 1.0* | |
| new file mode 100644 | |||
| @@ -0,0 +1,348 @@ | |||
| 1 | +# RSS Podcast Downloader - Plan de Développement | ||
| 2 | + | ||
| 3 | +## 1. Vue d'ensemble du Projet | ||
| 4 | + | ||
| 5 | +### 1.1 Description | ||
| 6 | +Application de bureau en Rust utilisant le framework **egui** pour télécharger automatiquement des épisodes de podcasts à partir de flux RSS. L'application permet à l'utilisateur de gérer plusieurs flux, de synchroniser les nouveaux épisodes et de les télécharger dans des dossiers dédiés. | ||
| 7 | + | ||
| 8 | +### 1.2 Fonctionnalités Principales | ||
| 9 | +- Ajout/suppression/édition de flux RSS | ||
| 10 | +- Synchronisation manuelle des flux | ||
| 11 | +- Téléchargement des nouveaux épisodes | ||
| 12 | +- Stockage local de la configuration | ||
| 13 | +- Interface graphique intuitive avec egui | ||
| 14 | + | ||
| 15 | +--- | ||
| 16 | + | ||
| 17 | +## 2. Stack Technique | ||
| 18 | + | ||
| 19 | +| Composant | Technologie | Rôle | | ||
| 20 | +|-----------|-------------|------| | ||
| 21 | +| Langage | Rust (edition 2021) | Langage principal | | ||
| 22 | +| UI | egui 0.24+ | Framework d'interface graphique | | ||
| 23 | +| Parsing RSS | rss (crate) | Lecture des flux RSS/Atom | | ||
| 24 | +| HTTP | reqwest | Requêtes HTTP pour téléchargements | | ||
| 25 | +| Async | tokio | Gestion asynchrone | | ||
| 26 | +| Sérialisation | serde + serde_json | Sauvegarde/restauration des flux | | ||
| 27 | +| Date/Heure | chrono | Gestion des timestamps | | ||
| 28 | +| Fichiers | std::fs + std::path | Gestion du système de fichiers | | ||
| 29 | +| Logging | log + env_logger | Journalisation | | ||
| 30 | + | ||
| 31 | +--- | ||
| 32 | + | ||
| 33 | +## 3. Architecture du Projet | ||
| 34 | + | ||
| 35 | +### 3.1 Structure des Fichiers | ||
| 36 | + | ||
| 37 | +``` | ||
| 38 | +rss-podcast-dl-egui/ | ||
| 39 | +├── Cargo.toml # Dépendances et métadonnées | ||
| 40 | +├── src/ | ||
| 41 | +│ ├── main.rs # Point d'entrée de l'application | ||
| 42 | +│ ├── app.rs # Structure principale de l'application egui | ||
| 43 | +│ ├── config/ | ||
| 44 | +│ │ ├── mod.rs # Module de configuration | ||
| 45 | +│ │ ├── feed.rs # Modèle Feed (flux RSS) | ||
| 46 | +│ │ └── storage.rs # Sauvegarde/chargement des flux | ||
| 47 | +│ ├── rss/ | ||
| 48 | +│ │ ├── mod.rs # Module de gestion des flux RSS | ||
| 49 | +│ │ ├── parser.rs # Parsing des flux | ||
| 50 | +│ │ └── downloader.rs # Téléchargement des épisodes | ||
| 51 | +│ └── ui/ | ||
| 52 | +│ ├── mod.rs # Module UI | ||
| 53 | +│ ├── home.rs # Écran d'accueil | ||
| 54 | +│ ├── feed_list.rs # Liste des flux | ||
| 55 | +│ └── add_feed.rs # Dialogue d'ajout de flux | ||
| 56 | +├── spec/ | ||
| 57 | +│ └── init-plan.md # Ce document | ||
| 58 | +└── assets/ | ||
| 59 | + └── icon.png # Icône de l'application (optionnel) | ||
| 60 | +``` | ||
| 61 | + | ||
| 62 | +### 3.2 Modèles de Données | ||
| 63 | + | ||
| 64 | +#### 3.2.1 Feed (Flux RSS) | ||
| 65 | +```rust | ||
| 66 | +#[derive(Debug, Clone, Serialize, Deserialize)] | ||
| 67 | +pub struct Feed { | ||
| 68 | + pub id: String, // UUID unique | ||
| 69 | + pub url: String, // URL du flux RSS | ||
| 70 | + pub name: String, // Nom du podcast (extraite du RSS ou personnalisé) | ||
| 71 | + pub download_path: PathBuf, // Chemin de téléchargement | ||
| 72 | + pub last_checked: Option<DateTime<Utc>>, // Dernière vérification | ||
| 73 | + pub last_episode_date: Option<DateTime<Utc>>, // Date du dernier épisode | ||
| 74 | + pub enabled: bool, // Actif/désactivé | ||
| 75 | +} | ||
| 76 | +``` | ||
| 77 | + | ||
| 78 | +#### 3.2.2 Episode | ||
| 79 | +```rust | ||
| 80 | +#[derive(Debug, Clone)] | ||
| 81 | +pub struct Episode { | ||
| 82 | + pub id: String, // UUID ou guid | ||
| 83 | + pub title: String, | ||
| 84 | + pub description: Option<String>, | ||
| 85 | + pub pub_date: DateTime<Utc>, | ||
| 86 | + pub audio_url: String, | ||
| 87 | + pub audio_filename: String, | ||
| 88 | + pub downloaded: bool, | ||
| 89 | + pub file_size: Option<u64>, | ||
| 90 | +} | ||
| 91 | +``` | ||
| 92 | + | ||
| 93 | +#### 3.2.3 AppState | ||
| 94 | +```rust | ||
| 95 | +pub struct AppState { | ||
| 96 | + pub feeds: Vec<Feed>, | ||
| 97 | + pub current_feed: Option<usize>, // Index du feed sélectionné | ||
| 98 | + pub show_add_feed_dialog: bool, | ||
| 99 | + pub sync_in_progress: bool, | ||
| 100 | + pub download_progress: HashMap<String, f32>, // feed_id -> progression 0.0-1.0 | ||
| 101 | + pub error_message: Option<String>, | ||
| 102 | + pub info_message: Option<String>, | ||
| 103 | +} | ||
| 104 | +``` | ||
| 105 | + | ||
| 106 | +--- | ||
| 107 | + | ||
| 108 | +## 4. Phases de Développement | ||
| 109 | + | ||
| 110 | +### 4.1 Phase 1 : Initialisation du Projet (Durée : 1 jour) | ||
| 111 | + | ||
| 112 | +**Objectif** : Créer la structure de base du projet Rust avec egui. | ||
| 113 | + | ||
| 114 | +| Tâche | Priorité | Description | Livrable | | ||
| 115 | +|-------|----------|-------------|----------| | ||
| 116 | +| 1.1 | High | Créer le projet Rust avec Cargo | `Cargo.toml` | | ||
| 117 | +| 1.2 | High | Ajouter les dépendances de base | `Cargo.toml` configuré | | ||
| 118 | +| 1.3 | High | Créer la structure de dossiers | Arboorescence complète | | ||
| 119 | +| 1.4 | Medium | Configurer le logging | Logging fonctionnel | | ||
| 120 | +| 1.5 | Medium | Vérifier la compilation de base | Projet compilable | | ||
| 121 | + | ||
| 122 | +**Dépendances Cargo.toml** : | ||
| 123 | +```toml | ||
| 124 | +[package] | ||
| 125 | +name = "rss-podcast-dl-egui" | ||
| 126 | +version = "0.1.0" | ||
| 127 | +edition = "2021" | ||
| 128 | + | ||
| 129 | +[dependencies] | ||
| 130 | +egui = "0.24" | ||
| 131 | +eframe = "0.24" | ||
| 132 | +serde = { version = "1.0", features = ["derive"] } | ||
| 133 | +serde_json = "1.0" | ||
| 134 | +reqwest = { version = "0.11", features = ["json"] } | ||
| 135 | +tokio = { version = "1.0", features = ["full"] } | ||
| 136 | +rss = "2.0" | ||
| 137 | +chrono = { version = "0.4", features = ["serde"] } | ||
| 138 | +log = "0.4" | ||
| 139 | +env_logger = "0.10" | ||
| 140 | +uuid = { version = "1.0", features = ["v4", "serde"] } | ||
| 141 | +``` | ||
| 142 | + | ||
| 143 | +--- | ||
| 144 | + | ||
| 145 | +### 4.2 Phase 2 : Modèles et Stockage (Durée : 2 jours) | ||
| 146 | + | ||
| 147 | +**Objectif** : Implémenter les modèles de données et la persistance. | ||
| 148 | + | ||
| 149 | +| Tâche | Priorité | Description | Livrable | | ||
| 150 | +|-------|----------|-------------|----------| | ||
| 151 | +| 2.1 | High | Créer le module `config/feed.rs` | Modèle `Feed` | | ||
| 152 | +| 2.2 | High | Créer le module `config/storage.rs` | Fonctions de sauvegarde/chargement | | ||
| 153 | +| 2.3 | High | Implémenter la sérialisation/désérialisation | JSON compatible | | ||
| 154 | +| 2.4 | Medium | Ajouter la validation des URLs | Vérification format URL | | ||
| 155 | +| 2.5 | Medium | Créer le fichier de configuration par défaut | `~/.config/rss-podcast-dl/config.json` | | ||
| 156 | + | ||
| 157 | +**Fonctions clés à implémenter** : | ||
| 158 | +```rust | ||
| 159 | +// storage.rs | ||
| 160 | +pub fn save_feeds(feeds: &[Feed], config_path: &Path) -> Result<(), StorageError> | ||
| 161 | +pub fn load_feeds(config_path: &Path) -> Result<Vec<Feed>, StorageError> | ||
| 162 | +pub fn get_config_path() -> PathBuf | ||
| 163 | +``` | ||
| 164 | + | ||
| 165 | +--- | ||
| 166 | + | ||
| 167 | +### 4.3 Phase 3 : Parsing RSS et Téléchargement (Durée : 3 jours) | ||
| 168 | + | ||
| 169 | +**Objectif** : Implémenter la récupération et le parsing des flux, ainsi que le téléchargement. | ||
| 170 | + | ||
| 171 | +| Tâche | Priorité | Description | Livrable | | ||
| 172 | +|-------|----------|-------------|----------| | ||
| 173 | +| 3.1 | High | Créer `rss/parser.rs` | Parsing des flux RSS/Atom | | ||
| 174 | +| 3.2 | High | Extraire les épisodes d'un flux | Liste d'épisodes | | ||
| 175 | +| 3.3 | High | Créer `rss/downloader.rs` | Téléchargement des fichiers audio | | ||
| 176 | +| 3.4 | High | Implémenter la détection des nouveaux épisodes | Comparaison par date | | ||
| 177 | +| 3.5 | Medium | Gérer les erreurs de réseau | Retry et timeout | | ||
| 178 | +| 3.6 | Medium | Afficher la progression du téléchargement | Callback de progression | | ||
| 179 | + | ||
| 180 | +**Fonctions clés** : | ||
| 181 | +```rust | ||
| 182 | +// parser.rs | ||
| 183 | +pub async fn fetch_feed(url: &str) -> Result<RssFeed, ParserError> | ||
| 184 | +pub fn extract_episodes(feed: &RssFeed) -> Vec<Episode> | ||
| 185 | + | ||
| 186 | +// downloader.rs | ||
| 187 | +pub async fn download_episode( | ||
| 188 | + episode: &Episode, | ||
| 189 | + download_path: &Path, | ||
| 190 | + progress_callback: Box<dyn Fn(f32) + Send + Sync>, | ||
| 191 | +) -> Result<PathBuf, DownloadError> | ||
| 192 | +``` | ||
| 193 | + | ||
| 194 | +--- | ||
| 195 | + | ||
| 196 | +### 4.4 Phase 4 : Interface Utilisateur (Durée : 4 jours) | ||
| 197 | + | ||
| 198 | +**Objectif** : Créer l'interface graphique complète avec egui. | ||
| 199 | + | ||
| 200 | +| Tâche | Priorité | Description | Livrable | | ||
| 201 | +|-------|----------|-------------|----------| | ||
| 202 | +| 4.1 | High | Créer la structure de base de l'app egui | `app.rs` + `main.rs` | | ||
| 203 | +| 4.2 | High | Implémenter l'écran d'accueil | `ui/home.rs` | | ||
| 204 | +| 4.3 | High | Créer la liste des flux avec actions | `ui/feed_list.rs` | | ||
| 205 | +| 4.4 | High | Implémenter le dialogue d'ajout de flux | `ui/add_feed.rs` | | ||
| 206 | +| 4.5 | Medium | Ajouter les boutons d'action (Ajouter, Synchroniser) | Boutons fonctionnels | | ||
| 207 | +| 4.6 | Medium | Afficher les messages d'erreur/info | Notifications UI | | ||
| 208 | +| 4.7 | Medium | Ajouter une barre de progression | Visual feedback | | ||
| 209 | +| 4.8 | Low | Personnaliser le thème egui | Thème cohérent | | ||
| 210 | + | ||
| 211 | +**Structure UI** : | ||
| 212 | +``` | ||
| 213 | ++------------------------------------------+ | ||
| 214 | +| RSS Podcast Downloader [⚙️] | | ||
| 215 | ++------------------------------------------+ | ||
| 216 | +| | | ||
| 217 | +| +----------------------+ | | ||
| 218 | +| | [+ Ajouter un flux] | | | ||
| 219 | +| +----------------------+ | | ||
| 220 | +| | | ||
| 221 | +| +----------------------+ | | ||
| 222 | +| | [🔄 Synchroniser] | | | ||
| 223 | +| +----------------------+ | | ||
| 224 | +| | | ||
| 225 | +| Liste des flux configurés : | | ||
| 226 | +| +------------------------------------+ | | ||
| 227 | +| | 🎙️ Le Podcast #1 | | | ||
| 228 | +| | URL: https://... | | | ||
| 229 | +| | Dossier: ~/podcasts/lepodcast | | | ||
| 230 | +| | [✏️] [🗑️] [🔄] | | | ||
| 231 | +| +------------------------------------+ | | ||
| 232 | +| | 🎙️ Tech News | | | ||
| 233 | +| | URL: https://... | | | ||
| 234 | +| | Dossier: ~/podcasts/tech | | | ||
| 235 | +| | [✏️] [🗑️] [🔄] | | | ||
| 236 | +| +------------------------------------+ | | ||
| 237 | +| | | ||
| 238 | +| Statut: Prêt | | | ||
| 239 | ++------------------------------------------+ | ||
| 240 | +``` | ||
| 241 | + | ||
| 242 | +--- | ||
| 243 | + | ||
| 244 | +### 4.5 Phase 5 : Synchronisation (Durée : 2 jours) | ||
| 245 | + | ||
| 246 | +**Objectif** : Implémenter la logique de synchronisation complète. | ||
| 247 | + | ||
| 248 | +| Tâche | Priorité | Description | Livrable | | ||
| 249 | +|-------|----------|-------------|----------| | ||
| 250 | +| 5.1 | High | Implémenter la synchronisation d'un flux | Vérification des nouveaux épisodes | | ||
| 251 | +| 5.2 | High | Synchroniser tous les flux | Boucle sur tous les flux | | ||
| 252 | +| 5.3 | High | Mettre à jour le `last_checked` | Persistance de l'état | | ||
| 253 | +| 5.4 | Medium | Gérer les conflits de noms de fichiers | Nom unique | | ||
| 254 | +| 5.5 | Medium | Ajouter un bouton "Tout synchroniser" | Action globale | | ||
| 255 | +| 5.6 | Low | Synchronisation automatique (optionnelle) | Minuterie | | ||
| 256 | + | ||
| 257 | +**Logique de synchronisation** : | ||
| 258 | +``` | ||
| 259 | +1. Pour chaque flux activé : | ||
| 260 | + a. Récupérer le flux RSS | ||
| 261 | + b. Extraire les épisodes | ||
| 262 | + c. Comparer avec last_episode_date | ||
| 263 | + d. Télécharger les nouveaux épisodes | ||
| 264 | + e. Mettre à jour last_checked et last_episode_date | ||
| 265 | +``` | ||
| 266 | + | ||
| 267 | +--- | ||
| 268 | + | ||
| 269 | +### 4.6 Phase 6 : Intégration et Tests (Durée : 2 jours) | ||
| 270 | + | ||
| 271 | +**Objectif** : Intégrer tous les composants et tester l'application. | ||
| 272 | + | ||
| 273 | +| Tâche | Priorité | Description | Livrable | | ||
| 274 | +|-------|----------|-------------|----------| | ||
| 275 | +| 6.1 | High | Connecter UI ↔ Logique métier | Événements gérés | | ||
| 276 | +| 6.2 | High | Tester l'ajout de flux | Flux persisté | | ||
| 277 | +| 6.3 | High | Tester la synchronisation | Épisodes téléchargés | | ||
| 278 | +| 6.4 | High | Tester la suppression de flux | Flux supprimé | | ||
| 279 | +| 6.5 | Medium | Gérer les erreurs gracefully | Pas de crash | | ||
| 280 | +| 6.6 | Medium | Optimiser les performances | Réactivité UI | | ||
| 281 | +| 6.7 | Low | Ajouter des logs détaillés | Debug facilitée | | ||
| 282 | + | ||
| 283 | +--- | ||
| 284 | + | ||
| 285 | +### 4.7 Phase 7 : Finalisation (Durée : 1 jour) | ||
| 286 | + | ||
| 287 | +**Objectif** : Préparer l'application pour la distribution. | ||
| 288 | + | ||
| 289 | +| Tâche | Priorité | Description | Livrable | | ||
| 290 | +|-------|----------|-------------|----------| | ||
| 291 | +| 7.1 | Medium | Ajouter une icône | `assets/icon.png` | | ||
| 292 | +| 7.2 | Medium | Configurer le nom et version | `Cargo.toml` | | ||
| 293 | +| 7.3 | Medium | Créer un README | Documentation | | ||
| 294 | +| 7.4 | Low | Builder pour Windows/Linux | Binaires | | ||
| 295 | +| 7.5 | Low | Nettoyer le code | Code propre | | ||
| 296 | + | ||
| 297 | +--- | ||
| 298 | + | ||
| 299 | +## 5. Calendrier Global | ||
| 300 | + | ||
| 301 | +| Phase | Durée | Dates Estimées | Statut | | ||
| 302 | +|-------|-------|----------------|--------| | ||
| 303 | +| Phase 1 | 1 jour | J1 | ⬜ | | ||
| 304 | +| Phase 2 | 2 jours | J2-J3 | ⬜ | | ||
| 305 | +| Phase 3 | 3 jours | J4-J6 | ⬜ | | ||
| 306 | +| Phase 4 | 4 jours | J7-J10 | ⬜ | | ||
| 307 | +| Phase 5 | 2 jours | J11-J12 | ⬜ | | ||
| 308 | +| Phase 6 | 2 jours | J13-J14 | ⬜ | | ||
| 309 | +| Phase 7 | 1 jour | J15 | ⬜ | | ||
| 310 | +| **Total** | **15 jours** | | | | ||
| 311 | + | ||
| 312 | +--- | ||
| 313 | + | ||
| 314 | +## 6. Points d'Attention | ||
| 315 | + | ||
| 316 | +### 6.1 Risques Identifiés | ||
| 317 | + | ||
| 318 | +| Risque | Probabilité | Impact | Mitigation | | ||
| 319 | +|--------|-------------|--------|------------| | ||
| 320 | +| Problème de compatibilité avec egui 0.24 | Moyenne | Élevé | Vérifier la documentation et exemples | | ||
| 321 | +| Parsing de flux RSS non-standards | Élevée | Moyen | Utiliser la crate `rss` robuste | | ||
| 322 | +| Gestion des chemins Windows/Linux | Moyenne | Moyen | Utiliser `PathBuf` et `std::path` | | ||
| 323 | +| Performance avec beaucoup de flux | Faible | Moyen | Async/await + tokio | | ||
| 324 | + | ||
| 325 | +### 6.2 Contraintes Techniques | ||
| 326 | +- L'application doit fonctionner sans serveur (standalone) | ||
| 327 | +- Les flux doivent être stockés localement dans un fichier unique | ||
| 328 | +- L'interface doit rester réactive pendant les téléchargements | ||
| 329 | +- Les téléchargements doivent être asynchrones | ||
| 330 | + | ||
| 331 | +### 6.3 Hypothèses | ||
| 332 | +- Les flux RSS suivent les standards RSS 2.0 ou Atom | ||
| 333 | +- Les URLs des épisodes pointent vers des fichiers audio (MP3, M4A, etc.) | ||
| 334 | +- L'utilisateur a les permissions d'écriture dans les dossiers de téléchargement | ||
| 335 | +- L'application sera utilisée sur Windows et Linux | ||
| 336 | + | ||
| 337 | +--- | ||
| 338 | + | ||
| 339 | +## 7. Prochaines Étapes | ||
| 340 | + | ||
| 341 | +1. **Valider ce plan** avec les parties prenantes | ||
| 342 | +2. **Créer le projet Rust** avec la structure initiale | ||
| 343 | +3. **Commencer par la Phase 1** : Initialisation du projet | ||
| 344 | +4. **Configurer l'environnement** de développement | ||
| 345 | + | ||
| 346 | +--- | ||
| 347 | + | ||
| 348 | +*Document généré le 03/07/2026 - Version 1.0* | ||
added
spec/init-tasks.md +263 -0 | new file mode 100644 | ||
| @@ -0,0 +1,263 @@ | ||
| 1 | +# RSS Podcast Downloader - Liste Détaillée des Tâches | |
| 2 | + | |
| 3 | +*Version 1.0 - 03/07/2026* | |
| 4 | +*Dérivé de spec/init-plan.md* | |
| 5 | + | |
| 6 | +--- | |
| 7 | + | |
| 8 | +## Légende | |
| 9 | + | |
| 10 | +- **ID** : Identifiant unique de la tâche (ex: T1.1) | |
| 11 | +- **Phase** : Phase du plan global (1-7) | |
| 12 | +- **Priorité** : High (H) | Medium (M) | Low (L) | |
| 13 | +- **Durée** : Temps estimé en heures | |
| 14 | +- **Statut** : ⬜ À faire | 🟡 En cours | ✅ Terminé | ❌ Annulé | |
| 15 | +- **Fichiers** : Fichiers concernés par la tâche | |
| 16 | +- **Dépendances** : IDs des tâches requises avant celle-ci | |
| 17 | + | |
| 18 | +--- | |
| 19 | + | |
| 20 | +## Phase 1 : Initialisation du Projet | |
| 21 | + | |
| 22 | +### Objectif : Créer la structure de base du projet Rust avec egui | |
| 23 | + | |
| 24 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | |
| 25 | +|----|-------|----------|-------|---------|-------------|--------| | |
| 26 | +| T1.1 | Créer le projet Rust avec `cargo init --name rss-podcast-dl-egui` | H | 0.5h | `Cargo.toml`, `src/main.rs` | Aucune | ⬜ | | |
| 27 | +| T1.2 | Configurer `Cargo.toml` avec toutes les dépendances nécessaires | H | 1h | `Cargo.toml` | T1.1 | ⬜ | | |
| 28 | +| T1.3 | Créer la structure de dossiers (`src/config/`, `src/rss/`, `src/ui/`, `spec/`, `assets/`) | H | 0.5h | Structure de dossiers | T1.1 | ⬜ | | |
| 29 | +| T1.4 | Créer les fichiers vides pour chaque module (`mod.rs` dans chaque dossier) | H | 0.5h | `src/config/mod.rs`, `src/rss/mod.rs`, `src/ui/mod.rs` | T1.3 | ⬜ | | |
| 30 | +| T1.5 | Configurer `main.rs` avec le squelette de base eframe | H | 1h | `src/main.rs` | T1.2 | ⬜ | | |
| 31 | +| T1.6 | Initialiser le logging avec `env_logger` dans `main.rs` | M | 0.5h | `src/main.rs` | T1.5 | ⬜ | | |
| 32 | +| T1.7 | Tester la compilation de base avec `cargo check` | M | 0.5h | - | T1.6 | ⬜ | | |
| 33 | +| T1.8 | Vérifier l'exécution avec `cargo run` (fenêtre egui vide) | M | 0.5h | - | T1.7 | ⬜ | | |
| 34 | + | |
| 35 | +**Total Phase 1** : 5 heures | |
| 36 | + | |
| 37 | +--- | |
| 38 | + | |
| 39 | +## Phase 2 : Modèles et Stockage | |
| 40 | + | |
| 41 | +### Objectif : Implémenter les modèles de données et la persistance | |
| 42 | + | |
| 43 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | |
| 44 | +|----|-------|----------|-------|---------|-------------|--------| | |
| 45 | +| T2.1 | Créer `config/feed.rs` avec la structure `Feed` | H | 1h | `src/config/feed.rs` | T1.3 | ⬜ | | |
| 46 | +| T2.2 | Implémenter `Default`, `Debug`, `Clone`, `Serialize`, `Deserialize` pour `Feed` | H | 1h | `src/config/feed.rs` | T2.1 | ⬜ | | |
| 47 | +| T2.3 | Créer `config/episode.rs` avec la structure `Episode` | H | 1h | `src/config/episode.rs` | T1.3 | ⬜ | | |
| 48 | +| T2.4 | Créer `config/app_state.rs` avec la structure `AppState` | H | 1h | `src/config/app_state.rs` | T1.3 | ⬜ | | |
| 49 | +| T2.5 | Mettre à jour `config/mod.rs` pour exporter les modules | H | 0.5h | `src/config/mod.rs` | T2.1, T2.3, T2.4 | ⬜ | | |
| 50 | +| T2.6 | Créer `config/storage.rs` avec les types d'erreur (`StorageError`) | H | 1h | `src/config/storage.rs` | T2.1 | ⬜ | | |
| 51 | +| T2.7 | Implémenter `get_config_path()` pour déterminer le chemin du fichier de config | H | 1h | `src/config/storage.rs` | T2.6 | ⬜ | | |
| 52 | +| T2.8 | Implémenter `save_feeds(feeds: &[Feed], path: &Path)` | H | 2h | `src/config/storage.rs` | T2.6 | ⬜ | | |
| 53 | +| T2.9 | Implémenter `load_feeds(path: &Path) -> Result<Vec<Feed>, StorageError>` | H | 2h | `src/config/storage.rs` | T2.6 | ⬜ | | |
| 54 | +| T2.10 | Ajouter la validation de l'URL dans `Feed` (méthode `validate_url()`) | M | 1h | `src/config/feed.rs` | T2.1 | ⬜ | | |
| 55 | +| T2.11 | Ajouter la validation du chemin dans `Feed` (méthode `validate_path()`) | M | 1h | `src/config/feed.rs` | T2.1 | ⬜ | | |
| 56 | +| T2.12 | Créer un test unitaire pour `save_feeds` et `load_feeds` | M | 1h | `src/config/storage.rs` | T2.8, T2.9 | ⬜ | | |
| 57 | + | |
| 58 | +**Total Phase 2** : 14 heures (2 jours) | |
| 59 | + | |
| 60 | +--- | |
| 61 | + | |
| 62 | +## Phase 3 : Parsing RSS et Téléchargement | |
| 63 | + | |
| 64 | +### Objectif : Implémenter la récupération, le parsing des flux et le téléchargement | |
| 65 | + | |
| 66 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | |
| 67 | +|----|-------|----------|-------|---------|-------------|--------| | |
| 68 | +| T3.1 | Créer `rss/parser.rs` avec les types d'erreur (`ParserError`) | H | 1h | `src/rss/parser.rs` | T1.3 | ⬜ | | |
| 69 | +| T3.2 | Implémenter `fetch_feed(url: &str) -> Result<String, ParserError>` (récupération HTTP) | H | 2h | `src/rss/parser.rs` | T3.1 | ⬜ | | |
| 70 | +| T3.3 | Implémenter `parse_rss_content(content: &str) -> Result<RssFeed, ParserError>` | H | 2h | `src/rss/parser.rs` | T3.1 | ⬜ | | |
| 71 | +| T3.4 | Créer `rss/episode_extractor.rs` avec `extract_episodes(feed: &RssFeed) -> Vec<Episode>` | H | 3h | `src/rss/episode_extractor.rs` | T2.3, T3.3 | ⬜ | | |
| 72 | +| T3.5 | Gérer les différents formats (RSS 2.0, Atom) dans l'extraction | H | 2h | `src/rss/episode_extractor.rs` | T3.4 | ⬜ | | |
| 73 | +| T3.6 | Créer `rss/downloader.rs` avec les types d'erreur (`DownloadError`) | H | 1h | `src/rss/downloader.rs` | T1.3 | ⬜ | | |
| 74 | +| T3.7 | Implémenter `download_file(url: &str, dest: &Path) -> Result<(), DownloadError>` | H | 2h | `src/rss/downloader.rs` | T3.6 | ⬜ | | |
| 75 | +| T3.8 | Implémenter `download_episode(episode: &Episode, download_path: &Path, progress_callback: Box<dyn Fn(f32)>)` | H | 3h | `src/rss/downloader.rs` | T3.7 | ⬜ | | |
| 76 | +| T3.9 | Gérer le timeout et retry pour les requêtes HTTP | M | 2h | `src/rss/parser.rs`, `src/rss/downloader.rs` | T3.2, T3.7 | ⬜ | | |
| 77 | +| T3.10 | Créer un système de cache pour éviter de re-télécharger les mêmes épisodes | M | 2h | `src/rss/downloader.rs` | T3.8 | ⬜ | | |
| 78 | +| T3.11 | Mettre à jour `rss/mod.rs` pour exporter les modules | H | 0.5h | `src/rss/mod.rs` | T3.1, T3.4, T3.6 | ⬜ | | |
| 79 | + | |
| 80 | +**Total Phase 3** : 23 heures (3 jours) | |
| 81 | + | |
| 82 | +--- | |
| 83 | + | |
| 84 | +## Phase 4 : Interface Utilisateur | |
| 85 | + | |
| 86 | +### Objectif : Créer l'interface graphique complète avec egui | |
| 87 | + | |
| 88 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | |
| 89 | +|----|-------|----------|-------|---------|-------------|--------| | |
| 90 | +| T4.1 | Créer `app.rs` avec la structure principale de l'application | H | 2h | `src/app.rs` | T1.5, T2.4 | ⬜ | | |
| 91 | +| T4.2 | Mettre à jour `main.rs` pour utiliser `app.rs` | H | 1h | `src/main.rs` | T4.1 | ⬜ | | |
| 92 | +| T4.3 | Créer `ui/mod.rs` pour exporter les composants UI | H | 0.5h | `src/ui/mod.rs` | T1.3 | ⬜ | | |
| 93 | +| T4.4 | Créer `ui/home.rs` avec le layout principal (container, scroll area) | H | 2h | `src/ui/home.rs` | T4.1 | ⬜ | | |
| 94 | +| T4.5 | Implémenter le bouton "Ajouter un flux" dans `home.rs` | H | 2h | `src/ui/home.rs` | T4.4 | ⬜ | | |
| 95 | +| T4.6 | Implémenter le bouton "Synchroniser tous" dans `home.rs` | H | 2h | `src/ui/home.rs` | T4.4 | ⬜ | | |
| 96 | +| T4.7 | Créer `ui/feed_list.rs` pour afficher la liste des flux | H | 3h | `src/ui/feed_list.rs` | T4.1, T2.1 | ⬜ | | |
| 97 | +| T4.8 | Ajouter les actions par flux (boutons éditer, supprimer, synchroniser) | H | 3h | `src/ui/feed_list.rs` | T4.7 | ⬜ | | |
| 98 | +| T4.9 | Créer `ui/add_feed_dialog.rs` avec le formulaire d'ajout | H | 3h | `src/ui/add_feed_dialog.rs` | T4.1, T2.1 | ⬜ | | |
| 99 | +| T4.10 | Implémenter la validation du formulaire dans `add_feed_dialog.rs` | H | 2h | `src/ui/add_feed_dialog.rs` | T4.9 | ⬜ | | |
| 100 | +| T4.11 | Intégrer le dialogue d'ajout dans `home.rs` | H | 1h | `src/ui/home.rs`, `src/ui/add_feed_dialog.rs` | T4.5, T4.9 | ⬜ | | |
| 101 | +| T4.12 | Créer `ui/status_bar.rs` pour afficher les messages et progressions | M | 2h | `src/ui/status_bar.rs` | T4.1 | ⬜ | | |
| 102 | +| T4.13 | Intégrer la barre de statut dans le layout principal | M | 1h | `src/ui/home.rs`, `src/app.rs` | T4.12 | ⬜ | | |
| 103 | +| T4.14 | Créer `ui/feed_edit_dialog.rs` pour éditer un flux existant | M | 2h | `src/ui/feed_edit_dialog.rs` | T4.1, T2.1 | ⬜ | | |
| 104 | +| T4.15 | Intégrer le dialogue d'édition dans `feed_list.rs` | M | 1h | `src/ui/feed_list.rs`, `src/ui/feed_edit_dialog.rs` | T4.8, T4.14 | ⬜ | | |
| 105 | +| T4.16 | Personnaliser le thème egui (couleurs, polices) | L | 2h | `src/app.rs` | T4.1 | ⬜ | | |
| 106 | +| T4.17 | Ajouter des icônes pour les boutons (optionnel) | L | 2h | `src/ui/*` | T4.4 | ⬜ | | |
| 107 | + | |
| 108 | +**Total Phase 4** : 32 heures (4 jours) | |
| 109 | + | |
| 110 | +--- | |
| 111 | + | |
| 112 | +## Phase 5 : Synchronisation | |
| 113 | + | |
| 114 | +### Objectif : Implémenter la logique de synchronisation complète | |
| 115 | + | |
| 116 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | |
| 117 | +|----|-------|----------|-------|---------|-------------|--------| | |
| 118 | +| T5.1 | Créer `rss/sync.rs` avec les types d'erreur (`SyncError`) | H | 1h | `src/rss/sync.rs` | T1.3 | ⬜ | | |
| 119 | +| T5.2 | Implémenter `sync_feed(feed: &mut Feed) -> Result<Vec<Episode>, SyncError>` | H | 3h | `src/rss/sync.rs` | T5.1, T3.3, T3.4 | ⬜ | | |
| 120 | +| T5.3 | Implémenter `download_new_episodes(feed: &Feed, episodes: &[Episode]) -> Result<(), SyncError>` | H | 2h | `src/rss/sync.rs` | T5.2, T3.8 | ⬜ | | |
| 121 | +| T5.4 | Implémenter `sync_all_feeds(feeds: &mut [Feed]) -> Result<(), SyncError>` | H | 2h | `src/rss/sync.rs` | T5.2 | ⬜ | | |
| 122 | +| T5.5 | Mettre à jour `last_checked` et `last_episode_date` après synchronisation | H | 1h | `src/rss/sync.rs` | T5.2 | ⬜ | | |
| 123 | +| T5.6 | Gérer les conflits de noms de fichiers (ajout de suffixe) | M | 2h | `src/rss/sync.rs` | T5.3 | ⬜ | | |
| 124 | +| T5.7 | Connecter le bouton "Synchroniser" à `sync_feed` | H | 1h | `src/ui/feed_list.rs`, `src/rss/sync.rs` | T4.8, T5.2 | ⬜ | | |
| 125 | +| T5.8 | Connecter le bouton "Synchroniser tous" à `sync_all_feeds` | H | 1h | `src/ui/home.rs`, `src/rss/sync.rs` | T4.6, T5.4 | ⬜ | | |
| 126 | +| T5.9 | Mettre à jour `rss/mod.rs` pour exporter le module sync | H | 0.5h | `src/rss/mod.rs` | T5.1 | ⬜ | | |
| 127 | +| T5.10 | Implémenter la détection des épisodes déjà téléchargés | M | 2h | `src/rss/sync.rs` | T5.2 | ⬜ | | |
| 128 | + | |
| 129 | +**Total Phase 5** : 16 heures (2 jours) | |
| 130 | + | |
| 131 | +--- | |
| 132 | + | |
| 133 | +## Phase 6 : Intégration et Tests | |
| 134 | + | |
| 135 | +### Objectif : Intégrer tous les composants et tester l'application | |
| 136 | + | |
| 137 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | |
| 138 | +|----|-------|----------|-------|---------|-------------|--------| | |
| 139 | +| T6.1 | Vérifier que tous les modules compilent ensemble | H | 1h | - | Toutes les tâches précédentes | ⬜ | | |
| 140 | +| T6.2 | Tester manuellement l'ajout de flux (validation, persistance) | H | 2h | - | T2.1-T2.12, T4.5, T4.9 | ⬜ | | |
| 141 | +| T6.3 | Tester manuellement la synchronisation d'un flux | H | 2h | - | T3.1-T3.11, T5.1-T5.10 | ⬜ | | |
| 142 | +| T6.4 | Tester manuellement le téléchargement d'épisodes | H | 2h | - | T3.6-T3.10, T5.3 | ⬜ | | |
| 143 | +| T6.5 | Tester la suppression de flux | H | 1h | - | T4.7, T4.8 | ⬜ | | |
| 144 | +| T6.6 | Tester l'édition de flux | H | 1h | - | T4.14, T4.15 | ⬜ | | |
| 145 | +| T6.7 | Vérifier la gestion des erreurs (URL invalide, réseau, permissions) | M | 2h | - | Toutes | ⬜ | | |
| 146 | +| T6.8 | Optimiser les performances (pas de blocage UI pendant les téléchargements) | M | 2h | `src/app.rs`, `src/rss/*` | Toutes | ⬜ | | |
| 147 | +| T6.9 | Ajouter des logs détaillés pour le debug | M | 1h | Tous les modules | Toutes | ⬜ | | |
| 148 | +| T6.10 | Créer des tests unitaires pour les fonctions critiques | M | 4h | `src/rss/parser.rs`, `src/rss/sync.rs`, `src/config/storage.rs` | Toutes | ⬜ | | |
| 149 | +| T6.11 | Vérifier la compatibilité Windows/Linux | M | 2h | - | Toutes | ⬜ | | |
| 150 | +| T6.12 | Corriger les bugs identifiés | M | 4h | Variables | T6.1-T6.11 | ⬜ | | |
| 151 | + | |
| 152 | +**Total Phase 6** : 24 heures (3 jours révisés) | |
| 153 | + | |
| 154 | +--- | |
| 155 | + | |
| 156 | +## Phase 7 : Finalisation | |
| 157 | + | |
| 158 | +### Objectif : Préparer l'application pour la distribution | |
| 159 | + | |
| 160 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | |
| 161 | +|----|-------|----------|-------|---------|-------------|--------| | |
| 162 | +| T7.1 | Ajouter une icône pour l'application (fichier `assets/icon.png`) | M | 1h | `assets/icon.png` | T1.3 | ⬜ | | |
| 163 | +| T7.2 | Configurer le nom, version, description dans `Cargo.toml` | M | 0.5h | `Cargo.toml` | T1.2 | ⬜ | | |
| 164 | +| T7.3 | Créer un fichier `README.md` avec la documentation | M | 2h | `README.md` | Toutes | ⬜ | | |
| 165 | +| T7.4 | Configurer le build pour Windows (`cargo build --release`) | M | 1h | - | Toutes | ⬜ | | |
| 166 | +| T7.5 | Configurer le build pour Linux | M | 1h | - | Toutes | ⬜ | | |
| 167 | +| T7.6 | Nettoyer le code (supprimer les debug prints, commentaires inutiles) | L | 2h | Tous les fichiers source | Toutes | ⬜ | | |
| 168 | +| T7.7 | Vérifier les warnings de compilation | L | 1h | - | Toutes | ⬜ | | |
| 169 | +| T7.8 | Créer un fichier `.gitignore` approprié | L | 0.5h | `.gitignore` | T1.1 | ⬜ | | |
| 170 | +| T7.9 | Commiter tout le code avec des messages clairs | L | 1h | - | Toutes | ⬜ | | |
| 171 | +| T7.10 | Créer une release GitHub (optionnel) | L | 1h | - | T7.9 | ⬜ | | |
| 172 | + | |
| 173 | +**Total Phase 7** : 11 heures (1.5 jours révisés) | |
| 174 | + | |
| 175 | +--- | |
| 176 | + | |
| 177 | +## Résumé Global | |
| 178 | + | |
| 179 | +| Phase | Nombre de Tâches | Durée Totale | Statut | | |
| 180 | +|-------|------------------|--------------|--------| | |
| 181 | +| Phase 1 | 8 tâches | 5h | ⬜ | | |
| 182 | +| Phase 2 | 12 tâches | 14h | ⬜ | | |
| 183 | +| Phase 3 | 11 tâches | 23h | ⬜ | | |
| 184 | +| Phase 4 | 17 tâches | 32h | ⬜ | | |
| 185 | +| Phase 5 | 10 tâches | 16h | ⬜ | | |
| 186 | +| Phase 6 | 12 tâches | 24h | ⬜ | | |
| 187 | +| Phase 7 | 10 tâches | 11h | ⬜ | | |
| 188 | +| **Total** | **80 tâches** | **125 heures** (~16 jours) | ⬜ | | |
| 189 | + | |
| 190 | +--- | |
| 191 | + | |
| 192 | +## Ordre Recommandé de Réalisation | |
| 193 | + | |
| 194 | +### Semaine 1 (Initialisation + Modèles + Parsing) | |
| 195 | +1. T1.1 → T1.8 (Phase 1 complète) | |
| 196 | +2. T2.1 → T2.12 (Phase 2 complète) | |
| 197 | +3. T3.1 → T3.11 (Phase 3 complète) | |
| 198 | + | |
| 199 | +### Semaine 2 (UI + Synchronisation) | |
| 200 | +4. T4.1 → T4.17 (Phase 4 complète) | |
| 201 | +5. T5.1 → T5.10 (Phase 5 complète) | |
| 202 | + | |
| 203 | +### Semaine 3 (Intégration + Finalisation) | |
| 204 | +6. T6.1 → T6.12 (Phase 6 complète) | |
| 205 | +7. T7.1 → T7.10 (Phase 7 complète) | |
| 206 | + | |
| 207 | +--- | |
| 208 | + | |
| 209 | +## Conseils de Développement | |
| 210 | + | |
| 211 | +### Bonnes Pratiques | |
| 212 | +- **Commits fréquents** : Commiter après chaque tâche terminée | |
| 213 | +- **Tests unitaires** : Ajouter des tests dès que possible (surtout Phase 2 et 3) | |
| 214 | +- **Documentation** : Documenter les fonctions publiques avec `///` | |
| 215 | +- **Gestion des erreurs** : Utiliser des types d'erreur custom plutôt que `String` | |
| 216 | +- **Logging** : Utiliser `log::info!`, `log::error!`, etc. pour le debug | |
| 217 | + | |
| 218 | +### Commandes Utiles | |
| 219 | +```bash | |
| 220 | +# Vérifier la compilation | |
| 221 | +cargo check | |
| 222 | + | |
| 223 | +# Exécuter l'application | |
| 224 | +cargo run | |
| 225 | + | |
| 226 | +# Build en mode release | |
| 227 | +cargo build --release | |
| 228 | + | |
| 229 | +# Exécuter les tests | |
| 230 | +cargo test | |
| 231 | + | |
| 232 | +# Formater le code | |
| 233 | +cargo fmt | |
| 234 | + | |
| 235 | +# Analyser le code (linter) | |
| 236 | +cargo clippy | |
| 237 | +``` | |
| 238 | + | |
| 239 | +### Resources | |
| 240 | +- Documentation egui : https://docs.rs/egui/latest/egui/ | |
| 241 | +- Documentation eframe : https://docs.rs/eframe/latest/eframe/ | |
| 242 | +- Crate rss : https://docs.rs/rss/latest/rss/ | |
| 243 | +- Crate reqwest : https://docs.rs/reqwest/latest/reqwest/ | |
| 244 | + | |
| 245 | +--- | |
| 246 | + | |
| 247 | +## Suivi des Progrès | |
| 248 | + | |
| 249 | +Crée un fichier `spec/progress.md` ou utilise un outil comme GitHub Projects pour suivre l'avancement de chaque tâche. | |
| 250 | + | |
| 251 | +*Exemple de format pour progress.md* : | |
| 252 | +```markdown | |
| 253 | +## Progrès | |
| 254 | + | |
| 255 | +- [x] T1.1 - Créer le projet Rust | |
| 256 | +- [x] T1.2 - Configurer Cargo.toml | |
| 257 | +- [ ] T1.3 - Créer la structure de dossiers | |
| 258 | +... | |
| 259 | +``` | |
| 260 | + | |
| 261 | +--- | |
| 262 | + | |
| 263 | +*Document généré le 03/07/2026 - Version 1.0* | |
| new file mode 100644 | |||
| @@ -0,0 +1,263 @@ | |||
| 1 | +# RSS Podcast Downloader - Liste Détaillée des Tâches | ||
| 2 | + | ||
| 3 | +*Version 1.0 - 03/07/2026* | ||
| 4 | +*Dérivé de spec/init-plan.md* | ||
| 5 | + | ||
| 6 | +--- | ||
| 7 | + | ||
| 8 | +## Légende | ||
| 9 | + | ||
| 10 | +- **ID** : Identifiant unique de la tâche (ex: T1.1) | ||
| 11 | +- **Phase** : Phase du plan global (1-7) | ||
| 12 | +- **Priorité** : High (H) | Medium (M) | Low (L) | ||
| 13 | +- **Durée** : Temps estimé en heures | ||
| 14 | +- **Statut** : ⬜ À faire | 🟡 En cours | ✅ Terminé | ❌ Annulé | ||
| 15 | +- **Fichiers** : Fichiers concernés par la tâche | ||
| 16 | +- **Dépendances** : IDs des tâches requises avant celle-ci | ||
| 17 | + | ||
| 18 | +--- | ||
| 19 | + | ||
| 20 | +## Phase 1 : Initialisation du Projet | ||
| 21 | + | ||
| 22 | +### Objectif : Créer la structure de base du projet Rust avec egui | ||
| 23 | + | ||
| 24 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | ||
| 25 | +|----|-------|----------|-------|---------|-------------|--------| | ||
| 26 | +| T1.1 | Créer le projet Rust avec `cargo init --name rss-podcast-dl-egui` | H | 0.5h | `Cargo.toml`, `src/main.rs` | Aucune | ⬜ | | ||
| 27 | +| T1.2 | Configurer `Cargo.toml` avec toutes les dépendances nécessaires | H | 1h | `Cargo.toml` | T1.1 | ⬜ | | ||
| 28 | +| T1.3 | Créer la structure de dossiers (`src/config/`, `src/rss/`, `src/ui/`, `spec/`, `assets/`) | H | 0.5h | Structure de dossiers | T1.1 | ⬜ | | ||
| 29 | +| T1.4 | Créer les fichiers vides pour chaque module (`mod.rs` dans chaque dossier) | H | 0.5h | `src/config/mod.rs`, `src/rss/mod.rs`, `src/ui/mod.rs` | T1.3 | ⬜ | | ||
| 30 | +| T1.5 | Configurer `main.rs` avec le squelette de base eframe | H | 1h | `src/main.rs` | T1.2 | ⬜ | | ||
| 31 | +| T1.6 | Initialiser le logging avec `env_logger` dans `main.rs` | M | 0.5h | `src/main.rs` | T1.5 | ⬜ | | ||
| 32 | +| T1.7 | Tester la compilation de base avec `cargo check` | M | 0.5h | - | T1.6 | ⬜ | | ||
| 33 | +| T1.8 | Vérifier l'exécution avec `cargo run` (fenêtre egui vide) | M | 0.5h | - | T1.7 | ⬜ | | ||
| 34 | + | ||
| 35 | +**Total Phase 1** : 5 heures | ||
| 36 | + | ||
| 37 | +--- | ||
| 38 | + | ||
| 39 | +## Phase 2 : Modèles et Stockage | ||
| 40 | + | ||
| 41 | +### Objectif : Implémenter les modèles de données et la persistance | ||
| 42 | + | ||
| 43 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | ||
| 44 | +|----|-------|----------|-------|---------|-------------|--------| | ||
| 45 | +| T2.1 | Créer `config/feed.rs` avec la structure `Feed` | H | 1h | `src/config/feed.rs` | T1.3 | ⬜ | | ||
| 46 | +| T2.2 | Implémenter `Default`, `Debug`, `Clone`, `Serialize`, `Deserialize` pour `Feed` | H | 1h | `src/config/feed.rs` | T2.1 | ⬜ | | ||
| 47 | +| T2.3 | Créer `config/episode.rs` avec la structure `Episode` | H | 1h | `src/config/episode.rs` | T1.3 | ⬜ | | ||
| 48 | +| T2.4 | Créer `config/app_state.rs` avec la structure `AppState` | H | 1h | `src/config/app_state.rs` | T1.3 | ⬜ | | ||
| 49 | +| T2.5 | Mettre à jour `config/mod.rs` pour exporter les modules | H | 0.5h | `src/config/mod.rs` | T2.1, T2.3, T2.4 | ⬜ | | ||
| 50 | +| T2.6 | Créer `config/storage.rs` avec les types d'erreur (`StorageError`) | H | 1h | `src/config/storage.rs` | T2.1 | ⬜ | | ||
| 51 | +| T2.7 | Implémenter `get_config_path()` pour déterminer le chemin du fichier de config | H | 1h | `src/config/storage.rs` | T2.6 | ⬜ | | ||
| 52 | +| T2.8 | Implémenter `save_feeds(feeds: &[Feed], path: &Path)` | H | 2h | `src/config/storage.rs` | T2.6 | ⬜ | | ||
| 53 | +| T2.9 | Implémenter `load_feeds(path: &Path) -> Result<Vec<Feed>, StorageError>` | H | 2h | `src/config/storage.rs` | T2.6 | ⬜ | | ||
| 54 | +| T2.10 | Ajouter la validation de l'URL dans `Feed` (méthode `validate_url()`) | M | 1h | `src/config/feed.rs` | T2.1 | ⬜ | | ||
| 55 | +| T2.11 | Ajouter la validation du chemin dans `Feed` (méthode `validate_path()`) | M | 1h | `src/config/feed.rs` | T2.1 | ⬜ | | ||
| 56 | +| T2.12 | Créer un test unitaire pour `save_feeds` et `load_feeds` | M | 1h | `src/config/storage.rs` | T2.8, T2.9 | ⬜ | | ||
| 57 | + | ||
| 58 | +**Total Phase 2** : 14 heures (2 jours) | ||
| 59 | + | ||
| 60 | +--- | ||
| 61 | + | ||
| 62 | +## Phase 3 : Parsing RSS et Téléchargement | ||
| 63 | + | ||
| 64 | +### Objectif : Implémenter la récupération, le parsing des flux et le téléchargement | ||
| 65 | + | ||
| 66 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | ||
| 67 | +|----|-------|----------|-------|---------|-------------|--------| | ||
| 68 | +| T3.1 | Créer `rss/parser.rs` avec les types d'erreur (`ParserError`) | H | 1h | `src/rss/parser.rs` | T1.3 | ⬜ | | ||
| 69 | +| T3.2 | Implémenter `fetch_feed(url: &str) -> Result<String, ParserError>` (récupération HTTP) | H | 2h | `src/rss/parser.rs` | T3.1 | ⬜ | | ||
| 70 | +| T3.3 | Implémenter `parse_rss_content(content: &str) -> Result<RssFeed, ParserError>` | H | 2h | `src/rss/parser.rs` | T3.1 | ⬜ | | ||
| 71 | +| T3.4 | Créer `rss/episode_extractor.rs` avec `extract_episodes(feed: &RssFeed) -> Vec<Episode>` | H | 3h | `src/rss/episode_extractor.rs` | T2.3, T3.3 | ⬜ | | ||
| 72 | +| T3.5 | Gérer les différents formats (RSS 2.0, Atom) dans l'extraction | H | 2h | `src/rss/episode_extractor.rs` | T3.4 | ⬜ | | ||
| 73 | +| T3.6 | Créer `rss/downloader.rs` avec les types d'erreur (`DownloadError`) | H | 1h | `src/rss/downloader.rs` | T1.3 | ⬜ | | ||
| 74 | +| T3.7 | Implémenter `download_file(url: &str, dest: &Path) -> Result<(), DownloadError>` | H | 2h | `src/rss/downloader.rs` | T3.6 | ⬜ | | ||
| 75 | +| T3.8 | Implémenter `download_episode(episode: &Episode, download_path: &Path, progress_callback: Box<dyn Fn(f32)>)` | H | 3h | `src/rss/downloader.rs` | T3.7 | ⬜ | | ||
| 76 | +| T3.9 | Gérer le timeout et retry pour les requêtes HTTP | M | 2h | `src/rss/parser.rs`, `src/rss/downloader.rs` | T3.2, T3.7 | ⬜ | | ||
| 77 | +| T3.10 | Créer un système de cache pour éviter de re-télécharger les mêmes épisodes | M | 2h | `src/rss/downloader.rs` | T3.8 | ⬜ | | ||
| 78 | +| T3.11 | Mettre à jour `rss/mod.rs` pour exporter les modules | H | 0.5h | `src/rss/mod.rs` | T3.1, T3.4, T3.6 | ⬜ | | ||
| 79 | + | ||
| 80 | +**Total Phase 3** : 23 heures (3 jours) | ||
| 81 | + | ||
| 82 | +--- | ||
| 83 | + | ||
| 84 | +## Phase 4 : Interface Utilisateur | ||
| 85 | + | ||
| 86 | +### Objectif : Créer l'interface graphique complète avec egui | ||
| 87 | + | ||
| 88 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | ||
| 89 | +|----|-------|----------|-------|---------|-------------|--------| | ||
| 90 | +| T4.1 | Créer `app.rs` avec la structure principale de l'application | H | 2h | `src/app.rs` | T1.5, T2.4 | ⬜ | | ||
| 91 | +| T4.2 | Mettre à jour `main.rs` pour utiliser `app.rs` | H | 1h | `src/main.rs` | T4.1 | ⬜ | | ||
| 92 | +| T4.3 | Créer `ui/mod.rs` pour exporter les composants UI | H | 0.5h | `src/ui/mod.rs` | T1.3 | ⬜ | | ||
| 93 | +| T4.4 | Créer `ui/home.rs` avec le layout principal (container, scroll area) | H | 2h | `src/ui/home.rs` | T4.1 | ⬜ | | ||
| 94 | +| T4.5 | Implémenter le bouton "Ajouter un flux" dans `home.rs` | H | 2h | `src/ui/home.rs` | T4.4 | ⬜ | | ||
| 95 | +| T4.6 | Implémenter le bouton "Synchroniser tous" dans `home.rs` | H | 2h | `src/ui/home.rs` | T4.4 | ⬜ | | ||
| 96 | +| T4.7 | Créer `ui/feed_list.rs` pour afficher la liste des flux | H | 3h | `src/ui/feed_list.rs` | T4.1, T2.1 | ⬜ | | ||
| 97 | +| T4.8 | Ajouter les actions par flux (boutons éditer, supprimer, synchroniser) | H | 3h | `src/ui/feed_list.rs` | T4.7 | ⬜ | | ||
| 98 | +| T4.9 | Créer `ui/add_feed_dialog.rs` avec le formulaire d'ajout | H | 3h | `src/ui/add_feed_dialog.rs` | T4.1, T2.1 | ⬜ | | ||
| 99 | +| T4.10 | Implémenter la validation du formulaire dans `add_feed_dialog.rs` | H | 2h | `src/ui/add_feed_dialog.rs` | T4.9 | ⬜ | | ||
| 100 | +| T4.11 | Intégrer le dialogue d'ajout dans `home.rs` | H | 1h | `src/ui/home.rs`, `src/ui/add_feed_dialog.rs` | T4.5, T4.9 | ⬜ | | ||
| 101 | +| T4.12 | Créer `ui/status_bar.rs` pour afficher les messages et progressions | M | 2h | `src/ui/status_bar.rs` | T4.1 | ⬜ | | ||
| 102 | +| T4.13 | Intégrer la barre de statut dans le layout principal | M | 1h | `src/ui/home.rs`, `src/app.rs` | T4.12 | ⬜ | | ||
| 103 | +| T4.14 | Créer `ui/feed_edit_dialog.rs` pour éditer un flux existant | M | 2h | `src/ui/feed_edit_dialog.rs` | T4.1, T2.1 | ⬜ | | ||
| 104 | +| T4.15 | Intégrer le dialogue d'édition dans `feed_list.rs` | M | 1h | `src/ui/feed_list.rs`, `src/ui/feed_edit_dialog.rs` | T4.8, T4.14 | ⬜ | | ||
| 105 | +| T4.16 | Personnaliser le thème egui (couleurs, polices) | L | 2h | `src/app.rs` | T4.1 | ⬜ | | ||
| 106 | +| T4.17 | Ajouter des icônes pour les boutons (optionnel) | L | 2h | `src/ui/*` | T4.4 | ⬜ | | ||
| 107 | + | ||
| 108 | +**Total Phase 4** : 32 heures (4 jours) | ||
| 109 | + | ||
| 110 | +--- | ||
| 111 | + | ||
| 112 | +## Phase 5 : Synchronisation | ||
| 113 | + | ||
| 114 | +### Objectif : Implémenter la logique de synchronisation complète | ||
| 115 | + | ||
| 116 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | ||
| 117 | +|----|-------|----------|-------|---------|-------------|--------| | ||
| 118 | +| T5.1 | Créer `rss/sync.rs` avec les types d'erreur (`SyncError`) | H | 1h | `src/rss/sync.rs` | T1.3 | ⬜ | | ||
| 119 | +| T5.2 | Implémenter `sync_feed(feed: &mut Feed) -> Result<Vec<Episode>, SyncError>` | H | 3h | `src/rss/sync.rs` | T5.1, T3.3, T3.4 | ⬜ | | ||
| 120 | +| T5.3 | Implémenter `download_new_episodes(feed: &Feed, episodes: &[Episode]) -> Result<(), SyncError>` | H | 2h | `src/rss/sync.rs` | T5.2, T3.8 | ⬜ | | ||
| 121 | +| T5.4 | Implémenter `sync_all_feeds(feeds: &mut [Feed]) -> Result<(), SyncError>` | H | 2h | `src/rss/sync.rs` | T5.2 | ⬜ | | ||
| 122 | +| T5.5 | Mettre à jour `last_checked` et `last_episode_date` après synchronisation | H | 1h | `src/rss/sync.rs` | T5.2 | ⬜ | | ||
| 123 | +| T5.6 | Gérer les conflits de noms de fichiers (ajout de suffixe) | M | 2h | `src/rss/sync.rs` | T5.3 | ⬜ | | ||
| 124 | +| T5.7 | Connecter le bouton "Synchroniser" à `sync_feed` | H | 1h | `src/ui/feed_list.rs`, `src/rss/sync.rs` | T4.8, T5.2 | ⬜ | | ||
| 125 | +| T5.8 | Connecter le bouton "Synchroniser tous" à `sync_all_feeds` | H | 1h | `src/ui/home.rs`, `src/rss/sync.rs` | T4.6, T5.4 | ⬜ | | ||
| 126 | +| T5.9 | Mettre à jour `rss/mod.rs` pour exporter le module sync | H | 0.5h | `src/rss/mod.rs` | T5.1 | ⬜ | | ||
| 127 | +| T5.10 | Implémenter la détection des épisodes déjà téléchargés | M | 2h | `src/rss/sync.rs` | T5.2 | ⬜ | | ||
| 128 | + | ||
| 129 | +**Total Phase 5** : 16 heures (2 jours) | ||
| 130 | + | ||
| 131 | +--- | ||
| 132 | + | ||
| 133 | +## Phase 6 : Intégration et Tests | ||
| 134 | + | ||
| 135 | +### Objectif : Intégrer tous les composants et tester l'application | ||
| 136 | + | ||
| 137 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | ||
| 138 | +|----|-------|----------|-------|---------|-------------|--------| | ||
| 139 | +| T6.1 | Vérifier que tous les modules compilent ensemble | H | 1h | - | Toutes les tâches précédentes | ⬜ | | ||
| 140 | +| T6.2 | Tester manuellement l'ajout de flux (validation, persistance) | H | 2h | - | T2.1-T2.12, T4.5, T4.9 | ⬜ | | ||
| 141 | +| T6.3 | Tester manuellement la synchronisation d'un flux | H | 2h | - | T3.1-T3.11, T5.1-T5.10 | ⬜ | | ||
| 142 | +| T6.4 | Tester manuellement le téléchargement d'épisodes | H | 2h | - | T3.6-T3.10, T5.3 | ⬜ | | ||
| 143 | +| T6.5 | Tester la suppression de flux | H | 1h | - | T4.7, T4.8 | ⬜ | | ||
| 144 | +| T6.6 | Tester l'édition de flux | H | 1h | - | T4.14, T4.15 | ⬜ | | ||
| 145 | +| T6.7 | Vérifier la gestion des erreurs (URL invalide, réseau, permissions) | M | 2h | - | Toutes | ⬜ | | ||
| 146 | +| T6.8 | Optimiser les performances (pas de blocage UI pendant les téléchargements) | M | 2h | `src/app.rs`, `src/rss/*` | Toutes | ⬜ | | ||
| 147 | +| T6.9 | Ajouter des logs détaillés pour le debug | M | 1h | Tous les modules | Toutes | ⬜ | | ||
| 148 | +| T6.10 | Créer des tests unitaires pour les fonctions critiques | M | 4h | `src/rss/parser.rs`, `src/rss/sync.rs`, `src/config/storage.rs` | Toutes | ⬜ | | ||
| 149 | +| T6.11 | Vérifier la compatibilité Windows/Linux | M | 2h | - | Toutes | ⬜ | | ||
| 150 | +| T6.12 | Corriger les bugs identifiés | M | 4h | Variables | T6.1-T6.11 | ⬜ | | ||
| 151 | + | ||
| 152 | +**Total Phase 6** : 24 heures (3 jours révisés) | ||
| 153 | + | ||
| 154 | +--- | ||
| 155 | + | ||
| 156 | +## Phase 7 : Finalisation | ||
| 157 | + | ||
| 158 | +### Objectif : Préparer l'application pour la distribution | ||
| 159 | + | ||
| 160 | +| ID | Tâche | Priorité | Durée | Fichiers | Dépendances | Statut | | ||
| 161 | +|----|-------|----------|-------|---------|-------------|--------| | ||
| 162 | +| T7.1 | Ajouter une icône pour l'application (fichier `assets/icon.png`) | M | 1h | `assets/icon.png` | T1.3 | ⬜ | | ||
| 163 | +| T7.2 | Configurer le nom, version, description dans `Cargo.toml` | M | 0.5h | `Cargo.toml` | T1.2 | ⬜ | | ||
| 164 | +| T7.3 | Créer un fichier `README.md` avec la documentation | M | 2h | `README.md` | Toutes | ⬜ | | ||
| 165 | +| T7.4 | Configurer le build pour Windows (`cargo build --release`) | M | 1h | - | Toutes | ⬜ | | ||
| 166 | +| T7.5 | Configurer le build pour Linux | M | 1h | - | Toutes | ⬜ | | ||
| 167 | +| T7.6 | Nettoyer le code (supprimer les debug prints, commentaires inutiles) | L | 2h | Tous les fichiers source | Toutes | ⬜ | | ||
| 168 | +| T7.7 | Vérifier les warnings de compilation | L | 1h | - | Toutes | ⬜ | | ||
| 169 | +| T7.8 | Créer un fichier `.gitignore` approprié | L | 0.5h | `.gitignore` | T1.1 | ⬜ | | ||
| 170 | +| T7.9 | Commiter tout le code avec des messages clairs | L | 1h | - | Toutes | ⬜ | | ||
| 171 | +| T7.10 | Créer une release GitHub (optionnel) | L | 1h | - | T7.9 | ⬜ | | ||
| 172 | + | ||
| 173 | +**Total Phase 7** : 11 heures (1.5 jours révisés) | ||
| 174 | + | ||
| 175 | +--- | ||
| 176 | + | ||
| 177 | +## Résumé Global | ||
| 178 | + | ||
| 179 | +| Phase | Nombre de Tâches | Durée Totale | Statut | | ||
| 180 | +|-------|------------------|--------------|--------| | ||
| 181 | +| Phase 1 | 8 tâches | 5h | ⬜ | | ||
| 182 | +| Phase 2 | 12 tâches | 14h | ⬜ | | ||
| 183 | +| Phase 3 | 11 tâches | 23h | ⬜ | | ||
| 184 | +| Phase 4 | 17 tâches | 32h | ⬜ | | ||
| 185 | +| Phase 5 | 10 tâches | 16h | ⬜ | | ||
| 186 | +| Phase 6 | 12 tâches | 24h | ⬜ | | ||
| 187 | +| Phase 7 | 10 tâches | 11h | ⬜ | | ||
| 188 | +| **Total** | **80 tâches** | **125 heures** (~16 jours) | ⬜ | | ||
| 189 | + | ||
| 190 | +--- | ||
| 191 | + | ||
| 192 | +## Ordre Recommandé de Réalisation | ||
| 193 | + | ||
| 194 | +### Semaine 1 (Initialisation + Modèles + Parsing) | ||
| 195 | +1. T1.1 → T1.8 (Phase 1 complète) | ||
| 196 | +2. T2.1 → T2.12 (Phase 2 complète) | ||
| 197 | +3. T3.1 → T3.11 (Phase 3 complète) | ||
| 198 | + | ||
| 199 | +### Semaine 2 (UI + Synchronisation) | ||
| 200 | +4. T4.1 → T4.17 (Phase 4 complète) | ||
| 201 | +5. T5.1 → T5.10 (Phase 5 complète) | ||
| 202 | + | ||
| 203 | +### Semaine 3 (Intégration + Finalisation) | ||
| 204 | +6. T6.1 → T6.12 (Phase 6 complète) | ||
| 205 | +7. T7.1 → T7.10 (Phase 7 complète) | ||
| 206 | + | ||
| 207 | +--- | ||
| 208 | + | ||
| 209 | +## Conseils de Développement | ||
| 210 | + | ||
| 211 | +### Bonnes Pratiques | ||
| 212 | +- **Commits fréquents** : Commiter après chaque tâche terminée | ||
| 213 | +- **Tests unitaires** : Ajouter des tests dès que possible (surtout Phase 2 et 3) | ||
| 214 | +- **Documentation** : Documenter les fonctions publiques avec `///` | ||
| 215 | +- **Gestion des erreurs** : Utiliser des types d'erreur custom plutôt que `String` | ||
| 216 | +- **Logging** : Utiliser `log::info!`, `log::error!`, etc. pour le debug | ||
| 217 | + | ||
| 218 | +### Commandes Utiles | ||
| 219 | +```bash | ||
| 220 | +# Vérifier la compilation | ||
| 221 | +cargo check | ||
| 222 | + | ||
| 223 | +# Exécuter l'application | ||
| 224 | +cargo run | ||
| 225 | + | ||
| 226 | +# Build en mode release | ||
| 227 | +cargo build --release | ||
| 228 | + | ||
| 229 | +# Exécuter les tests | ||
| 230 | +cargo test | ||
| 231 | + | ||
| 232 | +# Formater le code | ||
| 233 | +cargo fmt | ||
| 234 | + | ||
| 235 | +# Analyser le code (linter) | ||
| 236 | +cargo clippy | ||
| 237 | +``` | ||
| 238 | + | ||
| 239 | +### Resources | ||
| 240 | +- Documentation egui : https://docs.rs/egui/latest/egui/ | ||
| 241 | +- Documentation eframe : https://docs.rs/eframe/latest/eframe/ | ||
| 242 | +- Crate rss : https://docs.rs/rss/latest/rss/ | ||
| 243 | +- Crate reqwest : https://docs.rs/reqwest/latest/reqwest/ | ||
| 244 | + | ||
| 245 | +--- | ||
| 246 | + | ||
| 247 | +## Suivi des Progrès | ||
| 248 | + | ||
| 249 | +Crée un fichier `spec/progress.md` ou utilise un outil comme GitHub Projects pour suivre l'avancement de chaque tâche. | ||
| 250 | + | ||
| 251 | +*Exemple de format pour progress.md* : | ||
| 252 | +```markdown | ||
| 253 | +## Progrès | ||
| 254 | + | ||
| 255 | +- [x] T1.1 - Créer le projet Rust | ||
| 256 | +- [x] T1.2 - Configurer Cargo.toml | ||
| 257 | +- [ ] T1.3 - Créer la structure de dossiers | ||
| 258 | +... | ||
| 259 | +``` | ||
| 260 | + | ||
| 261 | +--- | ||
| 262 | + | ||
| 263 | +*Document généré le 03/07/2026 - Version 1.0* | ||