Files
oki-podcast-reader/README.md
T

93 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Radyobòkaz Player
Lecteur audio web pour la radio **Radyobòkaz**, hébergée sur l'instance Funkwhale
[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`). 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).
## Stack
- **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 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
```bash
yarn install
yarn dev # serveur de dev
yarn build # build statique (adapter-static) dans build/
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`)
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/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 |