Sert les couvertures depuis IndexedDB aussi en ligne, et libère les blob:

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mathieu
2026-08-20 23:09:17 +02:00
co-authored by Claude Opus 5
parent 70f6844a95
commit bdcf97a3e6
5 changed files with 145 additions and 26 deletions
+54
View File
@@ -2548,3 +2548,57 @@ jamais « créer une revue », c'est toujours « ranger un numéro ».
Vérifié en exécution : `9772466671438` saisi depuis « Ajouter un ouvrage » nomme toujours
« Médor » et propose d'ouvrir sa fiche.
## Les couvertures viennent du cache AUSSI en ligne — règle A5 renversée (2026-08-20)
Constat d'usage : sur téléphone, après un rechargement, les vignettes n'apparaissent pas tout de
suite — alors que deux couvertures dont l'URL avait été collée à la main (CDN de la Fnac)
s'affichaient sans attendre.
⚠️ **L'hypothèse naturelle était fausse, et c'est ce qu'il faut retenir** : « garder l'URL en base
pour charger plus vite » ne pouvait rien donner — `Livre.CoverUrl` **est** en base depuis
toujours, il n'y avait aucune résolution à supprimer. La comparaison avec la Fnac désignait la
vraie cause : `covers.openlibrary.org` répond **302, deux fois**, avant d'aboutir sur
`archive.org` (déjà mesuré au lot du relais), là où une URL de CDN va droit au fichier. Trois
allers-retours par vignette, dix vignettes à l'écran, sur un lien mobile.
Seconde cause, dans notre code : `Couverture.razor` ne lisait le magasin IndexedDB `couvertures`
que **hors ligne**. En ligne, chaque rechargement repartait du réseau pour une image déjà rangée
sur l'appareil.
**Décidé avec l'utilisateur : le cache est consulté d'abord, en ligne comme hors ligne. Le réseau
n'est sollicité que si rien n'est en cache.**
⚠️ **Ceci renverse la règle du lot A5** — « en ligne, l'affichage utilise l'URL réseau telle
quelle : rien ne doit ralentir la voie rapide ». Elle n'était pas absurde, elle était mal
calibrée : ce qu'on protégeait était une requête réseau avec redirections, ce qu'on refusait
était une lecture IndexedDB locale. La seconde est largement plus rapide que la première. Le
sens du mot « rapide » avait été supposé, pas mesuré.
Le fire-and-forget de mise en cache subsiste, mais **seulement quand le cache est vide** : rien
ne sert de le relancer pour une image déjà rangée (`couvertureMettreEnCache` court-circuitait
déjà sur son `getKey`, c'est maintenant explicite côté C#).
### ⚠️ Le corollaire à ne pas oublier : révoquer les `blob:`
`URL.createObjectURL` retient son Blob en mémoire **jusqu'à révocation ou fermeture de la page**.
Tant que le cache ne servait qu'hors-ligne, la fuite restait bornée à une consultation
ponctuelle ; avec une vignette par carte sur tous les écrans, elle ne l'est plus. `Couverture`
implémente donc `IAsyncDisposable` et libère aussi lorsqu'elle change d'URL
(`couvertureLiberer``URL.revokeObjectURL`).
### Vérifié en exécution
| Point | Résultat |
|---|---|
| `src` des vignettes au chargement | **`blob:`** pour les deux couvertures |
| Requêtes vers `editions-ambre.fr`, `openlibrary.org`, `/api/couvertures` | **aucune** |
| Contenu réellement servi par le `blob:` | `image/jpeg`, 15 777 o, **500×500** |
| URL d'objet après navigation vers un autre écran | **révoquée** (fetch rejeté) |
479 tests au vert.
⚠️ `naturalWidth` reste à 0 dans le navigateur d'automatisation : la fenêtre ne compose pas
d'image, donc `loading="lazy"` ne déclenche jamais le décodage. Ce n'est pas un défaut de la
couverture — le blob a été décodé à la main par `createImageBitmap` pour le prouver. Ne pas
partir en chasse là-dessus.