diff --git a/content/collections/lego/jurassic-world/76943/data/images/114520.yaml b/content/collections/lego/jurassic-world/76943/data/images/114520.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76943/data/images/114520.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76943/data/images/114589.yaml b/content/collections/lego/jurassic-world/76943/data/images/114589.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76943/data/images/114589.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76943/data/images/98891.yaml b/content/collections/lego/jurassic-world/76943/data/images/98891.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76943/data/images/98891.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76943/images/114520.jpg b/content/collections/lego/jurassic-world/76943/images/114520.jpg deleted file mode 100644 index 8f53656d..00000000 Binary files a/content/collections/lego/jurassic-world/76943/images/114520.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76943/images/114589.jpg b/content/collections/lego/jurassic-world/76943/images/114589.jpg deleted file mode 100644 index 921c1342..00000000 Binary files a/content/collections/lego/jurassic-world/76943/images/114589.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76943/images/98891.jpg b/content/collections/lego/jurassic-world/76943/images/98891.jpg deleted file mode 100644 index 88421194..00000000 Binary files a/content/collections/lego/jurassic-world/76943/images/98891.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76945/data/images/98882.yaml b/content/collections/lego/jurassic-world/76945/data/images/98882.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76945/data/images/98882.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76945/images/98882.jpg b/content/collections/lego/jurassic-world/76945/images/98882.jpg deleted file mode 100644 index 683a356b..00000000 Binary files a/content/collections/lego/jurassic-world/76945/images/98882.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76945/index.md b/content/collections/lego/jurassic-world/76945/index.md index 0b212fe6..c7ab96f3 100644 --- a/content/collections/lego/jurassic-world/76945/index.md +++ b/content/collections/lego/jurassic-world/76945/index.md @@ -1,7 +1,7 @@ --- cover: images/xegNty.jpg date: "2024-04-28 11:36:06" -title: 'Atrociraptor Dinosaur: Bike Chase' +title: "Atrociraptor Dinosaur: Bike Chase" links: - name: Page du catalogue LEGO url: https://www.lego.com/fr-fr/product/atrociraptor-dinosaur-bike-chase-76945 @@ -46,3 +46,9 @@ En outre, le set inclut un bien bel _Atrociraptor_. Parmi les petites touches sympathiques de ce set, on notera le crâne de dinosaure — vraisemblablement un _Triceratops_, la cage qui peut contenir un bébé _Velociraptor_, l'arène qui utilise une roue pour ajouter un peu d'interaction, ainsi que la moto d'Owen. Avec 169 pièces, il étoffera un peu le marché de Malte commencé avec le set [_30390_](/collections/lego/jurassic-world/30390/). + +## Images complémentaires + +![](images/103678.jpg) + +![](images/110688.jpg) diff --git a/content/collections/lego/jurassic-world/76947/data/images/103676.yaml b/content/collections/lego/jurassic-world/76947/data/images/103676.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76947/data/images/103676.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76947/data/images/103678.yaml b/content/collections/lego/jurassic-world/76947/data/images/103678.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76947/data/images/103678.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76947/data/images/137165.yaml b/content/collections/lego/jurassic-world/76947/data/images/137165.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76947/data/images/137165.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76947/data/images/98866.yaml b/content/collections/lego/jurassic-world/76947/data/images/98866.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76947/data/images/98866.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76947/images/103676.jpg b/content/collections/lego/jurassic-world/76947/images/103676.jpg deleted file mode 100644 index 9d6bcb9b..00000000 Binary files a/content/collections/lego/jurassic-world/76947/images/103676.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76947/images/103678.jpg b/content/collections/lego/jurassic-world/76947/images/103678.jpg deleted file mode 100644 index 63be9ba9..00000000 Binary files a/content/collections/lego/jurassic-world/76947/images/103678.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76947/images/137165.jpg b/content/collections/lego/jurassic-world/76947/images/137165.jpg deleted file mode 100644 index 85ad7cf4..00000000 Binary files a/content/collections/lego/jurassic-world/76947/images/137165.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76947/images/98866.jpg b/content/collections/lego/jurassic-world/76947/images/98866.jpg deleted file mode 100644 index 8909120c..00000000 Binary files a/content/collections/lego/jurassic-world/76947/images/98866.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76956/index.md b/content/collections/lego/jurassic-world/76956/index.md index 1e8156a7..402355cd 100644 --- a/content/collections/lego/jurassic-world/76956/index.md +++ b/content/collections/lego/jurassic-world/76956/index.md @@ -116,3 +116,15 @@ Je conclurai en disant qu'il m'a fallut une soirée pour terminer le montage (à Un très beau set, dont les dimensions sont parfaites pour qu'il siège au-dessus de mon bureau, où il sera en permanence dans mon champs de vision. Un très beau set pour démarrer la commémoration des 30 ans de mon film préféré depuis que j'en ai 10. Un très beau set, enfin, pour le passionné que je suis. + +## Images complémentaires + +![](images/107061.jpg) + +![](images/107063.jpg) + +![](images/107064.jpg) + +![](images/107067.jpg) + +![](images/142003.jpg) diff --git a/content/collections/lego/jurassic-world/76957/data/images/129892.yaml b/content/collections/lego/jurassic-world/76957/data/images/129892.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76957/data/images/129892.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76957/data/images/139248.yaml b/content/collections/lego/jurassic-world/76957/data/images/139248.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76957/data/images/139248.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76957/data/images/139250.yaml b/content/collections/lego/jurassic-world/76957/data/images/139250.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76957/data/images/139250.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76957/images/129892.jpg b/content/collections/lego/jurassic-world/76957/images/129892.jpg deleted file mode 100644 index 6e58f598..00000000 Binary files a/content/collections/lego/jurassic-world/76957/images/129892.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76957/images/139248.jpg b/content/collections/lego/jurassic-world/76957/images/139248.jpg deleted file mode 100644 index 4c376d16..00000000 Binary files a/content/collections/lego/jurassic-world/76957/images/139248.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76957/images/139250.jpg b/content/collections/lego/jurassic-world/76957/images/139250.jpg deleted file mode 100644 index 5850ad3e..00000000 Binary files a/content/collections/lego/jurassic-world/76957/images/139250.jpg and /dev/null differ diff --git a/content/collections/lego/jurassic-world/76958/index.md b/content/collections/lego/jurassic-world/76958/index.md index 1973359f..2f322a3b 100644 --- a/content/collections/lego/jurassic-world/76958/index.md +++ b/content/collections/lego/jurassic-world/76958/index.md @@ -59,3 +59,9 @@ La minifig de Dennis Nedry diffère un peu de celle fournie par le colossal set Certes, les différences ne sont pas évidentes, et il ne faudra rien de moins qu'un oeil attentif pour voir que la tenue n'est pas la même, ou les subtiles mimiques des quatre visages présentés par les deux minifigs. Dernier clin d'oeil au film, la fameuse canette de Barbasol, réceptacle réfrigéré contenant les embryons qu'il a tenté de dérober. + +## Images complémentaires + +![](images/128936.jpg) + +![](images/129866.jpg) diff --git a/content/collections/lego/jurassic-world/76959/index.md b/content/collections/lego/jurassic-world/76959/index.md index 32debaf7..a2620b59 100644 --- a/content/collections/lego/jurassic-world/76959/index.md +++ b/content/collections/lego/jurassic-world/76959/index.md @@ -62,3 +62,11 @@ Notons seulement que, possédant les deux sets, il est agréable de se retrouver ![4ZXYgy](images/4ZXYgy.webp) Encore une fois, LEGO fait mouche en proposant un set agréable à construire, satisfaisant, et assurant le _fan-service_ en remémorant l'une des scènes majeures du film. + +## Images complémentaires + +![](images/129861.jpg) + +![](images/137712.jpg) + +![](images/137714.jpg) diff --git a/content/collections/lego/jurassic-world/76960/index.md b/content/collections/lego/jurassic-world/76960/index.md index 4b2aabc3..2aa0f687 100644 --- a/content/collections/lego/jurassic-world/76960/index.md +++ b/content/collections/lego/jurassic-world/76960/index.md @@ -70,3 +70,13 @@ Enfin, le set nous propose les minifigs de John Hammond (équipé de sa canne re Un bien beau set, qui permet à la fois d'ouvrir sur la découverte des dinosaures par nos héros, mais aussi de revivre la scène du refuge d'Alan et des enfants après l'incident causé par Dennis Nedry. De quoi ranimer ou cultiver plein de souvenirs ! + +## Images complémentaires + +![](images/129836.jpg) + +![](images/139699.jpg) + +![](images/139700.jpg) + +![](images/139701.jpg) diff --git a/content/collections/lego/jurassic-world/76961/index.md b/content/collections/lego/jurassic-world/76961/index.md index d6015288..9a2d0593 100644 --- a/content/collections/lego/jurassic-world/76961/index.md +++ b/content/collections/lego/jurassic-world/76961/index.md @@ -75,3 +75,19 @@ Mais là encore, ce serait pour moi contre-nature... Voilà, j'ai acquis puis assemblé l'intégralité des sets proposés par LEGO à l'occasion des 30 ans du film. Je vous proposerai une photo de l'étagère que j'ai dédiée à leur exposition dans les jours qui viennent, dès que je me serai décidé concernant l'ordre dans lequel je vais les disposer 😋 + +## Images complémentaires + +![](images/129841.jpg) + +![](images/139692.jpg) + +![](images/139693.jpg) + +![](images/139735.jpg) + +![](images/139736.jpg) + +![](images/139737.jpg) + +![](images/139738.jpg) diff --git a/content/collections/lego/jurassic-world/76964/data/images/129065.yaml b/content/collections/lego/jurassic-world/76964/data/images/129065.yaml deleted file mode 100644 index b05d747a..00000000 --- a/content/collections/lego/jurassic-world/76964/data/images/129065.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: "© [Rebrickable](https://rebrickable.com/)" diff --git a/content/collections/lego/jurassic-world/76964/images/129065.jpg b/content/collections/lego/jurassic-world/76964/images/129065.jpg deleted file mode 100644 index b7637459..00000000 Binary files a/content/collections/lego/jurassic-world/76964/images/129065.jpg and /dev/null differ diff --git a/content/interets/divers/2022/10/19/un-opilion-curieux/data/videos/pGDYWA.yaml b/content/interets/divers/2022/10/19/un-opilion-curieux/data/videos/pGDYWA.yaml deleted file mode 100644 index f65524c8..00000000 --- a/content/interets/divers/2022/10/19/un-opilion-curieux/data/videos/pGDYWA.yaml +++ /dev/null @@ -1 +0,0 @@ -file: videos/pGDYWA.mov diff --git a/content/interets/divers/2025/12/04/etude-de-ma-collection-lego-jurassic-world/data/images/IMG_1069.yaml b/content/interets/divers/2025/12/04/etude-de-ma-collection-lego-jurassic-world/data/images/IMG_1069.yaml deleted file mode 100644 index b57aca7e..00000000 --- a/content/interets/divers/2025/12/04/etude-de-ma-collection-lego-jurassic-world/data/images/IMG_1069.yaml +++ /dev/null @@ -1,4 +0,0 @@ -#title: "" -attribution: "Richard Dern" -description: "Rexou vous souhaite un joyeux Noël en avance" -#prompt: "" diff --git a/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/Rz7pM4.yaml b/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/Rz7pM4.yaml deleted file mode 100644 index 81435d39..00000000 --- a/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/Rz7pM4.yaml +++ /dev/null @@ -1,2 +0,0 @@ -file: sounds/Rz7pM4.mp3 -title: Pic vert, à une trentaine de mètres diff --git a/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/giHuWL.yaml b/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/giHuWL.yaml deleted file mode 100644 index bea01a26..00000000 --- a/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/giHuWL.yaml +++ /dev/null @@ -1,2 +0,0 @@ -file: sounds/giHuWL.mp3 -title: Pie, dans le champ voisin diff --git a/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/lLgMhQ.yaml b/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/lLgMhQ.yaml deleted file mode 100644 index d3042e82..00000000 --- a/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/lLgMhQ.yaml +++ /dev/null @@ -1,2 +0,0 @@ -file: sounds/lLgMhQ.mp3 -title: Corneille noire, à une vingtaine de mètres diff --git a/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/pMWFOQ.yaml b/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/pMWFOQ.yaml deleted file mode 100644 index 5fc5bc57..00000000 --- a/content/interets/informatique/2023/01/24/mon-raspberry-pi4-est-enfin-utile/data/sounds/pMWFOQ.yaml +++ /dev/null @@ -1,2 +0,0 @@ -file: sounds/pMWFOQ.mp3 -title: Moineau, deux mètres au-dessus du micro diff --git a/content/interets/informatique/2023/06/05/wwdc2023/data/videos/Zf8iAR.yaml b/content/interets/informatique/2023/06/05/wwdc2023/data/videos/Zf8iAR.yaml deleted file mode 100644 index fcf06711..00000000 --- a/content/interets/informatique/2023/06/05/wwdc2023/data/videos/Zf8iAR.yaml +++ /dev/null @@ -1 +0,0 @@ -file: videos/Zf8iAR.mp4 diff --git a/content/interets/informatique/2023/06/05/wwdc2023/data/videos/fubVNP.yaml b/content/interets/informatique/2023/06/05/wwdc2023/data/videos/fubVNP.yaml deleted file mode 100644 index cd586a7d..00000000 --- a/content/interets/informatique/2023/06/05/wwdc2023/data/videos/fubVNP.yaml +++ /dev/null @@ -1 +0,0 @@ -file: videos/fubVNP.mp4 diff --git a/content/interets/informatique/2023/06/05/wwdc2023/data/videos/glsyvj.yaml b/content/interets/informatique/2023/06/05/wwdc2023/data/videos/glsyvj.yaml deleted file mode 100644 index 121d1489..00000000 --- a/content/interets/informatique/2023/06/05/wwdc2023/data/videos/glsyvj.yaml +++ /dev/null @@ -1 +0,0 @@ -file: videos/glsyvj.mp4 diff --git a/content/interets/informatique/2023/06/05/wwdc2023/data/videos/oOg5AS.yaml b/content/interets/informatique/2023/06/05/wwdc2023/data/videos/oOg5AS.yaml deleted file mode 100644 index 5e0eef8d..00000000 --- a/content/interets/informatique/2023/06/05/wwdc2023/data/videos/oOg5AS.yaml +++ /dev/null @@ -1 +0,0 @@ -file: videos/oOg5AS.mp4 diff --git a/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/data/images/404_not_found.yaml b/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/data/images/404_not_found.yaml deleted file mode 100644 index 6abdad81..00000000 --- a/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/data/images/404_not_found.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: https://commons.wikimedia.org/wiki/File:404_not_found.png diff --git a/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/data/images/500_Internal_Server_error.yaml b/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/data/images/500_Internal_Server_error.yaml deleted file mode 100644 index 94bd1890..00000000 --- a/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/data/images/500_Internal_Server_error.yaml +++ /dev/null @@ -1 +0,0 @@ -attribution: https://commons.wikimedia.org/wiki/File:500_Internal_Server_error.png diff --git a/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/images/404_not_found.png b/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/images/404_not_found.png deleted file mode 100644 index 6362bbe3..00000000 Binary files a/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/images/404_not_found.png and /dev/null differ diff --git a/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/images/500_Internal_Server_error.png b/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/images/500_Internal_Server_error.png deleted file mode 100644 index a530b612..00000000 Binary files a/content/interets/informatique/2026/01/19/echouer-a-echouer-la-triste-histoire-des-messages-d-erreur/images/500_Internal_Server_error.png and /dev/null differ diff --git a/content/interets/informatique/2026/03/04/free-ipv6-et-opnsense/data/images/ra.yaml b/content/interets/informatique/2026/03/04/free-ipv6-et-opnsense/data/images/ra.yaml deleted file mode 100644 index 489eacc9..00000000 --- a/content/interets/informatique/2026/03/04/free-ipv6-et-opnsense/data/images/ra.yaml +++ /dev/null @@ -1,4 +0,0 @@ -#title: "" -#attribution: "" -#description: "" -#prompt: "" diff --git a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/humidity_last_7_days.png b/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/humidity_last_7_days.png deleted file mode 100644 index 5572c48c..00000000 Binary files a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/humidity_last_7_days.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/illuminance_last_7_days.png b/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/illuminance_last_7_days.png deleted file mode 100644 index 15bfa549..00000000 Binary files a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/illuminance_last_7_days.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/pressure_last_7_days.png b/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/pressure_last_7_days.png deleted file mode 100644 index 3bf8eeb4..00000000 Binary files a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/pressure_last_7_days.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/rain_rate_last_7_days.png b/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/rain_rate_last_7_days.png deleted file mode 100644 index 8963f95f..00000000 Binary files a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/rain_rate_last_7_days.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/sun_elevation_last_7_days.png b/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/sun_elevation_last_7_days.png deleted file mode 100644 index 14df1d53..00000000 Binary files a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/sun_elevation_last_7_days.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/temperature_last_7_days.png b/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/temperature_last_7_days.png deleted file mode 100644 index 30c3e2ff..00000000 Binary files a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/temperature_last_7_days.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/wind_direction_last_7_days.png b/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/wind_direction_last_7_days.png deleted file mode 100644 index bb212eb2..00000000 Binary files a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/wind_direction_last_7_days.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/wind_speed_last_7_days.png b/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/wind_speed_last_7_days.png deleted file mode 100644 index 5bfcfe50..00000000 Binary files a/content/interets/meteorologie/2025/11/26/03-premiers-graphiques/images/wind_speed_last_7_days.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/04-correlations-binaires/images/pairwise_timeseries/timeseries_rain_rate_vs_illuminance.png b/content/interets/meteorologie/2025/11/26/04-correlations-binaires/images/pairwise_timeseries/timeseries_rain_rate_vs_illuminance.png deleted file mode 100644 index 8645883e..00000000 Binary files a/content/interets/meteorologie/2025/11/26/04-correlations-binaires/images/pairwise_timeseries/timeseries_rain_rate_vs_illuminance.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_pressure_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_pressure_lagged.png deleted file mode 100644 index f513df4a..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_pressure_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_rain_rate_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_rain_rate_lagged.png deleted file mode 100644 index e2c05cd0..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_rain_rate_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_wind_direction_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_wind_direction_lagged.png deleted file mode 100644 index 3cf828f6..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_wind_direction_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_wind_speed_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_wind_speed_lagged.png deleted file mode 100644 index c5c39d8c..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_humidity_vs_wind_speed_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_humidity_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_humidity_lagged.png deleted file mode 100644 index 71ca36b6..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_humidity_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_temperature_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_temperature_lagged.png deleted file mode 100644 index 27a90815..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_temperature_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_wind_direction_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_wind_direction_lagged.png deleted file mode 100644 index 0ccc70db..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_wind_direction_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_wind_speed_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_wind_speed_lagged.png deleted file mode 100644 index 76f65277..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_illuminance_vs_wind_speed_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_illuminance_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_illuminance_lagged.png deleted file mode 100644 index 15137e5d..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_illuminance_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_rain_rate_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_rain_rate_lagged.png deleted file mode 100644 index 4515e0ef..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_rain_rate_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_sun_elevation_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_sun_elevation_lagged.png deleted file mode 100644 index 264a8e57..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_sun_elevation_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_wind_direction_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_wind_direction_lagged.png deleted file mode 100644 index 248b4a49..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_wind_direction_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_wind_speed_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_wind_speed_lagged.png deleted file mode 100644 index bb481d4d..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_pressure_vs_wind_speed_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_illuminance_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_illuminance_lagged.png deleted file mode 100644 index 380d00a9..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_illuminance_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_sun_elevation_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_sun_elevation_lagged.png deleted file mode 100644 index 7df9e4c0..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_sun_elevation_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_wind_direction_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_wind_direction_lagged.png deleted file mode 100644 index be52683a..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_wind_direction_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_wind_speed_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_wind_speed_lagged.png deleted file mode 100644 index b28e86c4..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_rain_rate_vs_wind_speed_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_humidity_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_humidity_lagged.png deleted file mode 100644 index ced4cd8b..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_humidity_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_illuminance_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_illuminance_lagged.png deleted file mode 100644 index d31dd46f..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_illuminance_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_temperature_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_temperature_lagged.png deleted file mode 100644 index 8d9c78b1..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_sun_elevation_vs_temperature_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_humidity_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_humidity_lagged.png deleted file mode 100644 index f228d25e..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_humidity_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_pressure_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_pressure_lagged.png deleted file mode 100644 index 0e272495..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_pressure_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_rain_rate_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_rain_rate_lagged.png deleted file mode 100644 index 214d96f2..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_rain_rate_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_wind_direction_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_wind_direction_lagged.png deleted file mode 100644 index be53b555..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_wind_direction_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_wind_speed_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_wind_speed_lagged.png deleted file mode 100644 index 27161a90..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_temperature_vs_wind_speed_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_direction_vs_sun_elevation_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_direction_vs_sun_elevation_lagged.png deleted file mode 100644 index 10ce9cc8..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_direction_vs_sun_elevation_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_speed_vs_sun_elevation_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_speed_vs_sun_elevation_lagged.png deleted file mode 100644 index 81efcf1b..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_speed_vs_sun_elevation_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_speed_vs_wind_direction_lagged.png b/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_speed_vs_wind_direction_lagged.png deleted file mode 100644 index 3eb44ac9..00000000 Binary files a/content/interets/meteorologie/2025/11/26/05-correlations-binaires-avancees/images/pairwise_scatter/scatter_wind_speed_vs_wind_direction_lagged.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-base.png b/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-base.png deleted file mode 100644 index 1af10420..00000000 Binary files a/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-base.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-mini.png b/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-mini.png deleted file mode 100644 index 03f2edd3..00000000 Binary files a/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-mini.png and /dev/null differ diff --git a/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-small.png b/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-small.png deleted file mode 100644 index 287fe7f5..00000000 Binary files a/content/interets/meteorologie/2025/11/26/11-modele-chronos/images/chronos_errors_amazon__chronos-t5-small.png and /dev/null differ diff --git a/content/interets/microscopie/2024/11/14/swift-imaging-v3/data/images/header.yaml b/content/interets/microscopie/2024/11/14/swift-imaging-v3/data/images/header.yaml deleted file mode 100644 index 30d2399e..00000000 --- a/content/interets/microscopie/2024/11/14/swift-imaging-v3/data/images/header.yaml +++ /dev/null @@ -1,2 +0,0 @@ -title: "Interface du logiciel Swift Imaging" -file: images/screenshot.png diff --git a/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/cluster.yaml b/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/cluster.yaml deleted file mode 100644 index 3884550f..00000000 --- a/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/cluster.yaml +++ /dev/null @@ -1,3 +0,0 @@ -title: "Cluster d'organismes" -description: "Un cluster de quatre organismes. Couleurs naturelles." -file: videos/cluster.mp4 diff --git a/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/cluster_eosine.yaml b/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/cluster_eosine.yaml deleted file mode 100644 index 00c6bc39..00000000 --- a/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/cluster_eosine.yaml +++ /dev/null @@ -1,3 +0,0 @@ -title: "Cluster d'organismes colorés à l'éosine" -description: 'Un cluster de quatre organismes colorés à l''éosine. La membrane partagée est mieux visible. On peut également distinguer les "antennes".' -file: videos/cluster_eosine.mp4 diff --git a/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/solo.yaml b/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/solo.yaml deleted file mode 100644 index 9b44fa88..00000000 --- a/content/interets/microscopie/2025/01/26/premieres-observations/data/videos/solo.yaml +++ /dev/null @@ -1,3 +0,0 @@ -title: "Un organisme bien vigoureux !" -description: "Dur de suivre ce petit organisme ! La coloration à l'éosine ne semble pas l'avoir affecté. Notez que, outre ma difficulté à le garder dans le cadre, il faut garder à l'esprit que dans une lame concave, il peut aussi se balader sur le plan vertical : ça fait trois molettes avec lesquelles jouer. Vivement que je puisse m'équiper d'une platine motorisée !" -file: videos/solo.mp4 diff --git a/tools/check_unused_images.js b/tools/check_unused_images.js new file mode 100644 index 00000000..1a5d3c5b --- /dev/null +++ b/tools/check_unused_images.js @@ -0,0 +1,536 @@ +#!/usr/bin/env node + +const fs = require("node:fs/promises"); +const path = require("node:path"); +const readline = require("node:readline"); +const { collectBundles } = require("./lib/content"); + +const CONTENT_DIR = path.resolve("content"); +const IMAGE_EXTENSIONS = new Set([ + ".apng", + ".avif", + ".bmp", + ".gif", + ".heic", + ".heif", + ".jpeg", + ".jpg", + ".png", + ".svg", + ".tif", + ".tiff", + ".webp", +]); +let promptInterface = null; + +process.stdout.on("error", handleStdoutError); + +main().then( + () => { + closePromptInterface(); + process.exit(0); + }, + (error) => { + closePromptInterface(); + console.error(`❌ Vérification interrompue : ${error.message}`); + process.exit(1); + } +); + +/** + * Parcourt tous les bundles et affiche uniquement ceux qui contiennent + * au moins une image non référencée dans leur fichier index.md. + */ +async function main() { + const bundles = await resolveBundlesToScan(); + + for (const bundle of bundles) { + const unusedImages = await findUnusedBundleImages(bundle); + if (unusedImages.length === 0) { + continue; + } + + console.log(`${toRelativePath(bundle.dir)}:`); + for (const imagePath of unusedImages) { + console.log(`- ${toRelativePath(imagePath)}`); + } + + const action = await askBundleAction(); + if (action === "1") { + await appendUnusedImagesToMarkdown(bundle, unusedImages); + console.log("✔ Images ajoutées au markdown."); + continue; + } + + await deleteUnusedImages(unusedImages); + console.log("✔ Images non utilisées supprimées."); + } + + await cleanupBundleMetadataFiles(bundles); +} + +/** + * Demande le mode de recherche puis retourne les bundles à parcourir. + * @returns {Promise>} Bundles à analyser. + */ +async function resolveBundlesToScan() { + const prompt = [ + "Choisissez le mode de recherche:", + "1) Dernier article écrit (défaut)", + "2) Recherche globale", + "Votre choix [1/2]: ", + ].join("\n"); + + const answer = await askQuestion(prompt); + + if (answer === "" || answer === "1") { + const latestBundle = await findLatestBundle(CONTENT_DIR); + if (latestBundle) { + return [latestBundle]; + } + return []; + } + + if (answer === "2") { + return collectBundles(CONTENT_DIR); + } + + throw new Error('Choix invalide. Veuillez saisir "1" ou "2".'); +} + +/** + * Retourne le bundle le plus récent selon la date de modification du dossier. + * @param {string} rootDir Racine du contenu. + * @returns {Promise<{dir: string, indexPath: string}|null>} Bundle le plus récent. + */ +async function findLatestBundle(rootDir) { + const bundles = await collectBundles(rootDir); + let latestBundle = null; + let latestTime = 0; + + for (const bundle of bundles) { + const stat = await fs.stat(bundle.dir); + if (stat.mtimeMs > latestTime) { + latestBundle = bundle; + latestTime = stat.mtimeMs; + } + } + + return latestBundle; +} + +/** + * Pose une question interactive et retourne la réponse saisie. + * @param {string} query Question à afficher. + * @returns {Promise} Réponse sans espaces superflus. + */ +function askQuestion(query) { + return new Promise((resolve) => { + const rl = getPromptInterface(); + let resolved = false; + + const onClose = () => { + if (resolved) { + return; + } + resolved = true; + resolve(""); + }; + + rl.once("close", onClose); + rl.question(query, (answer) => { + if (resolved) { + return; + } + resolved = true; + rl.removeListener("close", onClose); + resolve(answer.trim()); + }); + }); +} + +/** + * Retourne l'interface readline réutilisable pour toute l'exécution. + * @returns {readline.Interface} Interface interactive. + */ +function getPromptInterface() { + if (promptInterface !== null) { + return promptInterface; + } + + promptInterface = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + return promptInterface; +} + +/** + * Ferme proprement l'interface readline si elle est ouverte. + */ +function closePromptInterface() { + if (promptInterface === null) { + return; + } + + promptInterface.close(); + promptInterface = null; +} + +/** + * Demande l'action à appliquer au bundle courant. + * @returns {Promise<"1"|"2">} Action choisie. + */ +async function askBundleAction() { + const prompt = [ + "Action pour ce bundle:", + "1) Ajouter les images au markdown", + "2) Supprimer les images non utilisées", + "Votre choix [1/2]: ", + ].join("\n"); + + const answer = await askQuestion(prompt); + if (answer === "1") { + return "1"; + } + if (answer === "2") { + return "2"; + } + + throw new Error('Choix invalide. Veuillez saisir "1" ou "2".'); +} + +/** + * Ajoute les images manquantes à la section "Images complémentaires". + * @param {{dir: string, indexPath: string}} bundle Bundle à modifier. + * @param {string[]} unusedImages Chemins absolus des images à ajouter. + */ +async function appendUnusedImagesToMarkdown(bundle, unusedImages) { + const articleText = await fs.readFile(bundle.indexPath, "utf8"); + const imageLines = buildImageLines(bundle.dir, unusedImages); + const updatedText = insertComplementaryImages(articleText, imageLines); + await fs.writeFile(bundle.indexPath, updatedText, "utf8"); +} + +/** + * Supprime les images non utilisées du disque. + * @param {string[]} imagePaths Chemins absolus des images à supprimer. + */ +async function deleteUnusedImages(imagePaths) { + for (const imagePath of imagePaths) { + await fs.unlink(imagePath); + } +} + +/** + * Construit les lignes Markdown d'inclusion d'images. + * @param {string} bundleDir Dossier du bundle. + * @param {string[]} imagePaths Chemins absolus des images. + * @returns {string[]} Lignes de type ![](images/...) + */ +function buildImageLines(bundleDir, imagePaths) { + const lines = []; + + for (const imagePath of imagePaths) { + const relativePath = toPosixPath(path.relative(bundleDir, imagePath)); + lines.push(`![](${relativePath})`); + } + + return lines; +} + +/** + * Insère les images dans la section "## Images complémentaires". + * @param {string} articleText Contenu de index.md. + * @param {string[]} imageLines Lignes Markdown des images à ajouter. + * @returns {string} Nouveau contenu Markdown. + */ +function insertComplementaryImages(articleText, imageLines) { + const headingRegex = /^##\s+Images complémentaires\s*$/m; + const headingMatch = headingRegex.exec(articleText); + const imageBlock = imageLines.join("\n\n"); + + if (headingMatch === null) { + const trimmed = articleText.trimEnd(); + return `${trimmed}\n\n## Images complémentaires\n\n${imageBlock}\n`; + } + + const headingEnd = headingMatch.index + headingMatch[0].length; + const afterHeading = articleText.slice(headingEnd); + const nextHeadingRegex = /\n##\s+/; + const nextHeadingMatch = nextHeadingRegex.exec(afterHeading); + + let sectionEnd = articleText.length; + if (nextHeadingMatch !== null) { + sectionEnd = headingEnd + nextHeadingMatch.index; + } + + const sectionPrefix = articleText.slice(0, sectionEnd).trimEnd(); + const sectionSuffix = articleText.slice(sectionEnd); + return `${sectionPrefix}\n\n${imageBlock}\n${sectionSuffix}`; +} + +/** + * Retourne la liste des images d'un bundle absentes du texte de l'article. + * @param {{dir: string, indexPath: string}} bundle Bundle à analyser. + * @returns {Promise} Chemins absolus des images non utilisées. + */ +async function findUnusedBundleImages(bundle) { + const imagesDir = path.join(bundle.dir, "images"); + const hasImagesDir = await directoryExists(imagesDir); + if (hasImagesDir === false) { + return []; + } + + const imageFiles = await collectImageFiles(imagesDir); + if (imageFiles.length === 0) { + return []; + } + + imageFiles.sort((left, right) => left.localeCompare(right)); + + const articleText = await fs.readFile(bundle.indexPath, "utf8"); + const searchableText = stripMarkdownCode(articleText); + const unusedImages = []; + + for (const imagePath of imageFiles) { + const relativePath = toPosixPath(path.relative(bundle.dir, imagePath)); + const candidatePaths = buildCandidatePaths(relativePath); + const isReferenced = hasAnyReference(searchableText, candidatePaths); + + if (isReferenced === false) { + unusedImages.push(imagePath); + } + } + + return unusedImages; +} + +/** + * Supprime les fichiers .yaml orphelins dans data/ pour chaque bundle. + * Un fichier est conservé si une image du bundle partage le même nom de base. + * @param {Array<{dir: string}>} bundles Bundles à nettoyer. + */ +async function cleanupBundleMetadataFiles(bundles) { + for (const bundle of bundles) { + await cleanupMetadataFilesForBundle(bundle); + } +} + +/** + * Nettoie les fichiers .yaml orphelins dans le dossier data/ d'un bundle. + * @param {{dir: string}} bundle Bundle à nettoyer. + */ +async function cleanupMetadataFilesForBundle(bundle) { + const imageBaseNames = await collectImageBaseNames(bundle.dir); + const dataDir = path.join(bundle.dir, "data"); + const hasDataDir = await directoryExists(dataDir); + if (hasDataDir === false) { + return; + } + + const yamlFiles = await collectYamlFiles(dataDir); + for (const yamlPath of yamlFiles) { + const yamlBaseName = path.parse(yamlPath).name; + if (imageBaseNames.has(yamlBaseName)) { + continue; + } + await fs.unlink(yamlPath); + } +} + +/** + * Retourne les noms de base des images du bundle (sans extension). + * @param {string} bundleDir Dossier du bundle. + * @returns {Promise>} Ensemble des noms de base. + */ +async function collectImageBaseNames(bundleDir) { + const imageBaseNames = new Set(); + const imagesDir = path.join(bundleDir, "images"); + const hasImagesDir = await directoryExists(imagesDir); + if (hasImagesDir === false) { + return imageBaseNames; + } + + const imageFiles = await collectImageFiles(imagesDir); + for (const imagePath of imageFiles) { + imageBaseNames.add(path.parse(imagePath).name); + } + + return imageBaseNames; +} + +/** + * Indique si au moins une variante de chemin est trouvée dans le texte. + * @param {string} articleText Contenu de index.md. + * @param {string[]} candidatePaths Variantes à tester. + * @returns {boolean} true si une référence est détectée. + */ +function hasAnyReference(articleText, candidatePaths) { + for (const candidatePath of candidatePaths) { + if (isPathReferenced(articleText, candidatePath)) { + return true; + } + } + return false; +} + +/** + * Supprime les zones de code Markdown pour éviter les faux positifs. + * @param {string} text Texte brut du fichier Markdown. + * @returns {string} Texte nettoyé des portions de code. + */ +function stripMarkdownCode(text) { + const withoutFencedBackticks = text.replace(/```[\s\S]*?```/g, "\n"); + const withoutFencedTildes = withoutFencedBackticks.replace(/~~~[\s\S]*?~~~/g, "\n"); + return withoutFencedTildes.replace(/`[^`\n]*`/g, ""); +} + +/** + * Construit les variantes de chemin pour gérer les chemins encodés. + * @param {string} relativePath Chemin relatif au bundle. + * @returns {string[]} Variantes uniques du chemin. + */ +function buildCandidatePaths(relativePath) { + const values = [relativePath]; + const encoded = encodeURI(relativePath); + if (encoded !== relativePath) { + values.push(encoded); + } + return values; +} + +/** + * Vérifie si un chemin est référencé comme unité complète dans le texte. + * @param {string} articleText Contenu de index.md. + * @param {string} pathValue Chemin relatif à rechercher. + * @returns {boolean} true si le chemin est présent. + */ +function isPathReferenced(articleText, pathValue) { + const escapedPath = escapeRegExp(pathValue); + const before = "(^|[\\s\"'`(=:/])"; + const after = "($|[\\s\"'`)#?&,:;.!\\]}<>])"; + const pattern = new RegExp(`${before}${escapedPath}${after}`, "u"); + return pattern.test(articleText); +} + +/** + * Échappe une chaîne pour un usage littéral dans une expression régulière. + * @param {string} value Valeur à échapper. + * @returns {string} Valeur échappée. + */ +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +/** + * Collecte récursivement les fichiers image d'un dossier. + * @param {string} rootDir Dossier à parcourir. + * @returns {Promise} Liste des fichiers image. + */ +async function collectImageFiles(rootDir) { + const files = []; + const entries = await fs.readdir(rootDir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(rootDir, entry.name); + if (entry.isDirectory()) { + const nestedFiles = await collectImageFiles(fullPath); + files.push(...nestedFiles); + continue; + } + + if (entry.isFile() === false) { + continue; + } + + const extension = path.extname(entry.name).toLowerCase(); + if (IMAGE_EXTENSIONS.has(extension) === false) { + continue; + } + + files.push(fullPath); + } + + return files; +} + +/** + * Collecte récursivement les fichiers .yaml d'un dossier. + * @param {string} rootDir Dossier à parcourir. + * @returns {Promise} Liste des chemins de fichiers .yaml. + */ +async function collectYamlFiles(rootDir) { + const files = []; + const entries = await fs.readdir(rootDir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(rootDir, entry.name); + if (entry.isDirectory()) { + const nestedFiles = await collectYamlFiles(fullPath); + files.push(...nestedFiles); + continue; + } + + if (entry.isFile() === false) { + continue; + } + + const extension = path.extname(entry.name).toLowerCase(); + if (extension !== ".yaml") { + continue; + } + + files.push(fullPath); + } + + return files; +} + +/** + * Vérifie l'existence d'un dossier. + * @param {string} dirPath Dossier à vérifier. + * @returns {Promise} true si le dossier existe. + */ +async function directoryExists(dirPath) { + const entries = await fs.readdir(path.dirname(dirPath), { withFileTypes: true }); + for (const entry of entries) { + if (entry.name !== path.basename(dirPath)) { + continue; + } + if (entry.isDirectory()) { + return true; + } + return false; + } + return false; +} + +/** + * Convertit un chemin en représentation relative à la racine du dépôt. + * @param {string} absolutePath Chemin absolu. + * @returns {string} Chemin relatif normalisé en POSIX. + */ +function toRelativePath(absolutePath) { + return toPosixPath(path.relative(process.cwd(), absolutePath)); +} + +/** + * Normalise les séparateurs de chemin au format POSIX. + * @param {string} value Chemin à normaliser. + * @returns {string} Chemin avec séparateurs "/". + */ +function toPosixPath(value) { + return value.split(path.sep).join("/"); +} + +/** + * Interrompt proprement le script si la sortie standard est fermée. + * @param {NodeJS.ErrnoException} error Erreur émise par stdout. + */ +function handleStdoutError(error) { + if (error.code === "EPIPE") { + process.exit(0); + } + throw error; +}