From 1fe68c2dac94821929dd5990002f367aa9ff899e Mon Sep 17 00:00:00 2001 From: Silberengel Date: Mon, 1 Jun 2026 20:27:52 +0200 Subject: [PATCH] kind 36787 rendering --- src/components/AudioPlayer/index.tsx | 36 ++- .../ContentPreview/MusicTrackNotePreview.tsx | 21 ++ src/components/ContentPreview/index.tsx | 15 ++ src/components/MediaGridItem/index.tsx | 11 +- src/components/Note/Highlight/index.tsx | 1 + src/components/Note/MusicTrackNote.tsx | 99 +++++++ src/components/Note/index.tsx | 5 +- src/components/WebPreview/index.tsx | 2 + src/constants.ts | 10 +- src/lib/feed-kind-filter.test.ts | 1 + src/lib/feed-kind-filter.ts | 3 +- src/lib/kind-description.ts | 2 + src/lib/music-track.test.ts | 243 ++++++++++++++++++ src/lib/music-track.ts | 119 +++++++++ src/lib/parent-reply-blurb.ts | 8 +- src/pages/secondary/NotePage/index.tsx | 4 + src/services/local-storage.service.ts | 10 +- src/services/mention-event-search.service.ts | 1 + src/services/nip89.service.ts | 1 + 19 files changed, 581 insertions(+), 11 deletions(-) create mode 100644 src/components/ContentPreview/MusicTrackNotePreview.tsx create mode 100644 src/components/Note/MusicTrackNote.tsx create mode 100644 src/lib/music-track.test.ts create mode 100644 src/lib/music-track.ts diff --git a/src/components/AudioPlayer/index.tsx b/src/components/AudioPlayer/index.tsx index 3658a1cf..d73eb9fe 100644 --- a/src/components/AudioPlayer/index.tsx +++ b/src/components/AudioPlayer/index.tsx @@ -13,12 +13,21 @@ interface AudioPlayerProps { className?: string /** Optional cover / still (e.g. NIP-53 `image` on live events). */ poster?: string + /** Tried when `src` fails to load (e.g. Primal r2a mirror for blossom URLs). */ + fallbackSrc?: string /** Fires when enough data is buffered to play (e.g. to swap out a blurhash placeholder). */ onReady?: () => void } -export default function AudioPlayer({ src, className, poster, onReady }: AudioPlayerProps) { +export default function AudioPlayer({ + src, + className, + poster, + fallbackSrc, + onReady +}: AudioPlayerProps) { const audioRef = useRef(null) + const [activeSrc, setActiveSrc] = useState(src) const [isPlaying, setIsPlaying] = useState(false) const [currentTime, setCurrentTime] = useState(0) const [duration, setDuration] = useState(0) @@ -26,6 +35,14 @@ export default function AudioPlayer({ src, className, poster, onReady }: AudioPl const seekTimeoutRef = useRef() const isSeeking = useRef(false) + useEffect(() => { + setActiveSrc(src) + setError(false) + setIsPlaying(false) + setCurrentTime(0) + setDuration(0) + }, [src, fallbackSrc]) + useEffect(() => { if (!onReady) return const audio = audioRef.current @@ -37,7 +54,7 @@ export default function AudioPlayer({ src, className, poster, onReady }: AudioPl } audio.addEventListener('canplay', notify, { once: true }) return () => audio.removeEventListener('canplay', notify) - }, [src, onReady]) + }, [activeSrc, onReady]) useEffect(() => { if (error) { @@ -122,6 +139,19 @@ export default function AudioPlayer({ src, className, poster, onReady }: AudioPl }, 300) } + const handleLoadError = () => { + const fb = fallbackSrc?.trim() + if (fb && activeSrc !== fb) { + setActiveSrc(fb) + setError(false) + setIsPlaying(false) + setCurrentTime(0) + setDuration(0) + return + } + setError(true) + } + if (error) { return } @@ -157,7 +187,7 @@ export default function AudioPlayer({ src, className, poster, onReady }: AudioPl !cover && 'max-w-md' )} > -