Removed the buffer.Length() check that was causing intermittent test failures.
The background goroutine started by newBufferedScrobbler can process and
dequeue scrobble entries before the test assertion runs, leading to a race
condition where the observed length is 0 instead of 1. The Eventually block
that follows already verifies the scrobble was processed correctly.
Signed-off-by: Deluan <deluan@navidrome.org>
Added a loadEnvVars parameter to InitConfig to control whether environment
variables should be loaded via viper.AutomaticEnv(). In tests, environment
variables (like ND_MUSICFOLDER) were overriding values from config test files,
causing tests to fail when these variables were set in the developer's
environment. Now tests can pass loadEnvVars=false to isolate from the
environment while production code continues to use loadEnvVars=true.
Signed-off-by: Deluan <deluan@navidrome.org>
Previously, the insights collector would only try to get an admin user once
at startup. If no admin user existed (e.g., fresh database before first user
registration), insights collection would silently fail forever.
This change moves the admin context creation inside the collection loop so it
retries on each interval. It also updates log messages in WithAdminUser to
remove the Scanner prefix since this function is now used by other components.
Signed-off-by: Deluan <deluan@navidrome.org>
Added TLS certificate validation that detects encrypted (password-protected)
private keys and provides a clear error message with instructions on how to
decrypt them using openssl. This addresses user confusion when Go's standard
library fails with the cryptic 'tls: failed to parse private key' error.
Changes:
- Added validateTLSCertificates function to validate certs before server start
- Added isEncryptedPEM helper to detect both PKCS#8 and legacy encrypted keys
- Added comprehensive tests for TLS validation including encrypted key detection
- Added integration test that starts server with TLS and verifies HTTPS works
- Added test certificates (valid for 100 years) with SAN for localhost
Signed-off-by: Deluan <deluan@navidrome.org>
Avoid UNIQUE constraint conflicts on library.name and library.path when
running tests in parallel. Both playlist_repository_test.go and
tag_library_filtering_test.go now generate timestamp-based unique
suffixes for library names and paths to ensure test isolation.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix low contrast in "delete missing files" button
* make login screen a bit nicer
* style modal similar to rest of ui
* Add custom styles for Ra Pagination
* Refactor styles in amusic.js
Removed albumSubtitle color and updated styles for albumPlayButton and albumArtistName
* Add NDDeleteLibraryButton and NDDeleteUserButton styles
low contrast
* low contrast text on delete buttons
* playbutton color back to pink without background
Smart playlists were including tracks from all libraries regardless of the
user's library access permissions. This resulted in ghost tracks that users
could not see or play, while the playlist showed incorrect song counts.
Added applyLibraryFilter to the refreshSmartPlaylist function to ensure only
tracks from libraries the user has access to are included when populating
smart playlist tracks. Added regression test to verify the fix.
Closes#4738
Added a new DevOptimizeDB configuration flag (default true) that controls
whether SQLite PRAGMA OPTIMIZE and ANALYZE commands are executed. This allows
disabling database optimization operations for debugging or testing purposes.
The flag guards optimization commands in:
- db/db.go: Initial connection, post-migration, and shutdown optimization
- persistence/library_repository.go: Post-scan optimization
- db/migrations/migration.go: ANALYZE during forced full rescans
Set ND_DEVOPTIMIZEDB=false to disable all database optimization commands.
* feat(model): add Rated At field - #4653
Signed-off-by: zacaj <zacaj@zacaj.com>
* fix(ui): ignore empty dates in rating/love tooltips - #4653
* refactor(ui): add isDateSet util function
Signed-off-by: zacaj <zacaj@zacaj.com>
* feat: add tests for isDateSet and rated_at sort mappings
Added comprehensive tests for isDateSet and urlValidate functions in
ui/src/utils/validations.test.js covering falsy values, Go zero date handling,
valid date strings, Date objects, and edge cases.
Added rated_at sort mapping to album, artist, and mediafile repositories,
following the same pattern as starred_at (sorting by rating first, then by
timestamp). This enables proper sorting by rating date in the UI.
---------
Signed-off-by: zacaj <zacaj@zacaj.com>
Co-authored-by: zacaj <zacaj@zacaj.com>
Co-authored-by: Deluan <deluan@navidrome.org>
Add integration tests verifying the workaround for checking if a tag has any
value in smart playlists. The tests confirm that using 'contains' with an empty
string generates SQL that matches any non-empty tag value (value LIKE '%%'),
which is the recommended workaround for issue #4728.
Tests added:
- Verify contains with empty string matches tracks with tag values
- Verify notContains with empty string excludes tracks with tag values
Also updated test context to use GinkgoT().Context() instead of context.TODO().
* feat: Add SquiddiesGlass Theme
* feat: fix commnets by gemini-code-assist in PR
* feat: fix Prettier format
* feat: fix play button, and text mobile
* feat: fix play button, and text mobile, prettier
* feat: fix chip, title artist
* fix: loading albbun, play button color
* prettier
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Xavier Araque <francisco.araque@toolfactory.net>
Co-authored-by: Deluan <deluan@navidrome.org>
* first show at AMuisc Theme
* prettier
* fix Duplicate key 'MuiButton'
* fix file name
* Update amusic.js
* Add styles for NDAlbumGridView in amusic.js
* Fix MuiToolbar background property in amusic.js
* Fix syntax error in amusic.js background property
* run prettier
* fix banded table styling and more
* more styling to player
- fix some appearances of green in queue
- match queue styling to rest of theme
- round albumart in player and prevent rotation
* fix queue panel background and border
to make it stand out more against the background
* fix stray comma
and lint+prettier
* queue hover still green
and player preview image not rounded properly
* Update amusic.css.js
* more mobile color fixes
* artist page
* prettier
* rounded art in albumgridview
* small tweaks to colors and radiuses
* artist and album heading
* external links colors
* unify font colors + albumgrid corner radius
* get rid of queue hover green
* unify colors in player
same red shades as primary
* mobile player floating panel background shade of green
* unify border colors
and attempt to get album cover corner radius working
* final touches
* Update amusic.css.js
* fix invisible button color fir muibutton
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* fix css syntax on player queue color overrides
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* remove unused MuiTableHead
* sort theme list in index.js alphabetically
* remove unused properties
* Revert "fix css syntax on player queue color overrides"
This reverts commit 503bba321d958aed5251667c58214822ceb70f59.
---------
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
The CacheWarmer was failing with data not found errors because PreCache was being called inside the database transaction before the data was committed. The CacheWarmer runs in a separate goroutine with its own database context and could not access the uncommitted data due to transaction isolation.
Changed the persistChanges method in phase_1_folders.go to collect artwork IDs during the transaction and only call PreCache after the transaction successfully commits. This ensures the artwork data is visible to the CacheWarmer when it attempts to retrieve and cache the images.
The fix eliminates the data not found errors and allows the cache warmer to properly pre-cache album and artist artwork during library scanning.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(deezer): add functions to fetch related artists, biographies, and top tracks for an artist
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(deezer): add language support for Deezer API client
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(deezer): Use GraphQL API for translated biographies
The previous implementation scraped the __DZR_APP_STATE__ from HTML,
which only contained English content. The actual biography displayed
on Deezer's website comes from their GraphQL API at pipe.deezer.com,
which properly respects the Accept-Language header and returns
translated content.
This change:
- Switches from HTML scraping to the GraphQL API
- Uses Accept-Language header instead of URL path for language
- Updates tests to match the new implementation
- Removes unused HTML fixture file
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(deezer): move JWT token handling to a separate file for better organization
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(deezer): enhance JWT token handling with expiration validation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(deezer): change log level for unknown agent warnings from Warn to Debug
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(deezer): reduce JWT token expiration buffer from 10 minutes to 1 minute
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
In `getAffectedAlbumIDs`, when one or more IDs is added, it adds a filter `"id": ids`.
This filter is ambiguous though, because the `getAll` query joins with library table, which _also_ has an `id` field.
Clarify this by adding the table name to the filter.
Note that this was not caught in testing, as it only uses mock db.
Collapse resolveRelativePath and resolveAbsolutePath into a unified
resolvePath function, extracting common library matching logic into a
new findInLibraries helper method.
This eliminates duplicate code (~20 lines) while maintaining clear
separation of concerns: resolvePath handles path normalization
(relative vs absolute), and findInLibraries handles library matching.
Update tests to call resolvePath directly with appropriate parameters,
maintaining full test coverage for both absolute and relative path
scenarios.
Signed-off-by: Deluan <deluan@navidrome.org>
Remove validatePathInLibrary function and its fallback logic in
resolveRelativePath. The library matcher should always find the correct
library, including the playlist's own library. If this fails, we now
return an invalid resolution instead of attempting a fallback validation.
This simplifies the code by removing redundant validation logic that
was masking test setup issues. Also fixes test mock configuration to
properly set up library paths that match folder LibraryPath values.
Playlists can now reference songs in other libraries using relative paths.
Previously, relative paths like '../Songs/abc.mp3' would not resolve correctly
when pointing to files in a different library than the playlist file.
The fix resolves relative paths to absolute paths first, then checks which
library they belong to using the library regex. This allows playlists to
reference files across library boundaries while maintaining backward
compatibility with existing single-library relative paths.
Fixes#4617
* fix: validate library selection state for single-library users
Fixes issues where users with a single library see no content when
selectedLibraries in localStorage contains library IDs they no longer
have access to (e.g., after removing libraries or switching accounts).
Changes:
- libraryReducer: Validate selectedLibraries when SET_USER_LIBRARIES
is dispatched, filtering out invalid IDs and resetting to empty for
single-library users (empty means 'all accessible libraries')
- wrapperDataProvider: Add defensive validation in getSelectedLibraries
to check against current user libraries before applying filters
- Add comprehensive test coverage for reducer validation logic
Fixes#4553, #4508, #4569
* style: format code with prettier