2026-07-23 05:10:04 +04:00
= 🎙️ ANNU KUTE CED — Hub multimédia du podcast
2025-07-24 22:12:30 +04:00
:toc: left
2026-07-23 05:10:04 +04:00
:toc-title: Sommaire / Contents
2025-07-24 22:12:30 +04:00
:toclevels: 3
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
[[top]]
🌍 *Hub multimédia du podcast ANNU KUTE CED* +
🌍 *Multimedia hub for the ANNU KUTE CED podcast*
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
[.text-center]
*Choisissez votre langue / Choose your language :* +
<<fr,🇫🇷 Version française>> · <<en,🇬🇧 English version>>
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
'''
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
[[fr]]
== 🇫🇷 Version française
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
=== 📖 Description
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
*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 :
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
- 🎥 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).
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
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.
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
🎯 *Mission* : offrir un point d'entrée unique, libre et décentralisé, pour découvrir, écouter et suivre le podcast ANNU KUTE CED sans dépendre des grandes plateformes propriétaires.
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
=== 🌳 Origine du projet
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
Cette application est un *fork* de https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI[*FEDIVERSE OKI*^], développée par l'https://o-k-i.net[ORGANISATION KA INTERNATIONALE (OKI)^], elle-même issue du projet https://codeberg.org/Ka-Ubuntu/kaubuntu.re[kaubuntu.re^] du mouvement https://kaubuntu.com[Ka-Ubuntu^]. La licence d'origine (GNU AGPL v3) est conservée et respectée.
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
[cols="1,3",options="header"]
|===
| Élément | Détail
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
| Dépôt upstream
| https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI
2025-07-17 20:43:15 +04:00
2026-07-23 05:10:04 +04:00
| Dépôt de ce fork
| `git@labola.o-k-i.net:cedric/annu-kute-ced.git`
| 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 est configuré par défaut pour agréger 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`^]
| 📡 Mastodon (timeline)
| BOKANTE — `https://bokante.o-k-i.net`
| https://bokante.o-k-i.net/@cedric[`@cedric`^]
| 🎵 Funkwhale (musique, optionnel, désactivé par défaut)
| MIZIK — `https://mizik.o-k-i.net`
| morceaux aléatoires de l'instance
|===
Toutes ces sources sont modifiables dans `includes/config.local.php` (voir <<fr-configuration,Configuration>>).
=== ✨ Fonctionnalités
==== 🎥 Vidéos PeerTube
- Vidéos récentes, tendances et par catégories (configurables)
- *Shorts* : carrousel dédié aux vidéos portrait de moins de 3 minutes (défilement tactile)
- Page vidéo complète : lecteur PeerTube embarqué, description Markdown, badge de licence Creative Commons, commentaires (lecture seule), vidéos suggérées
- *Téléchargement* : fichiers directs et playlists HLS, avec résolution et taille
- *Partage* : copie de lien, code d'intégration, e-mail, Facebook, X, WhatsApp, LinkedIn, Telegram
- Recherche plein texte et 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 https://gitlab.com/idotj/mastodon-embed-timeline[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é en `localStorage`)
- 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` (avec `SearchAction`), `VideoObject`, `CollectionPage`, `BreadcrumbList`
- Balises *Open Graph* et *Twitter Cards*
- `sitemap.xml` et `robots.txt` fournis en exemples
- Prêt pour *Plausible Analytics* (voir <<fr-analytics,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
2025-04-08 06:37:14 +04:00
2025-07-24 22:12:30 +04:00
[source]
----
2026-07-23 05:10:04 +04:00
├── ajax/
│ └── load-more-videos.php # Endpoint AJAX « Voir plus » (CSRF + Origin)
2025-07-21 13:24:12 +04:00
├── conf/
│ ├── .htaccess.sample # Configuration Apache sécurisée
│ └── nginx.conf.sample # Configuration Nginx sécurisée
2026-07-23 05:10:04 +04:00
├── css/ # Feuilles de style (styles, vidéo, catégories,
│ │ # recherche, dons, countdown, mastodon,
│ ├── castopod-podcasts.css # castopod, funkwhale, wordpress, grille…)
│ └── …
├── docs/
2026-07-23 05:48:43 +04:00
│ ├── 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
2026-07-23 05:10:04 +04:00
├── 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)
2025-07-17 20:43:15 +04:00
├── site.webmanifest.sample # Exemple de manifest PWA
2026-07-23 05:10:04 +04:00
├── browserconfig.xml # Tuiles Windows
2025-07-17 20:43:15 +04:00
├── sitemap.xml.sample # Exemple de sitemap
├── robots.txt.sample # Exemple de robots.txt
├── mentions-legales.php.sample # Exemple de mentions légales
2026-07-23 05:10:04 +04:00
├── dons.php.sample # Exemple de page de dons
├── LICENSE # GNU AGPL v3
2025-07-24 22:12:30 +04:00
└── README.adoc
----
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
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
2025-10-08 20:55:40 +04:00
- 🐘 *PHP 7.4+* (recommandé : PHP 8.0+)
- 📦 *Extensions PHP requises :*
2026-07-23 05:10:04 +04:00
* `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)
2025-10-08 20:55:40 +04:00
- 🌐 *Serveur web* : Apache ou Nginx
2026-07-23 05:10:04 +04:00
- 🔒 *HTTPS* : requis pour les fonctionnalités PWA
2025-10-08 20:55:40 +04:00
2026-07-23 05:10:04 +04:00
.Installation de l'extension `intl`
2025-10-08 20:55:40 +04:00
[source,bash]
----
2026-07-23 05:10:04 +04:00
# Ubuntu / Debian
2025-10-08 20:55:40 +04:00
sudo apt-get install php-intl
2026-07-23 05:10:04 +04:00
# Fedora / RHEL / CentOS
2025-10-08 20:55:40 +04:00
sudo dnf install php-intl
2026-07-23 05:10:04 +04:00
# Redémarrer le serveur web
sudo systemctl restart apache2 # Apache
sudo systemctl restart php8.3-fpm # Nginx + php-fpm
2025-10-08 20:55:40 +04:00
2026-07-23 05:10:04 +04:00
# Vérifier
2025-10-08 20:55:40 +04:00
php -m | grep intl
----
2026-07-23 05:10:04 +04:00
=== 🚀 Installation
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
. 📥 Clonez le dépôt :
2026-07-23 04:17:49 +04:00
+
[source,bash]
----
git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git
2026-07-23 05:10:04 +04:00
cd annu-kute-ced
----
. 📦 Vérifiez les prérequis PHP (voir ci-dessus).
. 🔧 Créez votre configuration locale et les fichiers d'instance :
+
[source,bash]
----
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
2026-07-23 04:17:49 +04:00
----
2026-07-23 05:10:04 +04:00
. 🛡️ Installez la configuration serveur sécurisée depuis `conf/` (voir <<fr-securite,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.
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
[[fr-configuration]]
=== ⚙️ Configuration
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
==== Le système en trois fichiers
2025-07-24 22:12:30 +04:00
2026-07-23 05:10:04 +04:00
[cols="1,2,2",options="header"]
|===
| Fichier | Rôle | Versionné ?
2025-04-08 16:43:18 +04:00
2026-07-23 05:10:04 +04:00
| `includes/config.php`
| Bootstrap : charge les autres fichiers et contient toutes les fonctions métier
| ✅ Oui
| `includes/config.default.php`
| Valeurs par défaut de chaque constante (définies seulement si absentes)
| ✅ Oui
| `includes/config.local.php`
| Vos surcharges locales — *prioritaires* car chargées en premier
| ❌ Non (`.gitignore`)
|===
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é.
2025-04-08 16:43:18 +04:00
2025-07-24 22:12:30 +04:00
[source,bash]
----
cp includes/config.local.php.sample includes/config.local.php
----
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
==== Référence des constantes
2025-04-08 16:43:18 +04:00
2026-07-23 05:10:04 +04:00
Valeurs par défaut issues de `includes/config.default.php`.
2025-04-08 16:43:18 +04:00
2026-07-23 05:10:04 +04:00
.Application et organisation
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
2025-10-08 20:55:40 +04:00
2026-07-23 05:10:04 +04:00
| `APP_HOST_NAME`
| `'annukuteced.buzz'`
| Nom de domaine affiché (mentions légales…)
2025-10-08 20:55:40 +04:00
2026-07-23 05:10:04 +04:00
| `ORGANIZATION_SHORT_NAME`
| `'ANNU KUTE CED'`
| Nom court de l'organisation
2025-10-08 20:55:40 +04:00
2026-07-23 05:10:04 +04:00
| `ORGANIZATION_NAME`
| `'ANNU KUTE CED'`
| Nom complet de l'organisation
|===
2025-10-08 20:55:40 +04:00
2026-07-23 05:10:04 +04:00
.PeerTube
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
2025-10-08 20:55:40 +04:00
2026-07-23 05:10:04 +04:00
| `PEERTUBE_URL`
| `'https://gade.o-k-i.net'`
| URL de l'instance PeerTube (obligatoire)
| `PEERTUBE_DISPLAY_NAME`
| `'gade.o-k-i.net'`
| Nom affiché de l'instance
| `API_KEY`
| `''`
| Clé API optionnelle (`Authorization: ApiKey …`)
| `SHOW_VIDEO_VIEWS`
| `false`
| Afficher le nombre de vues sur les cartes vidéo
| `PRIORITY_CATEGORIES`
| `[11, 15, 4, 9, 10]`
| Catégories mises en avant : `[ID => 'Nom']`, ordre = ordre d'affichage (accueil, sidebar, footer, menu mobile)
| `DEFAULT_TIMEZONE`
| `'America/Guadeloupe'`
| Fuseau horaire d'affichage (https://www.php.net/manual/fr/timezones.php[liste PHP^])
|===
.Section hero (bannière d'accueil)
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
2025-04-08 16:43:18 +04:00
2026-07-23 05:10:04 +04:00
| `HERO_TYPE`
| `'live'`
| `'live'` · `'video'` · `'playlist'` · `'none'`
| `LIVE_ACCOUNT_NAME`
| `'annu_kute_ced'`
| Compte PeerTube surveillé pour les directs (hero + page `/direct`)
2025-04-08 16:43:18 +04:00
2026-07-23 05:10:04 +04:00
| `HERO_VIDEO_ID`
| `'1aJ2u9euwF9fWKQhFxwFio'`
| UUID de la vidéo (mode `video`), extrait de l'URL `/w/<uuid>`
2025-04-08 16:43:18 +04:00
2026-07-23 05:10:04 +04:00
| `HERO_VIDEO_TITLE`
| `'Vidéo de présentation'`
| Titre (accessibilité)
2025-04-08 16:43:18 +04:00
2026-07-23 05:10:04 +04:00
| `PLAYLIST_PLATFORM`
| `'peertube'`
| `'peertube'` · `'funkwhale'` · `'castopod'`
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
| `PLAYLIST_INSTANCE_URL`
| `''`
| URL de base de la plateforme de playlist
| `PLAYLIST_ID`
| `''`
| ID de la playlist ; pour Castopod : `'@slug'`
| `PLAYLIST_TITLE` / `PLAYLIST_DESCRIPTION`
| `''` / `''`
| Textes optionnels (sinon récupérés via API)
|===
.Castopod (podcast)
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `CASTOPOD_ENABLED`
| `true`
| Activer la section podcast de l'accueil
| `CASTOPOD_URL`
| `'https://kute.o-k-i.net'`
| URL de l'instance Castopod
| `CASTOPOD_PODCAST_SLUGS`
| `['annu_kute_cedric']`
| Slug(s) de podcast ; flux RSS = `{URL}/@{slug}/feed`. Plusieurs podcasts : épisodes fusionnés et triés par date
| `CASTOPOD_EPISODES_COUNT`
| `5`
| 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.
.Funkwhale (musique, optionnel)
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `FUNKWHALE_ENABLED`
| `false`
| Activer la section musique
| `FUNKWHALE_URL`
| `'https://mizik.o-k-i.net'`
| URL de l'instance Funkwhale
| `FUNKWHALE_TRACKS_COUNT`
| `10`
| Morceaux aléatoires locaux affichés (50 mis en cache)
|===
.Mastodon (timeline)
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `MASTODON_INSTANCE_URL`
| `'https://bokante.o-k-i.net'`
| Instance Mastodon (ou Pleroma, via l'adaptateur)
| `MASTODON_URL`
| `'https://bokante.o-k-i.net/@cedric'`
| URL publique du compte (liens « Voir plus », footer)
| `MASTODON_DATE_FORMAT`
| `'fr-FR'`
| Locale de date des posts
| `MASTODON_BTN_SEE_MORE` / `MASTODON_BTN_RELOAD`
| `'Voir plus de post'` / `'Rafraichir'`
| Libellés des boutons
| `MASTODON_MAX_POST_FETCH` / `MASTODON_MAX_POST_SHOW`
| `'10'` / `'10'`
| Posts récupérés / affichés
| `MASTODON_S3_MEDIA_URL`
| _(non défini)_
| Origine S3 des médias (ajoutée à la CSP `media-src`)
|===
NOTE: La timeline n'a pas de flag d'activation : elle est toujours affichée sur l'accueil.
.WordPress (optionnel)
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `WORDPRESS_ENABLED`
| `false`
| Activer la section articles
| `WORDPRESS_URL`
| `''`
| URL du site WordPress (sans `/` final)
| `WORDPRESS_POSTS_COUNT`
| `6`
| Nombre d'articles (API REST `/wp-json/wp/v2/`)
|===
.Dons
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `DONATIONS_ENABLED`
| `false`
| Activer le système (icône cœur, lien « Soutenir », page `/dons.php`)
| `LIBERAPAY_URL` / `KOFI_URL`
| `''` / `''`
| URLs des plateformes externes
| `STRIPE_ENABLED`
| `false`
| Activer l'interface Stripe (onglets ponctuel / mensuel)
| `STRIPE_ONE_TIME_LINKS`
| `[1, 5, 10, 20, 50, 'custom'] => ''`
| Liens de paiement Stripe par montant
| `STRIPE_MONTHLY_LINKS`
| `[1, 5, 10, 20, 50] => ''`
| Liens d'abonnement mensuel Stripe
| `DONATION_AMOUNTS`
| `[1, 5, 10, 20, 50]`
| Montants suggérés
| `DONATION_CURRENCY`
| `'EUR'`
| 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.
.Compte à rebours (maintenance / lancement)
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `COUNTDOWN_ENABLED`
| `false`
| ⚠️ Si `true`, *toutes* les pages redirigent vers `countdown.php`
| `COUNTDOWN_TARGET_DATE`
| `'2025-10-11 00:00:00'`
| Date cible (`Y-m-d H:i:s`) ; à la fin, redirection vers `/`
| `COUNTDOWN_TIMEZONES`
| 5 territoires
| `[Libellé => fuseau PHP]` affichés sur la page
|===
.Annonce du prochain live
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `NEXT_LIVE_ENABLED`
| `false`
| Afficher l'annonce quand aucun direct n'est en cours
| `NEXT_LIVE_TITLE` / `NEXT_LIVE_DESCRIPTION`
| `'Prochain live'` / `'Rejoignez-nous…'`
| Textes (date et heure ajoutées automatiquement)
| `NEXT_LIVE_DATE`
| `''`
| Date du live (`Y-m-d H:i:s`)
| `NEXT_LIVE_IMAGE`
| `'uploads/next-live.jpg'`
| Image d'annonce (utilisée seulement si le fichier existe)
|===
.Site, réseaux sociaux et contact
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `SITE_NAME`
| `'ANNU KUTE CED'`
| Nom du site (titres, meta)
| `SITE_DESCRIPTION`
| `'Hub multimédia du podcast ANNU KUTE CED'`
| Description SEO
| `SITE_LOGO` / `SITE_FAVICON`
| `'img/logo.png'` / `'img/favicon.png'`
| Chemins des images
| `FACEBOOK_URL`, `X_URL`, `INSTAGRAM_URL`, `YOUTUBE_URL`, `TIKTOK_URL`
| `'#'`
| `'#'` ou vide = icône masquée
| `CONTACT_EMAIL`
| `'kontak@o-k-i.net'`
| E-mail de contact (footer)
|===
.Mentions légales
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `LEGAL_COPYRIGHT`
| `'ANNU KUTE CED'`
| Titulaire du copyright
| `LEGAL_WEBMASTER_NAME` / `LEGAL_WEBMASTER_EMAIL`
| `'Cédric Famibelle-Pronzola'` / `'contact@cedric-pronzola.dev'`
| Webmaster
| `LEGAL_HOST_NAME`, `LEGAL_HOST_COMPANY`, `LEGAL_HOST_RCS`, `LEGAL_HOST_ADDRESS`
| valeurs o2Switch
| Coordonnées de l'hébergeur
| `LEGAL_CONTACT_EMAIL`
| `'kontak@o-k-i.net'`
| Contact juridique
| `LEGAL_LICENSE` / `LEGAL_LICENSE_URL`
| AGPL-V3 + URL GNU
| Licence du code
| `LEGAL_SOURCE_CODE_URL`
| `'https://labola.o-k-i.net/cedric/annu-kute-ced'`
| Dépôt du code source (exigé par l'AGPL pour un service réseau)
| `LEGAL_SERVICE_DESCRIPTION`
| `'est le hub multimédia du podcast ANNU KUTE CED.'`
| Phrase de description du service
|===
.Tags et filtres
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
| `TAG_INDEPENDENCE`
| `'indépendance'`
| Tag de la fonction `getIndependenceVideos()` (pas de section d'accueil associée actuellement)
| `SHORTS_MAX_DURATION`
| `180`
| Durée max d'un short (s) ; ratio portrait (`aspectRatio ≤ 1`) aussi requis
| `IMPORTANT_TAGS`
| `['ANNUKUTECED', 'podcast', …]`
| Hashtags de la sidebar, du footer et du menu mobile
| `POPULAR_TAGS`
| `['podcast', 'annukuteced', …]`
| Hashtags affichés sur l'accueil
|===
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
.Pagination et volumes d'affichage
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
| `VIDEOS_PER_PAGE`
| `12`
| Vidéos par page (recherche)
2025-04-13 10:00:24 +04:00
2026-07-23 05:10:04 +04:00
| `COUNT_VIDEO_SEARCH`
| `20`
| Résultats récupérés par recherche
2025-04-13 10:00:24 +04:00
2026-07-23 05:10:04 +04:00
| `RECENT_VIDEOS_COUNT` / `TRENDING_VIDEOS_COUNT` / `CATEGORY_VIDEOS_COUNT`
| `6`
| Taille des sections d'accueil
2025-04-13 10:00:24 +04:00
2026-07-23 05:10:04 +04:00
| `SHORTS_COUNT` / `SHORTS_COUNT_SEARCH`
| `6` / `100`
| Shorts affichés / pool de recherche
2025-04-13 10:00:24 +04:00
2026-07-23 05:10:04 +04:00
| `LOAD_MORE_COUNT`
| `6`
| Vidéos chargées par clic sur « Voir plus »
2025-04-13 10:00:24 +04:00
2026-07-23 05:10:04 +04:00
| `FEATURED_VIDEOS_COUNT` / `INDEPENDENCE_VIDEOS_COUNT`
| `6`
| Réservés (sections non affichées actuellement)
|===
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
.Cache
[cols="2,2,3",options="header"]
|===
| Constante | Défaut | Description
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
| `CACHE_ENABLED`
| `false`
| Active le cache pour *Castopod et Funkwhale* (fortement recommandé)
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
| `CACHE_DURATION`
| `3600`
| Durée de vie du cache (s)
|===
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
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/`.
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
.Bloc « À propos » (pas de valeur par défaut — bloc masqué tant que non défini)
[cols="2,3",options="header"]
|===
| Constante | Description
| `MOVEMENT_TITLE`
| Titre du bloc (défaut template : « À propos »)
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
| `MOVEMENT_DESCRIPTION`
| Premier paragraphe ; *commenter cette ligne masque tout le bloc*
| `MOVEMENT_DESCRIPTION_2`
| Second paragraphe (optionnel)
| `MOVEMENT_IMAGE` / `MOVEMENT_IMAGE_ALT` / `MOVEMENT_CAPTION`
| Image (`img/movement_presentation.png`, non versionnée), texte alternatif et légende (HTML simple accepté)
|===
==== Exemple complet de `config.local.php`
2025-10-17 12:28:20 +04:00
[source,php]
----
2026-07-23 05:10:04 +04:00
<?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');
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
// Hero : direct de la chaîne, sinon annonce du prochain live
define('HERO_TYPE', 'live');
2026-07-23 04:17:49 +04:00
define('LIVE_ACCOUNT_NAME', 'annu_kute_ced');
2026-07-23 05:10:04 +04:00
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');
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04: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);
2025-10-17 14:23:31 +04:00
2026-07-23 05:10:04 +04:00
// Mastodon (compte BOKANTE)
define('MASTODON_INSTANCE_URL', 'https://bokante.o-k-i.net');
define('MASTODON_URL', 'https://bokante.o-k-i.net/@cedric');
2025-10-17 14:23:31 +04:00
2026-07-23 05:10:04 +04:00
// Cache : indispensable pour Castopod (rate limit RSS)
define('CACHE_ENABLED', true);
define('CACHE_DURATION', 3600);
----
2025-10-17 14:23:31 +04:00
2026-07-23 05:10:04 +04:00
=== 🎨 Personnalisation de l'apparence
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
. 🖼️ Remplacez `img/logo.png` par votre logo (et les favicons du dossier `img/`)
. 🎨 Modifiez les couleurs dans `css/styles.css`
. 📝 Textes : la plupart passent par les constantes de `config.local.php` (bloc « À propos », libellés Mastodon, etc.)
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
==== Fichiers d'instance à personnaliser
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
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`.
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
=== 🧭 Ordre des sections sur la page d'accueil
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
La page d'accueil assemble les sections dans cet ordre, chacune conditionnée par sa configuration :
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
. *Hero* — si `HERO_TYPE` ≠ `'none'` (live, vidéo ou playlist)
. *Podcasts Castopod* — si `CASTOPOD_ENABLED` et `CASTOPOD_URL` non vide
. *Morceaux Funkwhale* — si `FUNKWHALE_ENABLED` et `FUNKWHALE_URL` non vide
. *Timeline Mastodon* — toujours affichée
. *Articles WordPress* — si `WORDPRESS_ENABLED` et `WORDPRESS_URL` non 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_DESCRIPTION` défini) + aside hashtags
2025-10-17 14:23:31 +04:00
2026-07-23 05:10:04 +04:00
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.
2025-10-17 14:23:31 +04:00
2026-07-23 05:10:04 +04:00
[[fr-securite]]
=== 🛡️ Sécurité
2025-10-17 14:23:31 +04:00
2026-07-23 05:10:04 +04:00
==== Ce que l'application applique déjà
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
- *CSP dynamique* : `default-src 'self'` avec *nonce* unique par requête pour les scripts/styles inline ; origines PeerTube/Mastodon/CDN ajoutées automatiquement ; assouplissements `localhost` pour 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-Policy` restrictive, HSTS (HTTPS uniquement), CORP/COOP `same-origin`
+
NOTE: L'en-tête COEP a été *volontairement retiré* (commit `62d4d99`) : `require-corp` bloquait les embeds cross-origin de PeerTube, Mastodon, Castopod et Funkwhale.
- *CSRF* : jeton de session (`random_bytes(32)`) injecté en `<meta>`, vérifié par `hash_equals` sur l'endpoint AJAX ; vérification de l'en-tête `Origin`
- *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)
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
==== Configuration serveur (Apache)
[source,bash]
2025-10-17 12:28:20 +04:00
----
2026-07-23 05:10:04 +04:00
cp conf/.htaccess.sample .htaccess
2025-10-17 12:28:20 +04:00
----
2026-07-23 05:10:04 +04:00
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`).
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
WARNING: Cette configuration est *essentielle* : sans elle, vos fichiers de configuration sont exposés aux visiteurs.
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
==== Configuration serveur (Nginx)
[source,bash]
2025-10-17 12:28:20 +04:00
----
2026-07-23 05:10:04 +04:00
# 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
2025-10-17 12:28:20 +04:00
----
2026-07-23 05:10:04 +04:00
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.
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
=== 📱 Progressive Web App (PWA)
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
==== Fonctionnalités
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
- 📲 *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
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
==== Stratégies de cache du Service Worker (`sw.js`)
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
[cols="1,2,3",options="header"]
|===
| Type de requête | Stratégie | Détail
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
| Ressources statiques (`/css/`, `/js/`, `/img/`, CDN cdnjs)
| *Cache First*
| Mise en cache à l'installation et au premier accès ; repli sur `img/logo.png` si une image échoue
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
| Pages (`/`, `*.php`…)
| *Network First*
| Réseau d'abord, cache en secours hors ligne
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
| API et AJAX (`/ajax/`, `mastodon-config.php`…)
| *Network Only*
| Jamais de cache ; réponse JSON 503 synthétique hors ligne
|===
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
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.
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
==== Installation par les visiteurs
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
- 🌐 *Chrome/Edge* : menu → « Installer annukuteced.buzz »
- 🍎 *Safari iOS* : Partager → « Ajouter à l'écran d'accueil »
- 🦊 *Firefox Android* : menu → « Installer »
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
[[fr-analytics]]
=== 📊 Analytics (Plausible)
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
Le site est *pré-configuré* pour https://plausible.io[Plausible Analytics^] (sans cookies, conforme RGPD, données anonymes), mais le script est *désactivé par défaut*.
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
Pour l'activer :
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
. Ouvrez `index.php` et *décommentez* le snippet Plausible (balise `<script defer data-domain=… src="https://plausible.io/js/script…js">` et son shim `window.plausible`).
. C'est tout : la CSP autorise déjà `https://plausible.io` en `script-src` et `connect-src`, et le `data-domain` utilise automatiquement le domaine courant.
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
Données alors collectées (anonymes) : pages visitées, pays d'origine (IP non stockée), type d'appareil, navigateur, temps passé.
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
=== 🚀 Déploiement sur serveur mutualisé
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
. 🐘 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 : `644` pour les fichiers, `755` pour 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.sample` en `.htaccess` (Apache)
. 🌐 Faites pointer le domaine `annukuteced.buzz` vers le dossier d'installation
. 🧪 Testez la PWA via les outils de développement du navigateur (onglet Application)
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
=== 👨💻 Développement et contribution
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
. 🌿 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
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
Bonnes pratiques du dépôt :
2025-10-08 17:00:40 +04:00
2026-07-23 05:10:04 +04:00
- 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.php` ni 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
2025-10-08 17:00:40 +04:00
2026-07-23 05:48:43 +04:00
==== 📄 Exporter la documentation (HTML / PDF)
Ce README peut être exporté en HTML et en PDF en une seule commande :
[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
----
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.
2026-07-23 05:10:04 +04:00
=== 📜 Licence
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
Copyright (C) 2025 Cédric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE*
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
Ce programme est un logiciel libre : vous pouvez le redistribuer et/ou le modifier selon les termes de la licence publique générale GNU Affero publiée par la Free Software Foundation, soit la version 3 de la licence, soit (à votre choix) toute version ultérieure.
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de COMMERCIALISATION ou d'ADAPTATION À UN USAGE PARTICULIER. Voir la https://www.gnu.org/licenses/agpl-3.0.html[licence publique générale GNU Affero^] pour plus de détails (texte intégral dans `LICENSE`).
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
=== 📞 Contact
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
Pour toute question ou suggestion concernant cette plateforme : mailto:kontak@o-k-i.net[kontak@o-k-i.net]
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
<<top,⬆ Retour au sommaire>>
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
'''
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
[[en]]
== 🇬🇧 English version
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
=== 📖 Description
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
*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:
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
- 🎥 the podcast's *PeerTube* channel (videos, shorts, live streams);
- 🎙️ its *Castopod* account (latest episodes, built-in audio playback);
- 📡 its *Mastodon* timeline (news and announcements).
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
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.
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
🎯 *Mission*: provide a single, free and decentralized entry point to discover, listen to and follow the ANNU KUTE CED podcast without relying on Big Tech platforms.
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
=== 🌳 Project origin
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
This application is a *fork* of https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI[*FEDIVERSE OKI*^], developed by the https://o-k-i.net[ORGANISATION KA INTERNATIONALE (OKI)^], itself derived from the https://codeberg.org/Ka-Ubuntu/kaubuntu.re[kaubuntu.re^] project by the https://kaubuntu.com[Ka-Ubuntu^] movement. The original license (GNU AGPL v3) is preserved and respected.
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
[cols="1,3",options="header"]
|===
| Item | Detail
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
| Upstream repository
| https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
| This fork's repository
| `git@labola.o-k-i.net:cedric/annu-kute-ced.git`
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
| Production domain
| https://annukuteced.buzz
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
| Governance
| Application maintained by OKI; fork carried by the repository owner *cedric* (Cédric Famibelle-Pronzola)
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
| License
| https://www.gnu.org/licenses/agpl-3.0.html[GNU Affero General Public License v3^] (AGPL-V3) or later
|===
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
=== 🔗 Aggregated sources and instances
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
The hub is configured by default to aggregate the ANNU KUTE CED podcast's sources:
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
[cols="1,2,3",options="header"]
|===
| Service | Instance | Account / channel
2025-10-17 12:28:20 +04:00
2026-07-23 05:10:04 +04:00
| 🎥 PeerTube (videos, lives)
| GADE — `https://gade.o-k-i.net`
| https://gade.o-k-i.net/c/annu_kute_ced/videos[`annu_kute_ced`^]
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
| 🎙️ Castopod (audio episodes)
| KUTE — `https://kute.o-k-i.net`
| https://kute.o-k-i.net/@annu_kute_cedric[`@annu_kute_cedric`^]
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
| 📡 Mastodon (timeline)
| BOKANTE — `https://bokante.o-k-i.net`
| https://bokante.o-k-i.net/@cedric[`@cedric`^]
2025-09-28 20:39:47 +04:00
2026-07-23 05:10:04 +04:00
| 🎵 Funkwhale (music, optional, disabled by default)
| MIZIK — `https://mizik.o-k-i.net`
| random tracks from the instance
|===
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
All of these sources can be changed in `includes/config.local.php` (see <<en-configuration,Configuration>>).
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
=== ✨ Features
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
==== 🎥 PeerTube videos
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
- Recent, trending and per-category videos (configurable)
- *Shorts*: dedicated carousel for portrait videos under 3 minutes (touch scrolling)
- Full video page: embedded PeerTube player, Markdown description, Creative Commons licence badge, comments (read-only), suggested videos
- *Downloads*: direct files and HLS playlists, with resolution and size
- *Sharing*: copy link, embed code, e-mail, Facebook, X, WhatsApp, LinkedIn, Telegram
- Full-text search and hashtag search (`#` prefix)
- AJAX "Load more" pagination (protected by CSRF token and Origin check)
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
==== 📺 Live streams and announcements
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
- *Live page* (`/direct`): embeds the PeerTube live stream when one is running, with autoplay
- *Next live announcement*: date and time automatically converted for 5 territories (Ma'ohi Nui, Martinique/Guadeloupe, French Guiana, France, Kanaky), custom image (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 https://gitlab.com/idotj/mastodon-embed-timeline[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 in `localStorage`)
- 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` (with `SearchAction`), `VideoObject`, `CollectionPage`, `BreadcrumbList`
- *Open Graph* and *Twitter Cards* meta tags
- `sitemap.xml` and `robots.txt` provided as samples
- Ready for *Plausible Analytics* (see <<en-analytics,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, `Origin` header 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
[source]
----
├── 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/
2026-07-23 05:48:43 +04:00
│ ├── 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
2026-07-23 05:10:04 +04:00
├── 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
2025-10-17 17:38:16 +04:00
----
2026-07-23 05:10:04 +04:00
NOTE: Files marked "legacy" are kept for reference but are not included by any page; the homepage renders those sections internally.
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
=== 📋 Requirements
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
- 🐘 *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
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
.Installing the `intl` extension
[source,bash]
2025-10-17 17:38:16 +04:00
----
2026-07-23 05:10:04 +04:00
# Ubuntu / Debian
sudo apt-get install php-intl
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
# Fedora / RHEL / CentOS
sudo dnf install php-intl
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
# Restart the web server
sudo systemctl restart apache2 # Apache
sudo systemctl restart php8.3-fpm # Nginx + php-fpm
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
# Check
php -m | grep intl
----
=== 🚀 Installation
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
. 📥 Clone the repository:
2025-10-17 17:38:16 +04:00
+
[source,bash]
----
2026-07-23 05:10:04 +04:00
git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git
cd annu-kute-ced
2025-10-17 17:38:16 +04:00
----
2026-07-23 05:10:04 +04:00
. 📦 Check the PHP requirements (see above).
. 🔧 Create your local configuration and instance files:
2025-10-17 17:38:16 +04:00
+
2026-07-23 05:10:04 +04:00
[source,bash]
----
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 <<en-securite,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.
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
[[en-configuration]]
=== ⚙️ Configuration
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
==== The three-file system
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
[cols="1,2,2",options="header"]
|===
| File | Role | Versioned?
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
| `includes/config.php`
| Bootstrap: loads the other files and holds all business functions
| ✅ Yes
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
| `includes/config.default.php`
| Default values for every constant (defined only if missing)
| ✅ Yes
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
| `includes/config.local.php`
| Your local overrides — *take precedence* as they load first
| ❌ No (`.gitignore`)
|===
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
To customize the instance, never edit `config.default.php`: define the constant in `config.local.php`. Since it loads first, your values always win.
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
[source,bash]
----
cp includes/config.local.php.sample includes/config.local.php
----
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
==== Constants reference
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
Default values from `includes/config.default.php`.
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
.Application and organization
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
2025-10-17 17:38:16 +04:00
2026-07-23 05:10:04 +04:00
| `APP_HOST_NAME`
| `'annukuteced.buzz'`
| Displayed domain name (legal notice…)
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
| `ORGANIZATION_SHORT_NAME`
| `'ANNU KUTE CED'`
| Short organization name
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
| `ORGANIZATION_NAME`
| `'ANNU KUTE CED'`
| Full organization name
|===
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
.PeerTube
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
| `PEERTUBE_URL`
| `'https://gade.o-k-i.net'`
| PeerTube instance URL (required)
| `PEERTUBE_DISPLAY_NAME`
| `'gade.o-k-i.net'`
| Displayed instance name
| `API_KEY`
| `''`
| Optional API key (`Authorization: ApiKey …`)
| `SHOW_VIDEO_VIEWS`
| `false`
| Show view counts on video cards
| `PRIORITY_CATEGORIES`
| `[11, 15, 4, 9, 10]`
| Featured categories: `[ID => 'Name']`, order = display order (homepage, sidebar, footer, mobile menu)
| `DEFAULT_TIMEZONE`
| `'America/Guadeloupe'`
| Display timezone (https://www.php.net/manual/en/timezones.php[PHP list^])
|===
.Hero section (homepage banner)
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
| `HERO_TYPE`
| `'live'`
| `'live'` · `'video'` · `'playlist'` · `'none'`
| `LIVE_ACCOUNT_NAME`
| `'annu_kute_ced'`
| PeerTube account watched for live streams (hero + `/direct` page)
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
| `HERO_VIDEO_ID`
| `'1aJ2u9euwF9fWKQhFxwFio'`
| Video UUID (`video` mode), extracted from the `/w/<uuid>` URL
2025-07-21 13:15:35 +04:00
2026-07-23 05:10:04 +04:00
| `HERO_VIDEO_TITLE`
| `'Vidéo de présentation'`
| Title (accessibility)
2025-07-21 13:15:35 +04:00
2026-07-23 05:10:04 +04:00
| `PLAYLIST_PLATFORM`
| `'peertube'`
| `'peertube'` · `'funkwhale'` · `'castopod'`
2025-07-24 22:12:30 +04:00
2026-07-23 05:10:04 +04:00
| `PLAYLIST_INSTANCE_URL`
| `''`
| Base URL of the playlist platform
| `PLAYLIST_ID`
| `''`
| Playlist ID; for Castopod: `'@slug'`
| `PLAYLIST_TITLE` / `PLAYLIST_DESCRIPTION`
| `''` / `''`
| Optional texts (otherwise fetched via API)
|===
.Castopod (podcast)
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `CASTOPOD_ENABLED`
| `true`
| Enable the homepage podcast section
| `CASTOPOD_URL`
| `'https://kute.o-k-i.net'`
| Castopod instance URL
| `CASTOPOD_PODCAST_SLUGS`
| `['annu_kute_cedric']`
| Podcast slug(s); RSS feed = `{URL}/@{slug}/feed`. Multiple podcasts: episodes merged and date-sorted
| `CASTOPOD_EPISODES_COUNT`
| `5`
| 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.
.Funkwhale (music, optional)
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `FUNKWHALE_ENABLED`
| `false`
| Enable the music section
| `FUNKWHALE_URL`
| `'https://mizik.o-k-i.net'`
| Funkwhale instance URL
| `FUNKWHALE_TRACKS_COUNT`
| `10`
| Random local tracks displayed (50 cached)
|===
.Mastodon (timeline)
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `MASTODON_INSTANCE_URL`
| `'https://bokante.o-k-i.net'`
| Mastodon instance (or Pleroma, via the adapter)
| `MASTODON_URL`
| `'https://bokante.o-k-i.net/@cedric'`
| Public account URL ("See more" links, footer)
| `MASTODON_DATE_FORMAT`
| `'fr-FR'`
| Post date locale
| `MASTODON_BTN_SEE_MORE` / `MASTODON_BTN_RELOAD`
| `'Voir plus de post'` / `'Rafraichir'`
| Button labels
| `MASTODON_MAX_POST_FETCH` / `MASTODON_MAX_POST_SHOW`
| `'10'` / `'10'`
| Posts fetched / displayed
| `MASTODON_S3_MEDIA_URL`
| _(undefined)_
| S3 media origin (added to the CSP `media-src`)
|===
NOTE: The timeline has no enable flag: it is always displayed on the homepage.
.WordPress (optional)
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `WORDPRESS_ENABLED`
| `false`
| Enable the posts section
| `WORDPRESS_URL`
| `''`
| WordPress site URL (no trailing `/`)
| `WORDPRESS_POSTS_COUNT`
| `6`
| Number of posts (REST API `/wp-json/wp/v2/`)
|===
.Donations
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `DONATIONS_ENABLED`
| `false`
| Enable the system (heart icon, "Support" link, `/dons.php` page)
| `LIBERAPAY_URL` / `KOFI_URL`
| `''` / `''`
| External platform URLs
| `STRIPE_ENABLED`
| `false`
| Enable the Stripe interface (one-time / monthly tabs)
| `STRIPE_ONE_TIME_LINKS`
| `[1, 5, 10, 20, 50, 'custom'] => ''`
| Stripe payment links per amount
| `STRIPE_MONTHLY_LINKS`
| `[1, 5, 10, 20, 50] => ''`
| Stripe monthly subscription links
| `DONATION_AMOUNTS`
| `[1, 5, 10, 20, 50]`
| Suggested amounts
| `DONATION_CURRENCY`
| `'EUR'`
| 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.
.Countdown (maintenance / launch)
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `COUNTDOWN_ENABLED`
| `false`
| ⚠️ When `true`, *every* page redirects to `countdown.php`
| `COUNTDOWN_TARGET_DATE`
| `'2025-10-11 00:00:00'`
| Target date (`Y-m-d H:i:s`); on completion, redirects to `/`
| `COUNTDOWN_TIMEZONES`
| 5 territories
| `[Label => PHP timezone]` shown on the page
|===
.Next-live announcement
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `NEXT_LIVE_ENABLED`
| `false`
| Show the announcement when no live stream is running
| `NEXT_LIVE_TITLE` / `NEXT_LIVE_DESCRIPTION`
| `'Prochain live'` / `'Rejoignez-nous…'`
| Texts (date and time appended automatically)
| `NEXT_LIVE_DATE`
| `''`
| Live date (`Y-m-d H:i:s`)
| `NEXT_LIVE_IMAGE`
| `'uploads/next-live.jpg'`
| Announcement image (used only if the file exists)
|===
.Site, social networks and contact
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `SITE_NAME`
| `'ANNU KUTE CED'`
| Site name (titles, meta)
| `SITE_DESCRIPTION`
| `'Hub multimédia du podcast ANNU KUTE CED'`
| SEO description
| `SITE_LOGO` / `SITE_FAVICON`
| `'img/logo.png'` / `'img/favicon.png'`
| Image paths
| `FACEBOOK_URL`, `X_URL`, `INSTAGRAM_URL`, `YOUTUBE_URL`, `TIKTOK_URL`
| `'#'`
| `'#'` or empty = icon hidden
| `CONTACT_EMAIL`
| `'kontak@o-k-i.net'`
| Contact e-mail (footer)
|===
.Legal notice
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `LEGAL_COPYRIGHT`
| `'ANNU KUTE CED'`
| Copyright holder
| `LEGAL_WEBMASTER_NAME` / `LEGAL_WEBMASTER_EMAIL`
| `'Cédric Famibelle-Pronzola'` / `'contact@cedric-pronzola.dev'`
| Webmaster
| `LEGAL_HOST_NAME`, `LEGAL_HOST_COMPANY`, `LEGAL_HOST_RCS`, `LEGAL_HOST_ADDRESS`
| o2Switch values
| Hosting provider details
| `LEGAL_CONTACT_EMAIL`
| `'kontak@o-k-i.net'`
| Legal contact
| `LEGAL_LICENSE` / `LEGAL_LICENSE_URL`
| AGPL-V3 + GNU URL
| Code license
| `LEGAL_SOURCE_CODE_URL`
| `'https://labola.o-k-i.net/cedric/annu-kute-ced'`
| Source code repository (required by the AGPL for a network service)
| `LEGAL_SERVICE_DESCRIPTION`
| `'est le hub multimédia du podcast ANNU KUTE CED.'`
| Service description sentence
|===
.Tags and filters
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
| `TAG_INDEPENDENCE`
| `'indépendance'`
| Tag used by `getIndependenceVideos()` (no associated homepage section currently)
| `SHORTS_MAX_DURATION`
| `180`
| Max short duration (s); portrait ratio (`aspectRatio ≤ 1`) also required
| `IMPORTANT_TAGS`
| `['ANNUKUTECED', 'podcast', …]`
| Hashtags in the sidebar, footer and mobile menu
| `POPULAR_TAGS`
| `['podcast', 'annukuteced', …]`
| Hashtags displayed on the homepage
|===
2025-07-24 22:12:30 +04:00
2026-07-23 05:10:04 +04:00
.Pagination and display volumes
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
2025-07-21 13:15:35 +04:00
2026-07-23 05:10:04 +04:00
| `VIDEOS_PER_PAGE`
| `12`
| Videos per page (search)
2025-07-21 13:15:35 +04:00
2026-07-23 05:10:04 +04:00
| `COUNT_VIDEO_SEARCH`
| `20`
| Results fetched per search
2025-07-21 13:15:35 +04:00
2026-07-23 05:10:04 +04:00
| `RECENT_VIDEOS_COUNT` / `TRENDING_VIDEOS_COUNT` / `CATEGORY_VIDEOS_COUNT`
| `6`
| Homepage section sizes
2025-07-21 13:21:26 +04:00
2026-07-23 05:10:04 +04:00
| `SHORTS_COUNT` / `SHORTS_COUNT_SEARCH`
| `6` / `100`
| Shorts displayed / search pool
2025-07-21 13:21:26 +04:00
2026-07-23 05:10:04 +04:00
| `LOAD_MORE_COUNT`
| `6`
| Videos loaded per "Load more" click
2025-07-21 13:21:26 +04:00
2026-07-23 05:10:04 +04:00
| `FEATURED_VIDEOS_COUNT` / `INDEPENDENCE_VIDEOS_COUNT`
| `6`
| Reserved (sections not currently displayed)
|===
2025-07-24 22:12:30 +04:00
2026-07-23 05:10:04 +04:00
.Cache
[cols="2,2,3",options="header"]
|===
| Constant | Default | Description
2025-07-24 22:12:30 +04:00
2026-07-23 05:10:04 +04:00
| `CACHE_ENABLED`
| `false`
| Enable caching for *Castopod and Funkwhale* (strongly recommended)
| `CACHE_DURATION`
| `3600`
| 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/`.
."About" block (no default values — block hidden until defined)
[cols="2,3",options="header"]
|===
| Constant | Description
| `MOVEMENT_TITLE`
| Block title (template fallback: "À propos")
| `MOVEMENT_DESCRIPTION`
| First paragraph; *commenting this line hides the whole block*
| `MOVEMENT_DESCRIPTION_2`
| Second paragraph (optional)
| `MOVEMENT_IMAGE` / `MOVEMENT_IMAGE_ALT` / `MOVEMENT_CAPTION`
| Image (`img/movement_presentation.png`, not versioned), alt text and caption (simple HTML allowed)
|===
==== Complete `config.local.php` example
[source,php]
2025-07-24 22:12:30 +04:00
----
2026-07-23 05:10:04 +04:00
<?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);
2025-07-24 22:12:30 +04:00
----
2025-07-21 13:21:26 +04:00
2026-07-23 05:10:04 +04:00
=== 🎨 Appearance customization
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
. 🖼️ Replace `img/logo.png` with your logo (and the favicons in `img/`)
. 🎨 Edit the colors in `css/styles.css`
. 📝 Most texts are set through `config.local.php` constants ("About" block, Mastodon labels, etc.)
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
==== Instance files to customize
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
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.
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
=== 🧭 Homepage section order
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
The homepage assembles sections in this order, each gated by its configuration:
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
. *Hero* — if `HERO_TYPE` ≠ `'none'` (live, video or playlist)
. *Castopod podcasts* — if `CASTOPOD_ENABLED` and `CASTOPOD_URL` is not empty
. *Funkwhale tracks* — if `FUNKWHALE_ENABLED` and `FUNKWHALE_URL` is not empty
. *Mastodon timeline* — always displayed
. *WordPress posts* — if `WORDPRESS_ENABLED` and `WORDPRESS_URL` is 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_DESCRIPTION` is defined) + hashtags aside
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
Desktop layout: hero/Castopod/Funkwhale + Mastodon + WordPress are arranged in columns (1fr 2fr, or 1fr 2fr 1fr with WordPress); stacked vertically on mobile.
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
[[en-securite]]
=== 🛡️ Security
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
==== What the application already enforces
2025-07-17 20:14:14 +04:00
2026-07-23 05:10:04 +04:00
- *Dynamic CSP*: `default-src 'self'` with a unique per-request *nonce* for inline scripts/styles; PeerTube/Mastodon/CDN origins added automatically; `localhost` relaxations for development
- *Headers*: `X-Frame-Options: SAMEORIGIN`, `X-Content-Type-Options: nosniff`, `X-XSS-Protection`, `Referrer-Policy: strict-origin-when-cross-origin`, restrictive `Permissions-Policy`, HSTS (HTTPS only), CORP/COOP `same-origin`
+
NOTE: The COEP header was *deliberately removed* (commit `62d4d99`): `require-corp` broke cross-origin embeds from PeerTube, Mastodon, Castopod and Funkwhale.
- *CSRF*: session token (`random_bytes(32)`) injected as a `<meta>` tag, verified with `hash_equals` on the AJAX endpoint; `Origin` header 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)
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
==== Server configuration (Apache)
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
[source,bash]
----
cp conf/.htaccess.sample .htaccess
----
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
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`).
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
WARNING: This configuration is *essential*: without it, your configuration files are exposed to visitors.
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
==== Server configuration (Nginx)
2025-07-17 20:43:15 +04:00
2026-07-23 05:10:04 +04:00
[source,bash]
----
# 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
----
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
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.
2026-07-23 04:17:49 +04:00
2026-07-23 05:10:04 +04:00
=== 📱 Progressive Web App (PWA)
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
==== Features
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
- 📲 *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
2025-04-08 17:30:06 +04:00
2026-07-23 05:10:04 +04:00
==== Service Worker caching strategies (`sw.js`)
2025-04-08 17:28:46 +04:00
2026-07-23 05:10:04 +04:00
[cols="1,2,3",options="header"]
|===
| Request type | Strategy | Detail
2025-04-08 17:28:46 +04:00
2026-07-23 05:10:04 +04:00
| Static assets (`/css/`, `/js/`, `/img/`, cdnjs CDN)
| *Cache First*
| Cached at install time and on first access; falls back to `img/logo.png` if an image fails
2025-04-08 17:28:46 +04:00
2026-07-23 05:10:04 +04:00
| Pages (`/`, `*.php`…)
| *Network First*
| Network first, cache fallback when offline
2025-04-08 17:30:06 +04:00
2026-07-23 05:10:04 +04:00
| API and AJAX (`/ajax/`, `mastodon-config.php`…)
| *Network Only*
| Never cached; synthetic 503 JSON response when offline
|===
2025-04-08 17:28:46 +04:00
2026-07-23 05:10:04 +04:00
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.
2025-04-08 17:28:46 +04:00
2026-07-23 05:10:04 +04:00
==== Installation by visitors
2025-04-08 17:28:46 +04:00
2026-07-23 05:10:04 +04:00
- 🌐 *Chrome/Edge*: menu → "Install annukuteced.buzz"
- 🍎 *Safari iOS*: Share → "Add to Home Screen"
- 🦊 *Firefox Android*: menu → "Install"
2025-04-08 06:37:14 +04:00
2026-07-23 05:10:04 +04:00
[[en-analytics]]
=== 📊 Analytics (Plausible)
2025-07-24 08:40:35 +04:00
2026-07-23 05:10:04 +04:00
The site is *pre-configured* for https://plausible.io[Plausible Analytics^] (cookie-free, GDPR-compliant, anonymous data), but the script is *disabled by default*.
2025-07-24 08:40:35 +04:00
2026-07-23 05:10:04 +04:00
To enable it:
2025-07-24 08:40:35 +04:00
2026-07-23 05:10:04 +04:00
. Open `index.php` and *uncomment* the Plausible snippet (the `<script defer data-domain=… src="https://plausible.io/js/script…js">` tag and its `window.plausible` shim).
. That's it: the CSP already allows `https://plausible.io` in `script-src` and `connect-src`, and the `data-domain` automatically uses the current domain.
2025-07-24 08:40:35 +04:00
2026-07-23 05:10:04 +04:00
Data then collected (anonymous): visited pages, country of origin (IP not stored), device type, browser, time spent.
2025-07-24 08:40:35 +04:00
2026-07-23 05:10:04 +04:00
=== 🚀 Deploying to shared hosting
2025-07-24 22:12:30 +04:00
2026-07-23 05:10:04 +04:00
. 🐘 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: `644` for files, `755` for directories; `cache/` must be writable
. 📄 Create the instance files from the `.sample` files (config, manifest, robots, sitemap, legal notice, donations)
. 🛡️ Copy `conf/.htaccess.sample` to `.htaccess` (Apache)
. 🌐 Point the `annukuteced.buzz` domain to the installation directory
. 🧪 Test the PWA via the browser developer tools (Application tab)
2025-07-24 08:40:35 +04:00
2026-07-23 05:10:04 +04:00
=== 👨💻 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.php` or files derived from the `.sample` files
- 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
2026-07-23 05:48:43 +04:00
==== 📄 Exporting the documentation (HTML / PDF)
This README can be exported to HTML and PDF with a single command:
[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
----
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.
2026-07-23 05:10:04 +04:00
=== 📜 License
Copyright (C) 2025 Cédric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE*
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the https://www.gnu.org/licenses/agpl-3.0.html[GNU Affero General Public License^] for more details (full text in `LICENSE`).
2025-07-24 08:40:35 +04:00
2026-07-23 05:10:04 +04:00
=== 📞 Contact
2025-07-24 08:40:35 +04:00
2026-07-23 05:10:04 +04:00
For any question or suggestion about this platform: mailto:kontak@o-k-i.net[kontak@o-k-i.net]
2025-07-17 20:43:15 +04:00
2026-07-23 05:10:04 +04:00
<<top,⬆ Back to top>>