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>
);
const SideDrawer = ({ isOpen, onClose, view, setView, quality, setQuality }) => {
const SideDrawer = ({ isOpen, onClose, view, setView, quality, setQuality, onClearCache }) => {
if (!isOpen) return null;
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="px-4 py-2">
<label className="block text-sm text-gray-300 mb-2">默认播放音质</label>
<select
value={quality}
<select
value={quality}
onChange={(e) => setQuality(e.target.value)}
className="drawer-select"
>
@@ -365,6 +365,21 @@
<option value="flac">无损 (FLAC)</option>
</select>
</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 className="p-4 border-t border-white/10 text-xs text-gray-500 text-center">
@@ -719,17 +734,6 @@
audio.volume = volume;
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);
@@ -878,8 +882,11 @@
};
const handleSeek = (time) => {
audioRef.current.currentTime = time;
setCurrentTime(time);
if (Number.isFinite(time)) {
audioRef.current.currentTime = time;
setCurrentTime(time);
updateMediaSessionPosition();
}
};
const deleteFromPlaylist = (index) => {
@@ -915,6 +922,18 @@
// --- 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
useEffect(() => {
playNextRef.current = playNext;
@@ -958,24 +977,34 @@
}
}, [currentSong]);
// Media Session Playback State
// Media Session Playback State & Position
useEffect(() => {
if ('mediaSession' in navigator) {
navigator.mediaSession.playbackState = isPlaying ? 'playing' : 'paused';
updateMediaSessionPosition();
}
}, [isPlaying]);
// Update position when song loads
useEffect(() => {
const audio = audioRef.current;
const onLoadedMetadata = () => updateMediaSessionPosition();
audio.addEventListener('loadedmetadata', onLoadedMetadata);
return () => audio.removeEventListener('loadedmetadata', onLoadedMetadata);
}, []);
// --- Render ---
return (
<div className="flex flex-col h-full bg-darker font-sans">
<SideDrawer
isOpen={showSideDrawer}
<SideDrawer
isOpen={showSideDrawer}
onClose={() => setShowSideDrawer(false)}
view={view}
setView={setView}
quality={quality}
setQuality={setQuality}
onClearCache={handleClearCache}
/>
{/* Top Navigation / Search Bar */}