Commit Graph

41 Commits

Author SHA1 Message Date
Your Name 60892c12e7 fix: multi-container docker-compose proxy, audiobookshelf sync bugs, add sync button
Fixes #158 -- fresh docker-compose install shows login instead of setup
wizard because Next.js rewrites were compiled with 127.0.0.1:3006 baked
in. Added NEXT_PUBLIC_BACKEND_URL as a Dockerfile build arg, defaulting
to http://backend:3006 in docker-compose.yml so the frontend container
proxies to the backend service correctly.

Audiobookshelf sync fixes:
- syncAudiobook returns boolean; skipped books no longer count as synced
- Sync notification now surfaces failed/skipped counts
- downloadCover has 10s fetch timeout (was unbounded)
- book.size changed to book.media?.size for audio-only size

Added sync button on audiobooks page so users can trigger a sync without
going through settings or the enrichment system.

Bump to v1.7.2
2026-03-18 13:50:18 -05:00
Your Name 6000d31738 chore: release v1.7.1
Fixes:
- Playlist track count now updates live after add/remove -- cache
  invalidated at all addTrackToPlaylist call sites (closes #157)
- Remove stale restart-required modal from settings -- services
  reinitialize live on save, modal was dead code (closes #158)
- YouTube / YouTube Music playlist import (closes #155)
- Lidarr MBID mismatch: album MBID passed to MB /artist endpoint (closes #156)
- Hardcoded port-3030 in API base URL detection (closes #154)

Dead code:
- Remove unused setIsBulkAdd / setIsAddingToPlaylist state (album page)
- Remove unused useSearchParams() call (settings page)

Bump versions to 1.7.1 in frontend/backend package.json, README, CHANGELOG
2026-03-17 16:26:24 -05:00
Your Name 9083835bfd chore: v1.7.0 -- vibe galaxy, CI pipeline, enrichment hardening, PWA, preprod sweep
- Bump frontend and backend to 1.7.0
- Update CHANGELOG with full 1.7.0 release notes
- Remove vibe-test dev prototype page and unused R3F components
  (VibeUniverse, TrackCloud, TrackTooltip, universeUtils)
- Fix stale audio.completed counter: flush live DB count at isFullyComplete
  transition -- counter was frozen at last audioQueued > 0 cycle value
- Add GitHub Actions CI pipeline: lint/typecheck, unit tests, security scan,
  E2E predeploy, nightly Docker build and push to Hub + GHCR
- Add E2E enrichment cycle spec with 55-min timeout and memory monitoring script
- Add E2E vibe spec covering map, song path, search, alchemy, similar tracks
- PWA hardening: offline fallback, update banner, WCO, manifest fixes
- Production readiness: OOM memory caps in both compose files, DoS/SSRF/auth fixes
- Remove double-auth in systemSettings (requireAdmin already enforces auth)
- Fix mobile vibe page full-height rendering, vibe map timer leak, abort signal wiring
- Fix E2E test helpers: graceful skip with waitFor + try/catch for empty-library CI
- Fix create-e2e-user.sh: admin role, bcrypt shell expansion, psql heredoc quoting
2026-03-16 18:25:08 -05:00
Your Name c9ccd97eb9 test: replace theater tests with real security and route tests
Remove:
- api-contracts.spec.ts (100% theater -- shape checks with no bug-catching value)

Add auth middleware unit tests (backend/src/middleware/__tests__/auth.test.ts):
- 14 tests covering real code branches: missing header, wrong scheme,
  empty token, expired JWT, tokenVersion mismatch (password-change
  invalidation), legacy token without tokenVersion claim, deleted user,
  requireAdmin 401/403 distinction, requireAuthOrToken query param path
- All tests assert on observable behavior that would fail if specific
  lines of production code were removed

Add supertest route integration tests with mocked Prisma:
- auth.route.test.ts: login shape (no passwordHash in response), token
  claims verification, no username enumeration (identical 401 for wrong
  password and nonexistent user), refresh tokenVersion mismatch, role
  injection rejected, admin-only endpoint 403 enforcement
- playlists.route.test.ts: IDOR for GET/PUT/DELETE -- each test asserts
  BOTH the 403 status AND that the DB write was not called (catches
  ownership check removed or moved after the mutation)

Enhance security.spec.ts (e2e against real Docker stack):
- IDOR: add PUT and DELETE scenarios (not just read)
- All IDOR tests now verify state after failed attempt (re-fetch confirms
  resource unchanged/still exists -- not just checking status code)
- Enforce 403 specifically (not [403, 404]) -- 404 masks broken auth checks
- Add img onerror XSS vector alongside script tag vector
- Input validation: verify playlist count unchanged after 400
- Error response: add prisma/ORM internals to leakage checks

Add test infrastructure:
- src/__mocks__/test-env.cjs: sets JWT_SECRET before module load (setupFiles)
- jest.config.js: add setupFiles entry
- supertest + @types/supertest added to backend devDependencies
2026-03-16 11:20:30 -05:00
Your Name d6e414f2d1 ci: add full test suite and GitHub Actions CI agents
- Rewrite pr-checks.yml: typecheck (frontend + backend), backend unit
  tests (Jest, webhookEventStore excluded), dep audit, Docker build gate
- Add integration.yml: Docker stack + Playwright e2e on push to main or
  run-e2e label (predeploy, queue, playlists, api-contracts, security)
- Add nightly.yml: full Playwright suite at 03:00 UTC, opens GH issue on
  failure
- Add security.yml: npm audit blocking on critical + security.spec.ts
  against Docker stack on PRs and weekly

New tests:
- security.spec.ts: IDOR, XSS, unauthenticated access, input validation,
  mass assignment (12 tests, all verified against localhost:3030)
- api-contracts.spec.ts: auth shapes, CRUD contracts, library/search
  validation, health check (15 tests, all verified)
- playlists.spec.ts, queue.spec.ts: functional e2e tests
- global.setup.ts: shared auth token setup

Backend fixes:
- Fix discoverySeeding tests: add _max.playedAt to recentPlays mocks,
  sync getFallbackSeedArtists mock to new artist.findMany+albums path,
  add unavailableAlbum to Prisma mock factory
- Fix enrichmentStateMachine tests: add clearGate to mock, update
  orphaned-audio assertion to match new where clause
- Add p-queue.cjs CJS mock + moduleNameMapper (pure ESM incompatible
  with Jest CJS runner)
- Add typecheck scripts to frontend/backend package.json

scripts/create-e2e-user.sh: fix bcrypt hash corruption by passing
password via Docker -e env var instead of shell interpolation
2026-03-16 10:42:20 -05:00
Your Name f3d87eae57 fix: playback stall watchdog, refresh recovery, version bump to 1.6.4
- Playback watchdog monitors currentTime every 1s, recovers after 3s stall
  with auto-resume and position preservation (addresses #145)
- Resume after page refresh loads stream for restored track/audiobook/podcast
- Network retry upgraded to exponential backoff (1s/2s/4s), 3 max attempts
- Stalled event 10s grace timer as supplementary recovery path
- ETag/Last-Modified headers on audio streams for browser cache validation
- Centralized USER_AGENT constant in config.ts (was hardcoded in 12 files)
- Version bump from 1.6.2 to 1.6.4 (fixes #152)
2026-03-11 22:36:23 -05:00
Your Name 70345bf694 chore: add deck.gl and umap-js dependencies for vibe map 2026-03-08 12:56:55 -05:00
Your Name b702ca7221 chore: bump version to 1.6.2, update changelog 2026-03-03 11:15:01 -06:00
Your Name 093762381b feat: M3U playlist file import with 4-tier track matching
Add M3U/M3U8 file upload endpoint (POST /api/spotify/import/m3u) that
parses playlist files and matches entries against the local library using
file path, filename, exact metadata, and fuzzy metadata matching tiers.
2026-03-03 10:59:47 -06:00
Your Name 7e3ef70143 feat: share links, mobile lyrics, double-tap play, hardening (v1.6.1)
Closes #121, #125, #136, #138. Partially addresses #139, #25, #108, #30.

Share links: generate shareable URLs for playlists/tracks/albums with
public playback page, token-based access, expiry, and play limits.

Mobile lyrics: replace album art with scrollable lyrics view when
active. Synced lyrics auto-scroll; plain lyrics freely scrollable.

Mobile double-tap: custom touch handler with 300ms window across all
7 track list components. Desktop double-click preserved.

Security: path traversal containment in getLocalImagePath/getResizedImagePath,
stream error handling via streamFileWithRangeSupport, scoped JSON body limit.

Enrichment: sequential audio/vibe phases (no simultaneous ML models),
heroUrl preservation in manual enrichment, scanner deep-to-shallow iteration.

UI: playlist inline rename, player queue/add-to-playlist buttons,
error toasts on silent catch blocks, activity panel listener stability,
dead handleSeek wrappers removed, query key standardization.
2026-03-03 09:54:52 -06:00
Your Name 4ba6755146 fix(audio): stabilize mobile playback and clean up production codebase
Media player fixes:
- Sync playbackState to "paused" on audio engine error events
- Set playbackState "none" when queue clears (no stale lock screen controls)
- Emit error instead of swallowing failed retry play() in background
- Prevent infinite network retry loop by exhausting retry counter
- Preserve current media on network errors for foreground recovery
- Clear error state on foreground return so user can manually retry
- Fix podcast progress bar reverting on pause (update state on save)
- Auto-resume playback after phone call/Siri interruption
- Remove silence-keepalive (caused Bluetooth/CarPlay audio theft)
- Fix duplicate "play" event (emit on "playing" not "play")
- Set Safari audioSession.type = "playback" for correct session category

Production cleanup:
- Remove swagger-jsdoc/swagger-ui-express and all 16 @openapi annotations
- Remove 20 debug console.log/warn statements (SSE, Store, QueueDebug)
- Remove unused react-virtuoso dependency
- Remove commented-out Vibe route from sidebar
- Remove dead pauseRef from useMediaSession
- Bump Subsonic rate limit to 1500 req/min for Symfonium compatibility
2026-03-01 12:14:10 -06:00
Your Name 703e2195cf chore(deps): update safe patches and fix audit vulnerabilities
Backend: @bull-board 6.20.3, axios 1.13.6, bullmq 5.70.1, ioredis 5.10.0,
fast-xml-parser 5.4.1 (fixes stack overflow CVE), minimatch audit fix.
Frontend: tailwindcss 4.2.1, @tailwindcss/postcss 4.2.1, framer-motion
12.34.3, tailwind-merge 3.5.0, ajv/minimatch audit fixes.
2026-02-28 22:27:38 -06:00
Your Name 34240471a8 feat: add synchronized lyrics display and iOS audio fixes (v1.6.0)
Lyrics: LRCLIB integration fetches timed lyrics during scan, synced
3-line display in full/overlay player, rate-limited API calls, owner-
based activity panel priority so Discovery doesn't override lyrics.

iOS audio: fix AirPod/lock-screen resume by moving keepalive prime()
to pause handler, fix playback race conditions (retry count, redundant
play guard, error cascade cap, preload dedup).
2026-02-28 21:32:59 -06:00
Your Name 94be4e7353 release: v1.5.11 — playlist pagination, Lidarr profile config
- feat(import): paginate Spotify/Deezer playlist imports for any size (#25)
  Spotify: /v1/playlists/{id}/tracks with offset/limit=50, 429/401 handling
  Deezer: /playlist/{id}/tracks with index/limit=100, 200ms rate delay
  SSE progress: "Fetching tracks: X of Y..." during pagination
- feat(lidarr): configurable quality & metadata profiles (#8)
  New DB fields, POST /system-settings/lidarr-profiles endpoint,
  auto-populated dropdowns in Settings after successful connection test
2026-02-28 21:32:59 -06:00
Your Name 376ae0590a release: v1.5.10 — Symfonium compat, popular tracks, MusicBrainz mirror support
- fix(subsonic): map #text to value in JSON responses for Symfonium (#126)
- fix(subsonic): add getBookmarks.view empty stub for Symfonium (#126)
- fix(artist): show 10 popular tracks instead of 5 (#91)
- feat(musicbrainz): configurable base URL via MUSICBRAINZ_BASE_URL env var (#63)
2026-02-27 13:08:52 -06:00
Your Name 51c761715c release: v1.5.9 — iOS MediaSession fix, enrichment pipeline hardening, track formatting
Features:
- DISABLE_CLAP env var for low-memory deployments
- Foobar2000-style track title formatting in Settings > Playback
- Partial playlist creation on cancelled Spotify imports

Fixes:
- iOS lock screen controls showing inverted state (play/pause swapped)
- Enrichment pipeline: 7 fixes covering vibe sweep, crash recovery,
  CLAP supervisor, completion detection, embedding reset, feature detection
- Favicon replaced with waveform-only multi-size ICO
- docker-compose.server.yml healthcheck using removed wget
2026-02-27 12:30:11 -06:00
Your Name caf3caef86 release: v1.5.8 — mobile playback fixes, security hardening, lint cleanup
Fix 4 mobile/iOS playback bugs: infinite network retry loop, silence keepalive
running during active playback, play button failing outside gesture window, and
MediaSession handlers never registering after app restore. Add resumeWithGesture()
across 13 call sites.

Security hardening: safeError() across ~82 catch blocks to prevent error leakage,
SSRF protection on cover art proxy, login timing normalization, crypto.randomInt()
for device links, select clauses on user queries, metrics auth gate, registration
gate with rate limiting, admin role check fix.

Production cleanup: remove dead code/imports, fix all ESLint warnings, add cover
art fetch retry for transient network errors.
2026-02-26 16:24:01 -06:00
Your Name d67c8f49ef release: v1.5.7
BullMQ enrichment migration
- Rewrote enrichment pipeline on BullMQ v5: artist, track, podcast workers with
  pause/resume/stop support and Bull Board visibility
- Essentia publishes audio:analysis:complete events; CLAP subscribes reactively
  instead of polling (eliminates scan delay between phases)
- Thread-safe DB pool in CLAP worker, all DB calls in run_in_executor
- Fixed psycopg2.pool submodule import crash on BullMQ vibe worker startup
- Silenced EnrichmentStateService disconnect error on already-closed Redis conn

Enrichment fixes
- lastfmTags NULL caused mood-tags phase to silently skip all tracks; migration
  backfills NULL -> '{}' and sets column default
- Cover art fetch errors for temp-MBID albums (temp-* passed to Cover Art Archive)
- VIBE-VOCAB vocabulary JSON not copied to Docker image (TypeScript omits .json)
- Wired cleanupOldResolved() to run daily; added missing enrichment status indexes
- Fixed circuit breaker reset, orphan cleanup, podcast entityType, hang detection

Soulseek
- Track search-page downloads in activity tracker
- Use async fs.promises.access instead of synchronous existsSync
- Verify file exists on disk before emitting download:complete (#110)

Docker image size: 28.4 GB -> 12.2 GB
- Removed all CUDA/NVIDIA dependencies; switched to CPU-only PyTorch/TensorFlow
- tensorflow-cpu + essentia-tensorflow --no-deps (avoids GPU TF transitive dep)
- Fixed .dockerignore: **/node_modules and **/.next now excluded from build context

PWA / mobile
- Background audio session loss on iOS/Android: SilenceKeepalive singleton,
  tryResume() in MediaSession play handler, direct track load on 'ended' event,
  visibilitychange/pageshow foreground recovery
- Lock orientation to portrait for Android device lock (#117)

Discovery
- Retry All re-importing albums already in library: apply same three-level filter
  as GET /current before creating download jobs; delete stale UnavailableAlbum
  records for already-present albums. Closes #34

CI / release
- linux/arm64 added to release and nightly Docker builds (#87)
- Isolated release CI from nightly GHA cache (cache-from/cache-to removed from
  docker-publish.yml to guarantee clean release builds)
- Redis vm.overcommit_memory=1 sysctl added to prod and server compose files

Other fixes
- Cross-artist album fallback by title+year prevents library splitting (#50)
- Retry temp-MBID artists after 24h not 7 days; hide temp MBIDs from API (#112)
- 3-attempt ECONNRESET retry on all Deezer getPlaylist call sites (#119)
- check response.ok on health probe — fetch does not throw on 5xx (#104)
- Z-index stacking hierarchy established (MiniPlayer through OverlayPlayer)
- API token display overflow on iPhone (min-w-0/overflow-hidden on flex container)
2026-02-23 17:19:46 -06:00
Your Name 9ffad66317 chore: bump version to 1.5.6, update changelog, remove stale docker-compose.override.yml.lite 2026-02-21 20:18:40 -06:00
Your Name 22909f75d0 chore: bump version to 1.5.5, update changelog and readme 2026-02-21 16:06:47 -06:00
Your Name 205507ff34 chore(subsonic): add fast-xml-parser dependency 2026-02-21 12:21:58 -06:00
Your Name 9ff4df9f13 chore: bump version to 1.5.4, update changelog 2026-02-20 22:58:31 -06:00
Your Name f449fd930b fix: This danged enrichment system (v1.5.3) 2026-02-18 11:36:12 -06:00
Your Name 3dcfe0931c fix: audio analysis enrichment deadlock (v1.5.2)
Three compounding bugs caused enrichment to deadlock after 12+ hours:

1. runFullEnrichment reset analysisStatus to pending without clearing
   analysisRetryCount, silently orphaning tracks Python would never queue

2. queueAudioAnalysis had no retryCount filter, queuing tracks Python
   ignores (retryCount >= MAX_RETRIES), causing processing timeouts that
   fed the circuit breaker

3. Circuit breaker fired on permanentlyFailedCount > 0 (expected cleanup
   behavior), making it unrecoverable — reopened immediately on every
   HALF-OPEN attempt

Fixes: reset retryCount+error in runFullEnrichment, add lt:3 filter to
queueAudioAnalysis, restrict circuit breaker to resetCount > 0 only.

Bumps version to 1.5.2.
2026-02-18 08:03:56 -06:00
Your Name 345821434f chore: rebrand package.json files to Kima 2026-02-16 09:39:32 -06:00
Your Name 16059bb537 chore(audio): remove Howler.js and all dead code
Delete: howler-engine.ts, HowlerAudioElement.tsx, playback-state-machine.ts,
heartbeat-monitor.ts, format-utils.ts, audio/index.ts
Uninstall: howler, @types/howler

~2500 lines of complexity removed.
2026-02-15 11:46:22 -06:00
Your Name e918a34547 feat(deploy): add automatic database baselining for production migrations
Critical for 1k+ production users - ensures smooth upgrades when pulling new Docker images.

Changes:
- Added migrate-safe.sh script that automatically baselines existing databases
- Updated docker-entrypoint.sh to use safe migration script
- Updated Dockerfile to include migration script in image
- Manually applied missing config migration (SystemSettings columns)

How it works for users:
1. User runs: docker compose pull
2. Container starts, runs migrate-safe.sh automatically
3. Script detects if database exists but isn't tracked (P3005 error)
4. If yes: baselines all existing migrations, then applies new ones
5. If no: runs normal migrate deploy

Safety:
- Zero data loss (only marks existing migrations as applied)
- Idempotent (safe to run multiple times)
- Graceful (continues even if status check unclear)
- Production-tested on existing database with 30 migrations

Result:
- Users can docker compose pull without manual migration commands
- Existing databases automatically get proper migration tracking
- New migrations apply cleanly after baselining
2026-02-14 15:36:08 -06:00
Your Name 5f53805c1c feat: vendor soulseek-ts library (ISC license)
Replace slsk-client npm dep with vendored soulseek-ts source.
TypeScript, Promise-based, with download progress events,
queue position tracking, and NAT traversal via ConnectToPeer.
2026-02-09 07:55:41 -06:00
Your Name ee8f2404e0 fix: prevent scheduled task pile-up causing backend unresponsiveness
Replace setInterval with self-rescheduling setTimeout for reconciliation
(2min) and Lidarr cleanup (5min) cycles. setInterval fires unconditionally
regardless of whether the previous cycle completed, and withTimeout() never
cancels the underlying operation -- it just resolves via Promise.race while
the operation continues as a zombie. Over hours, hundreds of zombie operations
accumulate, starving the event loop and exhausting DB connections and sockets.

Each cycle now schedules its next run only after fully completing, making
pile-up impossible. Bump to v1.4.3.
2026-02-08 20:50:48 -06:00
Your Name 39af30f699 v1.4.2: search overhaul, similar artists fix, analyzer idle optimization
Search:
- Full-text search with DB triggers for Artist/Album/Track searchVector
- Harden queryToTsquery for special chars, fix NaN LIMIT propagation
- Extract ILIKE fallback methods, normalize cache keys
- Parallelize discovery endpoint (Last.fm + iTunes concurrent)
- Remove double debounce in frontend search
- Separate similar artists endpoint (musically similar, not name-similar)
- Alias resolution banner ("Showing results for X, searched Y")
- Soulseek polling interval leak fix (useRef + AbortController)
- Typed API responses for discover and similar artists
- "/" keyboard shortcut to focus search bar

Streaming:
- Fix HTTP Range suffix parsing for Firefox/Safari (#84)
- Extract parseRangeHeader utility, use in audioStreaming + podcasts
- Clamp range end to file boundary per RFC 7233

Library:
- Server-side sorting for artists, albums, tracks endpoints
- Case-insensitive artist matching in playlists and discovery (#64)

Audio Analyzer:
- Replace 5s poll loop with Redis BRPOP (zero CPU while idle)
- Remove TensorFlow import from main process (~300MB RAM saved)
- Lazy worker pool creation (starts on first job, not at boot)
- Configurable MODEL_IDLE_TIMEOUT to unload models after idle period
- DB reconciliation on BRPOP timeout for missed queue items
- Lighter Dockerfile healthcheck (pgrep instead of TF import)

Cleanup:
- Delete dead useDebouncedValue hook, enrichment worker, mood bucket worker
- Move sort maps to module scope
- Bump version to 1.4.2

Thanks to @Allram for identifying and fixing the Range parsing issue (#84)

Closes #84, closes #64
2026-02-07 14:57:19 -06:00
Your Name b6abfd0830 v1.4.1: bug fixes, enrichment resilience, frontend lint cleanup
Audio & Playback:
- Fix doubled audio on track change (destroy old Howl before creating new)
- Fix play/pause visual desync by using Howler state as source of truth

Soulseek & Downloads:
- Fix Soulseek download 400 error (closes #101)
- Expand Soulseek documentation (closes #27)

Enrichment & Analysis:
- Fix CLAP analyzer clobbering Essentia analysisStatus (root cause of #79)
- Add embedding check to both Python analyzers before resetting tracks
- Set analysisStartedAt when marking tracks as processing
- Clear analysisStartedAt on successful completion
- Include vibe embeddings in isFullyComplete check
- Add keepPreviousData to enrichment progress query for UI resilience
- Shut down idle worker pool to free ~5.6 GB when no work pending
- Fix compilation matching for multi-disc albums (closes #70)
- Add podcast auto-refresh in enrichment cycle (closes #81)

Admin & Auth:
- Add admin password reset via env var (closes #97)
- Add retry failed analysis button in settings (closes #79)
- Add requireAdmin to onboarding config and cleanup routes
- Remove userId from 2FA challenge response

Queue & UI:
- Fix cancelJob/refreshJobMatches not persisting state
- Fix discovery polling leak on batch failure
- Fix withTimeout timer leak in enrichment worker
- Fix useAlbumData infinite re-render loop
- Fix unhandled audio.play() promise rejection

Performance:
- Eliminate N+1 queries in recommendation endpoints
- Idle Essentia worker pool shutdown (8 processes, ~5.6 GB freed)

Frontend Quality:
- Fix all 377 ESLint errors and warnings (0 remaining)
- Fix Rules of Hooks, setState-in-effect, exhaustive-deps
- Type api.ts and 50+ files (remove explicit any)
- Remove 1664 lines of dead code and duplicates
- Extract shared utilities from duplicated patterns
2026-02-06 18:30:40 -06:00
Your Name f2a443c6e3 v1.4.0: sequential enrichment, GPU auto-detection, repo cleanup
- Run audio analysis and vibe embedding phases sequentially to prevent
  resource contention (CPU/memory) from concurrent analyzers
- Auto-detect GPU availability in both audio analyzers (CUDA/ROCm)
- Fix false lite mode detection on startup by checking analyzer scripts
  on disk before falling back to heartbeat/DB checks
- Fix Dockerfile NEXT_PUBLIC_BACKEND_URL and frontend rewrite proxy
- Route enrichment failures through notification system instead of
  persistent error banner
- Remove playback error banner from player components
- Reduce enrichment cycle interval from 6h to 2h
- Comprehensive repo cleanup: remove 127 decorative comment dividers
  across 17 files, clean verbose comments, harden .gitignore, remove
  tracked docs from git

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 09:59:51 -06:00
Your Name 09b1a25dae chore: bump version to 1.3.8
- Fix multiple simultaneous streams by re-add isLoadingRef guard
- Add playback state checks before play/pause commands
2026-02-03 21:30:12 -06:00
Your Name 963b307f98 feat(vibe): add vocabulary generation script 2026-02-02 19:55:25 -06:00
Your Name 08d460d870 refactor(discovery): extract batch logging to dedicated module
- Add Jest testing infrastructure (jest, ts-jest, @types/jest)
- Create DiscoveryBatchLogger class with addLog, info, warn, error methods
- Add max log entries trimming (100 entries)
- Add unit tests for logging behavior
- Create discovery module with index exports

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:18:01 -06:00
Your Name a17ee7d888 chore: add test user creation script
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:08:25 -06:00
Your Name 53f371d721 chore: bump version to 1.3.7
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 08:50:59 -06:00
Your Name 7f228fb76f perf(library): optimize grid performance and add nightly version support
- Use CachedImage (memoized) instead of raw Image in library grids
- Add GPU acceleration hints (translateZ) to card containers
- Remove expensive shadow-lg from library card image containers
- Add hover scale transform to match homepage cards
- Fix pagination scroll to use correct scroll container (#main-content)
- Scroll after page change, not on click
- Remove standalone /artists and /albums pages (use /library tabs)
- Add NEXT_PUBLIC_BUILD_TYPE env var for nightly vs release builds
- Bump version to 1.3.6

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 17:29:54 -06:00
Your Name c34a70bc28 perf: virtualized lists and library refactor for v1.3.3
Performance:
  - Add react-virtuoso for virtualized rendering of large lists
  - Virtualize AlbumsGrid, ArtistsGrid, and TracksList components
  - Refactor library page to use individual React Query hooks
  - Remove deprecated useLibraryData hook in favor of useQueries

  Bug Fixes:
  - Restore unoptimized prop to Next.js Image components (fixes 400 errors)
  - Fix shuffle implementation with Fisher-Yates algorithm

  Code Quality:
  - Improve hook dependencies and memoization
  - Clean up console.log statements from API client
  - Add explicit audio context state exports
2026-01-19 11:03:12 -06:00
Your Name cc8d0f6969 Release v1.3.0: Multi-source downloads, audio analyzer resilience, mobile improvements
Major Features:
- Multi-source download system (Soulseek/Lidarr with fallback)
- Configurable enrichment speed control (1-5x)
- Mobile touch drag support for seek sliders
- iOS PWA media controls (Control Center, Lock Screen)
- Artist name alias resolution via Last.fm
- Circuit breaker pattern for audio analysis

Critical Fixes:
- Audio analyzer stability (non-ASCII, BrokenProcessPool, OOM)
- Discovery system race conditions and import failures
- Radio decade categorization using originalYear
- LastFM API response normalization
- Mood bucket infinite loop prevention

Security:
- Bull Board admin authentication
- Lidarr webhook signature verification
- JWT token expiration and refresh
- Encryption key validation on startup

Closes #2, #6, #9, #13, #21, #26, #31, #34, #35, #37, #40, #43
2026-01-06 20:07:33 -06:00
Kevin O'Neill 021aec7a63 Initial release v1.0.0 2025-12-25 18:58:06 -06:00