docs: README à jour (stack, fonctionnalités mobile/PWA, exemple RSS en +page.server.ts)
This commit is contained in:
@@ -4,42 +4,31 @@ Lecteur audio web pour la radio **Radyobòkaz**, hébergée sur l'instance Funkw
|
||||
[mizik.o-k-i.net](https://mizik.o-k-i.net/library/radios/7) (~2000 titres).
|
||||
|
||||
Construit sur une version modifiée de [svelte-podcast](https://github.com/OllieJT/svelte-podcast)
|
||||
(librairie headless de lecteur audio, voir `src/lib`).
|
||||
(librairie headless de lecteur audio, voir `src/lib`). Dépôt de travail :
|
||||
[labola.o-k-i.net/cyber-mawonaj/oki-podcast-reader](https://labola.o-k-i.net/cyber-mawonaj/oki-podcast-reader).
|
||||
|
||||
## Utilitaires RSS (SSR)
|
||||
## Stack
|
||||
|
||||
La librairie inclut des utilitaires pour consommer des flux RSS de podcasts,
|
||||
compatibles SSR (pas de `DOMParser`, parsing via `fast-xml-parser`) :
|
||||
|
||||
```ts
|
||||
// src/routes/podcast/+page.ts
|
||||
import { fetch_podcast_feed } from '$lib/rss';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ fetch }) => ({
|
||||
// passer le `fetch` de SvelteKit : SSR, cache et hydration
|
||||
feed: await fetch_podcast_feed('https://feed.syntax.fm/rss', fetch),
|
||||
});
|
||||
```
|
||||
|
||||
- `fetch_podcast_feed(url, fetcher?)` — télécharge et parse un flux (RSS 2.0 + tags iTunes)
|
||||
- `parse_podcast_feed(xml)` — parse une chaîne XML déjà récupérée
|
||||
- Types exportés : `PodcastFeed`, `PodcastEpisode` (titre, guid, date ISO, durée en
|
||||
secondes, enclosure, pochette, numéros d'épisode/saison, explicit…)
|
||||
|
||||
Les durées `itunes:duration` sont acceptées aux formats `3723`, `62:03` et `1:02:03`.
|
||||
Les épisodes sans enclosure audio sont ignorés. Voir la route `/podcast` pour un
|
||||
exemple complet (flux chargé côté serveur, épisodes joués dans le lecteur).
|
||||
- **SvelteKit 2 + Svelte 5** (mode compatibilité : syntaxe `on:click`/`$:`/`export let` conservée) + TypeScript
|
||||
- **Tailwind CSS 3** — aucune autre dépendance UI
|
||||
- **adapter-static** — pré-rendu statique dans `build/`
|
||||
- Audio : `<audio>` natif unique (aucune lib tierce), stores Svelte legacy
|
||||
- Flux RSS : parsing maison via `fast-xml-parser` (compatible SSR, pas de `DOMParser`)
|
||||
|
||||
## Fonctionnalités
|
||||
|
||||
- 📻 **Mode radio aléatoire** : file de lecture infinie de titres piochés au hasard
|
||||
- 🎵 **Écoute à la carte** : liste complète des titres avec recherche (titre, artiste, album)
|
||||
- 🎙️ **Flux RSS de podcasts** : parsing SSR + lecture des épisodes (démo sur `/podcast`)
|
||||
- ⏭️ Passage automatique au titre suivant en fin de piste
|
||||
- 🎛️ Contrôles : lecture/pause, précédent/suivant, volume, mute, seek
|
||||
- 🖼️ Pochette, titre, artiste et album du morceau en cours
|
||||
- 🔃 L'audio continue de jouer lors de la navigation entre pages
|
||||
- 📻 **Mode radio aléatoire** : file de lecture infinie de titres piochés au hasard
|
||||
- 🎵 **Écoute à la carte** : liste complète des titres avec recherche (titre, artiste, album)
|
||||
- 🎙️ **Flux RSS de podcasts** : parsing côté serveur + lecture des épisodes (démo Syntax.fm sur `/podcast`)
|
||||
- ⏭️ Passage automatique au titre suivant en fin de piste
|
||||
- 🎛️ Contrôles : lecture/pause, précédent/suivant, volume persisté (masqué sur iOS, où `volume` est en lecture seule), mute persistant, seek
|
||||
- 📱 **Mobile** : cibles tactiles ≥ 48 px, barre de progression avec zone tactile de 44 px (tap + scrub au doigt), listes paginées 50×50
|
||||
- 🔒 **Media Session API** : titre/artiste/pochette + contrôles depuis l'écran de verrouillage
|
||||
- 📲 **PWA installable** : manifest, service worker (shell + pochettes en cache, streams audio exclus)
|
||||
- 🖼️ Pochette, titre, artiste et album du morceau en cours
|
||||
- 🔃 L'audio continue de jouer lors de la navigation entre pages
|
||||
- ⚠️ Message d'erreur + bouton Réessayer si l'API est indisponible
|
||||
- 💾 Préférences (volume, vitesse, mute) et progression persistées en localStorage (bornées à 200 entrées)
|
||||
|
||||
## Développement
|
||||
|
||||
@@ -47,27 +36,57 @@ exemple complet (flux chargé côté serveur, épisodes joués dans le lecteur).
|
||||
yarn install
|
||||
yarn dev # serveur de dev
|
||||
yarn build # build statique (adapter-static) dans build/
|
||||
yarn run check # svelte-check
|
||||
yarn preview # prévisualiser le build
|
||||
yarn run check # types + accessibilité (svelte-check)
|
||||
```
|
||||
|
||||
Note : la page `/podcast/` fetch son flux au build (pré-rendu côté serveur) —
|
||||
un build hors-ligne la fait échouer ; c'est attendu.
|
||||
|
||||
## Utilitaires RSS (SSR)
|
||||
|
||||
```ts
|
||||
// src/routes/podcast/+page.server.ts
|
||||
import { fetch_podcast_feed } from '$lib/rss';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ fetch }) => ({
|
||||
// le fetch reste côté serveur : le XML n'est jamais inliné dans le HTML
|
||||
// et la navigation client n'a pas de problème CORS
|
||||
feed: await fetch_podcast_feed('https://feed.syntax.fm/rss', fetch),
|
||||
});
|
||||
```
|
||||
|
||||
- `fetch_podcast_feed(url, fetcher?)` — télécharge et parse un flux (RSS 2.0 + tags iTunes)
|
||||
- `parse_podcast_feed(xml)` — parse une chaîne XML déjà récupérée
|
||||
- Types exportés : `PodcastFeed`, `PodcastEpisode` (titre, guid, date ISO, durée en
|
||||
secondes, enclosure, pochette, numéros d'épisode/saison, explicit…)
|
||||
|
||||
Les durées `itunes:duration` sont acceptées aux formats `3723`, `62:03` et `1:02:03`.
|
||||
Les épisodes sans enclosure audio sont ignorés.
|
||||
|
||||
## Comment ça marche
|
||||
|
||||
L'API publique de Funkwhale est utilisée côté client, sans authentification :
|
||||
|
||||
- `GET /api/v1/radios/radios/7/tracks/?page=N&page_size=50` — liste des titres de la radio
|
||||
- `GET /api/v1/listen/<uuid>/` — flux audio du titre (CORS ouvert, supporte `Range`)
|
||||
- `GET /api/v1/radios/radios/7/tracks/?page=N&page_size=50` — liste des titres de la radio
|
||||
- `GET /api/v1/listen/<uuid>/` — flux audio du titre (CORS ouvert, supporte `Range`)
|
||||
|
||||
Structure du code :
|
||||
|
||||
| Fichier | Rôle |
|
||||
| ------------------------------- | ----------------------------------------------------------------- |
|
||||
| `src/lib/` | Librairie svelte-podcast (store audio, composants headless) |
|
||||
| `src/lib/rss.ts` | Utilitaires SSR pour flux RSS de podcasts (parse + fetch) |
|
||||
| `src/radio/funkwhale.ts` | Client de l'API Funkwhale |
|
||||
| `src/radio/playable.ts` | Type `PlayableTrack` (titre jouable, quelle que soit la source) |
|
||||
| `src/radio/radio-store.ts` | File de lecture : mode radio aléatoire / liste, suivant/précédent |
|
||||
| `src/radio/library-store.ts` | Chargement progressif de la liste complète des titres |
|
||||
| `src/radio/radio-player.svelte` | Barre de lecture (pochette, contrôles, progression) |
|
||||
| `src/radio/track-list.svelte` | Liste des titres avec recherche |
|
||||
| `src/routes/+page.svelte` | Page radio Radyobòkaz |
|
||||
| `src/routes/podcast/` | Démo des utilitaires RSS (flux chargé en SSR, épisodes jouables) |
|
||||
| Fichier | Rôle |
|
||||
| --- | --- |
|
||||
| `src/lib/` | Librairie svelte-podcast (store audio, composants headless) |
|
||||
| `src/lib/rss.ts` | Utilitaires SSR pour flux RSS de podcasts (parse + fetch) |
|
||||
| `src/lib/volume-support.ts` | `can_set_volume()` — détection iOS par capacité |
|
||||
| `src/lib/Seo.svelte`, `src/lib/site.js` | Meta SEO (canonical, OG, Twitter) + URL du site |
|
||||
| `src/radio/funkwhale.ts` | Client de l'API Funkwhale |
|
||||
| `src/radio/playable.ts` | Type `PlayableTrack` (titre jouable, quelle que soit la source) |
|
||||
| `src/radio/radio-store.ts` | File de lecture : radio aléatoire / liste, erreurs, Media Session |
|
||||
| `src/radio/library-store.ts` | Chargement progressif de la liste complète des titres |
|
||||
| `src/radio/radio-player.svelte` | Barre de lecture (pochette, contrôles, progression) |
|
||||
| `src/radio/track-list.svelte` | Liste des titres avec recherche |
|
||||
| `src/routes/+page.svelte` | Page radio Radyobòkaz |
|
||||
| `src/routes/podcast/` | Démo des utilitaires RSS (flux chargé en SSR, épisodes jouables) |
|
||||
| `src/service-worker.js` | PWA : shell + pochettes en cache, streams audio exclus |
|
||||
| `static/` | Icônes PWA, manifest.webmanifest, robots.txt |
|
||||
|
||||
Reference in New Issue
Block a user