Files
annu-kute-ced/README.adoc
T

821 lines
40 KiB
Plaintext
Raw Normal View History

= 🎙️ ANNU KUTE CED — Hub multimédia du podcast (SvelteKit)
2025-07-24 22:12:30 +04:00
:toc: left
:toc-title: Sommaire / Contents
2025-07-24 22:12:30 +04:00
:toclevels: 3
2025-04-08 06:37:14 +04:00
[[top]]
🌍 *Hub multimédia du podcast ANNU KUTE CED — version SvelteKit statique* +
🌍 *Multimedia hub for the ANNU KUTE CED podcast — static SvelteKit version*
2025-04-08 06:37:14 +04:00
[.text-center]
*Choisissez votre langue / Choose your language :* +
<<fr,🇫🇷 Version française>> · <<en,🇬🇧 English version>>
2025-04-08 06:37:14 +04:00
'''
2025-04-08 06:37:14 +04:00
[[fr]]
== 🇫🇷 Version française
=== 📖 Description
*ANNU KUTE CED* est le *hub multimédia* du podcast du même nom. Il regroupe en un seul lieu :
- 🎥 la chaîne *PeerTube* du podcast (vidéos, shorts, directs) ;
- 🎙️ son compte *Castopod* (derniers épisodes, lecture audio intégrée) ;
- 🎵 une sélection aléatoire de morceaux *Funkwhale* (même lecteur intégré) ;
- 📡 sa timeline *Mastodon* (actualités et annonces).
Cette version est une *application SvelteKit 100 % statique* (Svelte 5 + TypeScript, `adapter-static`, prerender intégral) : toutes les données des instances sont *récupérées au moment du build* (« bake ») et le site généré peut être servi depuis n'importe quel hébergement statique — y compris un mutualisé comme o2switch — *sans PHP, sans Node, sans base de données*. C'est aussi une *Progressive Web App* installable, avec mode hors ligne, en français et en anglais.
🎯 *Mission* : offrir un point d'entrée unique, libre et décentralisé, pour découvrir, écouter et suivre le podcast ANNU KUTE CED sans dépendre des grandes plateformes propriétaires.
2025-04-08 06:37:14 +04:00
NOTE : La version historique PHP est conservée sur la branche `main`. Cette documentation décrit la branche `svelte`.
=== 🌳 Origine du projet
2025-04-08 06:37:14 +04:00
Cette application est un *fork* de https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI[*FEDIVERSE OKI*^], développée par l'https://o-k-i.net[ORGANISATION KA INTERNATIONALE (OKI)^], elle-même issue du projet https://codeberg.org/Ka-Ubuntu/kaubuntu.re[kaubuntu.re^] du mouvement https://kaubuntu.com[Ka-Ubuntu^]. La licence d'origine (GNU AGPL v3) est conservée et respectée. La refonte SvelteKit applique la https://o-k-i.net[charte OKI] (tokens panafricains, thème sombre par défaut, iconographie SVG kréyòl, cadences de motion « gwoka »).
2025-04-08 06:37:14 +04:00
[cols="1,3",options="header"]
|===
| Élément | Détail
2025-04-08 06:37:14 +04:00
| Dépôt upstream
| https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI
| Dépôt de ce fork
| `git@labola.o-k-i.net:cedric/annu-kute-ced.git` (branche `svelte`)
| Domaine de production
| https://annukuteced.buzz
| Gouvernance
| Application maintenue par OKI ; fork porté par le propriétaire du dépôt *cedric* (Cédric Famibelle-Pronzola)
| Licence
| https://www.gnu.org/licenses/agpl-3.0.html[GNU Affero General Public License v3^] (AGPL-V3) ou ultérieure
|===
=== 🔗 Sources et instances utilisées
Le hub agrège au build les sources du podcast ANNU KUTE CED :
[cols="1,2,3",options="header"]
|===
| Service | Instance | Compte / chaîne
| 🎥 PeerTube (vidéos, lives)
| GADE — `https://gade.o-k-i.net`
| https://gade.o-k-i.net/c/annu_kute_ced/videos[`annu_kute_ced`^]
| 🎙️ Castopod (épisodes audio)
| KUTE — `https://kute.o-k-i.net`
| https://kute.o-k-i.net/@annu_kute_cedric[`@annu_kute_cedric`^]
| 🎵 Funkwhale (musique)
| MIZIK — `https://mizik.o-k-i.net`
| morceaux aléatoires de l'instance
| 📡 Mastodon (timeline)
| BOKANTE — `https://bokante.o-k-i.net`
| https://bokante.o-k-i.net/@cedric[`@cedric`^]
|===
Toutes ces sources sont modifiables dans `src/lib/config.ts` (voir <<fr-configuration,Configuration>>).
=== ✨ Fonctionnalités
==== 🎥 Vidéos PeerTube
- Vidéos récentes, tendances et par catégories (configurables)
- *Shorts* : carrousel dédié aux vidéos portrait de moins de 3 minutes (défilement tactile)
- Page vidéo complète : lecteur PeerTube embarqué, description Markdown, badge de licence Creative Commons, commentaires (lecture seule), vidéos suggérées
- *Téléchargement* : fichiers directs et playlists HLS, avec résolution et taille
- *Partage* : copie de lien, code d'intégration, e-mail, Facebook, X, WhatsApp, LinkedIn, Telegram
- Recherche plein texte et par hashtag (préfixe `#`) sur un index JSON généré au build
==== 📺 Directs et annonces
- Page *Direct* (`/direct`) : embed du live PeerTube s'il est en cours, avec autoplay
- *Annonce du prochain live* : date et heure converties automatiquement pour 5 territoires (Ma'ohi Nui, Martinique/Guadeloupe, Guyane, France, Kanaky), image personnalisable
- Section *hero* d'accueil configurable : live, vidéo unique, playlist ou masquée
==== 🎙️ Podcast et musique
- *Castopod* : derniers épisodes via flux RSS, avec *lecteur audio intégré* (lecture/pause, avance automatique à l'épisode suivant, Media Session API)
- *Funkwhale* : sélection aléatoire de morceaux de l'instance, avec le même lecteur intégré
- *Un seul flux à la fois* entre les deux lecteurs (bus audio partagé)
==== 📡 Réseaux sociaux
- *Timeline Mastodon* : les 10 derniers posts récupérés au build et rendus en HTML sémantique (plus de bibliothèque JS embarquée)
==== 🌍 Internationalisation
- Interface en *français* (`/`) et en *anglais* (`/en/`) : routage par paramètre optionnel, bundles JSON, `hreflang`, attribut `lang` par route
- Kréyòl en signature : page 404 (« Paj la pa la »), page hors-ligne (« Pa gen koneksyon »), verrou maintenance (« An nou tann ! »)
==== 🎨 Charte OKI
- *Thème sombre par défaut* (identité de marque), thème clair en opt-in persisté en `localStorage`, appliqué sans FOUC
- Tokens panafricains (noir/or/vert/rouge), *flag-bar* de signature, typographies *Archivo* et *Inter* self-hébergées en woff2
- *Zéro emoji en interface* : sprite SVG maison (pictos kréyòl `ka`, `lambi`, `zetwal`… + icônes UI), zéro Font Awesome, zéro CDN
- Motion « gwoka » : KineticText au scroll (`animation-timeline: view()`), barre de progression, reveal syncopé (3+3+2), View Transitions — gate unique `prefers-reduced-motion`
==== 📱 PWA et confort d'utilisation
- *Progressive Web App* installable (bouton d'installation automatique)
- Mode hors ligne : shell et pages en cache via Service Worker (Workbox), page `/offline` dédiée
- *Indicateur visuel* de perte de connexion
- Interface entièrement responsive (mobile, tablette, desktop)
==== 💝 Dons, compte à rebours et divers
- *Page de dons* : LiberaPay, Ko-fi et Stripe (dons ponctuels et mensuels, montants suggérés)
- *Verrou maintenance* : compte à rebours multi-fuseaux affiché à la place de tout le site quand activé au build, redirection automatique à l'échéance
- Bloc « À propos » configurable (titre, deux paragraphes, image légendée)
==== 🔍 SEO et données structurées
- *JSON-LD* généré automatiquement : `WebSite` (avec `SearchAction`), `VideoObject`, `CollectionPage`, `BreadcrumbList`, `Organization`
- Balises *Open Graph* complètes et *Twitter Cards*, canonical, `hreflang` fr/en/x-default
- `sitemap.xml` *généré au build* (toutes les pages, vidéos comprises) et `robots.txt`
==== 🛡️ Sécurité
- *CSP stricte* : politique globale en en-tête (`_headers` Cloudflare / `.htaccess` Apache) + `script-src` délivré *par page* en balise `<meta>` avec les empreintes SHA-256 des scripts inline (aucun `'unsafe-inline'` pour les scripts)
- *Zéro requête tierce* au chargement hors instances first-party de l'écosystème (GADE, KUTE, BOKANTE, MIZIK) : ni Google Fonts, ni CDN, ni analytics
- HTML distant *sanitisé* au build (posts Mastodon, commentaires) ; descriptions Markdown échappées
- HSTS, `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy`, `Permissions-Policy` restrictive
==== ⚡ Performance (mesurée, Lighthouse mobile)
- *97 / 100 / 100 / 100* (performance, accessibilité, bonnes pratiques, SEO)
- JS initial ≈ 66 Ko gzip ; poids total de l'accueil ≈ 900 Ko ; LCP 2,4 s ; TBT 50 ms ; CLS 0
- Images distantes *optimisées au build* (WebP via ImageMagick) : vignettes PeerTube, avatars, médias Mastodon, pochettes Castopod
=== 🛠️ Technologies utilisées
- ⚡ *SvelteKit 2* + *Svelte 5* (runes) + *TypeScript* strict
- 📦 `@sveltejs/adapter-static` (prerender intégral, `trailingSlash: 'always'`)
- 📱 `vite-plugin-pwa` (Workbox, generateSW)
- 🖼️ *ImageMagick* (optimisation des images au prebuild)
- 🎨 CSS vanilla : tokens OKI + styles scopés — pas de framework CSS
- 🔤 `@fontsource/archivo` + `@fontsource/inter` (woff2 copiés dans `static/fonts/`)
=== 📁 Structure du projet
2025-04-08 06:37:14 +04:00
2025-07-24 22:12:30 +04:00
[source]
----
├── docs/
│ ├── wireframes/ # Maquettes d'origine (PNG desktop + mobile)
│ ├── DEPLOIEMENT-SVELTEKIT.md # Guide build + déploiement (o2switch, Cloudflare)
│ └── generate-readme-pdf.sh # Export de la doc : README.html / README.pdf
├── scripts/
│ ├── fetch-podcast-cover.mjs # Prebuild : pochettes Castopod optimisées (WebP)
│ ├── optimize-remote-images.mjs # Prebuild : vignettes/avatars/médias optimisés
│ └── postbuild-csp.mjs # Postbuild : CSP SHA-256 par page (balise meta)
├── src/
│ ├── app.html # %lang%, fonts, theme.js, registerSW.js
│ ├── hooks.server.ts # lang fr/en via transformPageChunk
│ ├── params/locale.ts # Matcher du paramètre [[locale]]
│ ├── lib/
│ │ ├── config.ts # ⭐ Toute la configuration d'instance
│ │ ├── types.ts # Types partagés (VideoSummary, Episode, Post…)
│ │ ├── audio-bus.svelte.ts # Un seul flux audio à la fois
│ │ ├── styles/ # oki-tokens.css (charte) + base.css (primitives)
│ │ ├── i18n/ # fr.json, en.json + helpers (locale, hrefFor…)
│ │ ├── server/ # Récupération des données au build :
│ │ │ ├── http.ts # fetch throttlé (429 → retry), sanitisation
│ │ │ ├── peertube.ts # API GADE (vidéos, shorts, live, commentaires)
│ │ │ ├── castopod.ts # Flux RSS KUTE (épisodes)
│ │ │ ├── funkwhale.ts # API MIZIK (morceaux aléatoires locaux)
│ │ │ ├── mastodon.ts # API BOKANTE (timeline)
│ │ │ ├── image-map.ts # Mapping images optimisées (mapImage)
│ │ │ └── image-map.json # (généré au prebuild)
│ │ ├── motion/ # tokens gwoka, action use:reveal
│ │ └── components/ # Seo, Nav, Sidebar, Footer, VideoCard,
│ │ # AudioPlayer, MastodonTimeline, HeroSection,
│ │ # CountdownLock, OfflineIndicator, motion/…
│ └── routes/
│ ├── +layout.ts # prerender = true, trailingSlash
│ ├── +error.svelte # 404 kréyòl (« Paj la pa la »)
│ ├── [[locale=locale]]/ # Toutes les pages, FR (/) et EN (/en/) :
│ │ ├── +page.svelte # accueil (agrégateur)
│ │ ├── video/[uuid]/ # page vidéo (embed, téléchargements, partage)
│ │ ├── categories/[id]/ # page catégorie
│ │ ├── recherche/ # recherche (index JSON + filtrage client)
│ │ ├── direct/ # live + annonce du prochain live
│ │ ├── dons/ # dons (LiberaPay, Ko-fi, Stripe)
│ │ ├── mentions-legales/ # mentions légales
│ │ └── offline/ # page hors-ligne (fallback du SW)
│ ├── search-index.json/ # Index de recherche (bake)
│ └── sitemap.xml/ # Sitemap (bake)
├── static/
│ ├── fonts/ # Archivo/Inter woff2 + fonts.css
│ ├── images/ # logo, favicons, pochettes, images optimisées
│ ├── icons.svg # Sprite SVG (pictos kréyòl + UI)
│ ├── theme.js # Anti-FOUC (thème sombre défaut, clair opt-in)
│ ├── registerSW.js # Enregistrement du Service Worker
│ ├── manifest.webmanifest # Manifest PWA
│ ├── _headers / .htaccess # Headers de sécurité (Cloudflare / Apache)
│ ├── 404.html # 404 statique autonome
│ ├── robots.txt / browserconfig.xml
├── uploads/ # Images d'annonces (non versionné, hors .gitkeep)
├── package.json / vite.config.ts # Adapter, PWA, paths.relative: false
2025-07-24 22:12:30 +04:00
└── README.adoc
----
2025-04-08 06:37:14 +04:00
=== 📋 Prérequis
- 🟢 *Node.js 20+* (recommandé : 22+)
- 🖼️ *ImageMagick* (`convert`) — optimisation des images au prebuild
- 🌐 Pour le développement : un accès réseau aux instances (les données sont fetchées au build)
.Installation d'ImageMagick
[source,bash]
----
# Ubuntu / Debian
sudo apt-get install imagemagick
# Fedora / RHEL / CentOS
sudo dnf install ImageMagick
----
=== 🚀 Installation et développement
2025-04-08 06:37:14 +04:00
. 📥 Clonez le dépôt et basculez sur la branche :
+
[source,bash]
----
git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git
cd annu-kute-ced
git checkout svelte
----
. 📦 Installez les dépendances :
+
[source,bash]
----
npm ci
----
. 🔧 Lancez le serveur de développement :
+
2025-07-24 22:12:30 +04:00
[source,bash]
----
npm run dev
----
. 🏗️ Buildez le site statique :
+
[source,bash]
----
npm run build # prebuild (images) → prerender (données) → postbuild (CSP)
npm run preview # vérification locale du build
2025-07-24 22:12:30 +04:00
----
2025-04-08 06:37:14 +04:00
Le dossier `build/` contient le site complet, prêt à déposer sur n'importe quel hébergement statique.
✅ *Vérifications qualité* : `npm run check` (svelte-check, 0 erreur / 0 warning exigé).
🔄 *Rafraîchissement du contenu* : les données étant bakées au build, un nouveau build est nécessaire pour afficher les dernières vidéos/épisodes/posts — voir `docs/DEPLOIEMENT-SVELTEKIT.md` pour un exemple de cron + rsync.
[[fr-configuration]]
=== ⚙️ Configuration
Toute la configuration d'instance vit dans *un seul fichier* : `src/lib/config.ts` (versionné). C'est l'équivalent des anciennes constantes PHP — modifiez-le puis rebuildez.
2025-04-08 06:37:14 +04:00
[cols="1,3",options="header"]
|===
| Export | Rôle
2025-04-13 10:00:24 +04:00
| `site`
| Nom, domaine (`baseUrl`), description, e-mail de contact, URLs licence/source, fuseau par défaut
2025-04-13 10:00:24 +04:00
| `legal`
| Coordonnées des mentions légales (webmaster, hébergeur o2Switch)
2025-04-13 10:00:24 +04:00
| `peertube`
| URL de l'instance, chaîne, compte live, durée max des shorts, volumes par section, tag « indépendance »
2025-04-13 10:00:24 +04:00
| `hero`
| Bannière d'accueil : `type` (`'live'`, `'video'`, `'playlist'`, `'none'`), vidéo/playlist associée
2025-04-13 10:00:24 +04:00
| `castopod`
| Activation, instance, slug(s) de podcast, nombre d'épisodes
| `funkwhale`
| Activation, instance MIZIK, nombre de morceaux (pool de 50, sélection aléatoire)
| `mastodon`
| Instance, compte, nombre de posts de la timeline
2025-10-17 12:28:20 +04:00
| `social`
| URLs des réseaux sociaux du header/footer (vide = icône masquée)
2025-10-17 12:28:20 +04:00
| `donations`
| Activation, URLs LiberaPay/Ko-fi, liens Stripe (ponctuels/mensuels), montants, devise
2025-10-17 12:28:20 +04:00
| `nextLive`
| Annonce du prochain live : activation, titre, description, date, image, 5 fuseaux horaires
| `categories` / `categoryNames` / `categoryIcons`
| Catégories prioritaires (ordre d'affichage), noms FR/EN, pictos du sprite
2025-10-17 12:28:20 +04:00
| `importantTags` / `popularTags`
| Hashtags de la sidebar/footer et de l'accueil
| `about`
| Bloc « À propos » : activation, titre, deux paragraphes, image + légende (masqué tant que `enabled: false`)
| `countdown`
| *Verrou maintenance* : quand `enabled: true`, tout le site buildé affiche le compte à rebours multi-fuseaux + date cible
|===
.Les textes d'interface
NOTE : Les libellés FR/EN vivent dans `src/lib/i18n/fr.json` et `en.json` (pas dans `config.ts`).
2025-10-17 12:28:20 +04:00
=== 🧭 Ordre des sections sur la page d'accueil
2025-10-17 12:28:20 +04:00
. *Hero* — si `hero.type` ≠ `'none'` (live, vidéo ou playlist)
. *Derniers épisodes* (Castopod) — si activé et épisodes disponibles
. *Morceaux* (Funkwhale) — si activé et morceaux disponibles
. *Actualités* (timeline Mastodon) — si posts disponibles
. *Shorts* — carrousel
. *Vidéos récentes*
. *Tendances*
. *Une section par catégorie prioritaire* (seulement si elle contient des vidéos) + lien « Voir plus »
. *Bloc « À propos »* (si activé) + aside hashtags populaires
2025-10-17 14:23:31 +04:00
[[fr-securite]]
=== 🛡️ Sécurité
2025-10-17 14:23:31 +04:00
==== Modèle CSP
2025-10-17 12:28:20 +04:00
- *En-tête global* (`static/_headers` pour Cloudflare Pages, `static/.htaccess` pour Apache/o2switch) : `style-src`, `img-src`, `font-src 'self'`, `connect-src 'self'`, `media-src`, `frame-src https://gade.o-k-i.net`, `frame-ancestors 'none'`, `base-uri 'self'`, `form-action 'self'`, `object-src 'none'`. Seules origines externes : les instances de l'écosystème.
- *`script-src` par page* : `scripts/postbuild-csp.mjs` calcule les empreintes SHA-256 des scripts inline de chaque page (script de démarrage SvelteKit + JSON-LD) et les injecte dans une balise `<meta http-equiv="Content-Security-Policy">` complète. Aucun `'unsafe-inline'` pour les scripts.
- Anti-FOUC, redirection de langue et enregistrement du SW en *fichiers externes* (`theme.js`, `registerSW.js`) : aucun script inline non hashé.
==== Redirections des anciennes URLs (Apache)
2025-10-17 12:28:20 +04:00
Le `.htaccess` redirige les URLs historiques PHP : `index.php` → `/`, `video.php?uuid=X` → `/video/X/`, `categories.php?id=N` → `/categories/N/`, `recherche.php?q=…` → `/recherche/?q=…`, `direct.php` → `/direct/`, `dons.php` → `/dons/`, `mentions-legales.php` → `/mentions-legales/`. Il force aussi HTTPS, sert `404.html` et met en cache immutable `/_app/` et `/fonts/`.
2025-10-17 12:28:20 +04:00
=== 📱 Progressive Web App (PWA)
2025-10-17 12:28:20 +04:00
- 📲 *Installation native* : bouton « Installer » dans le header (événement `beforeinstallprompt`)
- 🌐 *Mode hors ligne* : précache du shell (Workbox `generateSW`), `navigateFallback` vers `/offline/`
- 📡 *Détection de connexion* : indicateur visuel en cas de perte réseau
- 🔄 *Mise à jour* : `autoUpdate` + `skipWaiting` (mise à jour silencieuse au prochain chargement)
- L'enregistrement du SW se fait par le fichier statique `registerSW.js` (chemins absolus), jamais par injection du plugin
2025-10-17 12:28:20 +04:00
NOTE : Les flux audio/vidéo des instances ne sont *pas* interceptés par le SW (requêtes `Range`) — seuls le shell et les assets locaux sont précachés.
=== 🚀 Déploiement
Voir le guide complet : *`docs/DEPLOIEMENT-SVELTEKIT.md`*.
- *o2switch (Apache)* : déposer `build/` à la racine web ; le `.htaccess` inclus gère HTTPS, headers, redirections des anciennes URLs et 404
- *Cloudflare Pages* : build command `npm run build`, output `build` ; le `_headers` inclus applique la sécurité et le cache
- *Rafraîchissement* : rebuild planifié (cron + rsync, ou CI avec webhook après publication d'un épisode)
=== 👨‍💻 Développement et contribution
. 🌿 Créez une branche : `git checkout -b ma-fonctionnalite`
. 💾 Committez avec des *messages atomiques*, au format conventionnel :
* `feat: add …`, `fix: prevent …`, `docs: update …`, `refactor: …`
. ✅ Avant tout commit : `npm run check` (0 erreur / 0 warning) et `npm run build` vert
. 📤 Poussez : `git push origin ma-fonctionnalite`
. 🔀 Ouvrez une pull request
Bonnes pratiques du dépôt :
- Les remontées de bugs et propositions sont les bienvenues sur le dépôt du fork ; les améliorations génériques peuvent être proposées en upstream (FEDIVERSE OKI)
- `src/lib/server/image-map.json` et `static/images/remote/` sont régénérés au prebuild : pas d'édition manuelle
- Conventions Svelte 5 : runes uniquement, `{#each}` à clé unique, `onclick` (jamais `on:click`), durées lues depuis les tokens CSS
==== 📄 Exporter la documentation (HTML / PDF)
[source,bash]
----
docs/generate-readme-pdf.sh # README.html + README.pdf
docs/generate-readme-pdf.sh --html # HTML seulement
docs/generate-readme-pdf.sh --pdf # PDF seulement
----
Prérequis : `asciidoctor`, `chromium` et le paquet `fonts-noto-color-emoji`. La feuille de style `docs/docinfo.html` est injectée automatiquement via le mécanisme `docinfo` d'Asciidoctor.
=== 📜 Licence
2025-09-28 20:39:47 +04:00
Copyright (C) 2025 Cédric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE*
2025-09-28 20:39:47 +04:00
Ce programme est un logiciel libre : vous pouvez le redistribuer et/ou le modifier selon les termes de la licence publique générale GNU Affero publiée par la Free Software Foundation, soit la version 3 de la licence, soit (à votre choix) toute version ultérieure.
2025-09-28 20:39:47 +04:00
Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de COMMERCIALISATION ou d'ADAPTATION À UN USAGE PARTICULIER. Voir la https://www.gnu.org/licenses/agpl-3.0.html[licence publique générale GNU Affero^] pour plus de détails (texte intégral dans `LICENSE`).
2025-09-28 20:39:47 +04:00
=== 📞 Contact
2025-09-28 20:39:47 +04:00
Pour toute question ou suggestion concernant cette plateforme : mailto:kontak@o-k-i.net[kontak@o-k-i.net]
2025-09-28 20:39:47 +04:00
<<top,⬆ Retour au sommaire>>
2025-09-28 20:39:47 +04:00
'''
2025-10-17 12:28:20 +04:00
[[en]]
== 🇬🇧 English version
2025-10-17 12:28:20 +04:00
=== 📖 Description
2025-10-17 12:28:20 +04:00
*ANNU KUTE CED* is the *multimedia hub* of the podcast of the same name. It brings together in a single place:
2025-09-28 20:39:47 +04:00
- 🎥 the podcast's *PeerTube* channel (videos, shorts, live streams);
- 🎙️ its *Castopod* account (latest episodes, built-in audio playback);
- 🎵 a random selection of *Funkwhale* tracks (same built-in player);
- 📡 its *Mastodon* timeline (news and announcements).
2025-09-28 20:39:47 +04:00
This version is a *100% static SvelteKit application* (Svelte 5 + TypeScript, `adapter-static`, full prerender): all instance data is *fetched at build time* ("baked") and the generated site can be served from any static hosting — including shared hosting like o2switch — *with no PHP, no Node, no database*. It is also an installable *Progressive Web App* with offline support, in French and English.
2025-09-28 20:39:47 +04:00
🎯 *Mission*: provide a single, free and decentralized entry point to discover, listen to and follow the ANNU KUTE CED podcast without relying on Big Tech platforms.
2025-10-17 12:28:20 +04:00
NOTE: The historical PHP version is kept on the `main` branch. This documentation covers the `svelte` branch.
=== 🌳 Project origin
2025-09-28 20:39:47 +04:00
This application is a *fork* of https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI[*FEDIVERSE OKI*^], developed by the https://o-k-i.net[ORGANISATION KA INTERNATIONALE (OKI)^], itself derived from the https://codeberg.org/Ka-Ubuntu/kaubuntu.re[kaubuntu.re^] project by the https://kaubuntu.com[Ka-Ubuntu^] movement. The original license (GNU AGPL v3) is preserved and respected. The SvelteKit rewrite applies the OKI design system (panafrican tokens, dark theme by default, Kréyòl SVG iconography, "gwoka" motion cadences).
2025-09-28 20:39:47 +04:00
[cols="1,3",options="header"]
|===
| Item | Detail
2025-09-28 20:39:47 +04:00
| Upstream repository
| https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI
2025-09-28 20:39:47 +04:00
| This fork's repository
| `git@labola.o-k-i.net:cedric/annu-kute-ced.git` (`svelte` branch)
2025-09-28 20:39:47 +04:00
| Production domain
| https://annukuteced.buzz
2025-09-28 20:39:47 +04:00
| Governance
| Application maintained by OKI; fork carried by the repository owner *cedric* (Cédric Famibelle-Pronzola)
2025-10-17 12:28:20 +04:00
| License
| https://www.gnu.org/licenses/agpl-3.0.html[GNU Affero General Public License v3^] (AGPL-V3) or later
|===
2025-10-17 12:28:20 +04:00
=== 🔗 Aggregated sources and instances
2025-10-17 12:28:20 +04:00
The hub aggregates the ANNU KUTE CED podcast's sources at build time:
2025-10-17 12:28:20 +04:00
[cols="1,2,3",options="header"]
|===
| Service | Instance | Account / channel
2025-10-17 12:28:20 +04:00
| 🎥 PeerTube (videos, lives)
| GADE — `https://gade.o-k-i.net`
| https://gade.o-k-i.net/c/annu_kute_ced/videos[`annu_kute_ced`^]
2025-09-28 20:39:47 +04:00
| 🎙️ Castopod (audio episodes)
| KUTE — `https://kute.o-k-i.net`
| https://kute.o-k-i.net/@annu_kute_cedric[`@annu_kute_cedric`^]
2025-09-28 20:39:47 +04:00
| 🎵 Funkwhale (music)
| MIZIK — `https://mizik.o-k-i.net`
| random tracks from the instance
| 📡 Mastodon (timeline)
| BOKANTE — `https://bokante.o-k-i.net`
| https://bokante.o-k-i.net/@cedric[`@cedric`^]
|===
2025-10-17 17:38:16 +04:00
All of these sources can be changed in `src/lib/config.ts` (see <<en-configuration,Configuration>>).
2025-10-17 17:38:16 +04:00
=== ✨ Features
2025-10-17 17:38:16 +04:00
==== 🎥 PeerTube videos
2025-10-17 17:38:16 +04:00
- Recent, trending and per-category videos (configurable)
- *Shorts*: dedicated carousel for portrait videos under 3 minutes (touch scrolling)
- Full video page: embedded PeerTube player, Markdown description, Creative Commons licence badge, comments (read-only), suggested videos
- *Downloads*: direct files and HLS playlists, with resolution and size
- *Sharing*: copy link, embed code, e-mail, Facebook, X, WhatsApp, LinkedIn, Telegram
- Full-text search and hashtag search (`#` prefix) over a build-generated JSON index
2025-10-17 17:38:16 +04:00
==== 📺 Live streams and announcements
2025-10-17 17:38:16 +04:00
- *Live page* (`/direct`): embeds the PeerTube live stream when one is running, with autoplay
- *Next live announcement*: date and time automatically converted for 5 territories (Ma'ohi Nui, Martinique/Guadeloupe, French Guiana, France, Kanaky), custom image
- Configurable homepage *hero section*: live, single video, playlist or hidden
==== 🎙️ Podcast and music
- *Castopod*: latest episodes via RSS feed, with a *built-in audio player* (play/pause, auto-advance to the next episode, Media Session API)
- *Funkwhale*: random track selection from the instance, using the same built-in player
- *One stream at a time* across both players (shared audio bus)
==== 📡 Social networks
- *Mastodon timeline*: the 10 latest posts fetched at build time and rendered as semantic HTML (no embedded JS library anymore)
==== 🌍 Internationalization
- Interface in *French* (`/`) and *English* (`/en/`): optional-parameter routing, JSON bundles, `hreflang`, per-route `lang` attribute
- Kréyòl as a signature: 404 page ("Paj la pa la"), offline page ("Pa gen koneksyon"), maintenance lock ("An nou tann !")
==== 🎨 OKI design system
- *Dark theme by default* (brand identity), light theme as an opt-in persisted in `localStorage`, applied without FOUC
- Panafrican tokens (black/gold/green/red), signature *flag-bar*, self-hosted *Archivo* and *Inter* woff2 fonts
- *Zero emoji in the interface*: custom SVG sprite (Kréyòl pictograms `ka`, `lambi`, `zetwal`… + UI icons), no Font Awesome, no CDN
- "Gwoka" motion: scroll-driven KineticText (`animation-timeline: view()`), progress bar, syncopated reveal (3+3+2), View Transitions — single `prefers-reduced-motion` gate
==== 📱 PWA and user experience
- Installable *Progressive Web App* (automatic install button)
- Offline mode: shell and pages cached via Service Worker (Workbox), dedicated `/offline` page
- *Visual indicator* when the connection is lost
- Fully responsive interface (mobile, tablet, desktop)
==== 💝 Donations, countdown and more
- *Donation page*: LiberaPay, Ko-fi and Stripe (one-time and monthly donations, suggested amounts)
- *Maintenance lock*: multi-timezone countdown displayed instead of the whole site when enabled at build time, automatic redirect when it ends
- Configurable "About" block (title, two paragraphs, captioned image)
==== 🔍 SEO and structured data
- Automatically generated *JSON-LD*: `WebSite` (with `SearchAction`), `VideoObject`, `CollectionPage`, `BreadcrumbList`, `Organization`
- Full *Open Graph* and *Twitter Cards* meta tags, canonical, `hreflang` fr/en/x-default
- Build-generated `sitemap.xml` (every page, including videos) and `robots.txt`
==== 🛡️ Security
- *Strict CSP*: global policy in headers (`_headers` for Cloudflare / `.htaccess` for Apache) + per-page `script-src` delivered in a `<meta>` tag with SHA-256 hashes of inline scripts (no `'unsafe-inline'` for scripts)
- *Zero third-party requests* at load time outside the first-party ecosystem instances (GADE, KUTE, BOKANTE, MIZIK): no Google Fonts, no CDN, no analytics
- Remote HTML *sanitized* at build time (Mastodon posts, comments); Markdown descriptions escaped
- HSTS, `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy`, restrictive `Permissions-Policy`
==== ⚡ Performance (measured, mobile Lighthouse)
- *97 / 100 / 100 / 100* (performance, accessibility, best practices, SEO)
- Initial JS ≈ 66 KB gzip; homepage total weight ≈ 900 KB; LCP 2.4 s; TBT 50 ms; CLS 0
- Remote images *optimized at build time* (WebP via ImageMagick): PeerTube thumbnails, avatars, Mastodon media, Castopod covers
=== 🛠️ Tech stack
- ⚡ *SvelteKit 2* + *Svelte 5* (runes) + strict *TypeScript*
- 📦 `@sveltejs/adapter-static` (full prerender, `trailingSlash: 'always'`)
- 📱 `vite-plugin-pwa` (Workbox, generateSW)
- 🖼️ *ImageMagick* (build-time image optimization)
- 🎨 Vanilla CSS: OKI tokens + scoped styles — no CSS framework
- 🔤 `@fontsource/archivo` + `@fontsource/inter` (woff2 copied to `static/fonts/`)
=== 📁 Project structure
[source]
----
├── docs/
│ ├── wireframes/ # Original mockups (desktop + mobile PNGs)
│ ├── DEPLOIEMENT-SVELTEKIT.md # Build + deployment guide (o2switch, Cloudflare)
│ └── generate-readme-pdf.sh # Docs export: README.html / README.pdf
├── scripts/
│ ├── fetch-podcast-cover.mjs # Prebuild: optimized Castopod covers (WebP)
│ ├── optimize-remote-images.mjs # Prebuild: optimized thumbnails/avatars/media
│ └── postbuild-csp.mjs # Postbuild: per-page SHA-256 CSP (meta tag)
├── src/
│ ├── app.html # %lang%, fonts, theme.js, registerSW.js
│ ├── hooks.server.ts # fr/en lang via transformPageChunk
│ ├── params/locale.ts # [[locale]] param matcher
│ ├── lib/
│ │ ├── config.ts # ⭐ All instance configuration
│ │ ├── types.ts # Shared types (VideoSummary, Episode, Post…)
│ │ ├── audio-bus.svelte.ts # One audio stream at a time
│ │ ├── styles/ # oki-tokens.css (brand) + base.css (primitives)
│ │ ├── i18n/ # fr.json, en.json + helpers (locale, hrefFor…)
│ │ ├── server/ # Build-time data fetching:
│ │ │ ├── http.ts # throttled fetch (429 → retry), sanitizing
│ │ │ ├── peertube.ts # GADE API (videos, shorts, live, comments)
│ │ │ ├── castopod.ts # KUTE RSS feed (episodes)
│ │ │ ├── funkwhale.ts # MIZIK API (random local tracks)
│ │ │ ├── mastodon.ts # BOKANTE API (timeline)
│ │ │ ├── image-map.ts # Optimized images mapping (mapImage)
│ │ │ └── image-map.json # (generated at prebuild)
│ │ ├── motion/ # gwoka tokens, use:reveal action
│ │ └── components/ # Seo, Nav, Sidebar, Footer, VideoCard,
│ │ # AudioPlayer, MastodonTimeline, HeroSection,
│ │ # CountdownLock, OfflineIndicator, motion/…
│ └── routes/
│ ├── +layout.ts # prerender = true, trailingSlash
│ ├── +error.svelte # Kréyòl 404 ("Paj la pa la")
│ ├── [[locale=locale]]/ # Every page, FR (/) and EN (/en/):
│ │ ├── +page.svelte # home (aggregator)
│ │ ├── video/[uuid]/ # video page (embed, downloads, sharing)
│ │ ├── categories/[id]/ # category page
│ │ ├── recherche/ # search (JSON index + client filtering)
│ │ ├── direct/ # live + next-live announcement
│ │ ├── dons/ # donations (LiberaPay, Ko-fi, Stripe)
│ │ ├── mentions-legales/ # legal notice
│ │ └── offline/ # offline page (SW fallback)
│ ├── search-index.json/ # Search index (baked)
│ └── sitemap.xml/ # Sitemap (baked)
├── static/
│ ├── fonts/ # Archivo/Inter woff2 + fonts.css
│ ├── images/ # logo, favicons, covers, optimized images
│ ├── icons.svg # SVG sprite (Kréyòl pictograms + UI)
│ ├── theme.js # Anti-FOUC (dark default, light opt-in)
│ ├── registerSW.js # Service Worker registration
│ ├── manifest.webmanifest # PWA manifest
│ ├── _headers / .htaccess # Security headers (Cloudflare / Apache)
│ ├── 404.html # Self-contained static 404
│ ├── robots.txt / browserconfig.xml
├── uploads/ # Announcement images (not versioned, except .gitkeep)
├── package.json / vite.config.ts # Adapter, PWA, paths.relative: false
└── README.adoc
2025-10-17 17:38:16 +04:00
----
=== 📋 Requirements
2025-10-17 17:38:16 +04:00
- 🟢 *Node.js 20+* (recommended: 22+)
- 🖼️ *ImageMagick* (`convert`) — build-time image optimization
- 🌐 For development: network access to the instances (data is fetched at build time)
.Installing ImageMagick
[source,bash]
2025-10-17 17:38:16 +04:00
----
# Ubuntu / Debian
sudo apt-get install imagemagick
2025-10-17 17:38:16 +04:00
# Fedora / RHEL / CentOS
sudo dnf install ImageMagick
----
=== 🚀 Installation and development
2025-10-17 17:38:16 +04:00
. 📥 Clone the repository and switch to the branch:
2025-10-17 17:38:16 +04:00
+
[source,bash]
----
git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git
cd annu-kute-ced
git checkout svelte
2025-10-17 17:38:16 +04:00
----
. 📦 Install dependencies:
2025-10-17 17:38:16 +04:00
+
[source,bash]
----
npm ci
----
. 🔧 Start the development server:
+
[source,bash]
----
npm run dev
----
. 🏗️ Build the static site:
+
[source,bash]
----
npm run build # prebuild (images) → prerender (data) → postbuild (CSP)
npm run preview # local check of the build
----
2025-10-17 17:38:16 +04:00
The `build/` directory holds the complete site, ready to drop on any static hosting.
✅ *Quality gates*: `npm run check` (svelte-check, 0 errors / 0 warnings required).
🔄 *Content refresh*: since data is baked at build time, a new build is required to display the latest videos/episodes/posts — see `docs/DEPLOIEMENT-SVELTEKIT.md` for a cron + rsync example.
[[en-configuration]]
=== ⚙️ Configuration
All instance configuration lives in *a single file*: `src/lib/config.ts` (versioned). It is the equivalent of the old PHP constants — edit it, then rebuild.
2025-07-24 22:12:30 +04:00
[cols="1,3",options="header"]
|===
| Export | Role
2025-07-21 13:15:35 +04:00
| `site`
| Name, domain (`baseUrl`), description, contact e-mail, license/source URLs, default timezone
2025-07-21 13:15:35 +04:00
| `legal`
| Legal notice details (webmaster, o2Switch host)
2025-07-21 13:21:26 +04:00
| `peertube`
| Instance URL, channel, live account, max shorts duration, per-section volumes, "independence" tag
2025-07-21 13:21:26 +04:00
| `hero`
| Homepage banner: `type` (`'live'`, `'video'`, `'playlist'`, `'none'`), associated video/playlist
2025-07-21 13:21:26 +04:00
| `castopod`
| Toggle, instance, podcast slug(s), episode count
2025-07-24 22:12:30 +04:00
| `funkwhale`
| Toggle, MIZIK instance, track count (pool of 50, random selection)
2025-07-24 22:12:30 +04:00
| `mastodon`
| Instance, account, timeline post count
| `social`
| Header/footer social network URLs (empty = icon hidden)
| `donations`
| Toggle, LiberaPay/Ko-fi URLs, Stripe links (one-time/monthly), amounts, currency
| `nextLive`
| Next live announcement: toggle, title, description, date, image, 5 timezones
| `categories` / `categoryNames` / `categoryIcons`
| Priority categories (display order), FR/EN names, sprite pictograms
| `importantTags` / `popularTags`
| Sidebar/footer and homepage hashtags
| `about`
| "About" block: toggle, title, two paragraphs, image + caption (hidden while `enabled: false`)
| `countdown`
| *Maintenance lock*: when `enabled: true`, the whole built site shows the multi-timezone countdown + target date
|===
.Interface texts
NOTE: FR/EN labels live in `src/lib/i18n/fr.json` and `en.json` (not in `config.ts`).
2025-07-17 20:14:14 +04:00
=== 🧭 Homepage section order
2025-07-17 20:14:14 +04:00
. *Hero* — if `hero.type` ≠ `'none'` (live, video or playlist)
. *Latest episodes* (Castopod) — if enabled and episodes available
. *Tracks* (Funkwhale) — if enabled and tracks available
. *News* (Mastodon timeline) — if posts available
. *Shorts* — carousel
. *Recent videos*
. *Trending*
. *One section per priority category* (only when it has videos) + "See more" link
. *"About" block* (if enabled) + popular hashtags aside
2025-07-17 20:14:14 +04:00
[[en-securite]]
=== 🛡️ Security
2025-07-17 20:14:14 +04:00
==== CSP model
2025-07-17 20:14:14 +04:00
- *Global header* (`static/_headers` for Cloudflare Pages, `static/.htaccess` for Apache/o2switch): `style-src`, `img-src`, `font-src 'self'`, `connect-src 'self'`, `media-src`, `frame-src https://gade.o-k-i.net`, `frame-ancestors 'none'`, `base-uri 'self'`, `form-action 'self'`, `object-src 'none'`. Only external origins: the ecosystem instances.
- *Per-page `script-src`*: `scripts/postbuild-csp.mjs` computes SHA-256 hashes of each page's inline scripts (SvelteKit start script + JSON-LD) and injects them into a full `<meta http-equiv="Content-Security-Policy">` tag. No `'unsafe-inline'` for scripts.
- Anti-FOUC, language redirect and SW registration as *external files* (`theme.js`, `registerSW.js`): no unhashed inline script.
2025-04-08 06:37:14 +04:00
==== Legacy URL redirects (Apache)
2025-04-08 06:37:14 +04:00
The `.htaccess` redirects historical PHP URLs: `index.php` → `/`, `video.php?uuid=X` → `/video/X/`, `categories.php?id=N` → `/categories/N/`, `recherche.php?q=…` → `/recherche/?q=…`, `direct.php` → `/direct/`, `dons.php` → `/dons/`, `mentions-legales.php` → `/mentions-legales/`. It also forces HTTPS, serves `404.html` and sets immutable caching for `/_app/` and `/fonts/`.
=== 📱 Progressive Web App (PWA)
2025-04-08 06:37:14 +04:00
- 📲 *Native installation*: "Install" button in the header (`beforeinstallprompt` event)
- 🌐 *Offline mode*: shell precache (Workbox `generateSW`), `navigateFallback` to `/offline/`
- 📡 *Connection detection*: visual indicator when the network is lost
- 🔄 *Updates*: `autoUpdate` + `skipWaiting` (silent update on next load)
- SW registration is done by the static `registerSW.js` file (absolute paths), never via plugin injection
2025-04-08 17:30:06 +04:00
NOTE: Instance audio/video streams are *not* intercepted by the SW (`Range` requests) — only the shell and local assets are precached.
2025-07-24 08:40:35 +04:00
=== 🚀 Deployment
2025-07-24 08:40:35 +04:00
See the full guide: *`docs/DEPLOIEMENT-SVELTEKIT.md`*.
2025-07-24 08:40:35 +04:00
- *o2switch (Apache)*: drop `build/` at the web root; the bundled `.htaccess` handles HTTPS, headers, legacy URL redirects and 404
- *Cloudflare Pages*: build command `npm run build`, output `build`; the bundled `_headers` applies security and caching
- *Refresh*: scheduled rebuild (cron + rsync, or CI with a webhook after an episode is published)
2025-07-24 08:40:35 +04:00
=== 👨‍💻 Development and contribution
. 🌿 Create a branch: `git checkout -b my-feature`
. 💾 Commit with *atomic messages*, conventional format:
* `feat: add …`, `fix: prevent …`, `docs: update …`, `refactor: …`
. ✅ Before any commit: `npm run check` (0 errors / 0 warnings) and a green `npm run build`
. 📤 Push: `git push origin my-feature`
. 🔀 Open a pull request
Repository best practices:
- Bug reports and proposals are welcome on the fork's repository; generic improvements can be proposed upstream (FEDIVERSE OKI)
- `src/lib/server/image-map.json` and `static/images/remote/` are regenerated at prebuild: no manual editing
- Svelte 5 conventions: runes only, uniquely keyed `{#each}`, `onclick` (never `on:click`), durations read from CSS tokens
==== 📄 Exporting the documentation (HTML / PDF)
[source,bash]
----
docs/generate-readme-pdf.sh # README.html + README.pdf
docs/generate-readme-pdf.sh --html # HTML only
docs/generate-readme-pdf.sh --pdf # PDF only
----
Requirements: `asciidoctor`, `chromium` and the `fonts-noto-color-emoji` package. The `docs/docinfo.html` stylesheet is automatically injected via Asciidoctor's `docinfo` mechanism.
=== 📜 License
Copyright (C) 2025 Cédric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE*
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the https://www.gnu.org/licenses/agpl-3.0.html[GNU Affero General Public License^] for more details (full text in `LICENSE`).
2025-07-24 08:40:35 +04:00
=== 📞 Contact
2025-07-24 08:40:35 +04:00
For any question or suggestion about this platform: mailto:kontak@o-k-i.net[kontak@o-k-i.net]
<<top,⬆ Back to top>>