From c9f9eb4ee54730c1099d002220b5f97b9ee0df4a Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Wed, 21 Jan 2026 20:01:42 +0100 Subject: [PATCH] Fix cache image loading bug in webapp Fix the bug where cached images were not displaying in the webapp due to synchronous load events. Added checkImageComplete() function to detect already loaded images from cache and updated all affected components (CurrentTrack, QueueItem, MediaItem, RendererCard) to properly handle cached image loading. --- Blackboard/Report/bug_images_cache_webapp.md | 134 +++++ Blackboard/Todo/bug_images_cache_webapp.md | 35 ++ PMOMusic/Cargo.toml | 2 +- .../components/pmocontrol/CurrentTrack.vue | 28 +- .../src/components/pmocontrol/MediaItem.vue | 28 +- .../src/components/pmocontrol/QueueItem.vue | 28 +- .../components/pmocontrol/RendererCard.vue | 488 ++++++++++-------- version.txt | 2 +- 8 files changed, 524 insertions(+), 221 deletions(-) create mode 100644 Blackboard/Report/bug_images_cache_webapp.md create mode 100644 Blackboard/Todo/bug_images_cache_webapp.md diff --git a/Blackboard/Report/bug_images_cache_webapp.md b/Blackboard/Report/bug_images_cache_webapp.md new file mode 100644 index 00000000..620b476a --- /dev/null +++ b/Blackboard/Report/bug_images_cache_webapp.md @@ -0,0 +1,134 @@ +# Rapport : Correction du bug d'affichage des images en cache dans la webapp + +## Tâche originale + +Les images de couverture d'album ne s'affichaient plus dans l'application web Control Point. Seuls les logos SVG de fallback étaient visibles, bien que les URLs soient correctes et les images accessibles. + +## Analyse + +### Pattern d'affichage existant + +Les composants utilisaient le pattern suivant : + +```vue + +
+ +
+``` + +Avec : +```typescript +const imageLoaded = ref(false); + +watch(() => props.item.album_art_uri, () => { + imageLoaded.value = false; + imageError.value = false; +}); + +function handleImageLoad() { + imageLoaded.value = true; +} +``` + +### Cause du bug + +Lorsqu'une image est **déjà en cache du navigateur**, elle peut se charger de manière **synchrone** avant que Vue n'ait attaché l'écouteur d'événement `@load`. Dans ce cas : + +1. L'image est créée dans le DOM (via `v-if`) +2. Le navigateur charge l'image immédiatement depuis le cache +3. L'événement `load` se déclenche **avant** que Vue n'ait attaché `@load` +4. `imageLoaded` reste à `false` +5. L'image reste cachée par `v-show="imageLoaded"` +6. Le placeholder SVG s'affiche à la place + +Ce comportement est particulièrement fréquent avec des images déjà visitées ou après un rechargement de page. + +## Correction appliquée + +### Solution + +Ajout d'une fonction `checkImageComplete()` qui vérifie si l'image est déjà chargée via les propriétés natives de l'élément `` : + +```typescript +const coverImageRef = ref(null); + +function checkImageComplete() { + nextTick(() => { + if (coverImageRef.value?.complete && coverImageRef.value?.naturalWidth > 0) { + imageLoaded.value = true; + imageError.value = false; + } + }); +} + +onMounted(() => { + checkImageComplete(); +}); + +watch(() => metadata.value?.album_art_uri, (newUri) => { + imageLoaded.value = false; + imageError.value = false; + if (newUri) { + checkImageComplete(); + } +}); +``` + +Et ajout de la référence sur l'élément `` : + +```vue + +``` + +### Fichiers modifiés + +| Fichier | Modification | +|---------|--------------| +| `pmoapp/webapp/src/components/pmocontrol/CurrentTrack.vue` | Ajout `checkImageComplete()`, `coverImageRef`, `onMounted` | +| `pmoapp/webapp/src/components/pmocontrol/QueueItem.vue` | Ajout `checkImageComplete()`, `coverImageRef`, `onMounted` | +| `pmoapp/webapp/src/components/pmocontrol/MediaItem.vue` | Ajout `checkImageComplete()`, `coverImageRef`, `onMounted` | +| `pmoapp/webapp/src/components/pmocontrol/RendererCard.vue` | Ajout complet de la gestion d'état image (était absent) | + +### Détail des modifications par composant + +#### CurrentTrack.vue +- Import de `onMounted`, `nextTick` +- Ajout de `coverImageRef` +- Ajout de `checkImageComplete()` +- Modification du `watch` pour appeler `checkImageComplete()` après changement d'URL +- Ajout de `onMounted(() => checkImageComplete())` +- Ajout de `ref="coverImageRef"` sur l'élément `` + +#### QueueItem.vue +- Mêmes modifications que CurrentTrack.vue + +#### MediaItem.vue +- Mêmes modifications que CurrentTrack.vue + +#### RendererCard.vue +- Ce composant n'avait pas de gestion d'état de chargement d'image +- Ajout complet : `imageLoaded`, `imageError`, `coverImageRef`, `checkImageComplete()` +- Ajout des handlers `@load` et `@error` +- Modification de `hasCover` pour inclure `!imageError` +- Ajout de `v-show="imageLoaded"` sur l'image +- Modification de la condition du placeholder + +## Vérification + +- Build webpack réussi sans erreur +- Compilation TypeScript OK + +## Remarque technique + +La propriété `HTMLImageElement.complete` retourne `true` si : +- L'image a fini de charger (succès ou erreur) +- L'attribut `src` est vide ou absent + +C'est pourquoi on vérifie également `naturalWidth > 0` pour s'assurer que l'image a bien été chargée avec succès (une image en erreur a `naturalWidth === 0`). diff --git a/Blackboard/Todo/bug_images_cache_webapp.md b/Blackboard/Todo/bug_images_cache_webapp.md new file mode 100644 index 00000000..6260c8a4 --- /dev/null +++ b/Blackboard/Todo/bug_images_cache_webapp.md @@ -0,0 +1,35 @@ +# Bug : Images non affichées dans la webapp (fallback SVG systématique) + +## Description du bug + +Dans l'application web Control Point, les images de couverture d'album ne s'affichent plus correctement. Au lieu d'afficher les images, seuls les petits logos SVG de fallback (icône Music) sont visibles, alors que : +- Les URLs des images sont correctes +- Les images sont bien présentes dans le cache +- Les images sont accessibles via leur URL directe + +Ce bug est apparu après une correction précédente visant à éliminer les images grises. + +## Symptômes + +- Les composants affichent l'icône SVG de fallback au lieu des vraies images +- Le problème est plus fréquent qu'avant la correction précédente +- Les images en cache du navigateur ne s'affichent pas + +## Crates/Modules concernées + +- **pmoapp/webapp** (application Vue.js) + +## Composants à examiner + +- `src/components/pmocontrol/CurrentTrack.vue` +- `src/components/pmocontrol/QueueItem.vue` +- `src/components/pmocontrol/MediaItem.vue` +- `src/components/pmocontrol/RendererCard.vue` + +## Cause suspectée + +Le pattern d'affichage d'image avec `v-show="imageLoaded"` ne gère pas correctement le cas où l'image est déjà en cache du navigateur. Dans ce cas, l'événement `@load` peut se déclencher de manière synchrone avant que Vue n'ait attaché l'écouteur, laissant `imageLoaded` à `false`. + +## Solution attendue + +Ajouter une vérification de l'état `complete` de l'image après le montage du composant et après chaque changement d'URL, pour détecter les images déjà chargées depuis le cache. diff --git a/PMOMusic/Cargo.toml b/PMOMusic/Cargo.toml index 526e1fb0..c879644d 100644 --- a/PMOMusic/Cargo.toml +++ b/PMOMusic/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "PMOMusic" -version = "0.3.10" +version = "0.3.11" edition = "2024" [dependencies] diff --git a/pmoapp/webapp/src/components/pmocontrol/CurrentTrack.vue b/pmoapp/webapp/src/components/pmocontrol/CurrentTrack.vue index 214bd445..165b4ece 100644 --- a/pmoapp/webapp/src/components/pmocontrol/CurrentTrack.vue +++ b/pmoapp/webapp/src/components/pmocontrol/CurrentTrack.vue @@ -1,5 +1,5 @@