From 3c0b094e92255888bfd0597a9dc99d33ae6594e3 Mon Sep 17 00:00:00 2001 From: sucupira Date: Thu, 23 Jul 2026 08:04:41 -0400 Subject: [PATCH] =?UTF-8?q?R=C3=A9=C3=A9crit=20le=20README=20pour=20la=20v?= =?UTF-8?q?ersion=20SvelteKit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remplace la documentation PHP par celle de la branche svelte (FR/EN) : architecture statique et bake au build, fonctionnalités portées (Funkwhale inclus), référence de src/lib/config.ts, modèle CSP par page, PWA, structure du projet, prérequis Node + ImageMagick, mesures Lighthouse, déploiement --- README.adoc | 1836 ++++++++++++--------------------------------------- 1 file changed, 429 insertions(+), 1407 deletions(-) diff --git a/README.adoc b/README.adoc index f813cb7..7ec8878 100644 --- a/README.adoc +++ b/README.adoc @@ -1,13 +1,11 @@ -= 🎙️ ANNU KUTE CED — Hub multimédia du podcast += 🎙️ ANNU KUTE CED — Hub multimédia du podcast (SvelteKit) :toc: left :toc-title: Sommaire / Contents :toclevels: 3 -NOTE: Ce document décrit la version historique PHP (branche `main`). La branche `svelte` contient la réécriture **SvelteKit statique** (données bakées au build, charte OKI, FR/EN, PWA) — voir `docs/DEPLOIEMENT-SVELTEKIT.md` pour le build et le déploiement. - [[top]] -🌍 *Hub multimédia du podcast ANNU KUTE CED* + -🌍 *Multimedia hub for the ANNU KUTE CED podcast* +🌍 *Hub multimédia du podcast ANNU KUTE CED — version SvelteKit statique* + +🌍 *Multimedia hub for the ANNU KUTE CED podcast — static SvelteKit version* [.text-center] *Choisissez votre langue / Choose your language :* + @@ -20,19 +18,22 @@ NOTE: Ce document décrit la version historique PHP (branche `main`). La branche === 📖 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 : +*ANNU KUTE CED* est le *hub multimédia* du podcast du même nom. Il regroupe en un seul lieu : - 🎥 la chaîne *PeerTube* du podcast (vidéos, shorts, directs) ; - 🎙️ son compte *Castopod* (derniers épisodes, lecture audio intégrée) ; +- 🎵 une sélection aléatoire de morceaux *Funkwhale* (même lecteur intégré) ; - 📡 sa timeline *Mastodon* (actualités et annonces). -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. +Cette version est une *application SvelteKit 100 % statique* (Svelte 5 + TypeScript, `adapter-static`, prerender intégral) : toutes les données des instances sont *récupérées au moment du build* (« bake ») et le site généré peut être servi depuis n'importe quel hébergement statique — y compris un mutualisé comme o2switch — *sans PHP, sans Node, sans base de données*. C'est aussi une *Progressive Web App* installable, avec mode hors ligne, en français et en anglais. 🎯 *Mission* : offrir un point d'entrée unique, libre et décentralisé, pour découvrir, écouter et suivre le podcast ANNU KUTE CED sans dépendre des grandes plateformes propriétaires. +NOTE : La version historique PHP est conservée sur la branche `main`. Cette documentation décrit la branche `svelte`. + === 🌳 Origine du projet -Cette application est un *fork* de https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI[*FEDIVERSE OKI*^], développée par l'https://o-k-i.net[ORGANISATION KA INTERNATIONALE (OKI)^], elle-même issue du projet https://codeberg.org/Ka-Ubuntu/kaubuntu.re[kaubuntu.re^] du mouvement https://kaubuntu.com[Ka-Ubuntu^]. La licence d'origine (GNU AGPL v3) est conservée et respectée. +Cette application est un *fork* de https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI[*FEDIVERSE OKI*^], développée par l'https://o-k-i.net[ORGANISATION KA INTERNATIONALE (OKI)^], elle-même issue du projet https://codeberg.org/Ka-Ubuntu/kaubuntu.re[kaubuntu.re^] du mouvement https://kaubuntu.com[Ka-Ubuntu^]. La licence d'origine (GNU AGPL v3) est conservée et respectée. La refonte SvelteKit applique la https://o-k-i.net[charte OKI] (tokens panafricains, thème sombre par défaut, iconographie SVG kréyòl, cadences de motion « gwoka »). [cols="1,3",options="header"] |=== @@ -42,7 +43,7 @@ Cette application est un *fork* de https://labola.o-k-i.net/ORGANISATION-KA-INTE | https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI | Dépôt de ce fork -| `git@labola.o-k-i.net:cedric/annu-kute-ced.git` +| `git@labola.o-k-i.net:cedric/annu-kute-ced.git` (branche `svelte`) | Domaine de production | https://annukuteced.buzz @@ -56,7 +57,7 @@ Cette application est un *fork* de https://labola.o-k-i.net/ORGANISATION-KA-INTE === 🔗 Sources et instances utilisées -Le hub est configuré par défaut pour agréger les sources du podcast ANNU KUTE CED : +Le hub agrège au build les sources du podcast ANNU KUTE CED : [cols="1,2,3",options="header"] |=== @@ -70,16 +71,16 @@ Le hub est configuré par défaut pour agréger les sources du podcast ANNU KUTE | KUTE — `https://kute.o-k-i.net` | https://kute.o-k-i.net/@annu_kute_cedric[`@annu_kute_cedric`^] +| 🎵 Funkwhale (musique) +| MIZIK — `https://mizik.o-k-i.net` +| morceaux aléatoires de l'instance + | 📡 Mastodon (timeline) | BOKANTE — `https://bokante.o-k-i.net` | https://bokante.o-k-i.net/@cedric[`@cedric`^] - -| 🎵 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 <>). +Toutes ces sources sont modifiables dans `src/lib/config.ts` (voir <>). === ✨ Fonctionnalités @@ -90,794 +91,307 @@ Toutes ces sources sont modifiables dans `includes/config.local.php` (voir <>) : désactivé par défaut, sans cookies et conforme RGPD +- *JSON-LD* généré automatiquement : `WebSite` (avec `SearchAction`), `VideoObject`, `CollectionPage`, `BreadcrumbList`, `Organization` +- Balises *Open Graph* complètes et *Twitter Cards*, canonical, `hreflang` fr/en/x-default +- `sitemap.xml` *généré au build* (toutes les pages, vidéos comprises) et `robots.txt` ==== 🛡️ Sécurité -- 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/` +- *CSP stricte* : politique globale en en-tête (`_headers` Cloudflare / `.htaccess` Apache) + `script-src` délivré *par page* en balise `` avec les empreintes SHA-256 des scripts inline (aucun `'unsafe-inline'` pour les scripts) +- *Zéro requête tierce* au chargement hors instances first-party de l'écosystème (GADE, KUTE, BOKANTE, MIZIK) : ni Google Fonts, ni CDN, ni analytics +- HTML distant *sanitisé* au build (posts Mastodon, commentaires) ; descriptions Markdown échappées +- HSTS, `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy`, `Permissions-Policy` restrictive + +==== ⚡ Performance (mesurée, Lighthouse mobile) + +- *97 / 100 / 100 / 100* (performance, accessibilité, bonnes pratiques, SEO) +- JS initial ≈ 66 Ko gzip ; poids total de l'accueil ≈ 900 Ko ; LCP 2,4 s ; TBT 50 ms ; CLS 0 +- Images distantes *optimisées au build* (WebP via ImageMagick) : vignettes PeerTube, avatars, médias Mastodon, pochettes Castopod === 🛠️ Technologies utilisées -- 📄 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) +- ⚡ *SvelteKit 2* + *Svelte 5* (runes) + *TypeScript* strict +- 📦 `@sveltejs/adapter-static` (prerender intégral, `trailingSlash: 'always'`) +- 📱 `vite-plugin-pwa` (Workbox, generateSW) +- 🖼️ *ImageMagick* (optimisation des images au prebuild) +- 🎨 CSS vanilla : tokens OKI + styles scopés — pas de framework CSS +- 🔤 `@fontsource/archivo` + `@fontsource/inter` (woff2 copiés dans `static/fonts/`) === 📁 Structure du projet [source] ---- -├── 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 +│ ├── DEPLOIEMENT-SVELTEKIT.md # Guide build + déploiement (o2switch, Cloudflare) │ └── 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 +├── scripts/ +│ ├── fetch-podcast-cover.mjs # Prebuild : pochettes Castopod optimisées (WebP) +│ ├── optimize-remote-images.mjs # Prebuild : vignettes/avatars/médias optimisés +│ └── postbuild-csp.mjs # Postbuild : CSP SHA-256 par page (balise meta) +├── src/ +│ ├── app.html # %lang%, fonts, theme.js, registerSW.js +│ ├── hooks.server.ts # lang fr/en via transformPageChunk +│ ├── params/locale.ts # Matcher du paramètre [[locale]] +│ ├── lib/ +│ │ ├── config.ts # ⭐ Toute la configuration d'instance +│ │ ├── types.ts # Types partagés (VideoSummary, Episode, Post…) +│ │ ├── audio-bus.svelte.ts # Un seul flux audio à la fois +│ │ ├── styles/ # oki-tokens.css (charte) + base.css (primitives) +│ │ ├── i18n/ # fr.json, en.json + helpers (locale, hrefFor…) +│ │ ├── server/ # Récupération des données au build : +│ │ │ ├── http.ts # fetch throttlé (429 → retry), sanitisation +│ │ │ ├── peertube.ts # API GADE (vidéos, shorts, live, commentaires) +│ │ │ ├── castopod.ts # Flux RSS KUTE (épisodes) +│ │ │ ├── funkwhale.ts # API MIZIK (morceaux aléatoires locaux) +│ │ │ ├── mastodon.ts # API BOKANTE (timeline) +│ │ │ ├── image-map.ts # Mapping images optimisées (mapImage) +│ │ │ └── image-map.json # (généré au prebuild) +│ │ ├── motion/ # tokens gwoka, action use:reveal +│ │ └── components/ # Seo, Nav, Sidebar, Footer, VideoCard, +│ │ # AudioPlayer, MastodonTimeline, HeroSection, +│ │ # CountdownLock, OfflineIndicator, motion/… +│ └── routes/ +│ ├── +layout.ts # prerender = true, trailingSlash +│ ├── +error.svelte # 404 kréyòl (« Paj la pa la ») +│ ├── [[locale=locale]]/ # Toutes les pages, FR (/) et EN (/en/) : +│ │ ├── +page.svelte # accueil (agrégateur) +│ │ ├── video/[uuid]/ # page vidéo (embed, téléchargements, partage) +│ │ ├── categories/[id]/ # page catégorie +│ │ ├── recherche/ # recherche (index JSON + filtrage client) +│ │ ├── direct/ # live + annonce du prochain live +│ │ ├── dons/ # dons (LiberaPay, Ko-fi, Stripe) +│ │ ├── mentions-legales/ # mentions légales +│ │ └── offline/ # page hors-ligne (fallback du SW) +│ ├── search-index.json/ # Index de recherche (bake) +│ └── sitemap.xml/ # Sitemap (bake) +├── static/ +│ ├── fonts/ # Archivo/Inter woff2 + fonts.css +│ ├── images/ # logo, favicons, pochettes, images optimisées +│ ├── icons.svg # Sprite SVG (pictos kréyòl + UI) +│ ├── theme.js # Anti-FOUC (thème sombre défaut, clair opt-in) +│ ├── registerSW.js # Enregistrement du Service Worker +│ ├── manifest.webmanifest # Manifest PWA +│ ├── _headers / .htaccess # Headers de sécurité (Cloudflare / Apache) +│ ├── 404.html # 404 statique autonome +│ ├── robots.txt / browserconfig.xml ├── uploads/ # Images d'annonces (non versionné, hors .gitkeep) -├── 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 +├── package.json / vite.config.ts # Adapter, PWA, paths.relative: false └── 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 +- 🟢 *Node.js 20+* (recommandé : 22+) +- 🖼️ *ImageMagick* (`convert`) — optimisation des images au prebuild +- 🌐 Pour le développement : un accès réseau aux instances (les données sont fetchées au build) -.Installation de l'extension `intl` +.Installation d'ImageMagick [source,bash] ---- # Ubuntu / Debian -sudo apt-get install php-intl +sudo apt-get install imagemagick # 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 +sudo dnf install ImageMagick ---- -=== 🚀 Installation +=== 🚀 Installation et développement -. 📥 Clonez le dépôt : +. 📥 Clonez le dépôt et basculez sur la branche : + [source,bash] ---- git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git cd annu-kute-ced +git checkout svelte ---- -. 📦 Vérifiez les prérequis PHP (voir ci-dessus). -. 🔧 Créez votre configuration locale et les fichiers d'instance : +. 📦 Installez les dépendances : + [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 +npm ci ---- -. 🛡️ Installez la configuration serveur sécurisée depuis `conf/` (voir <>). -. ✍️ 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. +. 🔧 Lancez le serveur de développement : ++ +[source,bash] +---- +npm run dev +---- +. 🏗️ Buildez le site statique : ++ +[source,bash] +---- +npm run build # prebuild (images) → prerender (données) → postbuild (CSP) +npm run preview # vérification locale du build +---- + +Le dossier `build/` contient le site complet, prêt à déposer sur n'importe quel hébergement statique. + +✅ *Vérifications qualité* : `npm run check` (svelte-check, 0 erreur / 0 warning exigé). + +🔄 *Rafraîchissement du contenu* : les données étant bakées au build, un nouveau build est nécessaire pour afficher les dernières vidéos/épisodes/posts — voir `docs/DEPLOIEMENT-SVELTEKIT.md` pour un exemple de cron + rsync. [[fr-configuration]] === ⚙️ Configuration -==== Le système en trois fichiers +Toute la configuration d'instance vit dans *un seul fichier* : `src/lib/config.ts` (versionné). C'est l'équivalent des anciennes constantes PHP — modifiez-le puis rebuildez. -[cols="1,2,2",options="header"] +[cols="1,3",options="header"] |=== -| Fichier | Rôle | Versionné ? +| Export | Rôle -| `includes/config.php` -| Bootstrap : charge les autres fichiers et contient toutes les fonctions métier -| ✅ Oui +| `site` +| Nom, domaine (`baseUrl`), description, e-mail de contact, URLs licence/source, fuseau par défaut -| `includes/config.default.php` -| Valeurs par défaut de chaque constante (définies seulement si absentes) -| ✅ Oui +| `legal` +| Coordonnées des mentions légales (webmaster, hébergeur o2Switch) -| `includes/config.local.php` -| Vos surcharges locales — *prioritaires* car chargées en premier -| ❌ Non (`.gitignore`) +| `peertube` +| URL de l'instance, chaîne, compte live, durée max des shorts, volumes par section, tag « indépendance » + +| `hero` +| Bannière d'accueil : `type` (`'live'`, `'video'`, `'playlist'`, `'none'`), vidéo/playlist associée + +| `castopod` +| Activation, instance, slug(s) de podcast, nombre d'épisodes + +| `funkwhale` +| Activation, instance MIZIK, nombre de morceaux (pool de 50, sélection aléatoire) + +| `mastodon` +| Instance, compte, nombre de posts de la timeline + +| `social` +| URLs des réseaux sociaux du header/footer (vide = icône masquée) + +| `donations` +| Activation, URLs LiberaPay/Ko-fi, liens Stripe (ponctuels/mensuels), montants, devise + +| `nextLive` +| Annonce du prochain live : activation, titre, description, date, image, 5 fuseaux horaires + +| `categories` / `categoryNames` / `categoryIcons` +| Catégories prioritaires (ordre d'affichage), noms FR/EN, pictos du sprite + +| `importantTags` / `popularTags` +| Hashtags de la sidebar/footer et de l'accueil + +| `about` +| Bloc « À propos » : activation, titre, deux paragraphes, image + légende (masqué tant que `enabled: false`) + +| `countdown` +| *Verrou maintenance* : quand `enabled: true`, tout le site buildé affiche le compte à rebours multi-fuseaux + date cible |=== -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é. - -[source,bash] ----- -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`. - -.Application et organisation -[cols="2,2,3",options="header"] -|=== -| Constante | Défaut | Description - -| `APP_HOST_NAME` -| `'annukuteced.buzz'` -| Nom de domaine affiché (mentions légales…) - -| `ORGANIZATION_SHORT_NAME` -| `'ANNU KUTE CED'` -| Nom court de l'organisation - -| `ORGANIZATION_NAME` -| `'ANNU KUTE CED'` -| Nom complet de l'organisation -|=== - -.PeerTube -[cols="2,2,3",options="header"] -|=== -| Constante | Défaut | Description - -| `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 - -| `HERO_TYPE` -| `'live'` -| `'live'` · `'video'` · `'playlist'` · `'none'` - -| `LIVE_ACCOUNT_NAME` -| `'annu_kute_ced'` -| Compte PeerTube surveillé pour les directs (hero + page `/direct`) - -| `HERO_VIDEO_ID` -| `'1aJ2u9euwF9fWKQhFxwFio'` -| UUID de la vidéo (mode `video`), extrait de l'URL `/w/` - -| `HERO_VIDEO_TITLE` -| `'Vidéo de présentation'` -| Titre (accessibilité) - -| `PLAYLIST_PLATFORM` -| `'peertube'` -| `'peertube'` · `'funkwhale'` · `'castopod'` - -| `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 -|=== - -.Pagination et volumes d'affichage -[cols="2,2,3",options="header"] -|=== -| Constante | Défaut | Description - -| `VIDEOS_PER_PAGE` -| `12` -| Vidéos par page (recherche) - -| `COUNT_VIDEO_SEARCH` -| `20` -| Résultats récupérés par recherche - -| `RECENT_VIDEOS_COUNT` / `TRENDING_VIDEOS_COUNT` / `CATEGORY_VIDEOS_COUNT` -| `6` -| Taille des sections d'accueil - -| `SHORTS_COUNT` / `SHORTS_COUNT_SEARCH` -| `6` / `100` -| Shorts affichés / pool de recherche - -| `LOAD_MORE_COUNT` -| `6` -| Vidéos chargées par clic sur « Voir plus » - -| `FEATURED_VIDEOS_COUNT` / `INDEPENDENCE_VIDEOS_COUNT` -| `6` -| Réservés (sections non affichées actuellement) -|=== - -.Cache -[cols="2,2,3",options="header"] -|=== -| Constante | Défaut | Description - -| `CACHE_ENABLED` -| `false` -| Active le cache pour *Castopod et Funkwhale* (fortement recommandé) - -| `CACHE_DURATION` -| `3600` -| 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/`. - -.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 ») - -| `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` - -[source,php] ----- -`, 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) +- *En-tête global* (`static/_headers` pour Cloudflare Pages, `static/.htaccess` pour Apache/o2switch) : `style-src`, `img-src`, `font-src 'self'`, `connect-src 'self'`, `media-src`, `frame-src https://gade.o-k-i.net`, `frame-ancestors 'none'`, `base-uri 'self'`, `form-action 'self'`, `object-src 'none'`. Seules origines externes : les instances de l'écosystème. +- *`script-src` par page* : `scripts/postbuild-csp.mjs` calcule les empreintes SHA-256 des scripts inline de chaque page (script de démarrage SvelteKit + JSON-LD) et les injecte dans une balise `` complète. Aucun `'unsafe-inline'` pour les scripts. +- Anti-FOUC, redirection de langue et enregistrement du SW en *fichiers externes* (`theme.js`, `registerSW.js`) : aucun script inline non hashé. -==== Configuration serveur (Apache) +==== Redirections des anciennes URLs (Apache) -[source,bash] ----- -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) - -[source,bash] ----- -# 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. +Le `.htaccess` redirige les URLs historiques PHP : `index.php` → `/`, `video.php?uuid=X` → `/video/X/`, `categories.php?id=N` → `/categories/N/`, `recherche.php?q=…` → `/recherche/?q=…`, `direct.php` → `/direct/`, `dons.php` → `/dons/`, `mentions-legales.php` → `/mentions-legales/`. Il force aussi HTTPS, sert `404.html` et met en cache immutable `/_app/` et `/fonts/`. === 📱 Progressive Web App (PWA) -==== 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 +- 📲 *Installation native* : bouton « Installer » dans le header (événement `beforeinstallprompt`) +- 🌐 *Mode hors ligne* : précache du shell (Workbox `generateSW`), `navigateFallback` vers `/offline/` - 📡 *Détection de connexion* : indicateur visuel en cas de perte réseau -- 🔄 *Mise à jour* : proposition de rechargement quand une nouvelle version est détectée +- 🔄 *Mise à jour* : `autoUpdate` + `skipWaiting` (mise à jour silencieuse au prochain chargement) +- L'enregistrement du SW se fait par le fichier statique `registerSW.js` (chemins absolus), jamais par injection du plugin -==== Stratégies de cache du Service Worker (`sw.js`) +NOTE : Les flux audio/vidéo des instances ne sont *pas* interceptés par le SW (requêtes `Range`) — seuls le shell et les assets locaux sont précachés. -[cols="1,2,3",options="header"] -|=== -| Type de requête | Stratégie | Détail +=== 🚀 Déploiement -| 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 +Voir le guide complet : *`docs/DEPLOIEMENT-SVELTEKIT.md`*. -| Pages (`/`, `*.php`…) -| *Network First* -| Réseau d'abord, cache en secours hors ligne - -| API et AJAX (`/ajax/`, `mastodon-config.php`…) -| *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 » - -[[fr-analytics]] -=== 📊 Analytics (Plausible) - -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*. - -Pour l'activer : - -. Ouvrez `index.php` et *décommentez* le snippet Plausible (balise `