mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 06:25:41 +00:00
fix: Playback stability, seek stop bug, and UI polish
- playerStore: Guard onend against spurious 'ended' events fired by WebKit/GStreamer immediately after a direct audioNode.currentTime seek. Root cause of the deterministic "second click on progress bar stops song" bug: a lastSeekAt timestamp + position check now silently drops any 'ended' event that fires within 1 s of a seek if the playhead isn't actually near the track end. - playerStore: Debounce togglePlay with a 300 ms lock to prevent rapid double-clicks from issuing pause→play before GStreamer has finished its state transition, which caused a multi-second pipeline hang. - NowPlayingDropdown: Clicking a Live entry now navigates to the album page. - QueuePanel: DnD drop target index now calculated from clientY position at drop time instead of refs, eliminating the dragend-before-drop race on macOS WKWebView and Windows WebView2. - styles: Increased Hero background blur for a more immersive look. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,9 +4,11 @@ import { getNowPlaying, SubsonicNowPlaying, buildCoverArtUrl } from '../api/subs
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { usePlayerStore } from '../store/playerStore';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export default function NowPlayingDropdown() {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [nowPlaying, setNowPlaying] = useState<SubsonicNowPlaying[]>([]);
|
||||
const isPlaying = usePlayerStore(s => s.isPlaying);
|
||||
@@ -121,7 +123,11 @@ export default function NowPlayingDropdown() {
|
||||
) : (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
|
||||
{visible.map((stream, idx) => (
|
||||
<div key={`${stream.id}-${idx}`} style={{ display: 'flex', gap: '0.75rem', alignItems: 'center', background: 'var(--bg-hover)', padding: '0.5rem', borderRadius: '8px' }}>
|
||||
<div
|
||||
key={`${stream.id}-${idx}`}
|
||||
onClick={() => { if (stream.albumId) { setIsOpen(false); navigate(`/album/${stream.albumId}`); } }}
|
||||
style={{ display: 'flex', gap: '0.75rem', alignItems: 'center', background: 'var(--bg-hover)', padding: '0.5rem', borderRadius: '8px', cursor: stream.albumId ? 'pointer' : 'default' }}
|
||||
>
|
||||
<div style={{ width: '48px', height: '48px', flexShrink: 0, borderRadius: '6px', overflow: 'hidden', background: 'var(--bg-surface)' }}>
|
||||
{stream.coverArt ? (
|
||||
<img src={buildCoverArtUrl(stream.coverArt, 100)} alt="Cover" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
|
||||
|
||||
Reference in New Issue
Block a user