Porte la section Funkwhale (MIZIK) et corrige la CSP par page

- src/lib/server/funkwhale.ts : 50 morceaux aléatoires de mizik.o-k-i.net,
  filtre local, mapping vers le lecteur audio intégré (10 affichés)
- Section « Morceaux » sur l'accueil entre podcast et timeline, FR/EN
- Bus audio partagé (audio-bus.svelte.ts) : un seul flux à la fois entre
  le lecteur podcast et le lecteur musique
- Lecteur audio : méta générique (artiste — album) pour les morceaux
- CSP : mizik.o-k-i.net ajouté à img-src/media-src
- Fix critique : la balise meta CSP embarque désormais la politique complète
  (lue depuis _headers) — default-src 'self' seul bloquait par intersection
  les images et médias des instances ; frame-ancestors retiré de la meta
  (ignoré hors en-tête)
This commit is contained in:
sucupira
2026-07-23 01:19:22 -04:00
parent 28c2334927
commit ffe7f12fb9
11 changed files with 156 additions and 11 deletions
+16 -4
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { claimAudio, releaseAudio } from '$lib/audio-bus.svelte';
import { formatDate, formatDuration, t as format, type Bundle } from '$lib/i18n';
import type { Episode, Locale } from '$lib/types';
import Icon from './Icon.svelte';
@@ -7,11 +8,13 @@
let {
episodes,
locale,
t
t,
playTemplate = undefined
}: {
episodes: Episode[];
locale: Locale;
t: Bundle;
playTemplate?: string;
} = $props();
let audio: HTMLAudioElement;
@@ -56,6 +59,7 @@
if (index < 0 || index >= episodes.length) return;
currentIndex = index;
const episode = episodes[index];
claimAudio(audio);
audio.src = episode.audioUrl;
audio.play();
updateMediaSession(episode);
@@ -72,6 +76,7 @@
}
function onEnded() {
releaseAudio(audio);
if (currentIndex + 1 < episodes.length) {
playAt(currentIndex + 1);
} else {
@@ -90,7 +95,10 @@
bind:this={audio}
preload="none"
onplay={() => (playing = true)}
onpause={() => (playing = false)}
onpause={() => {
playing = false;
releaseAudio(audio);
}}
onended={onEnded}
ontimeupdate={() => (currentTime = audio.currentTime)}
ondurationchange={() => (duration = audio.duration)}
@@ -119,7 +127,11 @@
</a>
</h3>
<p class="episode-meta text-muted">
{format(t.podcast.episodeFrom, { date: formatDate(episode.date, locale) })}
{#if episode.date}
{format(t.podcast.episodeFrom, { date: formatDate(episode.date, locale) })}
{:else}
{episode.podcast}{#if episode.description}{episode.description}{/if}
{/if}
{#if episode.duration > 0}· {formatDuration(episode.duration)}{/if}
</p>
</div>
@@ -128,7 +140,7 @@
onclick={() => toggle(i)}
aria-label={currentIndex === i && playing
? t.podcast.pause
: format(t.podcast.play, { title: episode.title })}
: format(playTemplate ?? t.podcast.play, { title: episode.title })}
>
<Icon name={currentIndex === i && playing ? 'pause' : 'play'} />
</button>