Compare commits
2 Commits
67c701f85a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 6262a02fec | |||
| 220d6d8f2d |
@@ -1,20 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
/dist
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
**/components/_*
|
||||
|
||||
*.config.ts
|
||||
*.config.js
|
||||
*.config.cjs
|
||||
@@ -1,43 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
// 'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
'prettier',
|
||||
],
|
||||
plugins: ['svelte3', '@typescript-eslint', 'unused-imports'],
|
||||
ignorePatterns: ['*.cjs'],
|
||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
||||
settings: {
|
||||
'svelte3/typescript': () => require('typescript'),
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
rules: {
|
||||
// '@typescript-eslint/no-inferrable-types': 'off',
|
||||
// '@typescript-eslint/no-unsafe-argument': 'off',
|
||||
// '@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'logical-assignment-operators': ['error', 'always'],
|
||||
// "no-unused-vars": "off",
|
||||
'unused-imports/no-unused-imports': 'error',
|
||||
'unused-imports/no-unused-vars': [
|
||||
'warn',
|
||||
{
|
||||
vars: 'all',
|
||||
varsIgnorePattern: '^_',
|
||||
args: 'after-used',
|
||||
argsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
/dist
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"useTabs": true,
|
||||
"tabWidth": 3,
|
||||
"trailingComma": "all",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": { "parser": "svelte" }
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
-10
@@ -1,10 +0,0 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"aaron-bond.better-comments",
|
||||
"esbenp.prettier-vscode",
|
||||
"gruntfuggly.todo-tree"
|
||||
]
|
||||
}
|
||||
Vendored
-45
@@ -1,45 +0,0 @@
|
||||
{
|
||||
"[svelte]": {
|
||||
"editor.defaultFormatter": "svelte.svelte-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnType": false,
|
||||
"files.exclude": {
|
||||
"**/.cache": true,
|
||||
"**/.DS_Store": true,
|
||||
"**/.gitattributes": true,
|
||||
"**/.svelte-kit": true,
|
||||
"**/*-lock.*": true,
|
||||
"**/*.Identifier": true,
|
||||
"**/*.map": true,
|
||||
"**/.turbo": true,
|
||||
"**/.vercel": true,
|
||||
"**/node_modules": true,
|
||||
"**/tsconfig.tsbuildinfo": true,
|
||||
"**/.npmrc": true
|
||||
},
|
||||
"files.watcherExclude": {
|
||||
"**/node_modules": true,
|
||||
"**/.svelte-kit": true
|
||||
},
|
||||
"problems.sortOrder": "severity",
|
||||
"javascript.preferences.importModuleSpecifier": "relative",
|
||||
"typescript.preferences.importModuleSpecifier": "relative",
|
||||
"todo-tree.tree.scanMode": "workspace only"
|
||||
}
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
# svelte-podcast
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 528457f: Restructures package exports
|
||||
- 528457f: - improved export structure
|
||||
- simplify audio methods
|
||||
- improve typescript types
|
||||
- bba2421: Improve example components
|
||||
- bba2421: improve progress component style overrides
|
||||
- f42a00f: removes autoplay as it doesn't behave as users would expect
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- d18b0c7: refactor audio element logic
|
||||
- 29ef657: switch to jsdoc from ts
|
||||
- d18b0c7: rewrite docs with code samples
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 16366ec: improvements to headless components
|
||||
- 415d083: switch to jsdoc from ts
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 9232f4d: Improves theming with css variables
|
||||
Improves developer logs
|
||||
Fixes various package export issues
|
||||
Adds player components:
|
||||
|
||||
- Player: `<PlayerStack />`
|
||||
- Player: `<PlayerWidget />`
|
||||
- Utility: `<HeadlessTimeline />`
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feba0d4: Improvements to audio stores:
|
||||
|
||||
- Adds missing `is_paused` value.
|
||||
- Fixes to `start_at` value
|
||||
- Refactors localStorage stores & user preferences
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ff6a6d9: refactored audio element bindings for better control over element
|
||||
|
||||
## 0.3.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ff5caf2: fix to allow override of internal types
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 802c704: fixes dist exports
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6c849b7: Fixes derived store causing exessive updates
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 02598d4: fixes exported typings
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 0b12aab: Adds mechanic for managing user preferences
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 6f89448: Adds the ability to bind episode metadata to the audio store
|
||||
- a70d68d:
|
||||
- Restructures lib to make dist cleaner and dev easier to grock
|
||||
- Refactors <audio /> bindings to make it easier to change values when loading a different source
|
||||
- Moves more values to micro-stores
|
||||
- 1841199: Adds save/load mechanic for episode progress
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 549d858: Fixes release build
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 2e6f082: Adds initial audio element abstraction with store
|
||||
@@ -4,20 +4,55 @@ 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).
|
||||
|
||||
## 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)
|
||||
|
||||
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
|
||||
// src/routes/podcast/+page.server.ts
|
||||
import { fetch_podcast_feed } from '$lib/rss';
|
||||
import type { PageLoad } from './$types';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async ({ fetch }) => ({
|
||||
// passer le `fetch` de SvelteKit : SSR, cache et hydration
|
||||
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),
|
||||
});
|
||||
```
|
||||
@@ -28,27 +63,7 @@ export const load: PageLoad = async ({ fetch }) => ({
|
||||
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).
|
||||
|
||||
## 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
|
||||
|
||||
## Développement
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
yarn dev # serveur de dev
|
||||
yarn build # build statique (adapter-static) dans build/
|
||||
yarn run check # svelte-check
|
||||
```
|
||||
Les épisodes sans enclosure audio sont ignorés.
|
||||
|
||||
## Comment ça marche
|
||||
|
||||
@@ -60,14 +75,18 @@ L'API publique de Funkwhale est utilisée côté client, sans authentification :
|
||||
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 : mode radio aléatoire / liste, suivant/précédent |
|
||||
| `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 |
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
"sync": "svelte-kit sync",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint:prettier": "prettier --check --plugin-search-dir=. .",
|
||||
"lint:eslint": "TIMING=1 eslint . --ext .ts,.tsx,.svelte --cache",
|
||||
"lint": "yarn lint:prettier && yarn lint:eslint",
|
||||
"format": "prettier --write --plugin-search-dir=. .",
|
||||
"ts": "tsc --pretty --noImplicitAny --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -31,18 +27,9 @@
|
||||
"@sveltejs/vite-plugin-svelte": "^5",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.61.0",
|
||||
"@typescript-eslint/parser": "^5.61.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"postcss": "^8.4.25",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
"prettier-plugin-tailwindcss": "^0.3.0",
|
||||
"svelte": "^5",
|
||||
"svelte-check": "^4",
|
||||
"tailwindcss": "^3.3.2",
|
||||
|
||||
Reference in New Issue
Block a user