= đŸŽ™ïž ANNU KUTE CED — Hub multimĂ©dia du podcast (SvelteKit) :toc: left :toc-title: Sommaire / Contents :toclevels: 3 [[top]] 🌍 *Hub multimĂ©dia du podcast ANNU KUTE CED — version SvelteKit statique* + 🌍 *Multimedia hub for the ANNU KUTE CED podcast — static SvelteKit version* [.text-center] *Choisissez votre langue / Choose your language :* + <> · <> ''' [[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. NOTE : La version historique PHP est conservĂ©e sur la branche `main`. Cette documentation dĂ©crit la branche `svelte`. === 🌳 Origine du projet 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 »). [cols="1,3",options="header"] |=== | ÉlĂ©ment | DĂ©tail | 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 <>). === ✹ 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 `` 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 [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 └── README.adoc ---- === 📋 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 . đŸ“„ 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 : + [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 ---- 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. [cols="1,3",options="header"] |=== | Export | RĂŽle | `site` | Nom, domaine (`baseUrl`), description, e-mail de contact, URLs licence/source, fuseau par dĂ©faut | `legal` | CoordonnĂ©es des mentions lĂ©gales (webmaster, hĂ©bergeur o2Switch) | `peertube` | URL de l'instance, chaĂźne, compte live, durĂ©e max des shorts, volumes par section, tag « indĂ©pendance » | `hero` | BanniĂšre d'accueil : `type` (`'live'`, `'video'`, `'playlist'`, `'none'`), vidĂ©o/playlist associĂ©e | `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 | `social` | URLs des rĂ©seaux sociaux du header/footer (vide = icĂŽne masquĂ©e) | `donations` | Activation, URLs LiberaPay/Ko-fi, liens Stripe (ponctuels/mensuels), montants, devise | `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 | `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`). === 🧭 Ordre des sections sur la page d'accueil . *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 [[fr-securite]] === đŸ›Ąïž SĂ©curitĂ© ==== ModĂšle CSP - *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 `` 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) 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/`. === đŸ“± Progressive Web App (PWA) - đŸ“Č *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 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 Copyright (C) 2025 CĂ©dric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE* 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. 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`). === 📞 Contact Pour toute question ou suggestion concernant cette plateforme : mailto:kontak@o-k-i.net[kontak@o-k-i.net] <> ''' [[en]] == 🇬🇧 English version === 📖 Description *ANNU KUTE CED* is the *multimedia hub* of the podcast of the same name. It brings together in a single place: - đŸŽ„ 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). 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. 🎯 *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. NOTE: The historical PHP version is kept on the `main` branch. This documentation covers the `svelte` branch. === 🌳 Project origin 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). [cols="1,3",options="header"] |=== | Item | Detail | Upstream repository | https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI | This fork's repository | `git@labola.o-k-i.net:cedric/annu-kute-ced.git` (`svelte` branch) | Production domain | https://annukuteced.buzz | Governance | Application maintained by OKI; fork carried by the repository owner *cedric* (CĂ©dric Famibelle-Pronzola) | License | https://www.gnu.org/licenses/agpl-3.0.html[GNU Affero General Public License v3^] (AGPL-V3) or later |=== === 🔗 Aggregated sources and instances The hub aggregates the ANNU KUTE CED podcast's sources at build time: [cols="1,2,3",options="header"] |=== | Service | Instance | Account / channel | đŸŽ„ PeerTube (videos, lives) | GADE — `https://gade.o-k-i.net` | https://gade.o-k-i.net/c/annu_kute_ced/videos[`annu_kute_ced`^] | đŸŽ™ïž Castopod (audio episodes) | KUTE — `https://kute.o-k-i.net` | https://kute.o-k-i.net/@annu_kute_cedric[`@annu_kute_cedric`^] | đŸŽ” 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`^] |=== All of these sources can be changed in `src/lib/config.ts` (see <>). === ✹ Features ==== đŸŽ„ PeerTube videos - 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 ==== đŸ“ș Live streams and announcements - *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 `` 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 ---- === 📋 Requirements - 🟱 *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] ---- # Ubuntu / Debian sudo apt-get install imagemagick # Fedora / RHEL / CentOS sudo dnf install ImageMagick ---- === 🚀 Installation and development . đŸ“„ Clone the repository and switch to the branch: + [source,bash] ---- git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git cd annu-kute-ced git checkout svelte ---- . 📩 Install dependencies: + [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 ---- 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. [cols="1,3",options="header"] |=== | Export | Role | `site` | Name, domain (`baseUrl`), description, contact e-mail, license/source URLs, default timezone | `legal` | Legal notice details (webmaster, o2Switch host) | `peertube` | Instance URL, channel, live account, max shorts duration, per-section volumes, "independence" tag | `hero` | Homepage banner: `type` (`'live'`, `'video'`, `'playlist'`, `'none'`), associated video/playlist | `castopod` | Toggle, instance, podcast slug(s), episode count | `funkwhale` | Toggle, MIZIK instance, track count (pool of 50, random selection) | `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`). === 🧭 Homepage section order . *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 [[en-securite]] === đŸ›Ąïž Security ==== CSP model - *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 `` tag. No `'unsafe-inline'` for scripts. - Anti-FOUC, language redirect and SW registration as *external files* (`theme.js`, `registerSW.js`): no unhashed inline script. ==== Legacy URL redirects (Apache) 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) - đŸ“Č *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 NOTE: Instance audio/video streams are *not* intercepted by the SW (`Range` requests) — only the shell and local assets are precached. === 🚀 Deployment See the full guide: *`docs/DEPLOIEMENT-SVELTEKIT.md`*. - *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) === đŸ‘šâ€đŸ’» 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`). === 📞 Contact For any question or suggestion about this platform: mailto:kontak@o-k-i.net[kontak@o-k-i.net] <>