🎙️ ANNU KUTE CED — Hub multimédia du podcast
- 🇫🇷 Version française
- 📖 Description
- 🌳 Origine du projet
- 🔗 Sources et instances utilisées
- ✨ Fonctionnalités
- 🛠️ Technologies utilisées
- 📁 Structure du projet
- 📋 Prérequis
- 🚀 Installation
- ⚙️ Configuration
- 🎨 Personnalisation de l’apparence
- 🧭 Ordre des sections sur la page d’accueil
- 🛡️ Sécurité
- 📱 Progressive Web App (PWA)
- 📊 Analytics (Plausible)
- 🚀 Déploiement sur serveur mutualisé
- 👨💻 Développement et contribution
- 📜 Licence
- 📞 Contact
- 🇬🇧 English version
- 📖 Description
- 🌳 Project origin
- 🔗 Aggregated sources and instances
- ✨ Features
- 🛠️ Tech stack
- 📁 Project structure
- 📋 Requirements
- 🚀 Installation
- ⚙️ Configuration
- 🎨 Appearance customization
- 🧭 Homepage section order
- 🛡️ Security
- 📱 Progressive Web App (PWA)
- 📊 Analytics (Plausible)
- 🚀 Deploying to shared hosting
- 👨💻 Development and contributing
- 📜 License
- 📞 Contact
🌍 Hub multimédia du podcast ANNU KUTE CED
🌍 Multimedia hub for the ANNU KUTE CED podcast
Choisissez votre langue / Choose your language :
🇫🇷 Version française · 🇬🇧 English version
🇫🇷 Version française
📖 Description
ANNU KUTE CED est une interface web responsive qui fait office de hub multimédia pour le podcast du même nom. Elle 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) ;
-
📡 sa timeline Mastodon (actualités et annonces).
La plateforme est légère, déployable sur un serveur mutualisé (PHP + serveur web, sans base de données) et optimisée pour mobile et desktop. C’est aussi une Progressive Web App installable, avec mode hors ligne.
🎯 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.
🌳 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.
| É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 |
|
Domaine de production |
|
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 est configuré par défaut pour agréger les sources du podcast ANNU KUTE CED :
| Service | Instance | Compte / chaîne |
|---|---|---|
🎥 PeerTube (vidéos, lives) |
GADE — |
|
🎙️ Castopod (épisodes audio) |
KUTE — |
|
📡 Mastodon (timeline) |
BOKANTE — |
|
🎵 Funkwhale (musique, optionnel, désactivé par défaut) |
MIZIK — |
morceaux aléatoires de l’instance |
Toutes ces sources sont modifiables dans includes/config.local.php (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 recherche par hashtag (préfixe
#) -
Pagination AJAX « Voir plus » (protégée par jeton CSRF et vérification d’origine)
📺 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 (4:5, 1:1, 16:9)
-
Section hero d’accueil configurable : live, vidéo unique, playlist (PeerTube / Funkwhale / Castopod) ou masquée
🎙️ Podcast et audio
-
Castopod : derniers épisodes via flux RSS, avec lecteur audio intégré (lecture/pause, avance automatique à l’épisode suivant, un seul flux à la fois)
-
Funkwhale (optionnel) : sélection aléatoire de morceaux de l’instance, avec le même lecteur intégré
📡 Réseaux sociaux et contenus externes
-
Timeline Mastodon intégrée (bibliothèque vendored mastodon-embed-timeline v4.7.0, AGPLv3)
-
Compatibilité Pleroma : adaptateur qui convertit les réponses de l’API Pleroma au format Mastodon attendu par la timeline
-
WordPress (optionnel) : derniers articles via l’API REST, avec image à la une et auteur
📱 PWA et confort d’utilisation
-
Progressive Web App installable (bouton d’installation automatique)
-
Mode hors ligne : pages et ressources statiques en cache via Service Worker
-
Indicateur visuel de perte de connexion
-
Mode sombre (basé sur
prefers-color-scheme, mémorisé enlocalStorage) -
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)
-
Compte à rebours : page de lancement/maintenance multi-fuseaux qui verrouille le site jusqu’à la date cible
-
Bloc « À propos » configurable (titre, deux paragraphes, image légendée)
🔍 SEO et données structurées
-
JSON-LD généré automatiquement :
WebSite(avecSearchAction),VideoObject,CollectionPage,BreadcrumbList -
Balises Open Graph et Twitter Cards
-
sitemap.xmletrobots.txtfournis en exemples -
Prêt pour Plausible Analytics (voir Analytics) : désactivé par défaut, sans cookies et conforme RGPD
🛡️ Sécurité
-
En-têtes de sécurité complets : CSP dynamique avec nonce par requête, HSTS,
X-Frame-Options,nosniff,Referrer-Policy,Permissions-Policy -
Protection CSRF sur les requêtes AJAX, vérification de l’en-tête
Origin -
Validation anti-SSRF des URLs d’instances et liste blanche des endpoints de l’API PeerTube
-
Échappement systématique des sorties (anti-XSS)
-
Exemples de configuration sécurisée pour Apache et Nginx dans
conf/
🛠️ Technologies utilisées
-
📄 HTML5, 🎨 CSS3 (Media Queries), ⚡ JavaScript vanilla (sans framework, sans jQuery)
-
🐘 PHP 7.4+ (aucune base de données requise)
-
🔧 Service Worker (cache offline) et 📋 Web App Manifest (installation)
-
📦 Bibliothèques :
-
🎯 Font Awesome 7 (icônes, via CDN cdnjs)
-
📡 mastodon-embed-timeline v4.7.0 (vendored dans
js/, AGPLv3) -
📊 Plausible Analytics (pré-configuré, à activer manuellement)
-
📁 Structure du projet
├── ajax/
│ └── load-more-videos.php # Endpoint AJAX « Voir plus » (CSRF + Origin)
├── conf/
│ ├── .htaccess.sample # Configuration Apache sécurisée
│ └── nginx.conf.sample # Configuration Nginx sécurisée
├── css/ # Feuilles de style (styles, vidéo, catégories,
│ │ # recherche, dons, countdown, mastodon,
│ ├── castopod-podcasts.css # castopod, funkwhale, wordpress, grille…)
│ └── …
├── docs/
│ ├── wireframes/ # Maquettes d'origine (PNG desktop + mobile)
│ ├── docinfo.html # Styles d'impression (fallback emoji) pour l'export
│ └── generate-readme-pdf.sh # Export de la doc : README.html / README.pdf
├── img/ # Logo, favicons, icône de lecture
├── includes/
│ ├── config.php # Bootstrap + fonctions API (PeerTube, Castopod,
│ │ # Funkwhale) et formatage
│ ├── config.default.php # Valeurs par défaut de toutes les constantes
│ ├── config.local.php.sample # Modèle de configuration locale (à copier)
│ ├── security.php # CSRF, CSP + nonce, en-têtes, validateurs
│ ├── simple-cache.php # Cache fichier de l'API (cache/api/)
│ ├── wordpress.php # Intégration API REST WordPress
│ ├── structured-data.php # Générateurs JSON-LD
│ ├── header.php # Barre supérieure (recherche, réseaux, thème…)
│ ├── footer.php # Pied de page
│ ├── sidebar.php # Navigation latérale
│ ├── mobile-menu.php # Menu mobile coulissant
│ ├── hero-section.php # Bannière d'accueil (live/vidéo/playlist)
│ ├── featured-videos.php # ⚠️ legacy, non utilisé par les pages actuelles
│ ├── recent-videos.php # ⚠️ legacy, non utilisé par les pages actuelles
│ ├── pwa-init.php # ⚠️ legacy, PWA désormais inline dans index.php
│ └── lib/
│ └── markdown.php # Rendu Markdown (sous-ensemble PeerTube)
├── js/
│ ├── main.js # UI globale (thème, carrousel, « Voir plus »…)
│ ├── audio-player.js # Lecteur audio Castopod / Funkwhale
│ ├── categories.js # « Voir plus » de la page catégorie
│ ├── countdown.js # Compte à rebours
│ ├── search.js # Cartes cliquables de la recherche
│ ├── mastodon-config.php # Configuration JS de la timeline (servie en JS)
│ ├── mastodon-timeline.umd.js # mastodon-embed-timeline v4.7.0 (vendored)
│ └── pleroma-adapter.js # Adaptateur Pleroma → API Mastodon
├── uploads/ # Images d'annonces (non versionné, hors .gitkeep)
├── index.php # Page d'accueil (agrégateur)
├── video.php # Page de lecture d'une vidéo
├── categories.php # Page d'une catégorie
├── recherche.php # Page de recherche
├── direct.php # Page du direct / annonce du prochain live
├── countdown.php # Page de compte à rebours (maintenance)
├── sw.js # Service Worker (PWA)
├── site.webmanifest.sample # Exemple de manifest PWA
├── browserconfig.xml # Tuiles Windows
├── sitemap.xml.sample # Exemple de sitemap
├── robots.txt.sample # Exemple de robots.txt
├── mentions-legales.php.sample # Exemple de mentions légales
├── dons.php.sample # Exemple de page de dons
├── LICENSE # GNU AGPL v3
└── README.adoc
|
Note
|
Les fichiers marqués « legacy » sont conservés pour référence mais ne sont inclus par aucune page ; la page d’accueil rend ces sections en interne. |
📋 Prérequis
-
🐘 PHP 7.4+ (recommandé : PHP 8.0+)
-
📦 Extensions PHP requises :
-
curl— appels API (PeerTube, Castopod, Funkwhale, WordPress) -
json— traitement des réponses -
intl— dates internationales et fuseaux horaires -
mbstring— chaînes multi-octets -
xml(SimpleXML) — recommandée pour Castopod (un fallback regex existe)
-
-
🌐 Serveur web : Apache ou Nginx
-
🔒 HTTPS : requis pour les fonctionnalités PWA
intl# Ubuntu / Debian
sudo apt-get install php-intl
# Fedora / RHEL / CentOS
sudo dnf install php-intl
# Redémarrer le serveur web
sudo systemctl restart apache2 # Apache
sudo systemctl restart php8.3-fpm # Nginx + php-fpm
# Vérifier
php -m | grep intl
🚀 Installation
-
📥 Clonez le dépôt :
git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git cd annu-kute-ced -
📦 Vérifiez les prérequis PHP (voir ci-dessus).
-
🔧 Créez votre configuration locale et les fichiers d’instance :
cp includes/config.local.php.sample includes/config.local.php cp site.webmanifest.sample site.webmanifest cp robots.txt.sample robots.txt cp sitemap.xml.sample sitemap.xml cp mentions-legales.php.sample mentions-legales.php cp dons.php.sample dons.php -
🛡️ Installez la configuration serveur sécurisée depuis
conf/(voir Sécurité). -
✍️ Rendez le dossier
cache/accessible en écriture par le serveur web (créé automatiquement au premier appel API). -
🔒 Assurez-vous que HTTPS est actif (obligatoire pour la PWA).
-
🌐 Faites pointer votre domaine (
annukuteced.buzz) vers la racine du projet.
⚙️ Configuration
Le système en trois fichiers
| Fichier | Rôle | Versionné ? |
|---|---|---|
|
Bootstrap : charge les autres fichiers et contient toutes les fonctions métier |
✅ Oui |
|
Valeurs par défaut de chaque constante (définies seulement si absentes) |
✅ Oui |
|
Vos surcharges locales — prioritaires car chargées en premier |
❌ Non ( |
Pour personnaliser l’instance, ne modifiez jamais config.default.php : définissez la constante dans config.local.php. Comme ce dernier est chargé avant, vos valeurs ont toujours la priorité.
cp includes/config.local.php.sample includes/config.local.php
Référence des constantes
Valeurs par défaut issues de includes/config.default.php.
| Constante | Défaut | Description |
|---|---|---|
|
|
Nom de domaine affiché (mentions légales…) |
|
|
Nom court de l’organisation |
|
|
Nom complet de l’organisation |
| Constante | Défaut | Description |
|---|---|---|
|
|
URL de l’instance PeerTube (obligatoire) |
|
|
Nom affiché de l’instance |
|
|
Clé API optionnelle ( |
|
|
Afficher le nombre de vues sur les cartes vidéo |
|
|
Catégories mises en avant : |
|
|
Fuseau horaire d’affichage (liste PHP) |
| Constante | Défaut | Description |
|---|---|---|
|
|
|
|
|
Compte PeerTube surveillé pour les directs (hero + page |
|
|
UUID de la vidéo (mode |
|
|
Titre (accessibilité) |
|
|
|
|
|
URL de base de la plateforme de playlist |
|
|
ID de la playlist ; pour Castopod : |
|
|
Textes optionnels (sinon récupérés via API) |
| Constante | Défaut | Description |
|---|---|---|
|
|
Activer la section podcast de l’accueil |
|
|
URL de l’instance Castopod |
|
|
Slug(s) de podcast ; flux RSS = |
|
|
Nombre total d’épisodes affichés |
|
Warning
|
Castopod applique un rate limit strict (HTTP 429) sur les flux RSS. Le code patiente 5 s entre chaque podcast. Activez le cache (CACHE_ENABLED) pour éviter ces délais à chaque page.
|
| Constante | Défaut | Description |
|---|---|---|
|
|
Activer la section musique |
|
|
URL de l’instance Funkwhale |
|
|
Morceaux aléatoires locaux affichés (50 mis en cache) |
| Constante | Défaut | Description |
|---|---|---|
|
|
Instance Mastodon (ou Pleroma, via l’adaptateur) |
|
|
URL publique du compte (liens « Voir plus », footer) |
|
|
Locale de date des posts |
|
|
Libellés des boutons |
|
|
Posts récupérés / affichés |
|
(non défini) |
Origine S3 des médias (ajoutée à la CSP |
|
Note
|
La timeline n’a pas de flag d’activation : elle est toujours affichée sur l’accueil. |
| Constante | Défaut | Description |
|---|---|---|
|
|
Activer la section articles |
|
|
URL du site WordPress (sans |
|
|
Nombre d’articles (API REST |
| Constante | Défaut | Description |
|---|---|---|
|
|
Activer le système (icône cœur, lien « Soutenir », page |
|
|
URLs des plateformes externes |
|
|
Activer l’interface Stripe (onglets ponctuel / mensuel) |
|
|
Liens de paiement Stripe par montant |
|
|
Liens d’abonnement mensuel Stripe |
|
|
Montants suggérés |
|
|
Devise |
|
Note
|
Au moins une plateforme (LiberaPay, Ko-fi ou Stripe) doit être configurée pour que dons.php s’affiche, sinon la page renvoie une erreur 500.
|
| Constante | Défaut | Description |
|---|---|---|
|
|
⚠️ Si |
|
|
Date cible ( |
|
5 territoires |
|
| Constante | Défaut | Description |
|---|---|---|
|
|
Afficher l’annonce quand aucun direct n’est en cours |
|
|
Textes (date et heure ajoutées automatiquement) |
|
|
Date du live ( |
|
|
Image d’annonce (utilisée seulement si le fichier existe) |
| Constante | Défaut | Description |
|---|---|---|
|
|
Nom du site (titres, meta) |
|
|
Description SEO |
|
|
Chemins des images |
|
|
|
|
E-mail de contact (footer) |
| Constante | Défaut | Description |
|---|---|---|
|
|
Titulaire du copyright |
|
|
Webmaster |
|
valeurs o2Switch |
Coordonnées de l’hébergeur |
|
Contact juridique |
|
|
AGPL-V3 + URL GNU |
Licence du code |
|
|
Dépôt du code source (exigé par l’AGPL pour un service réseau) |
|
|
Phrase de description du service |
| Constante | Défaut | Description |
|---|---|---|
|
|
Tag de la fonction |
|
|
Durée max d’un short (s) ; ratio portrait ( |
|
|
Hashtags de la sidebar, du footer et du menu mobile |
|
|
Hashtags affichés sur l’accueil |
| Constante | Défaut | Description |
|---|---|---|
|
|
Vidéos par page (recherche) |
|
|
Résultats récupérés par recherche |
|
|
Taille des sections d’accueil |
|
|
Shorts affichés / pool de recherche |
|
|
Vidéos chargées par clic sur « Voir plus » |
|
|
Réservés (sections non affichées actuellement) |
| Constante | Défaut | Description |
|---|---|---|
|
|
Active le cache pour Castopod et Funkwhale (fortement recommandé) |
|
|
Durée de vie du cache (s) |
|
Note
|
Le cache de l’API PeerTube et de WordPress (includes/simple-cache.php) est toujours actif, indépendamment de CACHE_ENABLED, avec des TTL par endpoint (catégories 1 h, vidéos/recherche 10 min, articles WP 15 min, comptes 5 min). Les fichiers sont stockés dans cache/api/.
|
| Constante | Description |
|---|---|
|
Titre du bloc (défaut template : « À propos ») |
|
Premier paragraphe ; commenter cette ligne masque tout le bloc |
|
Second paragraphe (optionnel) |
|
Image ( |
Exemple complet de config.local.php
<?php
define('APP_HOST_NAME', 'annukuteced.buzz');
// PeerTube (chaîne GADE du podcast)
define('PEERTUBE_URL', 'https://gade.o-k-i.net');
define('PEERTUBE_DISPLAY_NAME', 'gade.o-k-i.net');
// Hero : direct de la chaîne, sinon annonce du prochain live
define('HERO_TYPE', 'live');
define('LIVE_ACCOUNT_NAME', 'annu_kute_ced');
define('NEXT_LIVE_ENABLED', true);
define('NEXT_LIVE_TITLE', 'Prochain live');
define('NEXT_LIVE_DESCRIPTION', 'Enregistrement du prochain épisode !');
define('NEXT_LIVE_DATE', '2025-10-11 10:00:00');
// Castopod (compte KUTE du podcast)
define('CASTOPOD_ENABLED', true);
define('CASTOPOD_URL', 'https://kute.o-k-i.net');
define('CASTOPOD_PODCAST_SLUGS', ['annu_kute_cedric']);
define('CASTOPOD_EPISODES_COUNT', 5);
// Mastodon (compte BOKANTE)
define('MASTODON_INSTANCE_URL', 'https://bokante.o-k-i.net');
define('MASTODON_URL', 'https://bokante.o-k-i.net/@cedric');
// Cache : indispensable pour Castopod (rate limit RSS)
define('CACHE_ENABLED', true);
define('CACHE_DURATION', 3600);
🎨 Personnalisation de l’apparence
-
🖼️ Remplacez
img/logo.pngpar votre logo (et les favicons du dossierimg/) -
🎨 Modifiez les couleurs dans
css/styles.css -
📝 Textes : la plupart passent par les constantes de
config.local.php(bloc « À propos », libellés Mastodon, etc.)
Fichiers d’instance à personnaliser
Les fichiers sitemap.xml, robots.txt, site.webmanifest, mentions-legales.php et dons.php sont ignorés par Git : copiez les .sample puis adaptez-les. Les exemples fournis sont pré-remplis pour annukuteced.buzz ; pour un autre domaine, remplacez simplement les occurrences du domaine. Dans mentions-legales.php, remplacez aussi le placeholder VOTRE-DATE-MAJ.
🧭 Ordre des sections sur la page d’accueil
La page d’accueil assemble les sections dans cet ordre, chacune conditionnée par sa configuration :
-
Hero — si
HERO_TYPE≠'none'(live, vidéo ou playlist) -
Podcasts Castopod — si
CASTOPOD_ENABLEDetCASTOPOD_URLnon vide -
Morceaux Funkwhale — si
FUNKWHALE_ENABLEDetFUNKWHALE_URLnon vide -
Timeline Mastodon — toujours affichée
-
Articles WordPress — si
WORDPRESS_ENABLEDetWORDPRESS_URLnon vide -
Hashtags populaires (
POPULAR_TAGS) -
Shorts — carrousel
-
Dernières vidéos + bouton « Voir plus »
-
Tendances + « Voir plus »
-
Une section par catégorie prioritaire (
PRIORITY_CATEGORIES, seulement si elle contient des vidéos) + « Voir plus » -
Bloc « À propos » (si
MOVEMENT_DESCRIPTIONdéfini) + aside hashtags
Mise en page desktop : hero/Castopod/Funkwhale + Mastodon + WordPress s’organisent en colonnes (1fr 2fr, ou 1fr 2fr 1fr avec WordPress) ; empilés verticalement sur mobile.
🛡️ Sécurité
Ce que l’application applique déjà
-
CSP dynamique :
default-src 'self'avec nonce unique par requête pour les scripts/styles inline ; origines PeerTube/Mastodon/CDN ajoutées automatiquement ; assouplissementslocalhostpour le développement -
En-têtes :
X-Frame-Options: SAMEORIGIN,X-Content-Type-Options: nosniff,X-XSS-Protection,Referrer-Policy: strict-origin-when-cross-origin,Permissions-Policyrestrictive, HSTS (HTTPS uniquement), CORP/COOPsame-originNoteL’en-tête COEP a été volontairement retiré (commit 62d4d99) :require-corpbloquait les embeds cross-origin de PeerTube, Mastodon, Castopod et Funkwhale. -
CSRF : jeton de session (
random_bytes(32)) injecté en<meta>, vérifié parhash_equalssur l’endpoint AJAX ; vérification de l’en-têteOrigin -
Anti-SSRF : validation des URLs d’instances (schéma http/https, blocage IP privées et
localhost), liste blanche des endpoints de l’API PeerTube, cURL sans redirections -
Anti-XSS : échappement systématique des sorties ; validation des entrées (UUID vidéo, requête de recherche ≤ 200 car., numéros de page, ID de catégorie 1–20)
Configuration serveur (Apache)
cp conf/.htaccess.sample .htaccess
Protections incluses : blocage des fichiers de configuration et .sample, des dossiers /includes/, /cache/, /docs/, /conf/ ; pas de listing de répertoires ; fichiers cachés bloqués ; HTTPS forcé ; masquage de l’extension .php (URLs propres /video au lieu de /video.php).
|
Warning
|
Cette configuration est essentielle : sans elle, vos fichiers de configuration sont exposés aux visiteurs. |
Configuration serveur (Nginx)
# Adaptez les chemins dans conf/nginx.conf.sample puis :
sudo cp conf/nginx.conf.sample /etc/nginx/sites-available/annukuteced.buzz
sudo ln -s /etc/nginx/sites-available/annukuteced.buzz /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
|
Warning
|
Le bloc location ~* \.(php|inc|conf|config|local)$ { deny all; } de l’exemple correspond tel quel à tous les fichiers .php. Ajustez-le pour ne cibler que les chemins sensibles (par exemple ^/includes/), sous peine de rendre l’application inaccessible.
|
📱 Progressive Web App (PWA)
Fonctionnalités
-
📲 Installation native : bouton « Installer » dans le header à la première visite
-
🌐 Mode hors ligne : cache des pages visitées et des ressources statiques
-
📡 Détection de connexion : indicateur visuel en cas de perte réseau
-
🔄 Mise à jour : proposition de rechargement quand une nouvelle version est détectée
Stratégies de cache du Service Worker (sw.js)
| Type de requête | Stratégie | Détail |
|---|---|---|
Ressources statiques ( |
Cache First |
Mise en cache à l’installation et au premier accès ; repli sur |
Pages ( |
Network First |
Réseau d’abord, cache en secours hors ligne |
API et AJAX ( |
Network Only |
Jamais de cache ; réponse JSON 503 synthétique hors ligne |
|
Tip
|
Pour déployer une nouvelle version des assets, changez le suffixe de version des noms de cache dans sw.js (format date, ex. 08072026-0720) : les anciens caches sont supprimés à l’activation.
|
Installation par les visiteurs
-
🌐 Chrome/Edge : menu → « Installer annukuteced.buzz »
-
🍎 Safari iOS : Partager → « Ajouter à l’écran d’accueil »
-
🦊 Firefox Android : menu → « Installer »
📊 Analytics (Plausible)
Le site est pré-configuré pour Plausible Analytics (sans cookies, conforme RGPD, données anonymes), mais le script est désactivé par défaut.
Pour l’activer :
-
Ouvrez
index.phpet décommentez le snippet Plausible (balise<script defer data-domain=… src="https://plausible.io/js/script…js">et son shimwindow.plausible). -
C’est tout : la CSP autorise déjà
https://plausible.ioenscript-srcetconnect-src, et ledata-domainutilise automatiquement le domaine courant.
Données alors collectées (anonymes) : pages visitées, pays d’origine (IP non stockée), type d’appareil, navigateur, temps passé.
🚀 Déploiement sur serveur mutualisé
-
🐘 Vérifiez que l’hébergeur fournit PHP 7.4+ et les extensions requises
-
🔒 Activez HTTPS (obligatoire pour la PWA)
-
📤 Transférez les fichiers via FTP à la racine du site
-
🔧 Permissions :
644pour les fichiers,755pour les dossiers ;cache/accessible en écriture -
📄 Créez les fichiers d’instance depuis les
.sample(config, manifest, robots, sitemap, mentions légales, dons) -
🛡️ Copiez
conf/.htaccess.sampleen.htaccess(Apache) -
🌐 Faites pointer le domaine
annukuteced.buzzvers le dossier d’installation -
🧪 Testez la PWA via les outils de développement du navigateur (onglet Application)
👨💻 Développement et contribution
-
🌿 Créez une branche :
git checkout -b ma-fonctionnalite -
💾 Committez avec des messages atomiques en anglais, au format conventionnel (< 70 caractères) :
-
feat: add …,fix: prevent …,docs: update …,refactor: …,typo: …
-
-
📤 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)
-
Ne versionnez jamais
config.local.phpni les fichiers dérivés des.sample -
Quelques constantes sont définies mais non utilisées par le code actuel (
ENABLE_SEARCH,ENABLE_COMMENTS,ENABLE_USER_ACCOUNTS,TAG_SHORT) : ne vous en servez pas comme points d’extension
📄 Exporter la documentation (HTML / PDF)
Ce README peut être exporté en HTML et en PDF en une seule commande :
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
Les fichiers sont produits à la racine du projet et ignorés par Git (.gitignore).
Prérequis : asciidoctor, chromium (rendu headless) et le paquet fonts-noto-color-emoji (émojis couleur dans le PDF). La feuille de style docs/docinfo.html (fallback emoji + règles d’impression) est injectée automatiquement via le mécanisme docinfo d’Asciidoctor.
|
Note
|
asciidoctor-pdf (utilisé par l’extension AsciiDoc de VSCodium) n’est pas utilisable ici : son moteur Prawn ne sait pas embarquer les polices emoji couleur (CBDT/COLR), les émojis disparaissent du PDF. Chromium les gère nativement.
|
📜 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).
🇬🇧 English version
📖 Description
ANNU KUTE CED is a responsive web interface acting as a multimedia hub for 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);
-
📡 its Mastodon timeline (news and announcements).
The platform is lightweight, deployable on shared hosting (PHP + web server, no database), and optimized for both mobile and desktop. It is also an installable Progressive Web App with offline support.
🎯 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.
🌳 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.
| Item | Detail |
|---|---|
Upstream repository |
https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI |
This fork’s repository |
|
Production domain |
|
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 is configured by default to aggregate the ANNU KUTE CED podcast’s sources:
| Service | Instance | Account / channel |
|---|---|---|
🎥 PeerTube (videos, lives) |
GADE — |
|
🎙️ Castopod (audio episodes) |
KUTE — |
|
📡 Mastodon (timeline) |
BOKANTE — |
|
🎵 Funkwhale (music, optional, disabled by default) |
MIZIK — |
random tracks from the instance |
All of these sources can be changed in includes/config.local.php (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) -
AJAX "Load more" pagination (protected by CSRF token and Origin check)
📺 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 (4:5, 1:1, 16:9)
-
Configurable homepage hero section: live, single video, playlist (PeerTube / Funkwhale / Castopod) or hidden
🎙️ Podcast and audio
-
Castopod: latest episodes via RSS feed, with a built-in audio player (play/pause, auto-advance to the next episode, one stream at a time)
-
Funkwhale (optional): random track selection from the instance, using the same built-in player
📡 Social networks and external content
-
Embedded Mastodon timeline (vendored mastodon-embed-timeline v4.7.0 library, AGPLv3)
-
Pleroma compatibility: adapter converting Pleroma API responses to the Mastodon format expected by the timeline
-
WordPress (optional): latest posts via the REST API, with featured image and author
📱 PWA and user experience
-
Installable Progressive Web App (automatic install button)
-
Offline mode: visited pages and static assets cached via Service Worker
-
Visual indicator when the connection is lost
-
Dark mode (based on
prefers-color-scheme, persisted inlocalStorage) -
Fully responsive interface (mobile, tablet, desktop)
💝 Donations, countdown and more
-
Donation page: LiberaPay, Ko-fi and Stripe (one-time and monthly donations, suggested amounts)
-
Countdown: multi-timezone launch/maintenance page that locks the whole site until the target date
-
Configurable "About" block (title, two paragraphs, captioned image)
🔍 SEO and structured data
-
Automatically generated JSON-LD:
WebSite(withSearchAction),VideoObject,CollectionPage,BreadcrumbList -
Open Graph and Twitter Cards meta tags
-
sitemap.xmlandrobots.txtprovided as samples -
Ready for Plausible Analytics (see Analytics): disabled by default, cookie-free and GDPR-compliant
🛡️ Security
-
Full security headers: dynamic CSP with a per-request nonce, HSTS,
X-Frame-Options,nosniff,Referrer-Policy,Permissions-Policy -
CSRF protection on AJAX requests,
Originheader verification -
Anti-SSRF validation of instance URLs and an allowlist of PeerTube API endpoints
-
Systematic output escaping (anti-XSS)
-
Hardened Apache and Nginx configuration samples in
conf/
🛠️ Tech stack
-
📄 HTML5, 🎨 CSS3 (Media Queries), ⚡ vanilla JavaScript (no framework, no jQuery)
-
🐘 PHP 7.4+ (no database required)
-
🔧 Service Worker (offline cache) and 📋 Web App Manifest (installation)
-
📦 Libraries:
-
🎯 Font Awesome 7 (icons, via cdnjs CDN)
-
📡 mastodon-embed-timeline v4.7.0 (vendored in
js/, AGPLv3) -
📊 Plausible Analytics (pre-configured, to be enabled manually)
-
📁 Project structure
├── ajax/
│ └── load-more-videos.php # "Load more" AJAX endpoint (CSRF + Origin)
├── conf/
│ ├── .htaccess.sample # Hardened Apache configuration
│ └── nginx.conf.sample # Hardened Nginx configuration
├── css/ # Stylesheets (styles, video, categories,
│ │ # search, donations, countdown, mastodon,
│ ├── castopod-podcasts.css # castopod, funkwhale, wordpress, grid…)
│ └── …
├── docs/
│ ├── wireframes/ # Original mockups (desktop + mobile PNGs)
│ ├── docinfo.html # Print styles (emoji fallback) for the export
│ └── generate-readme-pdf.sh # Docs export: README.html / README.pdf
├── img/ # Logo, favicons, play icon
├── includes/
│ ├── config.php # Bootstrap + API functions (PeerTube, Castopod,
│ │ # Funkwhale) and formatting helpers
│ ├── config.default.php # Default values for every constant
│ ├── config.local.php.sample # Local configuration template (to copy)
│ ├── security.php # CSRF, CSP + nonce, headers, validators
│ ├── simple-cache.php # File-based API cache (cache/api/)
│ ├── wordpress.php # WordPress REST API integration
│ ├── structured-data.php # JSON-LD generators
│ ├── header.php # Top bar (search, socials, theme…)
│ ├── footer.php # Footer
│ ├── sidebar.php # Side navigation
│ ├── mobile-menu.php # Slide-in mobile menu
│ ├── hero-section.php # Homepage banner (live/video/playlist)
│ ├── featured-videos.php # ⚠️ legacy, unused by current pages
│ ├── recent-videos.php # ⚠️ legacy, unused by current pages
│ ├── pwa-init.php # ⚠️ legacy, PWA now inlined in index.php
│ └── lib/
│ └── markdown.php # Markdown renderer (PeerTube-flavored subset)
├── js/
│ ├── main.js # Global UI (theme, carousel, "Load more"…)
│ ├── audio-player.js # Castopod / Funkwhale audio player
│ ├── categories.js # Category page "Load more"
│ ├── countdown.js # Countdown timer
│ ├── search.js # Clickable search result cards
│ ├── mastodon-config.php # Timeline JS config (served as JavaScript)
│ ├── mastodon-timeline.umd.js # mastodon-embed-timeline v4.7.0 (vendored)
│ └── pleroma-adapter.js # Pleroma → Mastodon API adapter
├── uploads/ # Announcement images (not versioned, except .gitkeep)
├── index.php # Homepage (aggregator)
├── video.php # Video playback page
├── categories.php # Category page
├── recherche.php # Search page
├── direct.php # Live stream / next-live announcement page
├── countdown.php # Countdown page (maintenance)
├── sw.js # Service Worker (PWA)
├── site.webmanifest.sample # PWA manifest sample
├── browserconfig.xml # Windows tiles
├── sitemap.xml.sample # Sitemap sample
├── robots.txt.sample # robots.txt sample
├── mentions-legales.php.sample # Legal notice sample
├── dons.php.sample # Donation page sample
├── LICENSE # GNU AGPL v3
└── README.adoc
|
Note
|
Files marked "legacy" are kept for reference but are not included by any page; the homepage renders those sections internally. |
📋 Requirements
-
🐘 PHP 7.4+ (recommended: PHP 8.0+)
-
📦 Required PHP extensions:
-
curl— API calls (PeerTube, Castopod, Funkwhale, WordPress) -
json— response handling -
intl— international dates and timezones -
mbstring— multi-byte strings -
xml(SimpleXML) — recommended for Castopod (a regex fallback exists)
-
-
🌐 Web server: Apache or Nginx
-
🔒 HTTPS: required for PWA features
intl extension# Ubuntu / Debian
sudo apt-get install php-intl
# Fedora / RHEL / CentOS
sudo dnf install php-intl
# Restart the web server
sudo systemctl restart apache2 # Apache
sudo systemctl restart php8.3-fpm # Nginx + php-fpm
# Check
php -m | grep intl
🚀 Installation
-
📥 Clone the repository:
git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git cd annu-kute-ced -
📦 Check the PHP requirements (see above).
-
🔧 Create your local configuration and instance files:
cp includes/config.local.php.sample includes/config.local.php cp site.webmanifest.sample site.webmanifest cp robots.txt.sample robots.txt cp sitemap.xml.sample sitemap.xml cp mentions-legales.php.sample mentions-legales.php cp dons.php.sample dons.php -
🛡️ Install the hardened server configuration from
conf/(see Security). -
✍️ Make the
cache/directory writable by the web server (created automatically on the first API call). -
🔒 Make sure HTTPS is enabled (mandatory for the PWA).
-
🌐 Point your domain (
annukuteced.buzz) to the project root.
⚙️ Configuration
The three-file system
| File | Role | Versioned? |
|---|---|---|
|
Bootstrap: loads the other files and holds all business functions |
✅ Yes |
|
Default values for every constant (defined only if missing) |
✅ Yes |
|
Your local overrides — take precedence as they load first |
❌ No ( |
To customize the instance, never edit config.default.php: define the constant in config.local.php. Since it loads first, your values always win.
cp includes/config.local.php.sample includes/config.local.php
Constants reference
Default values from includes/config.default.php.
| Constant | Default | Description |
|---|---|---|
|
|
Displayed domain name (legal notice…) |
|
|
Short organization name |
|
|
Full organization name |
| Constant | Default | Description |
|---|---|---|
|
|
PeerTube instance URL (required) |
|
|
Displayed instance name |
|
|
Optional API key ( |
|
|
Show view counts on video cards |
|
|
Featured categories: |
|
|
Display timezone (PHP list) |
| Constant | Default | Description |
|---|---|---|
|
|
|
|
|
PeerTube account watched for live streams (hero + |
|
|
Video UUID ( |
|
|
Title (accessibility) |
|
|
|
|
|
Base URL of the playlist platform |
|
|
Playlist ID; for Castopod: |
|
|
Optional texts (otherwise fetched via API) |
| Constant | Default | Description |
|---|---|---|
|
|
Enable the homepage podcast section |
|
|
Castopod instance URL |
|
|
Podcast slug(s); RSS feed = |
|
|
Total number of episodes displayed |
|
Warning
|
Castopod enforces a strict rate limit (HTTP 429) on RSS feeds. The code waits 5 s between podcasts. Enable the cache (CACHE_ENABLED) to avoid these delays on every page.
|
| Constant | Default | Description |
|---|---|---|
|
|
Enable the music section |
|
|
Funkwhale instance URL |
|
|
Random local tracks displayed (50 cached) |
| Constant | Default | Description |
|---|---|---|
|
|
Mastodon instance (or Pleroma, via the adapter) |
|
|
Public account URL ("See more" links, footer) |
|
|
Post date locale |
|
|
Button labels |
|
|
Posts fetched / displayed |
|
(undefined) |
S3 media origin (added to the CSP |
|
Note
|
The timeline has no enable flag: it is always displayed on the homepage. |
| Constant | Default | Description |
|---|---|---|
|
|
Enable the posts section |
|
|
WordPress site URL (no trailing |
|
|
Number of posts (REST API |
| Constant | Default | Description |
|---|---|---|
|
|
Enable the system (heart icon, "Support" link, |
|
|
External platform URLs |
|
|
Enable the Stripe interface (one-time / monthly tabs) |
|
|
Stripe payment links per amount |
|
|
Stripe monthly subscription links |
|
|
Suggested amounts |
|
|
Currency |
|
Note
|
At least one platform (LiberaPay, Ko-fi or Stripe) must be configured for dons.php to render, otherwise the page returns a 500 error.
|
| Constant | Default | Description |
|---|---|---|
|
|
⚠️ When |
|
|
Target date ( |
|
5 territories |
|
| Constant | Default | Description |
|---|---|---|
|
|
Show the announcement when no live stream is running |
|
|
Texts (date and time appended automatically) |
|
|
Live date ( |
|
|
Announcement image (used only if the file exists) |
| Constant | Default | Description |
|---|---|---|
|
|
Site name (titles, meta) |
|
|
SEO description |
|
|
Image paths |
|
|
|
|
Contact e-mail (footer) |
| Constant | Default | Description |
|---|---|---|
|
|
Copyright holder |
|
|
Webmaster |
|
o2Switch values |
Hosting provider details |
|
Legal contact |
|
|
AGPL-V3 + GNU URL |
Code license |
|
|
Source code repository (required by the AGPL for a network service) |
|
|
Service description sentence |
| Constant | Default | Description |
|---|---|---|
|
|
Tag used by |
|
|
Max short duration (s); portrait ratio ( |
|
|
Hashtags in the sidebar, footer and mobile menu |
|
|
Hashtags displayed on the homepage |
| Constant | Default | Description |
|---|---|---|
|
|
Videos per page (search) |
|
|
Results fetched per search |
|
|
Homepage section sizes |
|
|
Shorts displayed / search pool |
|
|
Videos loaded per "Load more" click |
|
|
Reserved (sections not currently displayed) |
| Constant | Default | Description |
|---|---|---|
|
|
Enable caching for Castopod and Funkwhale (strongly recommended) |
|
|
Cache lifetime (s) |
|
Note
|
The PeerTube API and WordPress cache (includes/simple-cache.php) is always on, regardless of CACHE_ENABLED, with per-endpoint TTLs (categories 1 h, videos/search 10 min, WP posts 15 min, accounts 5 min). Files are stored in cache/api/.
|
| Constant | Description |
|---|---|
|
Block title (template fallback: "À propos") |
|
First paragraph; commenting this line hides the whole block |
|
Second paragraph (optional) |
|
Image ( |
Complete config.local.php example
<?php
define('APP_HOST_NAME', 'annukuteced.buzz');
// PeerTube (the podcast's GADE channel)
define('PEERTUBE_URL', 'https://gade.o-k-i.net');
define('PEERTUBE_DISPLAY_NAME', 'gade.o-k-i.net');
// Hero: channel live stream, otherwise next-live announcement
define('HERO_TYPE', 'live');
define('LIVE_ACCOUNT_NAME', 'annu_kute_ced');
define('NEXT_LIVE_ENABLED', true);
define('NEXT_LIVE_TITLE', 'Prochain live');
define('NEXT_LIVE_DESCRIPTION', 'Recording the next episode!');
define('NEXT_LIVE_DATE', '2025-10-11 10:00:00');
// Castopod (the podcast's KUTE account)
define('CASTOPOD_ENABLED', true);
define('CASTOPOD_URL', 'https://kute.o-k-i.net');
define('CASTOPOD_PODCAST_SLUGS', ['annu_kute_cedric']);
define('CASTOPOD_EPISODES_COUNT', 5);
// Mastodon (BOKANTE account)
define('MASTODON_INSTANCE_URL', 'https://bokante.o-k-i.net');
define('MASTODON_URL', 'https://bokante.o-k-i.net/@cedric');
// Cache: essential for Castopod (RSS rate limit)
define('CACHE_ENABLED', true);
define('CACHE_DURATION', 3600);
🎨 Appearance customization
-
🖼️ Replace
img/logo.pngwith your logo (and the favicons inimg/) -
🎨 Edit the colors in
css/styles.css -
📝 Most texts are set through
config.local.phpconstants ("About" block, Mastodon labels, etc.)
Instance files to customize
The sitemap.xml, robots.txt, site.webmanifest, mentions-legales.php and dons.php files are Git-ignored: copy the .sample files then adapt them. The provided samples are pre-filled for annukuteced.buzz; for another domain, simply replace the domain occurrences. In mentions-legales.php, also replace the VOTRE-DATE-MAJ placeholder.
🧭 Homepage section order
The homepage assembles sections in this order, each gated by its configuration:
-
Hero — if
HERO_TYPE≠'none'(live, video or playlist) -
Castopod podcasts — if
CASTOPOD_ENABLEDandCASTOPOD_URLis not empty -
Funkwhale tracks — if
FUNKWHALE_ENABLEDandFUNKWHALE_URLis not empty -
Mastodon timeline — always displayed
-
WordPress posts — if
WORDPRESS_ENABLEDandWORDPRESS_URLis not empty -
Popular hashtags (
POPULAR_TAGS) -
Shorts — carousel
-
Latest videos + "Load more" button
-
Trending + "Load more"
-
One section per priority category (
PRIORITY_CATEGORIES, only when it has videos) + "Load more" -
"About" block (if
MOVEMENT_DESCRIPTIONis defined) + hashtags aside
Desktop layout: hero/Castopod/Funkwhale + Mastodon + WordPress are arranged in columns (1fr 2fr, or 1fr 2fr 1fr with WordPress); stacked vertically on mobile.
🛡️ Security
What the application already enforces
-
Dynamic CSP:
default-src 'self'with a unique per-request nonce for inline scripts/styles; PeerTube/Mastodon/CDN origins added automatically;localhostrelaxations for development -
Headers:
X-Frame-Options: SAMEORIGIN,X-Content-Type-Options: nosniff,X-XSS-Protection,Referrer-Policy: strict-origin-when-cross-origin, restrictivePermissions-Policy, HSTS (HTTPS only), CORP/COOPsame-originNoteThe COEP header was deliberately removed (commit 62d4d99):require-corpbroke cross-origin embeds from PeerTube, Mastodon, Castopod and Funkwhale. -
CSRF: session token (
random_bytes(32)) injected as a<meta>tag, verified withhash_equalson the AJAX endpoint;Originheader verification -
Anti-SSRF: instance URL validation (http/https scheme, blocking private IPs and
localhost), allowlist of PeerTube API endpoints, cURL without redirects -
Anti-XSS: systematic output escaping; input validation (video UUID, search query ≤ 200 chars, page numbers, category ID 1–20)
Server configuration (Apache)
cp conf/.htaccess.sample .htaccess
Included protections: blocking of configuration and .sample files, of the /includes/, /cache/, /docs/, /conf/ directories; no directory listing; hidden files blocked; HTTPS enforced; .php extension masking (clean URLs /video instead of /video.php).
|
Warning
|
This configuration is essential: without it, your configuration files are exposed to visitors. |
Server configuration (Nginx)
# Adjust the paths in conf/nginx.conf.sample, then:
sudo cp conf/nginx.conf.sample /etc/nginx/sites-available/annukuteced.buzz
sudo ln -s /etc/nginx/sites-available/annukuteced.buzz /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
|
Warning
|
The sample’s location ~* \.(php|inc|conf|config|local)$ { deny all; } block as written matches all .php files. Adjust it to target only sensitive paths (e.g. ^/includes/), or the whole application will become unreachable.
|
📱 Progressive Web App (PWA)
Features
-
📲 Native installation: an "Install" button in the header on first visit
-
🌐 Offline mode: visited pages and static assets cached
-
📡 Connection detection: visual indicator when the network is lost
-
🔄 Updates: reload prompt when a new version is detected
Service Worker caching strategies (sw.js)
| Request type | Strategy | Detail |
|---|---|---|
Static assets ( |
Cache First |
Cached at install time and on first access; falls back to |
Pages ( |
Network First |
Network first, cache fallback when offline |
API and AJAX ( |
Network Only |
Never cached; synthetic 503 JSON response when offline |
|
Tip
|
To deploy a new version of the assets, change the version suffix of the cache names in sw.js (date format, e.g. 08072026-0720): old caches are deleted on activation.
|
Installation by visitors
-
🌐 Chrome/Edge: menu → "Install annukuteced.buzz"
-
🍎 Safari iOS: Share → "Add to Home Screen"
-
🦊 Firefox Android: menu → "Install"
📊 Analytics (Plausible)
The site is pre-configured for Plausible Analytics (cookie-free, GDPR-compliant, anonymous data), but the script is disabled by default.
To enable it:
-
Open
index.phpand uncomment the Plausible snippet (the<script defer data-domain=… src="https://plausible.io/js/script…js">tag and itswindow.plausibleshim). -
That’s it: the CSP already allows
https://plausible.ioinscript-srcandconnect-src, and thedata-domainautomatically uses the current domain.
Data then collected (anonymous): visited pages, country of origin (IP not stored), device type, browser, time spent.
🚀 Deploying to shared hosting
-
🐘 Check that the host provides PHP 7.4+ and the required extensions
-
🔒 Enable HTTPS (mandatory for the PWA)
-
📤 Upload the files via FTP to the site root
-
🔧 Permissions:
644for files,755for directories;cache/must be writable -
📄 Create the instance files from the
.samplefiles (config, manifest, robots, sitemap, legal notice, donations) -
🛡️ Copy
conf/.htaccess.sampleto.htaccess(Apache) -
🌐 Point the
annukuteced.buzzdomain to the installation directory -
🧪 Test the PWA via the browser developer tools (Application tab)
👨💻 Development and contributing
-
🌿 Create a branch:
git checkout -b my-feature -
💾 Commit with atomic, English messages, in conventional format (< 70 characters):
-
feat: add …,fix: prevent …,docs: update …,refactor: …,typo: …
-
-
📤 Push:
git push origin my-feature -
🔀 Open a pull request
Repository best practices:
-
Bug reports and suggestions are welcome on the fork’s repository; generic improvements can be proposed upstream (FEDIVERSE OKI)
-
Never version
config.local.phpor files derived from the.samplefiles -
A few constants are defined but unused by the current code (
ENABLE_SEARCH,ENABLE_COMMENTS,ENABLE_USER_ACCOUNTS,TAG_SHORT): do not rely on them as extension points
📄 Exporting the documentation (HTML / PDF)
This README can be exported to HTML and PDF with a single command:
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
Files are produced in the project root and are Git-ignored (.gitignore).
Requirements: asciidoctor, chromium (headless rendering) and the fonts-noto-color-emoji package (color emoji in the PDF). The docs/docinfo.html stylesheet (emoji fallback + print rules) is automatically injected through Asciidoctor’s docinfo mechanism.
|
Note
|
asciidoctor-pdf (used by VSCodium’s AsciiDoc extension) cannot be used here: its Prawn engine cannot embed color-emoji fonts (CBDT/COLR), so emoji disappear from the PDF. Chromium handles them natively.
|
📜 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).