- Split ci.yml into two workflows for cleaner PR checks
- ci.yml: runs build-and-test on PRs and pushes (no Docker)
- docker.yml: runs build-and-test + Docker build/push on merges, tags, and manual triggers
- Eliminates 'docker: skipping' status on open PRs
- Add 15 unit tests covering authentication, download logic, and configuration
- Test IsAvailableAsync with various credential combinations
- Test download flow for unsupported providers, existing files, and missing songs
- Test album background download functionality
- Test quality format configuration (FLAC, MP3, default)
- All tests passing (127 total tests)
- Extract SubsonicRequestParser for HTTP parameter extraction
- Extract SubsonicResponseBuilder for XML/JSON response formatting
- Extract SubsonicModelMapper for search result parsing and merging
- Extract SubsonicProxyService for upstream Subsonic server communication
- Add comprehensive test coverage (45 tests) for all new services
- Reduce SubsonicController from 1174 to 666 lines (-43%)
All tests passing. Build succeeds with 0 errors.
Moved PathHelper from DeezerDownloadService to Services/Common/ to:
- Remove awkward dependency of Qobuz on Deezer namespace
- Make path utilities reusable by all services
- Improve code organization and clarify dependencies
Updated imports in DeezerDownloadService, QobuzDownloadService,
BaseDownloadService, and DeezerDownloadServiceTests.
- Register DeezerDownloadService and DeezerMetadataService as Singleton
to properly share state across requests (rate limiting, download tracking)
- Fix race condition in LocalLibraryService.LoadMappingsAsync with
double-check locking pattern
- Dispose HttpRequestMessage objects to prevent memory leaks (4 occurrences)
- Handle fire-and-forget TriggerLibraryScanAsync with proper error logging
- Replace Console.WriteLine with ILogger in SubsonicController
- Fix while loop in DownloadSongAsync to refresh activeDownload state
- Use modern C# range operator syntax for Substring calls
- Clean up appsettings.json template (remove private IP, clear ARL token)
- Add documentation comment for Blowfish decryption key
- Add downloads directory to gitignore
- getArtist now merges local Navidrome albums with Deezer albums
- getAlbum returns complete song metadata for Deezer albums
- Added missing fields (parent, isDir, suffix, contentType, type, isVideo, duration, genre) for Aonsoku compatibility
ASP.NET Core serializes anonymous objects with camelCase, producing
'subsonicResponse' instead of 'subsonic-response'. Fixed by using
Dictionary with explicit key names for all JSON responses.
- Remove custom /ping endpoint that returned non-standard JSON format
- Fix wildcard endpoint to return Subsonic-compatible error responses
- All requests now properly relay to/from the real Subsonic server