diff --git a/index.html b/index.html index 8fd95c2..6478b7d 100644 --- a/index.html +++ b/index.html @@ -691,6 +691,12 @@ const audioRef = useRef(new Audio()); + // Media Session Refs + const playNextRef = useRef(null); + const playPrevRef = useRef(null); + const togglePlayRef = useRef(null); + const handleSeekRef = useRef(null); + // --- Effects --- useEffect(() => { localStorage.setItem('th_playlist', JSON.stringify(playlist)); }, [playlist]); @@ -711,7 +717,20 @@ useEffect(() => { const audio = audioRef.current; audio.volume = volume; - const updateTime = () => setCurrentTime(audio.currentTime); + const updateTime = () => { + setCurrentTime(audio.currentTime); + if ('mediaSession' in navigator && !isNaN(audio.duration)) { + try { + navigator.mediaSession.setPositionState({ + duration: audio.duration, + playbackRate: audio.playbackRate, + position: audio.currentTime + }); + } catch (e) { + // Ignore errors + } + } + }; const updateDuration = () => setDuration(audio.duration); const onEnded = () => playNext(true); @@ -894,6 +913,58 @@ setMode(next); }; + // --- Media Session Integration --- + + // Update refs for Media Session actions + useEffect(() => { + playNextRef.current = playNext; + playPrevRef.current = playPrev; + togglePlayRef.current = togglePlay; + handleSeekRef.current = handleSeek; + }); + + // Media Session Actions (One-time setup) + useEffect(() => { + if (!('mediaSession' in navigator)) return; + + const actionHandlers = [ + ['play', () => togglePlayRef.current?.()], + ['pause', () => togglePlayRef.current?.()], + ['previoustrack', () => playPrevRef.current?.()], + ['nexttrack', () => playNextRef.current?.()], + ['seekto', (details) => handleSeekRef.current?.(details.seekTime)], + ]; + + for (const [action, handler] of actionHandlers) { + try { navigator.mediaSession.setActionHandler(action, handler); } catch (e) {} + } + }, []); + + // Media Session Metadata + useEffect(() => { + if (!('mediaSession' in navigator)) return; + + if (currentSong) { + navigator.mediaSession.metadata = new MediaMetadata({ + title: currentSong.name, + artist: currentSong.artist, + album: SOURCES.find(s => s.id === (currentSong.platform || currentSong.source))?.name || '', + artwork: [ + { src: api.getPicUrl(currentSong.id, currentSong.platform || currentSong.source), sizes: '512x512', type: 'image/jpeg' } + ] + }); + } else { + navigator.mediaSession.metadata = null; + } + }, [currentSong]); + + // Media Session Playback State + useEffect(() => { + if ('mediaSession' in navigator) { + navigator.mediaSession.playbackState = isPlaying ? 'playing' : 'paused'; + } + }, [isPlaying]); + // --- Render --- return (