# 🎧 Cachette > Mettez la musique et les vidĂ©os **de cĂŽtĂ©** pendant que vous avez du rĂ©seau. Écoutez-les quand vous n'en avez plus. [![Platform](https://img.shields.io/badge/Plateforme-Android%208.0%2B-3DDC84?logo=android&logoColor=white)](https://developer.android.com) [![Kotlin](https://img.shields.io/badge/Kotlin-2.1.0-7F52FF?logo=kotlin&logoColor=white)](https://kotlinlang.org) [![Compose](https://img.shields.io/badge/Jetpack%20Compose-Material%203-4285F4?logo=jetpackcompose&logoColor=white)](https://developer.android.com/jetpack/compose) [![Media3](https://img.shields.io/badge/Media3-1.11.1-FF6F00?logo=googleplay&logoColor=white)](https://developer.android.com/media/media3) [![Version](https://img.shields.io/badge/Version-1.2.0-6B4EFF)](VERSION) [![Hors ligne](https://img.shields.io/badge/Hors%20ligne-100%25-3FD8C0)](#-comment-ça-marche) Cachette est un lecteur audio et vidĂ©o pensĂ© pour les trajets, les tunnels, les avions et les forfaits Ă©puisĂ©s. On choisit ce qu'on emporte, l'application le tĂ©lĂ©charge, et tout reste lisible sans la moindre connexion. --- ## 📾 Aperçu | BibliothĂšque | Lecture | Hors ligne | Catalogues libres | |:---:|:---:|:---:|:---:| | ![BibliothĂšque](docs/screenshots/bibliotheque.png) | ![Lecture](docs/screenshots/lecture.png) | ![Hors ligne](docs/screenshots/hors-ligne.png) | ![Catalogue](docs/screenshots/catalogue.png) | --- ## ✹ FonctionnalitĂ©s | | | |---|---| | đŸŽ” **Audio et vidĂ©o** | Un seul lecteur, une seule file d'attente, la vidĂ©o bascule sur une surface dĂ©diĂ©e | | đŸ“„ **Mise en cache explicite** | Rien n'est tĂ©lĂ©chargĂ© sans un geste : vous dĂ©cidez quoi garder | | 🔍 **Parcours des sources** | On entre dans une source, on coche ce qu'on veut, on tĂ©lĂ©charge en lot | | 🎧 **Écoute avant tĂ©lĂ©chargement** | Chaque piste s'essaie en ligne d'un appui, sans rien mettre en cache | | đŸ§Ÿ **Choix piste par piste** | Un album ou un livre affiche ses pistes avec leur taille : on n'emporte que ce qu'on veut | | 🌍 **Filtrage par langue** | Français, anglais, allemand, espagnol, italien, nĂ©erlandais | | 📋 **Playlists** | Listes nommĂ©es, appui long pour y ajouter un titre, lecture enchaĂźnĂ©e | | đŸŽŒ **Catalogues libres de droits** | Recherche intĂ©grĂ©e dans Internet Archive et LibriVox, sans compte ni clĂ© d'API | | đŸ“» **Podcasts RSS** | Un flux, ses Ă©pisodes, et le choix de ceux qu'on emporte | | 🔗 **Liens directs** | N'importe quelle URL audio ou vidĂ©o, y compris un serveur mĂ©dia auto-hĂ©bergĂ© | | đŸ“± **Contenu de l'appareil** | Lecture de la bibliothĂšque MediaStore, dĂ©jĂ  disponible hors connexion par nature | | đŸŽ›ïž **Lecture en arriĂšre-plan** | Notification systĂšme, casque, Bluetooth, Ă©cran verrouillĂ© | | âŻïž **ContrĂŽles complets** | Lecture, pause, arrĂȘt, piste prĂ©cĂ©dente et suivante, ±15 s | | 🌙 **ThĂšme clair et sombre** | Material 3, palette de marque, contraste garanti | | 🔁 **Reprise automatique** | Un tĂ©lĂ©chargement coupĂ© repart tout seul via WorkManager | | 🆕 **Mise Ă  jour intĂ©grĂ©e** | Surveille les releases du dĂ©pĂŽt, tĂ©lĂ©charge l'APK en Wi-Fi et propose l'installation | --- ## 📩 Sources disponibles | Source | État | DĂ©tail | |---|:---:|---| | đŸ“± Appareil | ✅ | Musique et vidĂ©os MediaStore | | 🔗 Lien direct | ✅ | URL `http(s)` vers un fichier audio ou vidĂ©o | | đŸ“» Podcast RSS | ✅ | Flux standard avec `` | | đŸ›ïž Internet Archive | ✅ | Domaine public / Creative Commons | | 📚 LibriVox | ✅ | Livres audio du domaine public, filtrables par langue | | đŸŽŒ Wikimedia Commons | ✅ | Enregistrements classiques et archives sonores libres | ### 🔎 Catalogues Ă©valuĂ©s puis Ă©cartĂ©s | Candidat | Pourquoi non | |---|---| | **Openverse** | A cessĂ© de servir l'accĂšs anonyme : **401 sur huit requĂȘtes sur huit**, et jusqu'Ă  21 s de latence quand il rĂ©pondait encore. Exige dĂ©sormais une inscription. | | **ccMixter** | La recherche fonctionne, mais les fichiers ne sont servis qu'avec un en-tĂȘte `Referer` — que Media3 ne permet pas de poser par tĂ©lĂ©chargement. | | **Radio Browser** | Flux radio continus : rien Ă  mettre en cache. | ### ⚖ Ce que Cachette ne fait pas — et pourquoi | Service | Pourquoi | |---|---| | đŸŽ” **Spotify** | Le SDK ne donne aucun accĂšs au flux audio. Le hors-ligne n'existe que dans l'application Spotify. Un podcast Ă©galement diffusĂ© en RSS public reste ajoutable. | | ▶ **YouTube** | Les conditions d'utilisation interdisent d'extraire ou de stocker les flux. Le hors-ligne passe par YouTube Premium. | | ☁ **Google Drive / Photos** | Techniquement faisable pour vos propres fichiers, mais cela exige un identifiant OAuth Google liĂ© Ă  votre compte dĂ©veloppeur, volontairement non embarquĂ© ici. | C'est un choix assumĂ© : l'application ne contourne rien, elle travaille avec les sources qui autorisent la copie locale. --- ## 🧭 Comment ça marche ``` Source ──â–ș BibliothĂšque ──â–ș [ Garder ] ──â–ș Cache Media3 ──â–ș Lecture hors ligne │ reprise auto (WorkManager) ``` Trois propriĂ©taires de donnĂ©es, aucun doublon : - **MediaStore** possĂšde le contenu local — on le relit, on ne le recopie pas ; - **`imported.json`** possĂšde les seules rĂ©fĂ©rences distantes ajoutĂ©es Ă  la main ; - **l'index Media3** possĂšde l'Ă©tat du cache — taille, progression, complĂ©tude. Le cache utilise un `NoOpCacheEvictor` : il contient **exactement** ce que vous avez demandĂ© Ă  garder, et rien n'en est effacĂ© sans votre geste. La lecture lit ce cache mais n'y Ă©crit jamais, pour qu'une Ă©coute en ligne ne le fasse pas gonfler Ă  votre insu. --- ## 🚀 DĂ©marrage ### PrĂ©requis - ☕ JDK 17 - đŸ€– Android SDK avec la plateforme **36** et les build-tools 36 - đŸ“± Un appareil ou un Ă©mulateur en **Android 8.0 (API 26)** ou plus ### Construire ```bash make build # APK de debug make install # installe sur l'appareil connectĂ© make run # installe et lance make lint # analyse Android Lint make release # APK de release (signĂ© si keystore.properties existe) make publish # release Gitea : tag + notes + APK signĂ© make publish-dry # simulation, sans rien envoyer make deploy # release puis publish ``` `make help` liste toutes les cibles, groupĂ©es par catĂ©gorie. Sans `make`, les commandes Gradle Ă©quivalentes fonctionnent : ```bash ./gradlew assembleDebug ./gradlew installDebug ``` L'APK se trouve dans `app/build/outputs/apk/debug/app-debug.apk`. ### Signer une version de publication CrĂ©ez un `keystore.properties` Ă  la racine — il est ignorĂ© par git : ```properties storeFile=cachette.jks storePassword=... keyAlias=cachette keyPassword=... ``` ### đŸ“€ Publier une version `make publish` crĂ©e le tag, la release Gitea et y attache l'APK **signĂ©**. La cible est idempotente : relancĂ©e sur une version dĂ©jĂ  publiĂ©e, elle rĂ©utilise la release et remplace l'asset. `make publish-dry` rĂ©pĂšte l'opĂ©ration Ă  blanc. La publication dĂ©lĂšgue Ă  `gitea_release.sh` de **BorisSkill**, qui dĂ©duit l'hĂŽte, le propriĂ©taire et le dĂ©pĂŽt du remote `origin` — il n'y a donc aucun nom de dĂ©pĂŽt Ă  configurer ici. Le chemin du script est surchargeable : `make publish GITEA_RELEASE=/chemin/gitea_release.sh`. PrĂ©requis : | ÉlĂ©ment | RĂŽle | |---|---| | `VERSION` | Source unique de la version — `versionCode` en est dĂ©duit (`1.0.0` → `10000`) | | `CHANGELOG.md` | La section `## [x.y.z]` devient le corps des notes de release | | `keystore.properties` | Signature — sans lui l'APK est `-unsigned` et refusĂ© Ă  la publication | | DĂ©pĂŽt git | Un `origin` configurĂ© : le tag `vx.y.z` y est poussĂ© | Le jeton Gitea est rĂ©solu dans l'ordre : `$GITEA_TOKEN`, `.gitea-token` Ă  la racine du dĂ©pĂŽt, `~/.config/gitea/token`, puis repli sur `~/.git-credentials`. Aucun secret n'est stockĂ© dans ce dĂ©pĂŽt. Pour monter de version, Ă©ditez `VERSION` et ajoutez la section correspondante au `CHANGELOG.md` : Gradle, le tag git et les notes de release suivront seuls. --- ## 🔐 Permissions et vie privĂ©e | Permission | Pourquoi | |---|---| | `READ_MEDIA_AUDIO` / `READ_MEDIA_VIDEO` | Lister la musique et les vidĂ©os de l'appareil | | `INTERNET` | TĂ©lĂ©charger ce que vous avez choisi de garder | | `POST_NOTIFICATIONS` | Commandes de lecture et progression des tĂ©lĂ©chargements | | `FOREGROUND_SERVICE_*` | Continuer la lecture et les tĂ©lĂ©chargements Ă©cran Ă©teint | | `REQUEST_INSTALL_PACKAGES` | Proposer l'installation d'une mise Ă  jour tĂ©lĂ©chargĂ©e | Aucune donnĂ©e ne quitte l'appareil : pas de compte, pas de tĂ©lĂ©mĂ©trie, pas de sauvegarde cloud (`dataExtractionRules` exclut explicitement le contenu mis en cache). Les seules connexions sortantes sont celles des URL que vous ajoutez et des catalogues que vous interrogez. > ⚠ `usesCleartextTraffic` est activĂ© pour permettre l'usage d'un serveur mĂ©dia auto-hĂ©bergĂ© en > `http://` sur le rĂ©seau local. C'est un compromis assumĂ© ; prĂ©fĂ©rez `https` dĂšs que possible. --- ## 🆕 Mises Ă  jour Cachette Ă©tant distribuĂ©e hors magasin, elle surveille elle-mĂȘme les releases du dĂ©pĂŽt. ``` Release publiĂ©e ──â–ș vĂ©rification quotidienne (WorkManager, Wi-Fi) │ ├─ version plus rĂ©cente ? ──â–ș tĂ©lĂ©chargement de l'APK │ │ └─ sinon : rien â–Œ notification « prĂȘte Ă  installer » │ installation = geste utilisateur ``` L'installation reste un geste explicite : Android l'impose Ă  toute application hors magasin. L'Ă©cran **Sources** porte la mĂȘme vĂ©rification Ă  la demande, et affiche la version installĂ©e. Le dĂ©pĂŽt Ă©tant privĂ©, la lecture des releases demande un jeton. Il est lu depuis `update-token.properties` (ignorĂ© par git) et injectĂ© dans `BuildConfig` Ă  la compilation : ```properties giteaUpdateToken=
 ``` > ⚠ Un jeton embarquĂ© dans un APK est extractible. Celui-ci est volontairement limitĂ© Ă  la portĂ©e > `read:repository` et rĂ©vocable depuis Gitea. Il donne un accĂšs en lecture aux dĂ©pĂŽts du compte — > ne pas lui accorder davantage. --- ## đŸ—‚ïž Structure ``` app/src/main/java/fr/tuxgyver/cachette/ ├── CachetteApp.kt Application + conteneur de dĂ©pendances (assemblĂ© Ă  la main) ├── MainActivity.kt ├── model/ MediaEntry, MediaKind, SourceKind ├── library/ MediaStore, persistance des imports, bibliothĂšque unifiĂ©e ├── sources/ Import URL et RSS, catalogues Internet Archive et LibriVox ├── offline/ Cache Media3, gestionnaire et service de tĂ©lĂ©chargement ├── playback/ MediaSessionService, ExoPlayer, contrĂŽleur d'interface ├── update/ VĂ©rification des releases, tĂ©lĂ©chargement, notification └── ui/ Compose — thĂšme, bibliothĂšque, hors ligne, playlists, sources, parcours des catalogues, choix des pistes, lecteur ``` --- ## đŸ§Ș État de vĂ©rification ValidĂ© sur Ă©mulateur Pixel (Android 17, API 37) : - ✅ Scan MediaStore audio et vidĂ©o, vignettes comprises - ✅ Lecture avec session mĂ©dia systĂšme et position qui progresse - ✅ Import d'un flux RSS et de ses Ă©pisodes - ✅ TĂ©lĂ©chargement d'un Ă©pisode jusqu'Ă  l'Ă©tat « disponible hors connexion » - ✅ Recherche Internet Archive, rĂ©solution du fichier et mise en cache - ✅ Android Lint sans erreur --- ## 📄 Licence À dĂ©finir par l'auteur du dĂ©pĂŽt.