feat(ui): add clear cache and optimize media session

- Add button in side drawer settings to clear local cache data
- Refactor Media Session position updates to trigger on specific events (seek, play/pause, load) instead of every time update
- Add finite number validation for seek operations
This commit is contained in:
史悦
2026-01-06 10:59:14 +08:00
parent b1e76110ff
commit 33e3ec714e

View File

@@ -319,7 +319,7 @@
</div> </div>
); );
const SideDrawer = ({ isOpen, onClose, view, setView, quality, setQuality }) => { const SideDrawer = ({ isOpen, onClose, view, setView, quality, setQuality, onClearCache }) => {
if (!isOpen) return null; if (!isOpen) return null;
return ( return (
@@ -355,8 +355,8 @@
<div className="mt-8 px-4 mb-2 text-xs font-bold text-gray-500 uppercase tracking-wider">设置</div> <div className="mt-8 px-4 mb-2 text-xs font-bold text-gray-500 uppercase tracking-wider">设置</div>
<div className="px-4 py-2"> <div className="px-4 py-2">
<label className="block text-sm text-gray-300 mb-2">默认播放音质</label> <label className="block text-sm text-gray-300 mb-2">默认播放音质</label>
<select <select
value={quality} value={quality}
onChange={(e) => setQuality(e.target.value)} onChange={(e) => setQuality(e.target.value)}
className="drawer-select" className="drawer-select"
> >
@@ -365,6 +365,21 @@
<option value="flac">无损 (FLAC)</option> <option value="flac">无损 (FLAC)</option>
</select> </select>
</div> </div>
<div className="px-4 py-2 mt-2">
<button
onClick={() => {
if(confirm('确定要清除所有缓存数据吗?这将重置播放列表和收藏。')) {
onClearCache();
onClose();
}
}}
className="w-full py-2 px-4 rounded-lg border border-red-500/50 text-red-500 hover:bg-red-500/10 transition-colors text-sm flex items-center justify-center gap-2"
>
<Icon name="trash-can" />
清理缓存数据
</button>
</div>
</div> </div>
<div className="p-4 border-t border-white/10 text-xs text-gray-500 text-center"> <div className="p-4 border-t border-white/10 text-xs text-gray-500 text-center">
@@ -719,17 +734,6 @@
audio.volume = volume; audio.volume = volume;
const updateTime = () => { const updateTime = () => {
setCurrentTime(audio.currentTime); 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 updateDuration = () => setDuration(audio.duration);
const onEnded = () => playNext(true); const onEnded = () => playNext(true);
@@ -878,8 +882,11 @@
}; };
const handleSeek = (time) => { const handleSeek = (time) => {
audioRef.current.currentTime = time; if (Number.isFinite(time)) {
setCurrentTime(time); audioRef.current.currentTime = time;
setCurrentTime(time);
updateMediaSessionPosition();
}
}; };
const deleteFromPlaylist = (index) => { const deleteFromPlaylist = (index) => {
@@ -915,6 +922,18 @@
// --- Media Session Integration --- // --- Media Session Integration ---
const updateMediaSessionPosition = () => {
if ('mediaSession' in navigator && audioRef.current && !isNaN(audioRef.current.duration)) {
try {
navigator.mediaSession.setPositionState({
duration: audioRef.current.duration,
playbackRate: audioRef.current.playbackRate,
position: audioRef.current.currentTime
});
} catch (e) { console.error("MediaSession Position Error:", e); }
}
};
// Update refs for Media Session actions // Update refs for Media Session actions
useEffect(() => { useEffect(() => {
playNextRef.current = playNext; playNextRef.current = playNext;
@@ -958,24 +977,34 @@
} }
}, [currentSong]); }, [currentSong]);
// Media Session Playback State // Media Session Playback State & Position
useEffect(() => { useEffect(() => {
if ('mediaSession' in navigator) { if ('mediaSession' in navigator) {
navigator.mediaSession.playbackState = isPlaying ? 'playing' : 'paused'; navigator.mediaSession.playbackState = isPlaying ? 'playing' : 'paused';
updateMediaSessionPosition();
} }
}, [isPlaying]); }, [isPlaying]);
// Update position when song loads
useEffect(() => {
const audio = audioRef.current;
const onLoadedMetadata = () => updateMediaSessionPosition();
audio.addEventListener('loadedmetadata', onLoadedMetadata);
return () => audio.removeEventListener('loadedmetadata', onLoadedMetadata);
}, []);
// --- Render --- // --- Render ---
return ( return (
<div className="flex flex-col h-full bg-darker font-sans"> <div className="flex flex-col h-full bg-darker font-sans">
<SideDrawer <SideDrawer
isOpen={showSideDrawer} isOpen={showSideDrawer}
onClose={() => setShowSideDrawer(false)} onClose={() => setShowSideDrawer(false)}
view={view} view={view}
setView={setView} setView={setView}
quality={quality} quality={quality}
setQuality={setQuality} setQuality={setQuality}
onClearCache={handleClearCache}
/> />
{/* Top Navigation / Search Bar */} {/* Top Navigation / Search Bar */}