Files
annu-kute-ced/README.adoc
T
sucupira 3c0b094e92 Réécrit le README pour la version SvelteKit
Remplace la documentation PHP par celle de la branche svelte (FR/EN) :
architecture statique et bake au build, fonctionnalités portées (Funkwhale
inclus), référence de src/lib/config.ts, modÚle CSP par page, PWA, structure
du projet, prérequis Node + ImageMagick, mesures Lighthouse, déploiement
2026-07-23 08:04:41 -04:00

40 KiB
Raw Blame History

đŸŽ™ïž ANNU KUTE CED — Hub multimĂ©dia du podcast (SvelteKit)

Sommaire / Contents

🌍 Hub multimĂ©dia du podcast ANNU KUTE CED — version SvelteKit statique
🌍 Multimedia hub for the ANNU KUTE CED podcast — static SvelteKit version

Choisissez votre langue / Choose your language :
đŸ‡«đŸ‡· Version française · 🇬🇧 English version


đŸ‡«đŸ‡· 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 FEDIVERSE OKI, dĂ©veloppĂ©e par l’ORGANISATION KA INTERNATIONALE (OKI), elle-mĂȘme issue du projet kaubuntu.re du mouvement Ka-Ubuntu. La licence d’origine (GNU AGPL v3) est conservĂ©e et respectĂ©e. La refonte SvelteKit applique la charte OKI (tokens panafricains, thĂšme sombre par dĂ©faut, iconographie SVG krĂ©yĂČl, cadences de motion « gwoka »).

É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

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 :

Service Instance Compte / chaĂźne

đŸŽ„ PeerTube (vidĂ©os, lives)

GADE — https://gade.o-k-i.net

annu_kute_ced

đŸŽ™ïž Castopod (Ă©pisodes audio)

KUTE — https://kute.o-k-i.net

@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

@cedric

Toutes ces sources sont modifiables dans src/lib/config.ts (voir 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

├── 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
# Ubuntu / Debian
sudo apt-get install imagemagick

# Fedora / RHEL / CentOS
sudo dnf install ImageMagick

🚀 Installation et dĂ©veloppement

  1. đŸ“„ Clonez le dĂ©pĂŽt et basculez sur la branche :

    git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git
    cd annu-kute-ced
    git checkout svelte
  2. 📩 Installez les dĂ©pendances :

    npm ci
  3. 🔧 Lancez le serveur de dĂ©veloppement :

    npm run dev
  4. đŸ—ïž Buildez le site statique :

    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.

⚙ 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.

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

  1. Hero — si hero.type ≠ 'none' (live, vidĂ©o ou playlist)

  2. Derniers Ă©pisodes (Castopod) — si activĂ© et Ă©pisodes disponibles

  3. Morceaux (Funkwhale) — si activĂ© et morceaux disponibles

  4. ActualitĂ©s (timeline Mastodon) — si posts disponibles

  5. Shorts — carrousel

  6. Vidéos récentes

  7. Tendances

  8. Une section par catégorie prioritaire (seulement si elle contient des vidéos) + lien « Voir plus »

  9. Bloc « À propos » (si activĂ©) + aside hashtags populaires

đŸ›Ąïž 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 <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)

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

  1. 🌿 CrĂ©ez une branche : git checkout -b ma-fonctionnalite

  2. đŸ’Ÿ Committez avec des messages atomiques, au format conventionnel :

    • feat: add 
, fix: prevent 
, docs: update 
, refactor: 


  3. ✅ Avant tout commit : npm run check (0 erreur / 0 warning) et npm run build vert

  4. đŸ“€ Poussez : git push origin ma-fonctionnalite

  5. 🔀 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)

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 © 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 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 : kontak@o-k-i.net


🇬🇧 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 FEDIVERSE OKI, developed by the ORGANISATION KA INTERNATIONALE (OKI), itself derived from the kaubuntu.re project by the 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).

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

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:

Service Instance Account / channel

đŸŽ„ PeerTube (videos, lives)

GADE — https://gade.o-k-i.net

annu_kute_ced

đŸŽ™ïž Castopod (audio episodes)

KUTE — https://kute.o-k-i.net

@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

@cedric

All of these sources can be changed in src/lib/config.ts (see Configuration).

✹ 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 <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

├── 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
# Ubuntu / Debian
sudo apt-get install imagemagick

# Fedora / RHEL / CentOS
sudo dnf install ImageMagick

🚀 Installation and development

  1. đŸ“„ Clone the repository and switch to the branch:

    git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git
    cd annu-kute-ced
    git checkout svelte
  2. 📩 Install dependencies:

    npm ci
  3. 🔧 Start the development server:

    npm run dev
  4. đŸ—ïž Build the static site:

    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.

⚙ 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.

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

Note
Interface texts
FR/EN labels live in src/lib/i18n/fr.json and en.json (not in config.ts).

🧭 Homepage section order

  1. Hero — if hero.type ≠ 'none' (live, video or playlist)

  2. Latest episodes (Castopod) — if enabled and episodes available

  3. Tracks (Funkwhale) — if enabled and tracks available

  4. News (Mastodon timeline) — if posts available

  5. Shorts — carousel

  6. Recent videos

  7. Trending

  8. One section per priority category (only when it has videos) + "See more" link

  9. "About" block (if enabled) + popular hashtags aside

đŸ›Ąïž 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 <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.

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

  1. 🌿 Create a branch: git checkout -b my-feature

  2. đŸ’Ÿ Commit with atomic messages, conventional format:

    • feat: add 
, fix: prevent 
, docs: update 
, refactor: 


  3. ✅ Before any commit: npm run check (0 errors / 0 warnings) and a green npm run build

  4. đŸ“€ Push: git push origin my-feature

  5. 🔀 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)

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 © 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 GNU Affero General Public License for more details (full text in LICENSE).

📞 Contact

For any question or suggestion about this platform: kontak@o-k-i.net