Files
lidify/docs/HANDOFF_BUGS.md
T
Kevin O'Neill f8b464feec v1.0.2: Mood mix optimizations and media player improvements
- Fixed player seek flicker on podcasts (30s skip buttons)
- Added dual-layer seek lock mechanism to prevent stale time updates
- Optimized cached podcast seeking (direct seek before reload fallback)
- Large skips now execute immediately for responsive feel
- Mood mix performance optimizations
2025-12-26 13:06:17 -06:00

187 lines
7.7 KiB
Markdown

# Lidify Bug Handoff Guide
**Date:** 2025-12-26
**Project:** Lidify Music Server
---
## Overview
This document provides context for continuing work on several bugs in the Lidify application. The previous agent made partial fixes but issues remain.
---
## Bug 1: Mood Mixer - Multiple Issues
### Current State
- **Generation is slow** - Takes too long to generate mood mixes
- **UI not updating** - The playlist card on home page doesn't refresh when generating new mood mixes
- **Stale playlist persists** - User created "Happy" mix first, then replaced it 3 times with other emotions, but the original "Happy" card still shows on the home page even though the actual music changes
### Root Cause Analysis Needed
1. **Slow generation**: Check `backend/src/services/programmaticPlaylists.ts` - the `generateMoodOnDemand()` function (line ~3104) may be doing expensive database queries
2. **UI not updating**: The frontend uses React Query. Check:
- `frontend/components/MoodMixer.tsx` - dispatches `window.dispatchEvent(new CustomEvent("mix-generated"))` and `"mixes-updated"` events
- The home page component needs to listen for these events and invalidate/refetch
3. **Stale card**: The mix ID or cache key may not be changing. Look at:
- How mood mix preferences are saved: `POST /mixes/mood/save-preferences`
- How the home page fetches the mix to display
### Files to Investigate
- `backend/src/services/programmaticPlaylists.ts` - Main playlist generation logic
- `backend/src/routes/mixes.ts` - API endpoints for mood mixes
- `frontend/components/MoodMixer.tsx` - UI component
- `frontend/app/page.tsx` - Home page that displays mix cards
- `frontend/hooks/useQueries.ts` - React Query hooks
### Previous Fix Attempt
The previous agent added fallback logic in `generateMoodOnDemand()` (lines 3126-3183) to handle cases where enhanced audio analysis isn't available. The fix converts ML mood params to basic audio features as a fallback. This may have introduced complexity or bugs.
### Suggested Approach
1. **Check database indexes** - The query in `generateMoodOnDemand` filters by `analysisStatus`, `analysisMode`, and various audio features. Ensure proper indexes exist.
2. **Simplify the query** - Consider limiting the initial pool of tracks rather than applying all filters at once
3. **Fix cache invalidation** - The home page likely caches the mix data. Need to ensure proper invalidation when a new mix is generated
4. **User said "might need complete overhaul"** - Consider refactoring the mood mixer to be simpler
---
## Bug 2: Podcast Seeking - Still Broken
### Current Symptoms
1. **Slow press required** - User has to slowly press ±30s buttons, otherwise nothing happens
2. **Spam causes stuck state** - If user presses button rapidly, playback gets stuck in "perpetual play state" where fast forward/rewind stops working entirely
### Root Cause
The podcast seeking logic is complex and involves:
1. Checking cache status via API
2. Reloading the Howler audio engine
3. Seeking to position after reload
4. Multiple timeout-based checks
### Previous Fix Attempts
The previous agent added:
1. **Seek operation ID tracking** (`seekOperationIdRef`) to abort stale seeks
2. **Debouncing** (150ms) for podcast seeks via `seekDebounceRef`
3. **Better cleanup** of listeners and timeouts
These fixes were incomplete or introduced new issues.
### Files to Investigate
- `frontend/components/player/HowlerAudioElement.tsx` - Main seek handling logic (lines 672-853)
- The seek handler is in `useEffect` starting around line 672
- Uses `seekDebounceRef` and `pendingSeekTimeRef` for debouncing
- Uses `seekOperationIdRef` to track/abort stale operations
- `frontend/lib/howler-engine.ts` - Low-level audio engine wrapper
- `reload()` method (line ~293) - calls cleanup then load
- `cleanup()` method (line ~438) - handles Howl instance teardown
- The `cleanup()` has a delayed unload for playing audio which may cause race conditions
### Key Code Sections
**HowlerAudioElement.tsx - Seek Handler (lines 672-853):**
```typescript
useEffect(() => {
const handleSeek = async (time: number) => {
seekOperationIdRef.current += 1;
const thisSeekId = seekOperationIdRef.current;
// For podcasts: debounce, check cache, reload if cached, etc.
// Complex async logic with multiple timeouts
};
const unsubscribe = audioSeekEmitter.subscribe(handleSeek);
return unsubscribe;
}, [...deps]);
```
**howler-engine.ts - Cleanup (lines ~438-480):**
```typescript
private cleanup(): void {
// Has delayed unload when wasPlaying (12ms fade + timeout)
// This may race with new loads
}
```
### Suggested Approach
1. **Remove or increase debounce** - 150ms might be too short or the logic is wrong
2. **Fix the stuck state** - Likely caused by event listeners not being properly cleaned up
3. **Simplify the reload logic** - The cache check → reload → seek → play chain is fragile
4. **Consider immediate cleanup** - Skip the fade delay for podcast seeks to prevent race conditions
5. **Add loading/disabled state** - Disable seek buttons while a seek is in progress
---
## Bug 3: Similar Artists ("Fans Also Like") - Partially Fixed
### Current State
The previous agent made fixes to show library artists in the "Fans Also Like" section. The fix:
- Checks if similar artists exist in the user's library
- Returns `inLibrary` flag and `ownedAlbumCount`
- Shows a library badge icon
### Files Modified
- `backend/src/routes/library.ts` - Enhanced similar artists response (lines 1369-1533)
- `frontend/features/artist/types.ts` - Added `inLibrary?: boolean` to SimilarArtist type
- `frontend/features/artist/components/SimilarArtists.tsx` - Updated UI and navigation logic
### Status
Believed to be working but needs verification.
---
## Development Environment
### Key Commands
```bash
# Backend
cd backend
npm run dev # Dev server with hot reload
npm run build # Production build
npx tsc --noEmit # Type check only
# Frontend
cd frontend
npm run dev # Dev server
npm run build # Production build
```
### Architecture
- **Backend**: Express.js + Prisma + PostgreSQL + Redis
- **Frontend**: Next.js 14 (App Router) + React Query + TailwindCSS
- **Audio**: Howler.js for playback
- **Analysis**: Essentia Docker container for audio feature extraction
### Database
- **Prisma** ORM with PostgreSQL
- Key models: Track, Album, Artist, User
- Tracks have `analysisStatus` and `analysisMode` fields for audio analysis state
---
## Priority Order
1. **Podcast seeking** - Most user-facing, core functionality broken
2. **Mood mixer UI not updating** - Confusing UX
3. **Mood mixer slow** - Performance issue
---
## Quick Reference - Key Files
| Feature | Backend | Frontend |
|---------|---------|----------|
| Mood Mixer | `services/programmaticPlaylists.ts`, `routes/mixes.ts` | `components/MoodMixer.tsx`, `app/page.tsx` |
| Podcast Seek | `routes/podcasts.ts` | `components/player/HowlerAudioElement.tsx`, `lib/howler-engine.ts` |
| Similar Artists | `routes/library.ts` (lines 1369-1533) | `features/artist/components/SimilarArtists.tsx` |
---
## Notes from Previous Agent
1. The mood mixer presets all use ML mood params (`moodHappy`, `moodSad`, etc.) which require `analysisMode: "enhanced"`. A fallback to basic audio features was added but may be causing issues.
2. The podcast seek debounce was added at 150ms with a `pendingSeekTimeRef` to coalesce rapid seeks. This approach may be flawed.
3. The Howler engine's `cleanup()` method has an intentional 12ms fade delay before unloading to reduce audio pops. This delay may cause race conditions with rapid reloads.
4. The `seekOperationIdRef` counter was intended to abort stale seek operations but the logic may have bugs in how it's checked across async boundaries.