fix vibe engine audit findings: pg.Pool, plan replan, dead exclusions, legacy engine removal
Backend: - app.ts: switch shared pg.Client to pg.Pool with per-transaction clients (#205) - v2.routes.ts: replace plan instead of appending on replan, fixing self-duplication (#206) - session-director: populate recentExclusions, per-candidate ranking, batch repetition checks (#209/#211/#213/#215 + minor) - db.service.ts: claim-fusion watermark, legacy recommendation_batch engine removed (#216/#219/#232) - app.ts: drop test enqueue-job endpoint (#234) Frontend: - AudioEngine/Vibe/usePlaybackStore: dedupe completed feedback, gate feedback to vibe sessions, End Vibe stops playback, Keep toast, shuffle played-set (#207/#236/#237/#238/#239/#240) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,8 @@ interface PlaybackState {
|
||||
volume: number;
|
||||
shuffle: boolean;
|
||||
repeat: RepeatMode;
|
||||
/** Ids already played this shuffle "lap" (repeat-all), to avoid bouncing between the same few tracks. */
|
||||
shufflePlayed: Set<string>;
|
||||
|
||||
setQueue: (queue: Track[]) => void;
|
||||
playTrack: (track: Track) => void;
|
||||
@@ -36,8 +38,9 @@ export const usePlaybackStore = create<PlaybackState>((set, get) => ({
|
||||
volume: 1,
|
||||
shuffle: false,
|
||||
repeat: 'none',
|
||||
shufflePlayed: new Set<string>(),
|
||||
|
||||
setQueue: (queue) => set({ queue }),
|
||||
setQueue: (queue) => set({ queue, shufflePlayed: new Set() }),
|
||||
|
||||
playTrack: (track) =>
|
||||
set({
|
||||
@@ -45,13 +48,14 @@ export const usePlaybackStore = create<PlaybackState>((set, get) => ({
|
||||
isPlaying: true,
|
||||
position: 0,
|
||||
duration: track.duration ?? 0,
|
||||
shufflePlayed: new Set(),
|
||||
}),
|
||||
|
||||
play: () => set({ isPlaying: true }),
|
||||
pause: () => set({ isPlaying: false }),
|
||||
|
||||
next: () => {
|
||||
const { queue, currentTrack, shuffle, repeat } = get();
|
||||
const { queue, currentTrack, shuffle, repeat, shufflePlayed } = get();
|
||||
if (queue.length === 0) return;
|
||||
|
||||
const idx = currentTrack ? queue.findIndex((t) => t.id === currentTrack.id) : -1;
|
||||
@@ -63,17 +67,22 @@ export const usePlaybackStore = create<PlaybackState>((set, get) => ({
|
||||
}
|
||||
|
||||
if (shuffle) {
|
||||
// Shuffle: pick a random track from the remaining queue (excluding current)
|
||||
const remaining = queue.filter((t) => t.id !== currentTrack?.id);
|
||||
// Shuffle: pick a random track not yet played this lap (excludes current),
|
||||
// so repeat-all doesn't bounce between the same few tracks.
|
||||
const played = new Set(shufflePlayed);
|
||||
if (currentTrack) played.add(currentTrack.id);
|
||||
let remaining = queue.filter((t) => !played.has(t.id));
|
||||
if (remaining.length === 0) {
|
||||
if (repeat === 'all') {
|
||||
const pick = queue[Math.floor(Math.random() * queue.length)];
|
||||
set({ currentTrack: pick, position: 0, duration: pick.duration ?? 0, isPlaying: true });
|
||||
}
|
||||
return;
|
||||
if (repeat !== 'all') return;
|
||||
// Lap complete — start a fresh one.
|
||||
played.clear();
|
||||
if (currentTrack) played.add(currentTrack.id);
|
||||
remaining = queue.filter((t) => t.id !== currentTrack?.id);
|
||||
if (remaining.length === 0) return;
|
||||
}
|
||||
const pick = remaining[Math.floor(Math.random() * remaining.length)];
|
||||
set({ currentTrack: pick, position: 0, duration: pick.duration ?? 0, isPlaying: true });
|
||||
played.add(pick.id);
|
||||
set({ currentTrack: pick, shufflePlayed: played, position: 0, duration: pick.duration ?? 0, isPlaying: true });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user