From 85df3e42c187f163ec9450a70b1ea9ede3965047 Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Tue, 12 May 2026 14:22:38 +0200 Subject: [PATCH] =?UTF-8?q?refactor(player):=20E.12=20=E2=80=94=20extract?= =?UTF-8?q?=20skip-to-1=E2=98=85=20helper=20(#575)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `applySkipStarOnManualNext` — the helper that records a manual `next()` into the per-track skip counter and auto-rates the track 1★ once the configured threshold crosses — moves into `src/store/skipStarRating.ts`. File-private with one call site; no caller-side changes outside playerStore's own import. 10 focused tests pin each early-return branch (manual=false, null track, threshold not crossed, recordSkipStarManualAdvance returning null, already-rated via override / queue / passed-track) plus the happy path that calls setRating(1) + the state update for the queue, currentTrack, and override map. Promise rejections are verified to be swallowed. playerStore 3291 → 3263 LOC. --- src/store/playerStore.ts | 30 +------ src/store/skipStarRating.test.ts | 132 +++++++++++++++++++++++++++++++ src/store/skipStarRating.ts | 37 +++++++++ 3 files changed, 170 insertions(+), 29 deletions(-) create mode 100644 src/store/skipStarRating.test.ts create mode 100644 src/store/skipStarRating.ts diff --git a/src/store/playerStore.ts b/src/store/playerStore.ts index 1aa559b5..883238fb 100644 --- a/src/store/playerStore.ts +++ b/src/store/playerStore.ts @@ -74,6 +74,7 @@ import { getWaveformRefreshGen, } from './waveformRefreshGen'; import { touchHotCacheOnPlayback } from './hotCacheTouch'; +import { applySkipStarOnManualNext } from './skipStarRating'; // Re-export the playback-progress public surface so existing call sites // (PlayerBar, FullscreenPlayer, WaveformSeek, LyricsPane, MobilePlayerView, @@ -533,35 +534,6 @@ function scheduleSeekFallbackRetry(trackId: string, seconds: number) { // Guard against rapid double-click play/pause sending two state transitions // to the Rust backend before it has finished the previous one. let togglePlayLock = false; -/** - * Skip → 1★: counts in `authStore.skipStarManualSkipCountsByKey` (persisted). - * Only user-initiated `next()` increments. Natural track end (incl. gapless) clears the count; - * threshold reached clears count and sets 1★ if still unrated. - */ -function applySkipStarOnManualNext(skippedTrack: Track | null, manual: boolean): void { - if (!manual || !skippedTrack) return; - const id = skippedTrack.id; - const adv = useAuthStore.getState().recordSkipStarManualAdvance(id); - if (!adv?.crossedThreshold) return; - const live = usePlayerStore.getState(); - const fromQueue = live.queue.find(t => t.id === id); - const cur = - live.userRatingOverrides[id] ?? - fromQueue?.userRating ?? - skippedTrack.userRating ?? - 0; - if (cur >= 1) return; - setRating(id, 1) - .then(() => { - usePlayerStore.setState(s => ({ - queue: s.queue.map(t => (t.id === id ? { ...t, userRating: 1 } : t)), - currentTrack: s.currentTrack?.id === id ? { ...s.currentTrack, userRating: 1 } : s.currentTrack, - userRatingOverrides: { ...s.userRatingOverrides, [id]: 1 }, - })); - }) - .catch(() => {}); -} - // ── HTML5 Radio Player ──────────────────────────────────────────────────────── // Internet radio streams are played via a native