Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL
functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and
AbsoluteURL logs the error and returns an empty string, preventing malformed
URLs from being generated.
Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put
method with a single atomic INSERT ... ON CONFLICT statement. This eliminates
potential race conditions and improves consistency with the upsert pattern
already used in host_kvstore.go.
- Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors.
- Removed redundant error checks in test data plugins for cleaner code.
- Ensured consistent error handling across all plugins to improve reliability and maintainability.
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests.
- Introduced structured request and response types for various cache operations in `nd_host_cache.go`.
- Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity.
- Removed redundant memory allocation for string parameters in favor of JSON marshaling.
- Enhanced error handling in WebSocket and cache operations to return structured error responses.
- Implemented hostgen tool to generate wrappers from annotated Go interfaces.
- Added command-line flags for input/output directories and package name.
- Introduced parsing and code generation logic for host services.
- Created test data for various service interfaces and expected generated code.
- Added documentation for host services and annotations for code generation.
- Implemented SubsonicAPI service with corresponding generated code.
* fix(ui): improve the lyric button of the AMusic theme
* fix(amusic): update styles for music player panel SVG and disabled button states
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
Fixed issue #4787 where plugin scrobblers received an empty username during NowPlaying events. The async worker was passing context.Background() which lost all user information.
Changed nowPlayingEntry to store the full context (with cancellation removed via context.WithoutCancel) and pass it to dispatchNowPlaying. This ensures plugin scrobblers can extract username from the context for authorization checks.
Updated tests to verify username is properly propagated through the async workflow, matching the actual plugin adapter behavior of checking both request.UsernameFrom and request.UserFrom.
* fix: handle cross-library relative paths in playlists
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: enhance playlist path normalization for cross-library support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: improve handling of relative paths in playlists for cross-library compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: ensure longest library path matches first to resolve prefix conflicts in playlists
Signed-off-by: Deluan <deluan@navidrome.org>
* test: refactor tests isolation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance handling of library-qualified paths and improve cross-library playlist support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify mocks
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: lint
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: improve path resolution for cross-library playlists and enhance error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove unnecessary path validation fallback
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.
* refactor: consolidate path resolution logic
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>
* docs: add FindByPaths comment
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance Unicode normalization for path comparisons in playlists. Fixes 4663
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* ci: improve docker manifest push reliability and isolation
Split Docker manifest push into separate GHCR and Docker Hub jobs to improve pipeline reliability and resilience:
- Separated push-manifest job into push-manifest-ghcr and push-manifest-dockerhub for independent execution
- Filter tags per registry using jq to prevent cross-registry push attempts
- Add automatic retry logic (3 attempts with 30s delay) for Docker Hub push using nick-fields/retry action
- Make Docker Hub job continue-on-error to prevent Docker Hub intermittent failures from failing the entire pipeline
- Add dedicated cleanup-digests job that only requires GHCR job success
- GHCR is now the critical path and will fail the pipeline if it fails, while Docker Hub failures are tolerated with retries
This addresses the recurring 400 Bad Request errors from Docker Hub registry that were causing pipeline failures even when ghcr.io push succeeded.
* fix(ci): use ghcr.io as source for docker hub manifest creation
The docker buildx imagetools create command needs to reference the source images from where they exist (ghcr.io) rather than from Docker Hub. The digests uploaded during the build step are stored on ghcr.io, so we need to pull from there and tag to Docker Hub.
* fix(ci): simplify Docker manifest push job names for clarity
* fix(ci): add permissions for Docker manifest push jobs
* fix(ci): update permissions for GHCR manifest push to write
* fix(ci): update Docker Hub image tagging in manifest creation
* fix(ci): update permissions for GHCR manifest push to read contents and write packages
* Revert "fix(ci): update Docker Hub image tagging in manifest creation"
This reverts commit b5f04d9c8b.
* feat(server): add option Lastfm.ScrobbleFirstAlbumArtistOnly to send only the first album artist
* fix: remove config parameter scrobbleFirstAlbumArtist
* test: add NowPlaying test for ScrobbleFirstArtistOnly
Add a test case for the NowPlaying function when ScrobbleFirstArtistOnly is enabled. This ensures that only the first artist from the Participants list is sent to Last.fm for both artist and album artist fields, matching the existing test coverage for the Scrobble function.
* refactor: consolidate getArtistForScrobble and getAlbumArtistForScrobble
Merge the separate getArtistForScrobble and getAlbumArtistForScrobble functions into a single parameterized function. This eliminates code duplication and makes the scrobble artist handling logic more maintainable. The function now accepts a role parameter and display name, allowing it to handle both artist and album artist extraction based on the ScrobbleFirstArtistOnly configuration.
---------
Co-authored-by: Deluan <deluan@navidrome.org>
The bulk action buttons (Make Public, Make Private, Delete) on the playlists list were displaying with poor text contrast when using dark themes like AMusic. The buttons had pinkish text (theme's primary color) on a dark red background, making them difficult to read.
This fix applies the same styling pattern used for song bulk actions by adding a makeStyles hook that sets white text color for dark themes. This ensures proper contrast between the button text and background while maintaining correct styling on light themes.
Tested on AMusic (dark) and Light themes to verify contrast improvement and backward compatibility.
Signed-off-by: Deluan <deluan@navidrome.org>
Set document.body.style.backgroundColor to match the current theme's background
color whenever the theme changes. This fixes the white background that appeared
during pull-to-refresh gestures on mobile or overscroll on desktop, where the
browser reveals the area behind the app content.
The background color is determined by the theme's palette.background.default
value if defined, otherwise falls back to Material-UI defaults (#303030 for
dark themes, #fafafa for light themes).
Signed-off-by: Deluan <deluan@navidrome.org>
Always log the configuration source at startup: shows an INFO message with the
config file path when found, or a WARN message explaining how to specify one
when not found. This helps users understand why CLI commands may fail when
run outside of systemd (where --configfile is typically specified).
Closes#4758
* feat: make Unicode handling in external API calls configurable
- Add DevPreserveUnicodeInExternalCalls config option (default: false)
- Refactor external provider to use NameForExternal() method on auxArtist
- Remove redundant Name field from auxArtist struct
- Update all external API calls (image, URL, biography, similar, top songs, MBID) to use configurable Unicode handling
- Add comprehensive tests for both Unicode-preserving and normalized behaviors
- Refactor tests to use constants and improved structure with BeforeEach blocks
Fixes issue where Spotify integration failed to find artist images for artists with Unicode characters (e.g., en dash) in their names.
Signed-off-by: Deluan <deluan@navidrome.org>
* address comments
Signed-off-by: Deluan <deluan@navidrome.org>
* avoid calling str.Clean multiple times
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: apply Unicode handling pattern to auxAlbum
Extended the configurable Unicode handling to album names, matching the
pattern already implemented for artist names. This ensures consistent behavior
when DevPreserveUnicodeInExternalCalls is enabled for both artist and album
external API calls.
Changes:
- Removed Name field from auxAlbum struct, added Name() method with Unicode logic
- Updated getAlbum, UpdateAlbumInfo, populateAlbumInfo, and AlbumImage functions
- Added comprehensive tests for album Unicode handling (preserve and normalize)
- Fixed typo in artist image test description
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* Rename external auth options
ReverseProxyWhitelist was regularly confusing users that enabled it for
non-authenticating reverse proxy setups.
The new option name makes it clear that it's related to authentication, not
just reverse proxies.
* small refactor
Signed-off-by: Deluan <deluan@navidrome.org>
* add test
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
added: "quickscan", "fullscan"
updated:
- "manageUsers": `access` translates to `hozzáférés` in this context, not `elérés` (~reachableness)
- "quickscan", "fullscan", "scantype": updated to match new strings
* Signed-off-by: floatlesss <117862164+floatlesss@users.noreply.github.com>
fix(vscodedevcontainer): fix-taglib-build-issues - #4749
* Apply Gemini suggested changes
Signed-off-by: floatlesss <117862164+floatlesss@users.noreply.github.com>
* chore: install TagLib in devcontainer Dockerfile
Move TagLib installation from postCreateCommand script into the devcontainer Dockerfile to leverage Docker layer caching and simplify setup.\n\nChanges:\n- Install cross-taglib v2.1.1-1 directly in Dockerfile using TARGETARCH for multi-arch support (amd64/arm64).\n- Remove redundant libtag1-dev apt dependency; keep ffmpeg only.\n- Add CROSS_TAGLIB_VERSION as a build arg for consistency with CI/Makefile.\n- Remove postCreateCommand from devcontainer.json and delete install-taglib.sh script.\n\nWhy:\n- Avoid re-downloading TagLib on each container create; benefit from cached image layers.\n- Reduce redundancy and potential version mismatch between apt libtag and cross-taglib.\n- Keep devcontainer aligned with production build approach and CI settings.
---------
Signed-off-by: floatlesss <117862164+floatlesss@users.noreply.github.com>
Co-authored-by: Deluan <deluan@navidrome.org>
* feat: make NowPlaying dispatch asynchronous with worker pool
Implemented asynchronous NowPlaying dispatch using a queue worker pattern similar to cacheWarmer. Instead of dispatching NowPlaying updates synchronously during the HTTP request, they are now queued and processed by background workers at controlled intervals.
Key changes:
- Added nowPlayingEntry struct to represent queued entries
- Added npQueue map (keyed by playerId), npMu mutex, and npSignal channel to playTracker
- Implemented enqueueNowPlaying() to add entries to the queue
- Implemented nowPlayingWorker() that polls every 100ms, drains queue, and processes entries
- Changed NowPlaying() to queue dispatch instead of calling synchronously
- Renamed dispatchNowPlaying() to dispatchNowPlayingAsync() and updated it to use background context
Benefits:
- HTTP handlers return immediately without waiting for scrobbler responses
- Deduplication by key: rapid calls (seeking) only dispatch latest state
- Fire-and-forget: one-shot attempts with logged failures
- Backpressure-free: worker processes at its own pace
- Tests updated to use Eventually() assertions for async dispatch
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(play_tracker): increase timeout duration for signal handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(play_tracker): simplify queue processing by directly assigning entries
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add configurable transcoding cancellation
Implemented EnableTranscodingCancellation configuration option to control whether
FFmpeg transcoding processes can be interrupted when client requests are cancelled.
This addresses resource management issues on low-power hardware where transcoding
processes would accumulate and cause CPU spikes.
Key changes:
- Added EnableTranscodingCancellation bool to configuration (default: false)
- Added CLI flag --enabletranscodingcancellation and TOML/env support
- Modified FFmpeg package to always use exec.CommandContext for consistency
- Implemented conditional context handling in NewTranscodingCache function
- When enabled: uses request context directly (allows cancellation)
- When disabled: uses background context with request metadata preserved
- Added comprehensive tests for both FFmpeg and transcoding layers
- Maintained backward compatibility with existing behavior as default
The implementation follows proper layered architecture with policy decisions
at the media streaming layer and execution utilities remaining focused on
their core responsibilities.
Signed-off-by: Deluan <deluan@navidrome.org>
* test: refactor FFmpeg context cancellation tests for improved clarity and reliability
Signed-off-by: Deluan <deluan@navidrome.org>
* test: reset FFmpeg initialization
Signed-off-by: Deluan <deluan@navidrome.org>
* test: improve FFmpeg context cancellation tests for cross-platform compatibility
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
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 503bba321d.
---------
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.
* 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
* feat: Add selective folder scanning capability
Implement targeted scanning of specific library/folder pairs without
full recursion. This enables efficient rescanning of individual folders
when changes are detected, significantly reducing scan time for large
libraries.
Key changes:
- Add ScanTarget struct and ScanFolders API to Scanner interface
- Implement CLI flag --targets for specifying libraryID:folderPath pairs
- Add FolderRepository.GetByPaths() for batch folder info retrieval
- Create loadSpecificFolders() for non-recursive directory loading
- Scope GC operations to affected libraries only (with TODO for full impl)
- Add comprehensive tests for selective scanning behavior
The selective scan:
- Only processes specified folders (no subdirectory recursion)
- Maintains library isolation
- Runs full maintenance pipeline scoped to affected libraries
- Supports both full and quick scan modes
Examples:
navidrome scan --targets "1:Music/Rock,1:Music/Jazz"
navidrome scan --full --targets "2:Classical"
* feat(folder): replace GetByPaths with GetFolderUpdateInfo for improved folder updates retrieval
Signed-off-by: Deluan <deluan@navidrome.org>
* test: update parseTargets test to handle folder names with spaces
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(folder): remove unused LibraryPath struct and update GC logging message
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(folder): enhance external scanner to support target-specific scanning
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): simplify scanner methods
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(watcher): implement folder scanning notifications with deduplication
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(watcher): add resolveFolderPath function for testability
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(watcher): implement path ignoring based on .ndignore patterns
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): implement IgnoreChecker for managing .ndignore patterns
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(ignore_checker): rename scanner to lineScanner for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): enhance ScanTarget struct with String method for better target representation
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): validate library ID to prevent negative values
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): simplify GC method by removing library ID parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scanner): update folder scanning to include all descendants of specified folders
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): allow selective scan in the /startScan endpoint
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): update CallScan to handle specific library/folder pairs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): streamline scanning logic by removing scanAll method
Signed-off-by: Deluan <deluan@navidrome.org>
* test: enhance mockScanner for thread safety and improve test reliability
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): move scanner.ScanTarget to model.ScanTarget
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: move scanner types to model,implement MockScanner
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): update scanner interface and implementations to use model.Scanner
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(folder_repository): normalize target path handling by using filepath.Clean
Signed-off-by: Deluan <deluan@navidrome.org>
* test(folder_repository): add comprehensive tests for folder retrieval and child exclusion
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): simplify selective scan logic using slice.Filter
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): streamline phase folder and album creation by removing unnecessary library parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): move initialization logic from phase_1 to the scanner itself
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(tests): rename selective scan test file to scanner_selective_test.go
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(configuration): add DevSelectiveWatcher configuration option
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(watcher): enhance .ndignore handling for folder deletions and file changes
Signed-off-by: Deluan <deluan@navidrome.org>
* docs(scanner): comments
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): enhance walkDirTree to support target folder scanning
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner, watcher): handle errors when pushing ignore patterns for folders
Signed-off-by: Deluan <deluan@navidrome.org>
* Update scanner/phase_1_folders.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* refactor(scanner): replace parseTargets function with direct call to scanner.ParseTargets
Signed-off-by: Deluan <deluan@navidrome.org>
* test(scanner): add tests for ScanBegin and ScanEnd functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(library): update PRAGMA optimize to check table sizes without ANALYZE
Signed-off-by: Deluan <deluan@navidrome.org>
* test(scanner): refactor tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): add selective scan options and update translations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): add quick and full scan options for individual libraries
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): add Scan buttonsto the LibraryList
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scan): update scanning parameters from 'path' to 'target' for selective scans.
* refactor(scan): move ParseTargets function to model package
* test(scan): suppress unused return value from SetUserLibraries in tests
* feat(gc): enhance garbage collection to support selective library purging
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): prevent race condition when scanning deleted folders
When the watcher detects changes in a folder that gets deleted before
the scanner runs (due to the 10-second delay), the scanner was
prematurely removing these folders from the tracking map, preventing
them from being marked as missing.
The issue occurred because `newFolderEntry` was calling `popLastUpdate`
before verifying the folder actually exists on the filesystem.
Changes:
- Move fs.Stat check before newFolderEntry creation in loadDir to
ensure deleted folders remain in lastUpdates for finalize() to handle
- Add early existence check in walkDirTree to skip non-existent target
folders with a warning log
- Add unit test verifying non-existent folders aren't removed from
lastUpdates prematurely
- Add integration test for deleted folder scenario with ScanFolders
Fixes the issue where deleting entire folders (e.g., /music/AC_DC)
wouldn't mark tracks as missing when using selective folder scanning.
* refactor(scan): streamline folder entry creation and update handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scan): add '@Recycle' (QNAP) to ignored directories list
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(log): improve thread safety in logging level management
* test(scan): move unit tests for ParseTargets function
Signed-off-by: Deluan <deluan@navidrome.org>
* review
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: deluan <deluan.quintao@mechanical-orchard.com>
* fix(reader): prioritize cover art selection by base filename without numeric suffixes
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(reader): update image file comparison to use natural sorting and prioritize files without numeric suffixes
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(reader): simplify comparison, add case-sensitivity test case
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* Adding environmental variable so that navidrome can detect
if its running as an MSI install for insights
* Renaming to be ND_PACKAGE_TYPE so we can reuse this for the
.deb/.rpm stats as well
* Packaged implies a bool, this is a description so it should
be packaging or just package imo
* wixl currently doesn't support <Environment> so I'm swapping out
to a file next-door to the configuration file, we should be
able to reuse this for deb/rpm as well
* Using a file we should be able to add support for linux like this
also
* MSI should copy the package into place for us, it's not a KeyPath
as older versions won't have it, so it's presence doesn't indicate
the installed status of the package
* OK this doesn't exist, need to find another way to do it
* package to .package and moving to the datadir
* fix(scanner): better log message when AutoImportPlaylists is disabled
Fix#3861
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): support ID3v2 embedded images in WAV files
Fix#3867
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): show bitDepth in song info dialog
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(server): don't break if the ND_CONFIGFILE does not exist
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(docker): automatically loads a navidrome.toml file from /data, if available
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(server): custom ArtistJoiner config (#3873)
* feat(server): custom ArtistJoiner config
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(ui): organize ArtistLinkField, add tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): use display artist
* feat(ui): use display artist
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: remove some BFR-related TODOs that are not valid anymore
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: remove more outdated TODOs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): elapsed time for folder processing is wrong in the logs
Signed-off-by: Deluan <deluan@navidrome.org>
* Should be able to reuse this mechanism with deb and rpm, I think
it would be nice to know which specific one it is without guessing
based on /etc/debian_version or something; but it doesn't look like
that is exposed by goreleaser into an env or anything :/
* Need to reference the installed file and I think Id's don't require []
* Need to add into the root directory for this to work
* That was not deliberately removed
* feat: add RPM and DEB package configuration files for Navidrome
Signed-off-by: Deluan <deluan@navidrome.org>
* Don't need this as goreleaser will sort it out
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
Fixed race condition in the 'deduplicates items in buffer' test where the
background worker goroutine could process and clear the buffer before the
test could verify its contents. Added fc.SetReady(false) to keep the cache
unavailable during the test, ensuring buffered items remain in memory for
verification. This matches the pattern already used in the 'adds multiple
items to buffer' test.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add album refresh functionality after deleting missing files
Implemented RefreshAlbums method in AlbumRepository to recalculate album attributes (size, duration, song count) from their constituent media files. This method processes albums in batches to maintain efficiency with large datasets.
Added integration in deleteMissingFiles to automatically refresh affected albums in the background after deleting missing media files, ensuring album statistics remain accurate. Includes comprehensive test coverage for various scenarios including single/multiple albums, empty batches, and large batch processing.
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: extract missing files deletion into reusable service layer
Extracted inline deletion logic from server/nativeapi/missing.go into a new core.MissingFiles service interface and implementation. This provides better separation of concerns and testability.
The MissingFiles service handles:
- Deletion of specific or all missing files via transaction
- Garbage collection after deletion
- Extraction of affected album IDs from missing files
- Background refresh of artist and album statistics
The deleteMissingFiles HTTP handler now simply delegates to the service, removing 70+ lines of inline logic. All deletion, transaction, and stat refresh logic is now centralized in core/missing_files.go.
Updated dependency injection to provide MissingFiles service to the native API router. Renamed receiver variable from 'n' to 'api' throughout native_api.go for consistency.
* refactor: consolidate maintenance operations into unified service
Consolidate MissingFiles and RefreshAlbums functionality into a new Maintenance service. This refactoring:
- Creates core.Maintenance interface combining DeleteMissingFiles, DeleteAllMissingFiles, and RefreshAlbums methods
- Moves RefreshAlbums logic from AlbumRepository persistence layer to core Maintenance service
- Removes MissingFiles interface and moves its implementation to maintenanceService
- Updates all references in wire providers, native API router, and handlers
- Removes RefreshAlbums interface method from AlbumRepository model
- Improves separation of concerns by centralizing maintenance operations in the core domain
This change provides a cleaner API and better organization of maintenance-related database operations.
* refactor: remove MissingFiles interface and update references
Remove obsolete MissingFiles interface and its references:
- Delete core/missing_files.go and core/missing_files_test.go
- Remove RefreshAlbums method from AlbumRepository interface and implementation
- Remove RefreshAlbums tests from AlbumRepository test suite
- Update wire providers to use NewMaintenance instead of NewMissingFiles
- Update native API router to use Maintenance service
- Update missing.go handler to use Maintenance interface
All functionality is now consolidated in the core.Maintenance service.
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename RefreshAlbums to refreshAlbums and update related calls
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: optimize album refresh logic and improve test coverage
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify logging setup in tests with reusable LogHook function
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: add synchronization to logger and maintenance service for thread safety
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Fixed the multi-library selector dropdown background in the Ligera theme by changing the palette.background.paper value from 'inherit' to bLight['500'] ('#ffffff'). This ensures the dropdown has a solid white background that properly overlays content, making the library selection options clearly readable.
Closes#4502
* Update zh-Hant.json
Updated and optimized Traditional Chinese translation.
* Update zh-Hant.json
Updated and optimized Traditional Chinese translation.
* Update zh-Hant.json
Updated and optimized Traditional Chinese translation.
* fix(deps): update wazero dependencies to resolve issues
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(deps): update wazero dependency to latest version
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: correct track ordering when sorting playlists by album
Fixed issue #3177 where tracks within multi-disc albums were displayed out of order when sorting playlists by album. The playlist track repository was using an incomplete sort mapping that only sorted by album name and artist, missing the critical disc_number and track_number fields.
Changed the album sort mapping in playlist_track_repository from:
order_album_name, order_album_artist_name
to:
order_album_name, order_album_artist_name, disc_number, track_number, order_artist_name, title
This now matches the sorting used in the media file repository, ensuring tracks are sorted by:
1. Album name (groups by album)
2. Album artist (handles compilations)
3. Disc number (multi-disc album discs in order)
4. Track number (tracks within disc in order)
5. Artist name and title (edge cases with missing metadata)
Added comprehensive tests with a multi-disc test album to verify correct sorting behavior.
* chore: sync go.mod and go.sum with master
* chore: align playlist album sort order with mediafile_repository (use album_id)
* fix: clean up test playlist to prevent state leakage in randomized test runs
---------
Signed-off-by: Deluan <deluan@navidrome.org>
- Add optional locale parameter to formatNumber function
- Update tests to explicitly pass 'en-US' locale for deterministic results
- Maintains backward compatibility: defaults to system locale when no locale specified
- No need for cross-env or environment variable manipulation
- Tests now pass consistently regardless of system locale
Related to #4417
* fix: handle UTF-8 BOM in lyrics and playlist files
Added UTF-8 BOM (Byte Order Mark) detection and stripping for external lyrics files and playlist files. This ensures that files with BOM markers are correctly parsed and recognized as synced lyrics or valid playlists.
The fix introduces a new ioutils package with UTF8Reader and UTF8ReadFile functions that automatically detect and remove UTF-8, UTF-16 LE, and UTF-16 BE BOMs. These utilities are now used when reading external lyrics and playlist files to ensure consistent parsing regardless of BOM presence.
Added comprehensive tests for BOM handling in both lyrics and playlists, including test fixtures with actual BOM markers to verify correct behavior.
* test: add test for UTF-16 LE encoded LRC files
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add basic tag extraction fallback mechanism
Added basic tag extraction from TagLib's generic Tag interface as a fallback
when PropertyMap doesn't contain standard metadata fields. This ensures that
essential tags like title, artist, album, comment, genre, year, and track
are always available even when they're not present in format-specific
property maps.
Changes include:
- Extract basic tags (__title, __artist, etc.) in C++ wrapper
- Add parseBasicTag function to process basic tags in Go extractor
- Refactor parseProp function to be reusable across property parsing
- Ensure basic tags are preferred over PropertyMap when available
* feat(taglib): update tag parsing to use double underscores for properties
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: prevent infinite loop in Type filter autocomplete
Fixed an infinite loop issue in the album Type filter caused by an inline
arrow function in the optionText prop. The inline function created a new
reference on every render, causing React-Admin's AutocompleteInput to
continuously re-fetch data from the /api/tag endpoint.
The solution extracts the formatting function outside the component scope
as formatReleaseType, ensuring a stable function reference across renders.
This prevents unnecessary re-renders and API calls while maintaining the
humanized display format for release type values.
* fix: enable multi-valued releasetype in smart playlists
Smart playlists can now match all values in multi-valued releasetype tags.
Previously, the albumtype field was mapped to the single-valued mbz_album_type
database field, which only stored the first value from tags like album; soundtrack.
This prevented smart playlists from matching albums with secondary release types
like soundtrack, live, or compilation when tagged by MusicBrainz Picard.
The fix removes the direct database field mapping and allows both albumtype and
releasetype to use the multi-valued tag system. The albumtype field is now an
alias that points to the releasetype tag field, ensuring both query the same
JSON path in the tags column. This maintains backward compatibility with the
documented albumtype field while enabling proper multi-value tag matching.
Added tests to verify both releasetype and albumtype correctly generate
multi-valued tag queries.
Fixes#4616
* fix: resolve albumtype alias for all operators and sorting
Codex correctly identified that the initial fix only worked for Contains/StartsWith/EndsWith operators. The alias resolution was happening too late in the code path.
Fixed by resolving the alias in two places:
1. tagCond.ToSql() - now uses the actual field name (releasetype) in the JSON path
2. Criteria.OrderBy() - now uses the actual field name when building sort expressions
Added tests for Is/IsNot operators and sorting to ensure complete coverage.
* chore: update to Go 1.25.3
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: update to golangci-lint
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: update go dependencies
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: update vite dependencies in package.json and improve EventSource mock in tests
- Upgraded @vitejs/plugin-react to version 5.1.0 and @vitest/coverage-v8 to version 4.0.3.
- Updated vite to version 7.1.12 and vite-plugin-pwa to version 1.1.0.
- Enhanced the EventSource mock implementation in eventStream.test.js for better test isolation.
* ci: remove coverage flag from Go test command in pipeline
* chore: update Node.js version to v24 in devcontainer, pipeline, and .nvmrc
* chore: prettier
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: update actions/checkout from v4 to v5 in pipeline and update-translations workflows
* chore: update JS dependencies remove unused jest-dom import in Linkify.test.jsx
* chore: update actions/download-artifact from v4 to v5 in pipeline
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Added genre as a toggleable column in the playlist songs table. The Genre column
displays genre information for each song in playlists and is available through
the column toggle menu but disabled by default.
Implements feature request from GitHub discussion #4400.
Signed-off-by: Deluan <deluan@navidrome.org>
Added functionality to populate the Folder field in GetUser and GetUsers API responses
with the library IDs that the user has access to. This allows Subsonic API clients
to understand which music folders (libraries) a user can access for proper
content filtering and UI presentation.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add PluginList method
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance insights collection with plugin awareness and expanded metrics
Enhanced the insights collection system to provide more comprehensive telemetry data about Navidrome installations. This update adds plugin awareness through dependency injection integration, expands configuration detection capabilities, and includes additional library metrics.
Key improvements include:
- Added PluginLoader interface integration to collect plugin information when enabled
- Enhanced configuration detection with proper credential validation for LastFM, Spotify, and Deezer
- Added new library metrics including Libraries count and smart playlist detection
- Expanded configuration insights with reverse proxy, custom PID, and custom tags detection
- Updated Wire dependency injection to support the new plugin loader requirement
- Added corresponding data structures for plugin information collection
This enhancement provides valuable insights into feature usage patterns and plugin adoption while maintaining privacy and following existing telemetry practices.
* fix: correct type assertion in plugin manager test
Fixed type mismatch in test where PluginManifestCapabilitiesElem was being
compared with string literal. The test now properly casts the string to the
correct enum type for comparison.
* refactor: move static config checks to staticData function
Moved HasCustomTags, ReverseProxyConfigured, and HasCustomPID configuration checks from the dynamic collect() function to the static staticData() function where they belong. This eliminates redundant computation on every insights collection cycle and implements the actual logic for HasCustomTags instead of the hardcoded false value.
The HasCustomTags field now properly detects if custom tags are configured by checking the length of conf.Server.Tags. This change improves performance by computing static configuration values only once rather than on every insights collection.
* feat: add granular control for insights collection
Added DevEnablePluginsInsights configuration option to allow fine-grained control over whether plugin information is collected as part of the insights data. This change enhances privacy controls by allowing users to opt-out of plugin reporting while still participating in general insights collection.
The implementation includes:
- New configuration option DevEnablePluginsInsights with default value true
- Gated plugin collection in insights.go based on both plugin enablement and permission flag
- Enhanced plugin information to include version data alongside name
- Improved code organization with clearer conditional logic for data collection
* refactor: rename PluginNames parameter from serviceName to capability
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(auth): Do not try reverse proxy auth if internal auth succeeds
* cmp.Or will still require function results to be evaluated...
* move to a function
* fix: resolve playlist import issues with Unicode character paths
Fixes#3332 where songs with accented characters failed to import from Apple Music M3U playlists. The issue occurred because Apple Music exports use NFC Unicode normalization while macOS filesystem stores paths in NFD normalization.
Added normalizePathForComparison() function that normalizes both filesystem and M3U playlist paths to NFC form before comparison. This ensures consistent path matching regardless of the Unicode normalization form used.
Changes include comprehensive test coverage for Unicode normalization scenarios with both NFC and NFD character representations.
* address comments
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(tests): add check for unequal original Unicode paths in playlist normalization tests
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(server): remove includeMissing from search (always false)
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(search): optimize search order by using natural order for improved performance
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: improve URL path handling in local storage system
Enhanced the local storage implementation to properly handle URL-decoded paths
and fix issues with file paths containing special characters. Added decodedPath
field to localStorage struct to separate URL parsing concerns from file system
operations.
Key changes:
- Added decodedPath field to localStorage struct for proper URL decoding
- Modified newLocalStorage to use decoded path instead of modifying original URL
- Fixed Windows path handling to work with decoded paths
- Improved URL escaping in storage.For() to handle special characters
- Added comprehensive test suite covering URL decoding, symlink resolution,
Windows paths, and edge cases
- Refactored test extractor to use mockTestExtractor for better isolation
This ensures that file paths with spaces, hash symbols, and other special
characters are handled correctly throughout the storage system.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(tests): fix test file permissions and add missing tests.Init call
* refactor(tests): remove redundant test
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: URL building for Windows and remove redundant variable
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify URL path escaping in local storage
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* ui: reset activity icon after viewing error
* refactor: improve ActivityPanel error acknowledgment logic
Replaced boolean errorAcknowledged state with acknowledgedError string state to track which specific error was acknowledged. This prevents icon flickering when error messages change and simplifies the logic by removing the need for useEffect.
Key changes:
- Changed from errorAcknowledged boolean to acknowledgedError string state
- Added derived isErrorVisible computed value for cleaner logic
- Removed useEffect dependency on scanStatus.error changes
- Updated handleMenuOpen to store actual error string instead of boolean flag
- Fixed test mock to return proper error state matching test expectations
This change addresses code review feedback and follows React best practices by using derived state instead of imperative effects.
* fix: prevent foreign key constraint error in album participants
Prevent foreign key constraint errors when album participants contain
artist IDs that don't exist in the artist table. The updateParticipants
method now filters out non-existent artist IDs before attempting to
insert album_artists relationships.
- Add defensive filtering in updateParticipants() to query existing artist IDs
- Only insert relationships for artist IDs that exist in the artist table
- Add comprehensive regression test for both albums and media files
- Fixes scanner errors when JSON participant data contains stale artist references
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: optimize foreign key handling in album artists insertion
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: improve participants foreign key tests
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: clarify comments in album artists insertion query
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add cleanup to album repository tests
Added individual test cleanup to 4 album repository tests that create temporary
artists and albums. This ensures proper test isolation by removing test data
after each test completes, preventing test interference when running with
shuffle mode. Each test now cleans up its own temporary data from the artist,
library_artist, album, and album_artists tables using direct SQL deletion.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: refactor participant JSON handling for simpler and improved SQL processing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update test command description in Makefile for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: refactor album repository tests to use albumRepository type directly
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: prevent foreign key constraint error in tag UpdateCounts
Added JOIN clause with tag table in UpdateCounts SQL query to filter out
tag IDs from JSON that don't exist in the tag table. This prevents
'FOREIGN KEY constraint failed' errors when the library_tag table
tries to reference non-existent tag IDs during scanner operations.
The fix ensures only valid tag references are counted while maintaining
data integrity and preventing scanner failures during library updates.
* test(tag): add regression tests for foreign key constraint fix
Add comprehensive regression tests to prevent the foreign key constraint
error when tag IDs in JSON data don't exist in the tag table. Tests cover
both album and media file scenarios with non-existent tag IDs.
- Test UpdateCounts() with albums containing non-existent tag IDs
- Test UpdateCounts() with media files containing non-existent tag IDs
- Verify operations complete without foreign key errors
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enable library access for headless processes
Fixed multi-library filtering to allow headless processes (shares, external providers) to access data by skipping library restrictions when no user context is present.
Previously, the library filtering system returned empty results (WHERE 1=0) for processes without user authentication, breaking functionality like public shares and external service integrations.
Key changes:
- Modified applyLibraryFilter methods to skip filtering when user.ID == invalidUserId
- Refactored tag repository to use helper method for library filtering logic
- Fixed SQL aggregation bug in tag statistics calculation across multiple libraries
- Added comprehensive test coverage for headless process scenarios
- Updated genre repository to support proper column mappings for aggregated data
This preserves the secure "safe by default" approach for authenticated users while restoring backward compatibility for background processes that need unrestricted data access.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: resolve SQL ambiguity errors in share queries
Fixed SQL ambiguity errors that were breaking share links after the Multi-library PR.
The Multi-library changes introduced JOINs between album and library tables,
both of which have 'id' columns, causing 'ambiguous column name: id' errors
when unqualified column references were used in WHERE clauses.
Changes made:
- Updated core/share.go to use 'album.id' instead of 'id' in contentsLabelFromAlbums
- Updated persistence/share_repository.go to use 'album.id' in album share loading
- Updated persistence/sql_participations.go to use 'artist.id' for consistency
- Added regression tests to prevent future SQL ambiguity issues
This resolves HTTP 500 errors that users experienced when accessing existing
share URLs after the Multi-library feature was merged.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: improve headless library access handling
Added proper user context validation and reordered joins in applyLibraryFilterToArtistQuery to ensure library filtering works correctly for both authenticated and headless operations. The user_library join is now only applied when a valid user context exists, while the library_artist join is always applied to maintain proper data relationships. (+1 squashed commit)
Squashed commits:
[a28c6965b] fix: remove headless library access guard
Removed the invalidUserId guard condition in applyLibraryFilterToArtistQuery that was preventing proper library filtering for headless operations. This fix ensures that library filtering joins are always applied consistently, allowing headless library access to work correctly with the library_artist junction table filtering.
The previous guard was skipping all library filtering when no user context was present, which could cause issues with headless operations that still need to respect library boundaries through the library_artist relationship.
* fix: simplify genre selection query in genre repository
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance tag library filtering tests for headless access
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add comprehensive test coverage for headless library access
Added extensive test coverage for headless library access improvements including:
- Added 17 new tests across 4 test files covering headless access scenarios
- artist_repository_test.go: Added headless process tests for GetAll, Count,
Get operations and explicit library_id filtering functionality
- genre_repository_test.go: Added library filtering tests for headless processes
including GetAll, Count, ReadAll, and Read operations
- sql_base_repository_test.go: Added applyLibraryFilter method tests covering
admin users, regular users, and headless processes with/without custom table names
- share_repository_test.go: Added headless access tests and SQL ambiguity
verification for the album.id vs id fix in loadMedia function
- Cleaned up test setup by replacing log.NewContext usage with GinkgoT().Context()
and removing unnecessary configtest.SetupConfig() calls for better test isolation
These tests ensure that headless processes (background operations without user context)
can access all libraries while respecting explicit filters, and verify that the SQL
ambiguity fixes work correctly without breaking existing functionality.
* revert: remove user context handling from scrobble buffer getParticipants
Reverts commit 5b8ef74f05.
The artist repository no longer requires user context for proper library
filtering, so the workaround of temporarily injecting user context into
the scrobbleBufferRepository.Next method is no longer needed.
This simplifies the code and removes the dependency on fetching user
information during background scrobbling operations.
* fix: improve library access filtering for artists
Enhanced artist repository filtering to properly handle library access restrictions
and prevent artists with no accessible content from appearing in results.
Backend changes:
- Modified roleFilter to use direct JSON_EXTRACT instead of EXISTS subquery for better performance
- Enhanced applyLibraryFilterToArtistQuery to filter out artists with empty stats (no content)
- Changed from LEFT JOIN to INNER JOIN with library_artist table for stricter filtering
- Added condition to exclude artists where library_artist.stats = '{}' (empty content)
Frontend changes:
- Added null-checking in getCounter function to prevent TypeError when accessing undefined records
- Improved optional chaining for safer property access in role-based statistics display
These changes ensure that users only see artists that have actual accessible content
in their permitted libraries, fixing issues where artists appeared in the list
despite having no albums or songs available to the user.
* fix: update library access logic for non-admin users and enhance test coverage
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: refine library artist query and implement cleanup for empty entries
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: consolidate artist repository tests to eliminate duplication
Significantly refactored artist_repository_test.go to reduce code duplication and
improve maintainability by ~27% (930 to 680 lines). Key improvements include:
- Added test helper functions createTestArtistWithMBID() and createUserWithLibraries()
to eliminate repetitive test data creation
- Consolidated duplicate MBID search tests using DescribeTable for parameterized testing
- Removed entire 'Permission-Based Behavior Comparison' section (~150 lines) that
duplicated functionality already covered in other test contexts
- Reorganized search tests into cohesive 'MBID and Text Search' section with proper
setup/teardown and shared test infrastructure
- Streamlined missing artist tests and moved them to dedicated section
- Maintained 100% test coverage while eliminating redundant test patterns
All tests continue to pass with identical functionality and coverage.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Add EnsureCompiled calls in plugin test BeforeEach blocks to wait for
WebAssembly compilation before loading plugins. This prevents race conditions
where tests would attempt to load plugins before compilation completed,
causing flaky test failures in CI environments.
The race condition occurred because ScanPlugins() registers plugins
synchronously but compiles them asynchronously in background goroutines
with a concurrency limit of 2. Tests that immediately called LoadPlugin()
or LoadMediaAgent() after ScanPlugins() could fail if compilation wasn't
finished yet.
Fixed in both adapter_media_agent_test.go and manager_test.go which had
multiple tests vulnerable to this timing issue.
* feat(database): add user_library table and library access methods
Signed-off-by: Deluan <deluan@navidrome.org>
# Conflicts:
# tests/mock_library_repo.go
* feat(database): enhance user retrieval with library associations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(api): implement library management and user-library association endpoints
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(api): restrict access to library and config endpoints to admin users
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(library): implement library management service and update API routes
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(database): add library filtering to album, folder, and media file queries
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor library service to use REST repository pattern and remove CRUD operations
Signed-off-by: Deluan <deluan@navidrome.org>
* add total_duration column to library and update user_library table
Signed-off-by: Deluan <deluan@navidrome.org>
* fix migration file name
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add library management features including create, edit, delete, and list functionalities - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): enhance library validation and management with path checks and normalization - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): improve library path validation and error handling - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* use utils/formatBytes
Signed-off-by: Deluan <deluan@navidrome.org>
* simplify DeleteLibraryButton.jsx
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): enhance validation messages and error handling for library paths
Signed-off-by: Deluan <deluan@navidrome.org>
* lint
Signed-off-by: Deluan <deluan@navidrome.org>
* test(scanner): add tests for multi-library scanning and validation
Signed-off-by: Deluan <deluan@navidrome.org>
* test(scanner): improve handling of filesystem errors and ensure warnings are returned
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(controller): add function to retrieve the most recent scan time across all libraries
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add additional fields and restructure LibraryEdit component for enhanced statistics display
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): enhance LibraryCreate and LibraryEdit components with additional props and styling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(mediafile): add LibraryName field and update queries to include library name
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(missingfiles): add library filter and display in MissingFilesList component
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): implement scanner interface for triggering library scans on create/update
Signed-off-by: Deluan <deluan@navidrome.org>
# Conflicts:
# cmd/wire_gen.go
# cmd/wire_injectors.go
# Conflicts:
# cmd/wire_gen.go
# Conflicts:
# cmd/wire_gen.go
# cmd/wire_injectors.go
* feat(library): trigger scan after successful library deletion to clean up orphaned data
Signed-off-by: Deluan <deluan@navidrome.org>
* rename migration file for user library table to maintain versioning order
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: move scan triggering logic into a helper method for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add library path and name fields to album and mediafile models
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add/remove watchers on demand, not only when server starts
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scanner): streamline library handling by using state-libraries for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: track processed libraries by updating state with scan timestamps
Signed-off-by: Deluan <deluan@navidrome.org>
* prepend libraryID for track and album PIDs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(repository): apply library filtering in CountAll methods for albums, folders, and media files
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(user): add library selection for user creation and editing
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): implement library selection functionality with reducer and UI component
Signed-off-by: Deluan <deluan@navidrome.org>
# Conflicts:
# .github/copilot-instructions.md
# Conflicts:
# .gitignore
* feat(library): add tests for LibrarySelector and library selection hooks
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add unit tests for file utility functions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add library ID filtering for album resources
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): streamline library ID filtering in repositories and update resource filtering logic
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(repository): add table name handling in filter functions for SQL queries
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): add refresh functionality on LibrarySelector close
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(artist): add library ID filtering for artists in repository and update resource filtering logic
Signed-off-by: Deluan <deluan@navidrome.org>
# Conflicts:
# persistence/artist_repository.go
* Add library_id field support for smart playlists
- Add library_id field to smart playlist criteria system
- Supports Is and IsNot operators for filtering by library ID
- Includes comprehensive test coverage for single values and lists
- Enables creation of library-specific smart playlists
* feat(subsonic): implement user-specific library access in GetMusicFolders
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(library): enhance LibrarySelectionField to extract library IDs from record
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): update GetIndexes and GetArtists method to support library ID filtering
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: ensure LibrarySelector dropdown refreshes on button close
Added refresh() call when closing the dropdown via button click to maintain
consistency with the ClickAwayListener behavior. This ensures the UI
updates properly regardless of how the dropdown is closed, fixing an
inconsistent refresh behavior between different closing methods.
The fix tracks the previous open state and calls refresh() only when
the dropdown was open and is being closed by the button click.
* refactor: simplify getUserAccessibleLibraries function and update related tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance selectedMusicFolderIds function to handle valid music folder IDs and improve fallback logic
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: change ArtistRepository.GetIndex to accept multiple library IDs
Updated the GetIndex method signature to accept a slice of library IDs instead of a single ID, enabling support for filtering artists across multiple libraries simultaneously.
Changes include:
- Modified ArtistRepository interface in model/artist.go
- Updated implementation in persistence/artist_repository.go with improved library filtering logic
- Refactored Subsonic API browsing.go to use new selectedMusicFolderIds helper
- Added comprehensive test coverage for multiple library scenarios
- Updated mock repository implementation for testing
This change improves flexibility for multi-library operations while maintaining backward compatibility through the selectedMusicFolderIds helper function.
* feat: add library access validation to selectedMusicFolderIds
Enhanced the selectedMusicFolderIds function to validate musicFolderId parameters
against the user's accessible libraries. Invalid library IDs (those the user
doesn't have access to) are now silently filtered out, improving security by
preventing users from accessing libraries they don't have permission for.
Changes include:
- Added validation logic to check musicFolderId parameters against user's accessible libraries
- Added slices package import for efficient validation
- Enhanced function documentation to clarify validation behavior
- Added comprehensive test cases covering validation scenarios
- Maintains backward compatibility with existing behavior
* feat: implement multi-library support for GetAlbumList and GetAlbumList2 endpoints
- Enhanced selectedMusicFolderIds helper to validate and filter library IDs
- Added ApplyLibraryFilter function in filter/filters.go for library filtering
- Updated getAlbumList to support musicFolderId parameter filtering
- Added comprehensive tests for multi-library functionality
- Supports single and multiple musicFolderId values
- Falls back to all accessible libraries when no musicFolderId provided
- Validates library access permissions for user security
* feat: implement multi-library support for GetRandomSongs, GetSongsByGenre, GetStarred, and GetStarred2
- Added multi-library filtering to GetRandomSongs endpoint using musicFolderId parameter
- Added multi-library filtering to GetSongsByGenre endpoint using musicFolderId parameter
- Enhanced GetStarred and GetStarred2 to filter artists, albums, and songs by library
- Added Options field to MockMediaFileRepo and MockArtistRepo for test compatibility
- Added comprehensive Ginkgo/Gomega tests for all new multi-library functionality
- All tests verify proper SQL filter generation and library access validation
- Supports single/multiple musicFolderId values with fallback to all accessible libraries
* refactor: optimize starred items queries with parallel execution and fix test isolation
Refactored starred items functionality by extracting common logic into getStarredItems()
method that executes artist, album, and media file queries in parallel for better performance.
This eliminates code duplication between GetStarred and GetStarred2 methods while improving
response times through concurrent database queries using run.Parallel().
Also fixed test isolation issues by adding missing auth.Init(ds) call in album lists test setup.
This resolves nil pointer dereference errors in GetStarred and GetStarred2 tests when run independently.
* fix: add ApplyArtistLibraryFilter to filter artists by associated music folders
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add library access methods to User model
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement library access filtering for artist queries based on user permissions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance artist library filtering based on user permissions and optimize library ID retrieval
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: return error when any musicFolderId is invalid or inaccessible
Changed behavior from silently filtering invalid library IDs to returning
ErrorDataNotFound (code 70) when any provided musicFolderId parameter
is invalid or the user doesn't have access to it.
The error message includes the specific library number for better debugging.
This affects album/song list endpoints (getAlbumList, getRandomSongs,
getSongsByGenre, getStarred) to provide consistent error handling
across all Subsonic API endpoints.
Updated corresponding tests to expect errors instead of silent filtering.
* feat: add musicFolderId parameter support to Search2 and Search3 endpoints
Implemented musicFolderId parameter support for Subsonic API Search2 and Search3 endpoints, completing multi-library functionality across all Subsonic endpoints.
Key changes:
- Added musicFolderId parameter handling to Search2 and Search3 endpoints
- Updated search logic to filter results by specified library or all accessible libraries when parameter not provided
- Added proper error handling for invalid/inaccessible musicFolderId values
- Refactored SearchableRepository interface to support library filtering with variadic QueryOptions
- Updated repository implementations (Album, Artist, MediaFile) to handle library filtering in search operations
- Added comprehensive test coverage with robust assertions verifying library filtering works correctly
- Enhanced mock repositories to capture QueryOptions for test validation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: refresh LibraryList on scan end
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: allow editing name of main library
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: implement SendBroadcastMessage method for event broadcasting
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add event broadcasting for library creation, update, and deletion
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add useRefreshOnEvents hook for custom refresh logic on event changes
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance library management with refresh event broadcasting
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: replace AddUserLibrary and RemoveUserLibrary with SetUserLibraries for better library management
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: remove commented-out genre repository code from persistence tests
* feat: enhance library selection with master checkbox functionality
Added a master checkbox to the SelectLibraryInput component, allowing users to select or deselect all libraries at once. This improves user experience by simplifying the selection process when multiple libraries are available. Additionally, updated translations in the en.json file to include a new message for selecting all libraries, ensuring consistency in user interface messaging.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add default library assignment for new users
Introduced a new column `default_new_users` in the library table to
facilitate automatic assignment of default libraries to new regular users.
When a new user is created, they will now be assigned to libraries marked
as default, enhancing user experience by ensuring they have immediate access
to essential resources. Additionally, updated the user repository logic
to handle this new functionality and modified the user creation validation
to reflect that library selection is optional for non-admin users.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: correct updated_at assignment in library repository
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: improve cache buffering logic
Refactored the cache buffering logic to ensure thread safety when checking
the buffer length
Signed-off-by: Deluan <deluan@navidrome.org>
* fix formating
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement per-library artist statistics with automatic aggregation
Implemented comprehensive multi-library support for artist statistics that
automatically aggregates stats from user-accessible libraries. This fundamental
change moves artist statistics from global scope to per-library granularity
while maintaining backward compatibility and transparent operation.
Key changes include:
- Migrated artist statistics from global artist.stats to per-library library_artist.stats
- Added automatic library filtering and aggregation in existing Get/GetAll methods
- Updated role-based filtering to work with per-library statistics storage
- Enhanced statistics calculation to process and store stats per library
- Implemented user permission-aware aggregation that respects library access control
- Added comprehensive test coverage for library filtering and restricted user access
- Created helper functions to ensure proper library associations in tests
This enables users to see statistics that accurately reflect only the content
from libraries they have access to, providing proper multi-tenant behavior
while maintaining the existing API surface and UI functionality.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add multi-library support with per-library tag statistics - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: genre and tag repositories. add comprehensive tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add multi-library support to tag repository system
Implemented comprehensive library filtering for tag repositories to support the multi-library feature. This change ensures that users only see tags from libraries they have access to, while admin users can see all tags.
Key changes:
- Enhanced TagRepository.Add() method to accept libraryID parameter for proper library association
- Updated baseTagRepository to implement library-aware queries with proper joins
- Added library_tag table integration for per-library tag statistics
- Implemented user permission-based filtering through user_library associations
- Added comprehensive test coverage for library filtering scenarios
- Updated UI data provider to include tag filtering by selected libraries
- Modified scanner to pass library ID when adding tags during folder processing
The implementation maintains backward compatibility while providing proper isolation between libraries for tag-based operations like genres and other metadata tags.
* refactor: simplify artist repository library filtering
Removed conditional admin logic from applyLibraryFilterToArtistQuery method
and unified the library filtering approach to match the tag repository pattern.
The method now always uses the same SQL join structure regardless of user role,
with admin access handled automatically through user_library associations.
Added artistLibraryIdFilter function to properly qualify library_id column
references and prevent SQL ambiguity errors when multiple tables contain
library_id columns. This ensures the filter targets library_artist.library_id
specifically rather than causing ambiguous column name conflicts.
* fix: resolve LibrarySelectionField validation error for non-admin users
Fixed validation error 'At least one library must be selected for non-admin users' that appeared even when libraries were selected. The issue was caused by a data format mismatch between backend and frontend.
The backend sends user data with libraries as an array of objects, but the LibrarySelectionField component expects libraryIds as an array of IDs. Added data transformation in the data provider's getOne method to automatically convert libraries array to libraryIds format when fetching user records.
Also extracted validation logic into a separate userValidation module for better code organization and added comprehensive test coverage to prevent similar issues.
* refactor: remove unused library access functions and related tests
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename search_test.go to searching_test.go for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: add user context to scrobble buffer getParticipants call
Added user context handling to scrobbleBufferRepository.Next method to resolve
SQL error 'no such column: library_artist.library_id' when processing scrobble
entries in multi-library environments. The artist repository now requires user
context for proper library filtering, so we fetch the user and temporarily
inject it into the context before calling getParticipants. This ensures
background scrobbling operations work correctly with multi-library support.
* feat: add cross-library move detection for scanner
Implemented cross-library move detection for the scanner phase 2 to properly handle files moved between libraries. This prevents users from losing play counts, ratings, and other metadata when moving files across library boundaries.
Changes include:
- Added MediaFileRepository methods for two-tier matching: FindRecentFilesByMBZTrackID (primary) and FindRecentFilesByProperties (fallback)
- Extended scanner phase 2 pipeline with processCrossLibraryMoves stage that processes files unmatched within their library
- Implemented findCrossLibraryMatch with MusicBrainz Release Track ID priority and intrinsic properties fallback
- Updated producer logic to handle missing tracks without matches, ensuring cross-library processing
- Updated tests to reflect new producer behavior and cross-library functionality
The implementation uses existing moveMatched function for unified move operations, automatically preserving all user data through database foreign key relationships. Cross-library moves are detected using the same Equals() and IsEquivalent() matching logic as within-library moves for consistency.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add album annotation reassignment for cross-library moves
Implemented album annotation reassignment functionality for the scanner's missing tracks phase. When tracks move between libraries and change album IDs, the system now properly reassigns album annotations (starred status, ratings) from the old album to the new album. This prevents loss of user annotations when tracks are moved across library boundaries.
The implementation includes:
- Thread-safe annotation reassignment using mutex protection
- Duplicate reassignment prevention through processed album tracking
- Graceful error handling that doesn't fail the entire move operation
- Comprehensive test coverage for various scenarios including error conditions
This enhancement ensures data integrity and user experience continuity during cross-library media file movements.
* fix: address PR review comments for multi-library support
Fixed several issues identified in PR review:
- Removed unnecessary artist stats initialization check since the map is already initialized in PostScan()
- Improved code clarity in user repository by extracting isNewUser variable to avoid checking count == 0 twice
- Fixed library selection logic to properly handle initial library state and prevent overriding user selections
These changes address code quality and logic issues identified during the multi-library support PR review.
* feat: add automatic playlist statistics refreshing
Implemented automatic playlist statistics (duration, size, song count) refreshing
when tracks are modified. Added new refreshStats() method to recalculate
statistics from playlist tracks, and SetTracks() method to update tracks
and refresh statistics atomically. Modified all track manipulation methods
(RemoveTracks, AddTracks, AddMediaFiles) to automatically refresh statistics.
Updated playlist repository to use the new SetTracks method for consistent
statistics handling.
* refactor: rename AddTracks to AddMediaFilesByID for clarity
Renamed the AddTracks method to AddMediaFilesByID throughout the codebase
to better reflect its purpose of adding media files to a playlist by their IDs.
This change improves code readability and makes the method name more descriptive
of its actual functionality. Updated all references in playlist model, tests,
core playlist logic, and Subsonic API handlers to use the new method name.
* refactor: consolidate user context access in persistence layer
Removed duplicate helper functions userId() and isAdmin() from sql_base_repository.go and consolidated all user context access to use loggedUser(r.ctx).ID and loggedUser(r.ctx).IsAdmin consistently across the persistence layer.
This change eliminates code duplication and provides a single, consistent pattern for accessing user context information in repository methods. All functionality remains unchanged - this is purely a code cleanup refactoring.
* refactor: eliminate MockLibraryService duplication using embedded struct
- Replace 235-line MockLibraryService with 40-line embedded struct pattern
- Enhance MockLibraryRepo with service-layer methods (192→310 lines)
- Maintain full compatibility with existing tests
- All 72 nativeapi specs pass with proper error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: cleanup
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: prevent disabled Show in Playlist menu item from triggering actions
Fixed bug where clicking on the disabled 'Show in Playlist' menu item would unintentionally trigger music playback and replace the queue. The menu item now properly prevents event propagation when disabled and takes no action.
This resolves the issue where users would accidentally start playing music when clicking on the greyed-out menu option. The fix includes:
- Custom onClick handler that stops event propagation for disabled state
- Proper styling to maintain visual disabled state while allowing event handling
- Comprehensive test coverage for the disabled behavior
* style: clean up disabled menu item styling code
Simplified the arrow function for disabled onClick handler and changed inline style from empty object to undefined when not needed. Also added a CSS class for disabled menu items for potential future use.
These changes improve code readability and follow React best practices by using undefined instead of empty objects for conditional styles.
Fixed a race condition in the plugin manager where goroutines started during
plugin registration could concurrently access shared plugin maps while the
main registration loop was still running. The fix separates plugin registration
from background processing by collecting all plugins first, then starting
background goroutines after registration is complete.
This prevents concurrent read/write access to the plugins and adapters maps
that was causing data races detected by the Go race detector. The solution
maintains the same functionality while ensuring thread safety during the
plugin scanning and registration process.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add TimeNow function to SchedulerService plugin
Added new TimeNow RPC method to the SchedulerService host service that returns
the current time in two formats: RFC3339Nano string and Unix milliseconds int64.
This provides plugins with a standardized way to get current time information
from the host system.
The implementation includes:
- TimeNowRequest/TimeNowResponse protobuf message definitions
- Go host service implementation using time.Now()
- Complete test coverage with format validation
- Generated WASM interface code for plugin communication
* feat: add LocalTimeZone field to TimeNow response
Added LocalTimeZone field to TimeNowResponse message in the SchedulerService
plugin host service. This field contains the server's local timezone name
(e.g., 'America/New_York', 'UTC') providing plugins with timezone context
alongside the existing RFC3339Nano and Unix milliseconds timestamps.
The implementation includes:
- New local_time_zone protobuf field definition
- Go implementation using time.Now().Location().String()
- Updated test coverage with timezone validation
- Generated protobuf serialization/deserialization code
* docs: update plugin README with TimeNow function documentation
Updated the plugins README.md to document the new TimeNow function in the
SchedulerService. The documentation includes detailed descriptions of the
three return formats (RFC3339Nano, UnixMilli, LocalTimeZone), practical
use cases, and a comprehensive Go code example showing how plugins can
access current time information for logging, calculations, and timezone-aware
operations.
* docs: remove wrong comment from InitRequest
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: add missing TimeNow method to namedSchedulerService
Added TimeNow method implementation to namedSchedulerService struct to satisfy the scheduler.SchedulerService interface contract. This method was recently added to the interface but the namedSchedulerService wrapper was not updated, causing compilation failures in plugin tests. The implementation is a simple pass-through to the underlying scheduler service since TimeNow doesn't require any special handling for named callbacks.
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Added console.log mock in eventStream.test.js to suppress the 'EventStream error' message that was appearing during test execution. This improves test output cleanliness by preventing the expected error logging from the eventStream error handling code from cluttering the test console output.
The mock follows the existing pattern used in the codebase for suppressing console output during tests and only affects the test environment, preserving the original logging functionality in production code.
Improved the error handling logic in the checkErr function to map specific error strings to their corresponding API error constants. This change ensures that errors from plugins are correctly identified and returned, enhancing the robustness of error reporting.
Signed-off-by: Deluan <deluan@navidrome.org>
Updated the error handling logic in the plugin lifecycle manager to accurately record the success of the OnInit method. The change ensures that the metrics reflect whether the initialization was successful, improving the reliability of plugin metrics tracking. Additionally, removed the unused errorMapper interface from base_capability.go to clean up the codebase.
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: enhance agent loading with structured data
Introduced a new struct, EnabledAgent, to encapsulate agent name and type
information (plugin or built-in). Updated the getEnabledAgentNames function
to return a slice of EnabledAgent instead of a slice of strings, allowing
for more detailed agent management. This change improves the clarity and
maintainability of the code by providing a structured approach to handling
enabled agents and their types.
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove agent caching logic
Eliminated the caching mechanism for agents, including the associated
data structures and methods. This change simplifies the agent loading
process by directly retrieving agents without caching, which is no longer
necessary for the current implementation. The removal of this logic helps
reduce complexity and improve maintainability of the codebase.
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: replace range with slice.Contains
Signed-off-by: Deluan <deluan@navidrome.org>
* test: simplify agent name extraction in tests
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: implement OnSchedulerCallback method in wasmSchedulerCallback
Added the OnSchedulerCallback method to the wasmSchedulerCallback struct, enabling it to handle scheduler callback events. This method constructs a SchedulerCallbackRequest and invokes the corresponding plugin method, facilitating better integration with the scheduling system. The changes improve the plugin's ability to respond to scheduled events, enhancing overall functionality.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update executeCallback method to use callMethod
Modified the executeCallback method to accept an additional parameter,
methodName, which specifies the callback method to be executed. This change
ensures that the correct method is called for each WebSocket event,
improving the accuracy of callback execution for plugins.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): capture OnInit metrics
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve logging for metrics in callMethod
Updated the logging statement in the callMethod function to include the
elapsed time as a separate key in the log output. This change enhances
the clarity of the logged metrics, making it easier to analyze the
performance of plugin requests and troubleshoot any issues that may arise.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): enhance logging for schedule callback execution
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(server): streamline scrobbler stopping logic
Refactored the logic for stopping scrobbler instances when they are removed.
The new implementation introduces a `stoppableScrobbler` interface to
simplify the type assertion process, allowing for a more concise and
readable code structure. This change ensures that any scrobbler
implementing the `Stop` method is properly stopped before removal,
improving the overall reliability of the plugin management system.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): improve plugin lifecycle management and error handling
Enhanced the plugin lifecycle management by implementing error handling in the OnInit method. The changes include the addition of specific error conditions that can be returned during plugin initialization, allowing for better management of plugin states. Additionally, the unregisterPlugin method was updated to ensure proper cleanup of plugins that fail to initialize, improving overall stability and reliability of the plugin system.
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): remove unused LoadAllPlugins and related methods
Eliminated the LoadAllPlugins, LoadAllMediaAgents, and LoadAllScrobblers
methods from the manager implementation as they were not utilized in the codebase.
This cleanup reduces complexity and improves maintainability by removing
redundant code, allowing for a more streamlined plugin management process.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update logging configuration for plugins
Configured logging for multiple plugins to remove timestamps and source file/line information, while adding specific prefixes for better identification.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): clear initialization state when unregistering a plugin
Added functionality to clear the initialization state of a plugin in the
lifecycle manager when it is unregistered. This change ensures that the
lifecycle state is accurately maintained, preventing potential issues with
plugins that may be re-registered after being unregistered. The new method
`clearInitialized` was implemented to handle this state management.
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add unit tests for convertError function, rename to checkErr
Added comprehensive unit tests for the convertError function to ensure
correct behavior across various scenarios, including handling nil responses,
typed nils, and responses implementing errorResponse. These tests validate
that the function returns the expected results without panicking and
correctly wraps original errors when necessary.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): update plugin base implementation and method calls
Refactored the plugin base implementation by renaming `wasmBasePlugin` to `baseCapability` across multiple files. Updated method calls in the `wasmMediaAgent`, `wasmSchedulerCallback`, and `wasmScrobblerPlugin` to align with the new base structure. These changes improve code clarity and maintainability by standardizing the plugin architecture, ensuring consistent usage of the base capabilities across different plugin types.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(discord): handle failed connections and improve heartbeat checks
Added a new method to clean up failed connections, which cancels the heartbeat schedule, closes the WebSocket connection, and removes cache entries. Enhanced the heartbeat check to log failures and trigger the cleanup process on the first failure. These changes ensure better management of user connections and improve the overall reliability of the RPC system.
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add translation validation script and update JSON files
Introduced a new script `validate-translations.sh` to validate the structure
of JSON translation files against an English reference. This script checks
for missing and extra translation keys, ensuring consistency across language
files. Additionally, several JSON files were updated to include new keys
and improve existing translations, enhancing the overall localization
efforts for the application.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance translation validation script
Updated the translation validation script to improve its functionality and usability. The script now validates JSON translation files against a reference English file, checking for JSON syntax, structural integrity, and reporting missing or extra keys. It also integrates with GitHub Actions for CI/CD, providing annotations for errors and warnings. Additionally, the usage instructions have been clarified, and verbose output options have been added for better debugging.
Signed-off-by: Deluan <deluan@navidrome.org>
* revert translations
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: Hungarian translation JSON structure
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: update testall target in Makefile
Modified the 'testall' target in the Makefile to include 'test-i18n' in the test sequence. This change ensures that internationalization tests are run alongside other tests, improving the overall testing process and ensuring that translation-related issues are caught early in the development cycle.
Signed-off-by: Deluan <deluan@navidrome.org>
* run validation with verbose output
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
- Add ErrNotImplemented error to plugins/api package with proper documentation
- Refactor callMethod in wasm_base_plugin to use api.ErrNotImplemented
- Improve metrics recording logic to exclude not-implemented methods
- Add better tracing and context handling for plugin calls
- Reorganize error definitions with clear documentation
* fix(taglib): read cover art from dsf
* address feedback and alsi realize wma/wavpack are missing
* feedback
* more const char and remove unused import
Not all systems have bash at `/bin/bash`. `/bin/sh` is POSIX and should
be present on all systems making this much more portable. No bash
features are currently used in the script so this change should be safe.
* fix(plugins): silence repeated “Plugin not found” spam for inactive Spotify/Last.fm plugins
Navidrome was emitting a warning when the optional Spotify or
Last.fm agents weren’t enabled, filling the journal with entries like:
level=warning msg="Plugin not found" capability=MetadataAgent name=spotify
Fixed by completely disable the plugin system when Plugins.Enabled = false.
Signed-off-by: Deluan <deluan@navidrome.org>
* style: update test description for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: ensure plugin folder is created only if plugins are enabled
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* Hungarian: added new strings
new strings from the comparition of d903d3f1 and 4909232e
* Hungarian: fixed my mistakes
---------
Co-authored-by: ChekeredList71 <asd@asd.com>
Introduced a new pull request template to standardize contributions and improve clarity in the review process. This template includes sections for description, related issues, type of change, checklist, testing instructions, and additional notes. By providing a structured format, contributors can better communicate their changes and maintainers can more easily review submissions.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): search by MBID functionality
Updated the search methods in the mediaFileRepository, albumRepository, and artistRepository to support searching by MBID in addition to the existing query methods. This change improves the efficiency of media file, album, and artist searches, allowing for faster retrieval of records based on MBID.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(subsonic): enhance MBID search functionality for albums and artists
Updated the search functionality to support searching by MBID for both
albums and artists. The fullTextFilter function was modified to accept
additional MBID fields, allowing for more comprehensive searches. New
tests were added to ensure that the search functionality correctly
handles MBID queries, including cases for missing entries and the
includeMissing parameter. This enhancement improves the overall search
capabilities of the application, making it easier for users to find
specific media items by their unique identifiers.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(subsonic): normalize MBID to lowercase for consistent querying
Updated the MBID handling in the SQL search logic to convert the input
to lowercase before executing the query. This change ensures that
searches are case-insensitive, improving the accuracy and reliability
of the search results when querying by MBID.
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: update CROSS_TAGLIB_VERSION to 2.1.1-1
* feat: add run-docker target
Introduced a new Makefile target `run-docker` that allows users to run a Navidrome Docker image with specified tags. This addition simplifies the process of launching the Docker container by handling volume mappings for configuration and music folders. The change enhances the development workflow by making it easier to test and run PR images
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: implement RecentlyAddedByModTime support for mediafiles
Fixes#4046 by adding recently_added sort mapping to MediaFileRepository that respects the RecentlyAddedByModTime configuration setting. Previously, this feature only worked for albums, causing inconsistent behavior when clients requested tracks sorted by 'recently added'.
Changes include:
- Add mediaFileRecentlyAddedSort() function that returns 'updated_at' when RecentlyAddedByModTime=true, 'created_at' otherwise
- Add 'recently_added' sort mapping to mediafile repository
- Add comprehensive tests to verify both configuration scenarios
This ensures consistent sorting behavior between albums and tracks when using the RecentlyAddedByModTime feature.
* fix: update createdAt field to sort by recently added
Modified the createdAt field in the SongList component to include a sortBy
attribute set to "recently_added". This change ensures that the media files
are displayed in the order they were added, improving the user experience
when browsing through recently added items.
Signed-off-by: Deluan <deluan@navidrome.org>
* better testing
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Introduced a new event, EVENT_STREAM_RECONNECTED, to track the last
timestamp of stream reconnections. This change updates the activity
reducer to handle the new event and modifies the NowPlayingPanel to
refresh data based on server and stream status.
Signed-off-by: Deluan <deluan@navidrome.org>
Added a new event stream connection method to enhance the handling of
server events. This includes a reconnect mechanism for improved reliability
in case of connection errors. The configuration now allows toggling the
new event stream feature via `devNewEventStream`. Additionally, tests
were added to ensure the new functionality works as expected, including
reconnection behavior after an error.
Signed-off-by: Deluan <deluan@navidrome.org>
* attempt using artist | albumartist
* add primary stats, expose to ND and Subsonic
* response to feedback (1)
* address feedback part 1
* fix docs and artist show
* fix migration order
---------
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
* feat(agents): Add Deezer API artist image provider agent
* fix(agents): Use proper naming convention of consts
* fix(agents): Check if json test data can be read
* fix(agents): Use underscores for unused function arguments
* fix(agents): Move int literal to deezerArtistSearchLimit const
* feat: add Deezer configuration option to disable it.
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
* Add prometheus metrics to subsonic and plugins
* address feedback, do not log error if operation is not supported
* add missing timestamp and client to stats
* remove .view from subsonic route
* directly inject DataStore in Prometheus, to avoid having to pass it in every call
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* Fix artist not being marked as touched during quick scans
When a new album is added during quick scans, artists were not being
marked as 'touched' due to media files having older modification times
than the scan completion time.
Changes:
- Add 'updated_at' to artist Put() columns in scanner to ensure
timestamp is set when artists are processed
- Simplify RefreshStats query to check artist.updated_at directly
instead of complex media file joins
- Artists from new albums now properly get refreshed in later phases
This fixes the issue where newly added albums would have incomplete
artist information after quick scans.
* fix(missing): refresh artist stats in background after deleting missing files
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(request): add InternalAuth to user context
Signed-off-by: Deluan <deluan@navidrome.org>
* Add comprehensive test for artist stats update during quick scans
- Add test that verifies artist statistics are correctly updated when new files are added during incremental scans
- Test ensures both overall stats (AlbumCount, SongCount) and role-specific stats are properly refreshed
- Validates fix for artist stats not being refreshed during quick scans when new albums are added
- Uses real artist repository instead of mock to verify actual stats calculation behavior
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: ensure full scan refreshes all artist stats
After PR #4059, full scans were not forcing a refresh of all artists.
This change ensures that during full scans, all artist stats are refreshed
instead of only those with recently updated media files.
Changes:
- Set changesDetected=true at start of full scans to ensure maintenance operations run
- Add allArtists parameter to RefreshStats() method
- Pass fullScan state to RefreshStats to control refresh scope
- Update mock repository to match new interface
Fixes#4246
Related to PR #4059
* fix: add tests for full and incremental scans
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: eliminate race condition in plugin system
Added compilation waiting mechanism to prevent WASM plugins from being instantiated
before their background compilation completes. This fixes the intermittent error
'source module must be compiled before instantiation' that occurred when tests
or plugin usage happened before asynchronous compilation finished.
Changes include:
- Added manager reference to wasmBasePlugin for compilation synchronization
- Modified all plugin adapter constructors to accept manager parameter
- Updated getInstance() to wait for compilation before loading instances
- Fixed runtime test to handle manually created plugins appropriately
The race condition was caused by plugins trying to compile WASM modules
synchronously during Load() calls while background compilation was still
in progress. This change ensures proper coordination between the compilation
and instantiation phases.
* fix: add plugin-clean target to Makefile for easier plugin cleanup
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reorder plugin constructor parameters and add nil safety
Moved manager parameter to third position in pluginConstructor signature for\nbetter parameter ordering consistency.\n\nAlso added nil check for adapter creation to prevent registration of failed\nplugin adapters, which could lead to nil-pointer dereferences. Plugin\ncreation failures are now logged with context and gracefully skipped.\n\nChanges:\n- Reordered pluginConstructor parameters: manager moved before runtime\n- Updated all 4 adapter constructor signatures to match new order\n- Added nil safety check in registerPlugin to skip failed adapters\n- Updated runtime test to use new parameter order\n\nThis improves both code consistency and runtime safety by preventing\nnil adapters from being registered in the plugin manager.
* fix: prevent concurrent WASM compilation race condition
* refactor: remove unnecessary manager parameter from plugin constructors
* fix: update parameter name in newWasmSchedulerCallback for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add minimal test agent plugin with API definitions
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add plugin manager with auto-registration and unique agent names
Introduced a plugin manager that scans the plugins folder for subdirectories containing plugin.wasm files and auto-registers them as agents using the directory name as the unique agent name. Updated the configuration to support plugins with enabled/folder options, and ensured the plugin manager is started as a concurrent task during server startup. The wasmAgent now returns the plugin directory name for AgentName, ensuring each plugin agent is uniquely identifiable. This enables dynamic plugin discovery and integration with the agents orchestrator.
* test: add Ginkgo suite and test for plugin manager auto-registration
Added a Ginkgo v2 suite bootstrap (plugins_suite_test.go) for the plugins package and a test (manager_test.go) to verify that plugins in the testdata folder are auto-registered and can be loaded as agents. The test uses a mock DataStore and asserts that the agent is registered and its AgentName matches the plugin directory. Updated go.mod and go.sum for wazero dependency required by plugin WASM support.
* test(plugins): ensure test WASM plugin is always freshly built before running suite; add real-plugin Ginkgo tests. Add BeforeSuite to plugins suite to build plugins/testdata/agent/plugin.wasm using Go WASI build command, matching README instructions. Remove plugin.wasm before build to guarantee a clean build. Add full real-plugin Ginkgo/Gomega tests for wasmAgent, covering all methods and error cases. Fix manager_test.go to use pointer to Manager. This ensures plugin tests are always run against a freshly compiled WASM binary, increasing reliability and reproducibility.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement persistent compilation cache for WASM agent plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement instance pooling for wasmAgent to improve resource management
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance logging for wasmAgent and plugin manager operations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement HttpService for handling HTTP requests in WASM plugins
Also add a sample Wikimedia plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): standardize error handling in wasmAgent and MinimalAgent
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: clean up wikimedia plugin code
Standardized error creation using 'errors.New' where formatting was not needed. Introduced a constant for HTTP request timeouts. Removed commented-out log statement. Improved code comments for clarity and accuracy.
* refactor: use unified SPARQLResult struct and parser for SPARQL responses
Introduced a single SPARQLResult struct to represent all possible SPARQL response fields (sitelink, wiki, comment, img). Added a parseSPARQLResult helper to unmarshal and check for empty results, simplifying all fetch functions and improving type safety and maintainability.
* feat(plugins): improve error handling in HTTP request processing
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: background plugin compilation, logging, and race safety
Implemented background WASM plugin compilation with concurrency limits, proper closure capture, and global compilation cache to avoid data races. Added debug and warning logs for plugin compilation results, including elapsed time. Ensured plugin registration is correct and all tests pass.
* perf: implement true lazy loading for agents
Changed agent instantiation to be fully lazy. The Agents struct now stores agent names in order and only instantiates each agent on first use, caching the result. This preserves agent call order, improves server startup time, and ensures thread safety. Updated all agent methods and tests to use the new pattern. No changes to agent registration or interface. All tests pass.
* fix: ensure wasm plugin instances are closed via runtime.AddCleanup
Introduced runtime.AddCleanup to guarantee that the Close method of WASM plugin instances is called, even if they are garbage collected from the sync.Pool. Modified the sync.Pool.New function in manager.go to register a cleanup function for each loaded instance that implements Close. Updated agent.go to handle the pooledInstance wrapper containing the instance and its cleanup handle. Ensured cleanup.Stop() is called before explicitly closing an instance (on error or agent shutdown) to prevent double closing. This fixes a potential resource leak where instances could be GC'd from the pool without proper cleanup.
* refactor: break down long functions in plugin manager and agent
Refactored plugins/manager.go and plugins/agent.go to improve readability and reduce function length. Extracted pool initialization logic into newPluginPool and background compilation/agent factory logic into precompilePlugin/createAgentFactory in manager.go. Extracted pool retrieval/validation and cleanup function creation into getValidPooledInstance/createPoolCleanupFunc in agent.go.
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename wasmAgent to wasmArtistAgent
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(api): add AlbumMetadataService with AlbumInfo and AlbumImages requests
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugin): rename MinimalAgent for artist metadata service
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(api): implement wasmAlbumAgent for album metadata service with GetAlbumInfo and GetAlbumImages methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): simplify wasmAlbumAgent and wasmArtistAgent by using wasmBasePlugin
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add support for ArtistMetadataService and AlbumMetadataService in plugin manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): enhance plugin pool creation with custom runtime and precompilation support
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): implement generic plugin pool and agent factory for improved service handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): reorganize plugin management
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): improve function signatures for clarity and consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement background precompilation for plugins and agent factory creation
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): include instanceID in logging for better traceability
Signed-off-by: Deluan <deluan@navidrome.org>
* test(plugins): add tests for plugin pre-compilation and agent factory synchronization
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add minimal album test agent plugin for AlbumMetadataService
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): rename fake artist and album test agent plugins for metadata services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(makefile): add Makefile for building plugin WASM binaries
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add FakeMultiAgent plugin implementing Artist and Album metadata services
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): remove log statements from FakeArtistAgent and FakeMultiAgent methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: split AlbumInfoRetriever and AlbumImageRetriever, update all usages
Split the AlbumInfoRetriever interface into two: AlbumInfoRetriever (for album metadata) and AlbumImageRetriever (for album images), to better separate concerns and simplify implementations. Updated all agents, providers, plugins, and tests to use the new interfaces and methods. Removed the now-unnecessary mockAlbumAgents in favor of the shared mockAgents. Fixed a missing images slice declaration in lastfm agent. All tests pass except for known ignored persistence tests. This change reduces code duplication, improves clarity, and keeps the codebase clean and organized.
* feat(plugins): add Cover Art Archive AlbumMetadataService plugin for album cover images
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove wasm module pooling
it was causing issues with the GC and the Close methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename metadata service files to adapter naming convention
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: unify album and artist method calls by introducing callMethod function
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: unify album and artist method calls by introducing callMethod function
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle nil values in data redaction process
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: add timeout for plugin compilation to prevent indefinite blocking
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement ScrobblerService plugin with authorization and scrobbling capabilities
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify generalization
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: tests
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: enhance plugin management by improving scanning and loading mechanisms
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update plugin creation functions to return specific interfaces for better type safety
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: enhance wasmBasePlugin to support specific plugin types for improved type safety
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: implement MediaMetadataService with combined artist and album methods
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: improve MediaMetadataService plugin implementation and testing structure
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: add tests for Adapter Media Agent and improve plugin documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: add README for Navidrome Plugin System with detailed architecture and usage guidelines
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: enhance agent management with plugin loading and caching
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: update agent discovery logic to include only local agent when no config is specified
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: encapsulate agent caching logic in agentCache struct\n\nReplaced direct map/mutex usage for agent caching in Agents with a dedicated agentCache struct. This improves readability, maintainability, and testability by centralizing TTL and concurrency logic. Cleaned up comments and ensured all linter and test requirements are met.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: correct file extension filter in goimports command
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: use defer to unlock the mutex
Signed-off-by: Deluan <deluan@navidrome.org>
* chore: move Cover Art Archive AlbumMetadataService plugins to an example folder
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: handle errors when creating media metadata and scrobbler service plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: increase compilation timeout to one minute
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add configurable plugin compilation timeout
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement plugin scrobbler support in PlayTracker
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add context management and Stop method to buffered scrobbler
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add username field to scrobbler requests and update logging
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: data race in test
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename http proto files to host and update references
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove unused plugin registration methods from manager
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: extend plugin manifests and implement plugin management commands
Signed-off-by: Deluan <deluan@navidrome.org>
* Update utils/files.go
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
* fix for code scanning alert no. 43: Arbitrary file access during archive extraction ("Zip Slip")
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* feat: add plugin dev workflow support
Added new CLI commands to improve plugin development workflow: 'plugin dev' to create symlinks from development directories to plugins folder, 'plugin refresh' to reload plugins without restarting Navidrome, enhanced 'plugin remove' to handle symlinked development plugins correctly, and updated 'plugin list' to display development plugins with '(dev)' indicator. These changes make the plugin development workflow more efficient by allowing developers to work on plugins in their own directories, link them to Navidrome without copying files, refresh plugins after changes without restart, and clean up safely.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement timer service with register and cancel functionality - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement timer service with register and cancel functionality - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement timer service with register and cancel functionality - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement timer service with register and cancel functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: lint errors
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(README): update documentation to include TimerCallbackService and its functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add InitService with OnInit method and initialization tracking - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add tests for InitService and plugin initialization tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): expand documentation on plugin system implementation and architecture
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: panic
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): redirect plugins' stderr to logs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add safe accessor methods for TimerService
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add plugin-specific configuration support in InitRequest and documentation
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add TimerCallbackService plugin adapter and integration
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename services for consistency and clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add mutex for configuration access and clone plugin config
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(tests): remove configtest dependency to prevent data races in integration tests
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): remove PluginName method from WASM plugin implementations and update LoadPlugin to accept service type
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement instance pooling for wasmBasePlugin to improve performance - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add wasmInstancePool for managing WASM plugin instances with TTL and max size
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(plugins): correctly pass error to done function in wasmBasePlugin
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename service types to capabilities for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): simplify instance management in wasmBasePlugin by removing error handling in closure
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): update wasmBasePlugin and wasmInstancePool to return errors for better error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename InitService to LifecycleManagement for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): fix instance ID logging in wasmBasePlugin
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): extract instance ID logging to a separate function in wasmBasePlugin, to avoid vet error
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): make timers be isolated per plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): make timers be isolated per plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugins): rename HttpServiceImpl to httpServiceImpl for consistency and improve logging
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add config service for plugin-specific configuration management
Signed-off-by: Deluan <deluan@navidrome.org>
* Update plugins/manager.go
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
* Update plugins/manager.go
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
* feat(crontab): implement crontab service for scheduling and canceling jobs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(singleton): fix deadlock issue when a constructor calls GetSingleton again
Signed-off-by: Deluan <deluan@navidrome.org> (+1 squashed commit)
Squashed commits:
[325a96ea2] fix(singleton): fix deadlock issue when a constructor calls GetSingleton again
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement Scheduler for one-time and recurring job scheduling, merging CrontabService and TimerService
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scheduler): race condition in the scheduleOneTime and scheduleRecurring methods when replacing jobs with the same ID
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(scheduler): consolidate job scheduling logic into a single helper function
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(plugin): rename GetInstance method to Instantiate for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add WebSocket service for handling connections and messages
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(crypto-ticker): add WebSocket plugin for real-time cryptocurrency price tracking
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(websocket): enhance connection management and callback handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(manager): only create one adapter instance for each adapter/capability pair
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(websocket): ensure proper resource management by closing response body and use defer to unlocking mutexes
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: flaky test
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugin): refactor WebSocket service integration and improve error logging
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugin): add SchedulerCallback support and improve reconnection logic
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: test panic
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: add crypto-ticker plugin example to README
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(manager): add LoadAllPlugins and LoadAllMediaAgents methods with slice.Map integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(api): add Timestamp field to ScrobblerNowPlayingRequest and update related methods
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(websocket): add error field to response messages for better error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(cache): implement CacheService with string, int, float, and byte operations
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(tests): update buffered scrobbler tests for improved scrobble verification and use RWMutex in mock repo
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(cache): simplify cache service implementation and remove unnecessary synchronization
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(tests): add build step for test plugins in the test suite
Signed-off-by: Deluan <deluan@navidrome.org>
* wip
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scheduler): implement named scheduler callbacks and enhance Discord plugin integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(rpc): enhance activity image processing and improve error handling in Discord integration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(discord): enhance activity state with artist list and add large text asset
Signed-off-by: Deluan <deluan@navidrome.org>
* fix tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(artwork): implement ArtworkService for retrieving artwork URLs
Signed-off-by: Deluan <deluan@navidrome.org>
* Add playback position to scrobble NowPlaying (#4089)
* test(playtracker): cover playback position
* address review comment
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix merge
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: remove unnecessary check for empty slice in Map function
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: update reflex.conf to include .wasm file extension
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): normalize attribute strings and add edge case tests for PID calculation
Relates to https://github.com/navidrome/navidrome/issues/4183#issuecomment-2952729458
Signed-off-by: Deluan <deluan@navidrome.org>
* test(ui): fix warnings (#4187)
* fix(ui): address test warnings
* ignore lint error in test
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(server): optimize top songs lookup (#4189)
* optimize top songs lookup
* Optimize title matching queries
* refactor: simplify top songs matching
* improve error handling and logging in track loading functions
Signed-off-by: Deluan <deluan@navidrome.org>
* test: add cases for fallback to title matching and combined MBID/title matching
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): playlist details overflow in spotify-based themes (#4184)
* test: ensure playlist details width
* fix(test): simplify expectation for minWidth in NDPlaylistDetails
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(test): test all themes
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* chore(deps): update TagLib to version 2.1 (#4185)
* chore: update cross-taglib
* fix(taglib): add logging for TagLib version
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* test: verify agents fallback (#4191)
* build(docker): downgrade Alpine version from 3.21 to 3.19, oldest supported version.
This is to reduce the image size, as we don't really need the latest.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix tests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(runtime): implement pooled WASM runtime and module for better instance management
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(discord-plugin): adjust timer delay calculation for track completion
Signed-off-by: Deluan <deluan@navidrome.org>
* resolve PR comments
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): implement cache cleanup by size functionality
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(manager): return error from getCompilationCache and handle it in ScanPlugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix possible rce condition
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(docs): update README to include Cache and Artwork services
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(manager): add permissions support for host services in custom runtime - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(manifest): add permissions field to plugin manifests - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* test(permissions): implement permission validation and testing for plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(plugins): add unauthorized_plugin to test permission enforcement - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(docs): add Plugin Permission System section to README - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(manifest): add detailed reasons for permissions in plugin manifests - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(permissions): implement granular HTTP permissions for plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(permissions): implement HTTP and WebSocket permissions for plugins - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: unexport all plugins package private symbols
Signed-off-by: Deluan <deluan@navidrome.org>
* update docs
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename plugin_lifecycle_manager
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: add discord-rich-presence plugin example to README
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add support for PATCH, HEAD, and OPTIONS HTTP methods
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: use folder names as unique identifiers for plugins
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: read config just once, to avoid data race in tests
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename pluginName to pluginID for consistency across services
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: use symlink name instead of folder name for plugin registration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update plugin output format to include ID and enhance README with symlink usage
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: implement shared plugin discovery function to streamline plugin scanning and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: show plugin permissions in `plugin info`
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add JSON schema for Navidrome Plugin manifest and generate corresponding Go types - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement typed permissions for plugins to enhance permission handling
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: refactor plugin permissions to use typed schema and improve validation - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update HTTP permissions handling to use typed schema for allowed URLs - WIP
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: remove unused JSON schema validation for plugin manifests
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: remove unused fields from PluginPackage struct in package.go
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: update file permissions in tests and remove unused permission parsing function
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: refactor test plugin creation to use typed permissions and remove legacy helper
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: add website field to plugin manifests and update test cases
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: permission schema to use basePermission structure for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance host service management by adding permission checks for each service
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: reorganize code files
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: simplify custom runtime creation by removing compilation cache parameter
Signed-off-by: Deluan <deluan@navidrome.org>
* doc: add WebSocketService and update ConfigService for plugin-specific configuration
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: implement WASM loading optimization to enhance plugin instance creation speed
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: rename custom runtime functions and update related tests for clarity
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: enhance plugin structure with compilation handling and error reporting
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: improve logging and context tracing in runtime and wasm base plugin
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: enhance runtime management with scoped runtime and caching improvements
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: implement EnsureCompiled method for improved plugin compilation handling
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: implement cached module management with TTL for improved performance
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: replace map with sync.Map
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: adjust time tolerance in scrobble buffer repository tests to avoid flakiness
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: enhance image processing with fallback mechanism for improved error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* docs: review test plugins readme
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: set default timeout for HTTP client to 10 seconds
Signed-off-by: Deluan <deluan@navidrome.org>
* feat: enhance wasm instance pool with concurrency limits and timeout settings
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(discordrp): implement caching for processed image URLs with configurable TTL
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* fix(ui,scanner,subsonic): Allow nullable replaygain and support 0.0
Resolves#4236.
Makes the replaygain columns (track/album gain/peak) nullable.
Converts the type to a pointer, allowing for 0.0 (a valid value) to be returned from Subsonic.
Updates tests for this behavior.
* small refactor
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* fix(subsonic): Sort songs by presence of lyrics for `getLyrics`
The current implementation of `getLyrics` fetches any songs matching the artist and title.
However, this misses a case where there may be multiple matches for the same artist/song, and one has lyrics while the other doesn't.
Resolve this by adding a custom SQL dynamic column that checks for the presence of lyrics.
* add options to selectMediaFile, update test
* more robust testing of GetAllByLyrics
* fix(subsonic): refactor GetAllByLyrics to GetAll with lyrics sorting
Signed-off-by: Deluan <deluan@navidrome.org>
* use has_lyrics, and properly support multiple sort parts
* better handle complicated internal sorts
* just use a simpler filter
* add note to setSortMappings
* remove custom sort mapping, improve test with different updatedat
* refactor tests and mock
Signed-off-by: Deluan <deluan@navidrome.org>
* default order when not specified is `asc`
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* fix(db): add user foreign key constraint to annotation table
Associates user_id with user.id, with cascade for delete (drop annotation) and update (update annotation).
Migration script will only copy/insert annotations for user IDs that exist
* remove default for user_id
* refactor(db): rename migration correct sequencing
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* Add migration converting playqueue current to index
* refactor
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(queue): ensure valid current index and improve test coverage
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): add Now Playing panel and integrate now playing count updates
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: check return value in test to satisfy linter
* fix: format React code with prettier
* fix: resolve race condition in play tracker test
* fix: log error when fetching now playing data fails
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): refactor Now Playing panel with new components and error handling
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): adjust padding and height in Now Playing panel for improved layout
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(cache): add automatic cleanup to prevent goroutine leak on cache garbage collection
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* ui: add Play button to artist toolbar
* refactor
Signed-off-by: Deluan <deluan@navidrome.org>
* test(ui): add tests for Play button functionality in ArtistActions
Signed-off-by: Deluan <deluan@navidrome.org>
* ui: update Play button label to Top Songs in ArtistActions
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* Add Play Similar option
* Add pt-br translation for Play Similar
* Refactor playSimilar and add helper
* Improve Play Similar feedback
* Add artist actions bar with shuffle and radio
* Add Play Similar menu and align artist actions
* Refine artist actions and revert menu option
* fix(ui): enhance layout of ArtistActions and ArtistShow components
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(i18n): revert unused changes
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): improve layout for mobile
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): improve error handling for fetching similar songs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(ui): enhance error logging for fetching songs in shuffle
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(ui): shuffle handling to use async/await for better readability
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(ui): simplify button label handling in ArtistActions component
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
- Fix GetUser JukeboxRole to properly respect AdminOnly setting
- Extract buildUserResponse helper to eliminate duplication between GetUser and GetUsers
- Fix username field inconsistency (GetUsers was using loggedUser.Name instead of UserName)
- Add comprehensive tests covering jukebox role permissions and consistency between methods
Fixes#4160
* fix(configuration.go, mpv.go): Jukebox mode doesn't include MusicFolder in mpv command - #4066
The call to createMPVCommand is not including the MusicFolder path in
mpv command causing it to fail with file not found errors.
Updated default command template and createMPVCommand to use additional
substitution with conf.server.MusicFolder
Signed-off-by: Pat <patso.oshea@gmail.com>
* Revert config.go change, use filepath.Join for cross platform
* Update track.go with mf.AbsolutePath()
---------
Signed-off-by: Pat <patso.oshea@gmail.com>
Co-authored-by: Deluan <deluan@navidrome.org>
* Update song playlist menu and endpoint
* feat(ui): show submenu on click, not on hover
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): integrate dataProvider for fetching playlists in song context menu
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): update song context menu to use dataProvider for fetching playlists and inspecting songs
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): stop event propagation when closing playlist submenu
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(ui): add 'show in playlist' option to options object
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: enhance artist folder detection with directory traversal
Enhanced fromArtistFolder function to implement directory traversal fallback for finding artist images. The original implementation only searched in the calculated artist folder, which failed for single album artists where artist.jpg files were not detected.
Changes: Modified fromArtistFolder to search up to 3 directory levels (artist folder + 2 parent levels), extracted findImageInFolder helper function for cleaner code organization, added proper boundary checks to prevent infinite traversal, maintained backward compatibility with existing functionality.
This fix ensures artist.jpg files are properly detected for single album artists while preserving all existing behavior for multi-album artists.
* refactor: address PR review suggestions
Applied review suggestions from gemini-code-assist bot:
- Added maxArtistFolderTraversalDepth constant instead of hardcoded value 3
- Updated error message to mention that parent directories were also searched
- Enhanced test assertion to verify the improved error message
* fix: improve artist folder traversal logic and enhance error logging
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: remove test for special glob characters in artist folder detection
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: add logging for artist image search in folder
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Changed translation of "Top Rated" from "Los Mejores Calificados" to "Mejor Calificados" for consistency purposes with other list entries. While the previous version was correct, this version is shorter and aligns better with the rest of the terms.
* Update eu.json
Added roles, reordered some strings, small fixes
* fix(ui): update Basque translation
* Update eu.json
third time's the charm
* please bear with me
I'm not a developer. I'm trying my hardest.
* Update eu.json
Added newest strings
* find artist by multivalued exact match, instead of 'artist' field
* check if lyrics are not empty
* refactor(filters): rename function to better reflect its purpose
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* feat(scanner): add LastScanError tracking to scanner status
- Introduced LastScanErrorKey constant for error tracking.
- Updated StatusInfo struct to include LastError field.
- Modified scanner logic to store and retrieve last scan error.
- Enhanced ScanStatus response to include error information.
- Updated UI components to display last scan error when applicable.
- Added tests to verify last scan error functionality.
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(scanner): enhance scan status with type and elapsed time tracking
- Added LastScanTypeKey and LastScanStartTimeKey constants for tracking scan type and start time.
- Updated StatusInfo struct to include ScanType and ElapsedTime fields.
- Implemented getScanInfo method to retrieve scan type, elapsed time, and last error.
- Modified scanner logic to store scan type and start time during scans.
- Enhanced ScanStatus response and UI components to display scan type and elapsed time.
- Added formatShortDuration utility for better elapsed time representation.
- Updated activity reducer to handle new scan status fields.
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(tests): consolidate controller status tests into a single file
- Removed the old controller_status_test.go file.
- Merged relevant tests into the new controller_test.go file for better organization and maintainability.
- Ensured all existing test cases for controller status are preserved and functional.
Signed-off-by: Deluan <deluan@navidrome.org>
* Fix formatting issues
* refactor(scanner): update getScanInfo method documentation
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(artist): update RefreshStats to only process artists with recently updated media files
Signed-off-by: Deluan <deluan@navidrome.org>
* fix: paginate Artist's RefreshStats, also replace rawSQL with Expr
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Removed all code, config, and test references to DevEnableBufferedScrobble. Buffered scrobbling is now always enabled. Added this option to the list of deprecated config options with a warning. Updated all logic and tests to reflect this. No linter issues remain. Some PlayTracker tests are failing, but these are likely due to test data or logic unrelated to this change. All other tests pass. Review required for PlayTracker test failures.
Signed-off-by: Deluan <deluan@navidrome.org>
Added Ginkgo/Gomega tests for userName and AbsolutePath functions in core/common.go. Tests cover normal and error cases, using existing mocks and helpers. This improves coverage and ensures correct behavior for user context extraction and library path resolution.
* fix(ui): ensure album tracks are always ordered by disc and track number (fixes#3720)
* refactor(ui): remove obsolete release date grouping logic from SongDatagrid and AlbumSongs
* fix(ui): ensure correct album track ordering in context menu and play button
* fix: Update album sort to use album_id instead of release_date
* refactor: Adjust filters in PlayButton and AlbumContextMenu
* fix: correct typo in comment regarding participants in GetMissingAndMatching function
* fix: prevent visual separation of tracks on same disc
Removes the leftover `releaseDate` check from the `firstTracksOfDiscs` calculation in `SongDatagridBody`. This check caused unnecessary `DiscSubtitleRow` insertions when tracks on the same disc had different release dates, leading to an incorrect visual grouping that resembled a multi-disc layout.
This change ensures disc subtitles are only shown when the actual `discNumber` changes, correcting the UI presentation issue reported in issue #3720 after PR #3975.
* fix: remove remaining releaseDate references in SongDatagrid
Cleaned up leftover `releaseDate` references in `SongDatagrid.jsx`:
- Removed `releaseDate` parameter and usage from `handlePlaySubset` in `DiscSubtitleRow`.
- Removed `releaseDate` prop passed to `AlbumContextMenu` in `DiscSubtitleRow`.
- Removed `releaseDate` from the drag item data in `SongDatagridRow`.
- Removed `releaseDate` parameter and the corresponding `else` block from the `playSubset` function in `SongDatagridBody`.
This ensures the component consistently uses `discNumber` for grouping and playback actions initiated from the disc subtitle, fully resolving the inconsistencies related to issue #3720.
* fix(server): bring back legacy date mappings
Signed-off-by: Deluan <deluan@navidrome.org>
* reuse the mapDates logic in the legacyReleaseDate function
Signed-off-by: Deluan <deluan@navidrome.org>
* fix mappings
Signed-off-by: Deluan <deluan@navidrome.org>
* show original and release dates in album grid
Signed-off-by: Deluan <deluan@navidrome.org>
* fix tests based on new year mapping
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(subsonic): prefer returning original_year over (recording) year
when sorting albums
Signed-off-by: Deluan <deluan@navidrome.org>
* fix case when we don't have originalYear
Signed-off-by: Deluan <deluan@navidrome.org>
* show all dates in album's info, and remove the recording date from the album page
Signed-off-by: Deluan <deluan@navidrome.org>
* better?
Signed-off-by: Deluan <deluan@navidrome.org>
* add snapshot tests for Album Details
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(subsonic): sort order for getAlbumList?type=byYear
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* chore(server): add more info to scrobble errors
Signed-off-by: Deluan <deluan@navidrome.org>
* chore(server): add more info to scrobble errors
Signed-off-by: Deluan <deluan@navidrome.org>
* chore(server): add more info to scrobble errors
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* chore(scanner): add trace logs
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(bfr): force upgrade to read all folders. It was skipping folders for certain timezones
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
- `-map 0:v` selects all video streams from the input
- `-map -0:V` excludes all "main" video streams (capital V)
This combination effectively selects only the attached pictures
Signed-off-by: Deluan <deluan@navidrome.org>
Previously addLine would add-or-update, resulting in the custom settings being overriden on upgrade. createLine will only add to the ini if the key doesn't already exist.
* chore(ui): Fix minor inconsistencies
1. The icons in the user menu are a mix of MUI and react-icons. Move them all to react-icons, and use a standard size (24px)
2. On missing files page, provide a custom Empty component that just removes 'yet'
* use RA's builtin support for custom empty message
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* only do subsonic instead
* make sure to actually populate response first
* navidrome artist filtering
* address discord feedback
* perPage min 36
* various artist artist_id -> albumartist_id
* artist_id, role_id separate
* remove all ui changes I guess
* Revert role filters
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
With old metadata, Disc Subtitle was one of `tsst`, `discsubtitle`, or `setsubtitle`.
With the updated, `setsubtitle` is only available for flac.
Update `mappings.yaml` to maintain prior behavior.
* fix(server): db migration was not working for MusicFolders ending with a trailing slash.
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(server): db migration for relative paths
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
1. For some bizarre reason, importing inflection by itself is undefined. But you can import specific functions
2. Per https://github.com/vite-pwa/vite-plugin-pwa/issues/419, `type: 'module',` is only for non-chromium browsers
* fix(server): db migration not working when MusicFolder is a relative path
Signed-off-by: Deluan <deluan@navidrome.org>
* remove todo
Signed-off-by: Deluan <deluan@navidrome.org>
* fix migration of paths in Windows
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(scanner): Always refresh folder image time when adding first image
Currently, the `images_updated_at` field is only set to the image modification time.
However, in cases where a new image is added _and_ said image is older than the folder mod time, the field is not updated properly.
In this the case where `images_updated_at` is null (no images were ever added) and a new images is found, use the folder modification time instead of image modification time.
**Note**, this doesn't handle cases such as replacing a newer image with an older one.
* simplify image update at
* we don't want to set imagesUpdatedAt when there's no images in the folder
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* feat(subsonic): Set SortName for OS AlbumList, test to JSON/XML
* albumlist2, star2 updated properly
* fix(subsonic): add sort or order name based on config
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* fix(scanner): remove transactions where they are not strictly needed
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(server): force setStar transaction to start as IMMEDIATE
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(server): encapsulated way to upgrade tx to write mode
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(server): use tx immediate for some playlist endpoints
Signed-off-by: Deluan <deluan@navidrome.org>
* make more transactions immediate (#3759)
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Kendall Garner <17521368+kgarner7@users.noreply.github.com>
* test(server): validate play tracker participants, scrobble buffer
* tests(server): nit: remove duplicated tests and small cleanups
Signed-off-by: Deluan <deluan@navidrome.org>
* tests(server): nit: replace panics with assertions
Signed-off-by: Deluan <deluan@navidrome.org>
* just use random ids, and store it instead
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* feat(ui): Improve Artist Album pagination
- use maximum of albumartist/artist credits for determining pagination
- reduce default maxPerPage considerably. This gives values of 36/72/108 at largest size
* enable pagination when over 90
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
* fix(ui): Update Russian translations
- Adds missing strings added in the past couple releases
- Fixes a few confusing translations in the "share" section
* Add missing comma
* fix(server): backup not working from cli
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(server): make backup-file required for restore
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(ci): add updated languages to the POEditor PR title
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(ci): add an author to the PR
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
As documented in the OCI Image Format,
org.opencontainers.image.source[1] identifies an image's source
repository. This is purely for documentation purposes. It does however
help tools such as Renovate[2] to find the changelogs when a new
Navidrome version is released. The changelogs would then be included in
the PR Renovate creates.
[1]: 5325ec4885/annotations.md (L24)
[2]: https://docs.renovatebot.com/modules/datasource/docker/#description
Signed-off-by: Dany Marcoux <git@dmarcoux.com>
* fix(insights): show error whn reading library counts
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): wait 30 mins before send first report
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): send number of active players, grouped by client type
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): disable reports when running in dev mode
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): add Dockerfile to the docker build, to avoid `vcs.modified=true`
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): add more linux fs types
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): need admin permissions to retrieve library counts
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): dev flag to disable player insights
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* Completed the translation of zh-Hant and zh-Hans
* Update translation terms in zh-Hans and zh-Hant files
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* feat(insights): initial code (WIP)
* feat(insights): add more info
* feat(insights): add fs info
* feat(insights): export insights.Data
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(insights): more config info
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(insights): move data struct to its own package
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(insights): omit some attrs if empty
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(insights): send insights to server, add option to disable
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): remove info about anonymous login
Signed-off-by: Deluan <deluan@navidrome.org>
* chore(insights): fix lint
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): disable collector if EnableExternalServices is false
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): fix type casting for 32bit platforms
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): remove EnableExternalServices from the collection (as it will always be false)
Signed-off-by: Deluan <deluan@navidrome.org>
* chore(insights): fix lint
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor(insights): rename function for consistency
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(insights): log the data sent to the collector server
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(insights): add last collection timestamp to the "about" dialog.
Also add opt-out info to the SignUp form
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(insights): only sends the initial data collection after an admin user is created
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(insights): remove dangling comment
Signed-off-by: Deluan <deluan@navidrome.org>
* feat(insights): Translate insights messages
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(insights): reporting empty library
Signed-off-by: Deluan <deluan@navidrome.org>
* refactor: move URL to consts.js
Signed-off-by: Deluan <deluan@navidrome.org>
---------
Signed-off-by: Deluan <deluan@navidrome.org>
* fix(artwork): get the first image from vorbis comments, not the last. fixes#3254
This uses a fork for now.
* fix(artwork): prioritize getting embedded types that are listed as "front" covers
* fix: cleanup
* feat(build): add a make target to build a msi installer locally
* Testing wrapping the executable in cmd
* build(ci): build msis in parallel
* feat(server): add LogFile config option
* Revert "Testing wrapping the executable in cmd"
This reverts commit be29592254.
* Adding --log-file for service executable
* feat(ini): wip
* feat(ini): parse nested ini section
* fix(conf): fix fatal error messages
* Now navidrome supports INI, we can use the built-in msi ini system
and not require the VBScript to convert it into toml
* File needs to be called .ini to be parsed as an INI and correct filename
needs to be passed to the service
* fix(msi): build msi locally
* fix(msi): pipeline
* fix(msi): pipeline
* fix(msi): pipeline
* fix(msi): pipeline
* fix(msi): pipeline
* fix(msi): Makefile
* fix(msi): more clean up
* fix(log): convert LF to CRLF on Windows
* fix(msi): config filename should be case-insensitive
* fix(msi): make it a little more idiomatic
* Including the latest windows release of ffmpeg into the msi
as built by https://www.gyan.dev/ffmpeg/builds/ (linked
to on the official ffmpeg source)
* This should version independent
* Need bash expansion for the * to work
* This will run twice, once for x86 and once for x64, I'll make it cache
the executable for now as it'll be quicker
* Silencing wget
* Add ffmpeg path to the config so Navidrome knows where to find it
* refactor: download ffmpeg from our repository
* When going back from the "Are you ready to install?" it should go back to the
Settings dialogue that you just came from
* fix: comments
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* build: new pipeline, new way to cross-compile and build docker images locally. (#3383)
* build: use alternative repositories
* build: fix
* build: validate taglib downloads
* build: control concurrency
* build: validate xx version
* build: remove taglib download validation as the version can be changed as an argument.
* [enhancement]: Provide native backup/restore mechanism
- db.go: add Backup/Restore functions that utilize Sqlite's built-in online backup mechanism
- support automatic backup with schedule, limit number of files
- provide commands to manually backup/restore Navidrome
Notes:
`Step(-1)` results in a read-only lock being held for the entire duration of the backup.
This will block out any other write operation (and may hold additional locks.
An alternate implementation that doesn't block but instead retries is available at https://www.sqlite.org/backup.html#:~:text=of%20a%20Running-,database,-%2F*%0A**%20Perform%20an%20online (easily adaptable to go), but has the potential problem of continually getting restarted by background writes.
Additionally, the restore should still only be called when Navidrome is offline, as the restore process does not run migrations that are missing.
* remove empty line
* add more granular backup schedule
* do not remove files when bypass is set
* move prune
* refactor: small nitpicks
* change commands and flags
* tests, return path from backup
* refactor: small nitpicks
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* First version/rough layout of the required wix to build an MSI that embeds everything
* Don't need revision number
* produced exe from existing build process is navidrome not Navidrome
* Adding Kardianos wrapper around Cobra so the callbacks are handled
automatically (this is basically only for windows)
* Adding pointless check to shut up lint for now
* make format
* Revert disabling npm tidy
* Using Kardianos always will result in the application hanging so it
needs only be wrapped to handle the callbacks if it's being used in
the service context, otherwise use cobra directly
* Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295
* Under Linux this installs a user service (I don't think this is
correct, but lets get this working first). User units/services
cannot depends on system units, so previously this bombed out
with Exit Code 5.
* Under Windows we can install both the x86 and x64 builds, they
will install to different folders, but previously they would
overwrite the service as they were both called Navidrome. Now,
it will install 2 services. This will still be weird/broken as
they will attempt to listen on the same port, however uninstalling
the "wrong" arch will not cause the "right" one to be partially
uninstalled anymore
* Reverting changes to the context as they don't really seem necessary anyway
* Need to consistently name the service
* Fixing broken context
* The included files should be removed when the app is uninstalled
* Reverting back to the original context here, I don't think
it makes any difference to running under kardianos
* Let's see what we have immediately available
* OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky
* Need -r on directory copy, plus we'll probably need to install wixl
* No sudo cmd, so I assume this runs as root
* WORKSPACE!
* Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever
* Might as well put the msi in the right folder, it's tidier
* Writing the version number into the msi, from the output of goreleaser
* Using jq to parse the goreleaser metadata, so need to install it
* MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater
* -r or --raw (on newer versions) means we don't get the "" around the value
* Running as a user service I think makes limited sense for this
* Will now ask for configuration settings during install.
MSI/WiX only supports writing out INI files, Toml is almost
INI compatable, except that the INI needs to write out a section
first, so we need to have a script to strip that off.
We are forced to display a License.rtf file by the UI so I think
the build process should probably rename the default licence file
and that will suffice.
Uninstalling works cleanly, howvever upgrades seem to leave the old
version installed in "programs and features" currently.
Adding the UI has introduced a requirement for WiX 0.103
* Updating the build to include --ext ui for the new config ui
* Configuration dialog should not display for upgrades as the config file
is already written
* Making description consistent with the systemd service and making
the build process produce the required License.rtf
* Fixing " non-constant format string in call to fmt.Errorf (govet)"
* Its a string, not an int; read better.
* Wixl 103 is required for --ext ui, so we need 24.04
* OK this is still installing Wix 0.101, maybe it all needs to be 24.04?
* Switching the builds back to ubuntu-latest (22.04 at current)
as it runs on a custom container, it's actually debian anyway
Moving msi build into its own job so it can run on 24.04 so
we have access to wixl 0.103 for --ext ui support
* Forcing build
* Whitespace fix
* Adding sudo I guess
* Gotta checkout as well
* Adding debugging for when there's soemthing wrong with the paths
* Adding more ls to see if the output has worked
* The msi's are in subdirs
* Actually they're in the ./wix directory
* Still can't find these msi's?
* I think that was being treated literally previously
* No idea why this isn't working, give it a relative path instead?
* Making explicit on the dialogue that the configuration file will be
where the installation dir is
* The lint keeps failing and it's just getting in the way so I'll
turn this off for now and we'll edit out this commit from the merge
* Cutting more out of the build to get more stuff out of the way
* Need to increase the width to fit the text in
* Calling everything License.rtf, presumably one of them is correct
* I am pretty sure the License.rtf loading is broken under Wixl; so
let's just bypass the EULA from the UI which is a nicer experience
for the users anyway
* This needs to be after WelcomeDlg now the Eula isn't displayed
* You're supposed to be able to use <WixVariable> to override the
location that the bmp's are loaded from, I can't get this to work
under wixl so I'm guessing given that the ui extension is new, it
hasn't been implemented with that in mind. So we'll hack it by
overwriting the files installed with the package.
* We should make this less brittle so when wixl is updated it still works
* Re-enabling the lint and tests etc
* Improving the scaling quality and removing borders from images to
tidy them up a tad
* Pretty sure this isn't necessary as MY_PROPERTY will always be false
* Without publishing this event, we can't continue to the next dialogue
however I think we should be able to get away without the property
* Refactoring out the duplication so we only have one service
defined and we can run that either way
* Pushing the Interactive check into the root commmand? Feels like it
is probably getting closer to the right place at least
* go tidy
* OK this didn't work under windows, I'm guessing it's because
it's lacking all the metadata about the service it needs to
report back to Windows on.
* We need to run service execute now so that the windows
service will behave (hopefully)!
* Lint
* go tidy
* Renaming service to "navidrome" rather than "Navidrome" as this
is the filename that systemd writes and it's unusual to have
capital letters in service names under Linux.
Switching to use service execute for Linux to mirror Windows
* Need to provide the arguments to append
* Without passing the context around, the DB isn't closed gracefully
so we end up with with .db-shm and .db-wal files for recovery
* We should log fatal rather than outputting directly to stdout
* go tidy
* refactor: small nitpicks
* fix: terminate service gracefully
---------
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
* refactor(server): replace RangeByChunks with Go 1.23 iterators
* chore: fix comments re: SQLITE_MAX_VARIABLE_NUMBER
* test: improve playqueue test
* refactor(server): don't create a new iterator when it is not required
* fix(ui): update sort mapping for title in mediafile repository
* fix(ui): create sort mapping for username in share repository
* fix(ui): create sort mapping for owner_name in playlist repository
* fix(ui): create sort mapping for username in player repository
* fix(ui): remove sort mapping for track number in mediafile repository
* chore: add todo to change user_name
* fix(scanner): use sort_artist_name when the config PreferSortTags is true - #3285
* revert unwanted modifications
* refactor(server): use cmp.Or to simplify nested ifs
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* [bugfix] player: use userId, other fixes
This PR primarily resolves#1928 by switching the foreign key of `player` from `user.user_name` to `user.id`.
There are also a few other fixes/changes:
- For some bizarre reason, `ip_address` is never returned from `read`/`get`. Change the field to `ip`, which works. Somehow
- Update `players_test.go` mock to also check for user agent, replicating the actual code
- Update `player_repository.go` `isPermitted` to check user id. I don't know how this worked before...
- tests!
- a few places referred to `typ`, when it is really `userAgent`. Change the field names
* baseRequest -> selectPlayer
* remove comment
* update migration, make all of persistence foreign key enabled
* maybe don't forget to save the file first
* Deterministic pagination in random albums sort
* Reseed on first random page
* Add unit tests
* Use rand in Subsonic API
* Use different seeds per user on SEEDEDRAND() SQLite3 function
* Small refactor
* Fix id mismatch
* Add seeded random to media_file (subsonic endpoint `getRandomSongs`)
* Refactor
* Remove unneeded import
---------
Co-authored-by: Deluan <deluan@navidrome.org>
that the scanner was run, the ttlcache was also created each time.
This caused (under testing with 166 genres in the database) the
memory consumed by navidrome to 101.18MB over approx 3 days; 96%
of which is in instances of this cache. Swapping to a singleton
has reduced this to down to ~ 2.6MB
Co-authored-by: Rob Emery <git@mintsoft.net>
* Terminate all mpv instances when stopping Navidrome
* Exit trackSwitcher goroutine when terminating
* Remove potential race condition when starting the Playback device
* Fix lint error
* Removed unused and unneeded vars/functions
* Use device short name in log
* Small refactor
* Small nitpick
* Make start functions more uniform
With synchronized lyrics with repeated text, there is not a guarantee that the repeat is in order (e.g. `[00:00.00][00:10.00] a\n[00:05.00]b`).
This change will post-process lyrics with repeated timestamps in one line to ensure that it is always sorted.
Closes#1032
* feat(album_repository.go): add kodi-style album playcount option - #1032
Signed-off-by: Victor van der Veen <vvdveen@gmail.com>
* fix format issue and remove reference to kodi (now normalized)
Signed-off-by: Victor van der Veen <vvdveen@gmail.com>
* reduced complexity but added rounding
Signed-off-by: Victor van der Veen <vvdveen@gmail.com>
* Use constants for AlbumPlayCountMode values
---------
Signed-off-by: Victor van der Veen <vvdveen@gmail.com>
Co-authored-by: Deluan <deluan@navidrome.org>
* Use the RealIP middleware only behind a reverse proxy
* Fix proxy ip source in tests
* Fix test for PR#2087
The PR did not update the test after changing the behavior, but the test still
passed because another condition was preventing the user from being created in
the test.
* Use RealIP even without a trusted reverse proxy
* Use own type for context key
* Fix casing to follow go's conventions
* Do not apply RealIP middleware twice
* Fix IP source in logs
The most interesting data point in the log message is the proxy's IP, but
having the client IP too can help identify integration issues.
Closes#1737
* wrapping playlist comment in a <Collapse> element
* Extract common collapsible logic into a component
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* bug(core/playback/mpv): jukebox mode under windows - #2767
Use named pipe for socket path under windows during mpv playback, change function name, unexport function
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* bug(core/playback/mpv): jukebox mode under windows - #2767
Fix typo
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* bug(core/playback/mpv): jukebox mode under windows - navidrome#2767
Early return for Close on Windows
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* bug(core/playback/mpv): jukebox mode under windows - navidrome#2767
Update import and run prettier
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* bug(core/playback/mpv): jukebox mode under windows - navidrome#2767
Update function name
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* bug(core/playback/mpv): jukebox mode under windows - navidrome#2767
Create track_close files for both platforms and move MpvTrack Close into new file
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* bug(core/playback/mpv): jukebox mode under windows - navidrome#2767
Create SocketName function for both platforms, restore name of TempFileName
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* bug(core/playback/mpv): jukebox mode under windows - navidrome#2767
Add missing params to SocketName on windows
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* Unexport SocketName, use socketName in NewTrack
---------
Signed-off-by: apkatsikas <apkatsikas@gmail.com>
* Fix album image_files being null.
* Fix small nitpick.
* Use ExecContext instead of Exec.
* Change more columns to not null and set default values.
* Remove columns that don't need to be changed from migration.
* Fix typo.
* Remove unnecessary select statements.
* Remove duplicate code.
* Do not apply changes to radio table.
* Do not apply changes full_text columns and respective indexes.
* Fix musicbrainz columns.
* Rename migration.
* Make ExternalInfoUpdatedAt nullable
* Make Share's timestamps nullable
---------
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
Closes#1417
A smart playlist can use the playlist id for filtering. This can be
used to create combined playlists or to filter multiple playlists.
To filter by a playlist id, a subquery is created that will match the
media ids with the playlists within the playlist_tracks table.
Signed-off-by: flyingOwl <ofenfisch@googlemail.com>
* draft commit
* time to fight pipeline
* round 2 changes
* remove unnecessary line
* fight taglib. again
* make taglib work again???
* add id3 tags
* taglib 1.12 vs 1.13
* use int instead for windows
* store as json now
* add migration, more tests
* support repeated line, multiline
* fix ms and support .m, .mm, .mmm
* address some concerns, make cpp a bit safer
* separate responses from model
* remove [:]
* Add trace log
* Try to unblock pipeline
* Fix merge errors
* Fix SIGSEGV error (proper handling of empty frames)
* Add fallback artist/title to structured lyrics
* Rename conflicting named vars
* Fix tests
* Do we still need ffmpeg in the pipeline?
* Revert "Do we still need ffmpeg in the pipeline?"
Yes we do.
This reverts commit 87df7f6df7.
* Does this passes now, with a newer ffmpeg version?
* Revert "Does this passes now, with a newer ffmpeg version?"
No, it does not :(
This reverts commit 372eb4b0ae.
* My OCD made me do it :P
---------
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
Beep isn't needed anymore since we rely on MPV instead.
The changes to `go.mod` and `go.sum` were done with:
```
go get github.com/faiface/beep@none
go mod tidy
```
Signed-off-by: Dany Marcoux <git@dmarcoux.com>
* Start migration to dbx package
* Fix annotations and bookmarks bindings
* Fix tests
* Fix more tests
* Remove remaining references to beego/orm
* Add PostScanner/PostMapper interfaces
* Fix importing SmartPlaylists
* Renaming
* More renaming
* Fix artist DB mapping
* Fix playlist updates
* Remove bookmarks at the end of the test
* Remove remaining `orm` struct tags
* Fix user timestamps DB access
* Fix smart playlist evaluated_at DB access
* Fix search3
* Optimize pagination, removing offset
* For search, don't add `where` clause for empty queries
* Revert "Replace `COUNT(DISTINCT primary_key)` with `COUNT(*)`"
Genres are required as part of the count queries, so filter by genres work
* Optimize search3 query, using order by id if it is a "" query.
Also fix the optimizePagination query logic
* Allow offset optimizer threshold to be configured
* Update mapping.go
fallback in the case there's no Date tagged but Original Date or Release Date are tagged
* Add tests
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* Update mapping.go
CreatedAt = BirthTime
* Update metadata.go
Add BirthTime() function
* Update spread_fs.go
Replacing djherbis/atime package with djherbis/times, as times includes the functionality of atime
* Update go.mod
remove djherbis/atime, add djherbis/times
* Update mapping.go
time package not used anymore
* Update go.sum
removed djherbis/atime, added djherbis/times
* Update spread_fs.go
revert to previous, cannot get rid of /atime after all since it's a dependency of /fscache
* Update go.mod
djherbis/times 1.6.0 now released
* Update go.sum
new sums
* Update metadata.go
Inverted if statement, more readable
* Update go.mod
format fix
* Update go.sum
format fix
* Update go.sum
format fix
* Update go.sum
format fix
* Update metadata.go
variable name times -> fileProperties
check for errors
* Update metadata.go
reverse order of error check
* Update metadata.go
typo
* Update metadata.go
https://github.com/navidrome/navidrome/pull/2553#issuecomment-1787967615
* wip: API endpoint for creating playlists from m3u files
* wip: get user id from context
* temporarily disable failing test
* custom logic for playlist route to accomodate m3u content type
* incorporate playlist parsing into existing logic in core
* re-enable test
* fix locally failing test
* Address requested changes.
* Improve ImportFile tests.
* Remove ownerID as a parameter of ImportM3U.
* Write tests for ImportM3U.
* Separate ImportM3U test into two.
* Test OwnerID and playlist Name.
---------
Co-authored-by: Sam Watson <SwatsonCodes@users.noreply.github.com>
Co-authored-by: caiocotts <caio@cotts.com.br>
* Adding cache directory to ignore-list
* Adding jukebox-related config options
* Adding DevEnableJukebox config option pls. dummy server
* Adding types and routers
* Now without panic
* First draft on parsing the action
* Some cleanups
* Adding playback server
* Verify audio device configuration
* Adding debug-build target to have full symbol support
* Adding beep sound library pls some example code. Not working yet
* Play a fixed mp3 on any interface access for testing purposes
* Put action code into separate file, adding stringer, more debug output, prepare structs, validation
* Put action parameter parser code where it belongs
* Have a single Action transporting all information
* User fmt.Errorf for error-generation
* Adding wide playback interface
* Use action map for parsing, stringer instead switch stmt.
* Use but only one switch case and direct dispatch, refactoring
* Add error handling and pushing to client
* send decent errormessage, no internal server error
* Adding playback devices slice and load it from config
* Combine config-verification and structure init
* Return user-specific device
* Separate playback server from device
* Use dataStore to retrieve mediafile by id
* WIP: Playlist and start/stop handling. Doing start/stop the hard way as of now
* WIP: set, start and stop work on one single song. More to come
* Dont need to wait for the end
* Merge jukebox_action.go into jukebox.go
* Remove getParameterAsInt64(). Use existing requiredParamInt() instead
* Dont need to call newFailure() explicitly
* Remove int64, use int instead.
* Add and set action now accept multiple ids
* Kickout copy of childFromMediaFile(). It is not needed here.
* Refactoring devices and playbackServer
* Turn (internal) playback.DeviceStatus into subsonic JukeboxStatus when rendering output. Indexes int64 -> int
* Now we have a position and playing status
* Switching gain to float32, xs:float is defined as 32 bit. Fixing nasty copy/pointer bug
* Now with volume control
* Start working the queue
* Remove user from device interface
* Rename function GetDevice -> GetDeviceForUser to make intention clearer
* Have a nice stringer for the queue
* User Prepared boolean for now to allow pause/unpause
* Skipping works, but without offsets
* Make ChildFromMediaFile public to be used in jukebox get() implementation
* Return position in seconds and implement offset-skip in seconds
* Default offset to 0
* Adding a simple setGain implementation
* Prepare for transcoding AAC
* WIP: transcode to WAV to use beeps wav decoder. Not done yet.
* WIP: out of sheer desparation: convert to MP3 (which works) rather than WAV to troubleshoot issue.
* Use FLAC as intermediate format to play Apple AAC
* A bit of cleanup
* Catching the end-of-stream event for further reactions
* Have a trackSwitching goroutine waiting on channel when track ends
* Move decoder code into own file. Restructure code a bit
* Now with going on to play the next song in the playlist
* Adding shuffle feature
* Implementing remove action
* Cleanup code
* Remove templates for ffmpeg mp3 generation. Not needed anymore.
* Adding some documentation
* Check whether offset into track is in range. Fixing potential remove track bug. Documentation
* Make golangci-lint happy: handling return values
* Adding test suite and example dummy for playback package
* Adding some basic queue tests
* Only use Jukebox.Enabled config option
* Adding stream closing handling
* Pass context.Context to all PlaybackDevice methods
* Remove unneeded function
* Correct spelling
* Reduce visibility of ChildFromMediaFile
* Decomplicate action-parsing
* Adding simple tempfile-based AAC->FLAC transcoding. No parallel reading and writing yet.
* Try to optimize pipe-writing, tempfile-handling and reading. Not done yet.
* Do a synchronous copy of the tempfile. Racecondition detected
* More debugging statements and fixing the play/pause bug. More work needed
* Start the trackSwitcher() with each device once. Return JSON position even if its 0. More debug-output
* Moving all track-handling code into own module
* Fix typo. Do not pass ctx around when not applicable
* WIP: More refactoring, debugging output
* Fix nil pointer
* Repairing MP3 playback by pinning indirect dependencies: hajimehoshi/go-mp3 and hajimehoshi/oto
* Do not forget to cleanup after a skip action
* Make resync with master easy
* Adding missing mocks
* Adding missing error-handling found by linter
* Updating github.com/hajimehoshi/oto
* Removing duplicate function
* Move BEEP-related code into own package
* Juggle beep-related code around as preparation for interface access
* More refactoring for interface separation
* Gather CloseDevice() behind Track interface.
* Adding skeleton, draft audio-interface using mpv.io
* Adding majority of interface commands using messages to mpv socket.
* Adding end-of-stream handling
* MPV: start/stop are working
* postition is given in float in mpv
* Unify Close() and CloseDevice(). Using temp filename for controlling socket
* Wait until control-socket shows up. Cleanup socket in Close()
* Use canceable command. Rename to Executor
* Skipping tracks works now
* Now with actually setting the position
* Fix regain
* Add missing error-handling found by linter
* Adding retry mode on time-pos property getter
* Remove unneeded code on queue
* Putting build-tag beep onto beep files
* Remove deprecated call to rand.Seed()
"As of Go 1.20 there is no reason to call Seed with a random value. Programs that call Seed with a known value to get a specific sequence of results should use New(NewSource(seed)) to obtain a local random generator."
* Using int32 to conform to Subsonic API spec
* Fix merge error
* Minor style changes
* Get username from context
---------
Co-authored-by: Deluan <deluan@navidrome.org>
* Add support for lyrics tag `unsynced_lyrics`
* Update metadata.go
* Update metadata.go
resolve lint issue
* format the code with `goimports`
format the code with `goimports`
* Fix MB recording ID parameter name for ListenBrainz submission
This follows the ListenBrainz API documentation.
Fixes#1657
* Rename MediaFile.MbzTrackID to MbzRecordingID
This better reflects the actual data. That the MusicBrainz
recording ID is stored in file metadata as musicbrainz_trackid
is a historical artifact.
* Rename database column mbz_track_id to mbz_recording_id
* Set all clients to dev_download for make get-music
* Use multiple TranscodingCache instances in tests
This fixes flaky tests. The issue is that the TranscodingCache object
was being reused in tests from media_stream_Internal_test.go and
media_stream_test.go. If tests from the former was run first, the cache
would be filled up, so that when running tests from the latter, the `NON
seekable` test would fail.
* Allow configuring cache folder
This commit introduces a new configuration option to configure the cache
folder. This allows the cache to be in a separate folder such as
/var/cache/navidrome on Linux distributions.
* Fix tests
* Removed unused test setup code
---------
Co-authored-by: Deluan <deluan@deluan.com>
Co-authored-by: Deluan <deluan@navidrome.org>
Changes the default transcoding commands to only use the first audio
stream, instead of the first arbitrary stream.
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
* fix(persistence): Update play_date on scrobble only when newer - #2262
Signed-off-by: Xidorn Quan <me@upsuper.org>
* expand iff
---------
Signed-off-by: Xidorn Quan <me@upsuper.org>
* playlist view: optionally show genre and comment columns
* Remove genre from Playlist columns, as it is not a valid attribute of playlist
Co-authored-by: Deluan <deluan@navidrome.org>
* Create accounts automatically when authenticating from HTTP header
* Disable password check when header auth is enabled
* Formatting
* Password change is valid when no password (old or new) is provided
* Test suite runs with header auth disabled (mock config)
Prevents nil pointer access (panic) while testing password validating logic
* Use a constant prefix for autogenerated passwords (header auth case)
* Add tests
* Add context to log messages
Co-authored-by: Deluan <deluan@navidrome.org>
* feat: Add metrics worker
* refactor: Add todos for useful for metrics methods
* feat: Run MetricsWorker is Prometheus is Enabled
* refactor: Unused low-level variable was removed in metrics
* feat: No worker for metrics, add more
* refactor: Unnecessary todo removed
* refactor: Remove dead unused constant
* Reduce metrics public interface
Co-authored-by: Deluan <deluan@navidrome.org>
* persistence/genre: change Put() to upsert
Absolutely disgusting hack to work around [1]. Try to insert the genre,
but if it conflicts, ignore it and update the genre with the existing
ID.
[1]: https://github.com/navidrome/navidrome/issues/1918.
* scanner: remove cached genre repository
Not needed anytmore. And remember:
"Many Small Queries Are Efficient In SQLite" [1].
[1]: https://www.sqlite.org/np1queryprob.html
* Revert "scanner: remove cached genre repository"
This reverts commit c5d900aa43.
* Use squirrel to build SQL, to reduce risk of SQL injection
Co-authored-by: Deluan <deluan@navidrome.org>
* lastfm album.getInfo, getAlbuminfo(2) endpoints
* ... for description and reduce not found log level
* address first comments
* return all images
* Update migration timestamp
* Handle a few edge cases
* Add CoverArtPriority option to retrieve albumart from external sources
* Make agents methods more descriptive
* Use Last.fm name consistently
Co-authored-by: Deluan <deluan@navidrome.org>
* ReplayGain support
- extract ReplayGain tags from files, expose via native api
- use metadata to normalize audio in web player
* make pre-push happy
* remove unnecessary prints
* remove another unnecessary print
* add tooltips, see metadata
* address comments, use settings instead
* remove console.log
* use better language for gain modes
* add internet radio support
* Add dynamic sidebar icon to Radios
* Fix typos
* Make URL suffix consistent
* Fix typo
* address feedback
* Don't need to preload when playing Internet Radios
* Reorder migration, or else it won't be applied
* Make Radio list view responsive
Also added filter by name, removed RadioActions and RadioContextMenu, and added a default radio icon, in case of favicon is not available.
* Simplify StreamField usage
* fix button, hide progress on mobile
* use js styles over index.css
Co-authored-by: Deluan <deluan@navidrome.org>
* Don't cache transcoded files if the request was cancelled (or there was a transcoding error)
* Add context to logs
* Simplify Wait error handling
* Fix flaky test
* Change log level for "populating cache" error message
* Small cleanups
* Add global downsampling feature
* Default to Opus & consider player transcoder
* Add a test case for DefaultDownsamplingFormat
Co-authored-by: Deluan <deluan@navidrome.org>
* fix(taglib): Fix misleading error message on unreadable media - #1576
Signed-off-by: reo <reo_999@proton.me>
* fix(taglib): Add unit test and exclude scan for only unreadable file - #1576
Signed-off-by: reo <reo_999@proton.me>
* fix(taglib): Add unit test and exclude scan for only unreadable file - #1576
Signed-off-by: reo <reo_999@proton.me>
* fix(taglib): Add unit test and exclude scan for only unreadable file - #1576
Signed-off-by: reo <reo_999@proton.me>
* fix(taglib): Add unit test and exclude scan for only unreadable file - #1576
Signed-off-by: reo <reo_999@proton.me>
* fix(taglib): Add unit test and exclude scan for only unreadable file - #1576
Signed-off-by: reo <reo_999@proton.me>
* Fix test and simplify code a bit
We don't need to expose the type of error: `taglib.Parse()` always return nil
* Fix comment
Signed-off-by: reo <reo_999@proton.me>
Co-authored-by: Deluan <deluan@navidrome.org>
* Corrected some Simplified Chinese translations
* Fix wrong expression symbols in Traditional Chinese translation
* Modify punctuation to Chinese punctuation in Chinese translation
Add spaces between Chinese and English words in Chinese translation
* Added missing Traditional Chinese translation
* Improve some Chinese translations
* Remove redundant punctuation in Traditional Chinese translation
* Adjust the order of fields in `zh-Hans` and `zh-Hant` to be consistent with `en`
* Re-add tpbnick's Nord theme
* Run Prettier formatter on Nord theme
* Update themes index
* Fix button margins
* Modernise the look of switches
* Adjust margins and padding
* Fix sidebar's background colour not applying to all of sidebar when scrolling down
* Adjust App Bar box shadow
* Adjust roundedness
* Adjust shadows
* Adjust outlined inputs
* Add transitions to items in sidebar when hovered / losing hover
* Adjust border radiuses
* Adjust pagination buttons
* Add big play button from Spotify theme
* Remove playlist background gradient
* Adjust colour of MuiChip elelments
* Adjust table borders
* Remove duplicate MuiTableRow key
* Attempt to make switches in both the playlist section and settings section visable against background & the toggle. Not ideal.
* Style the player
* Format CSS to Prettier standards
* Fix mobile player style
* Make play button in album grid view blue
* Make main view background lighter
* Allow ArtistExternalLink icons to be styled
* Allow AlbumExternalLink icons to be styled
* Standardize external links' classes to kebab-case
Co-authored-by: Deluan <deluan@navidrome.org>
* add new translations
* translation: fix improper full width character usage in zh-Hans translation
Full width % messed up with format strings.
* translation: fix two machine translations in zh-Hans
* translation: fix one mistranslation in zh-Hans
* translation: fix format in zh-Hans
* translation: fix format and two translations in zh-Hans
* translation: fix format in zh-Hans
* feat: Add listenbrainz base url configuration
- ListenBrainz.BaseURL config value
* Don't need to store baseUrl
* Use `url.JoinPath` to concatenate url paths
* Replace url.JoinPath (Go 1.19 only) with custom function
Co-authored-by: Deluan <deluan@navidrome.org>
* None is deprecated and will fallback to Lax in the future.
* Using Strict is future proof and provides additional CSR protection
Signed-off-by: Manuel Kroeber <manuel.kroeber@gmail.com>
Signed-off-by: Manuel Kroeber <manuel.kroeber@gmail.com>
* fix: make signaler exit on cancel
`break` is incorrect here, as it just breaks out of the select.
`return` to exit the function instead.
Fixes#1636.
Signed-off-by: Ian Kerins <ianskerins@gmail.com>
* fix: exit non-zero on fatal error
Signed-off-by: Ian Kerins <ianskerins@gmail.com>
* Adding 'x-content-duratin' and 'x-total-count' to CORS exposed headers
* Moving cors setup to middlewares.go
* adding x-nd-authorization to exposed headers
* Refactor session_keys to its own package
* Adjust play_tracker
- Don't send external NowPlaying/Scrobble for tracks with unknown artist
- Continue to the next agent on error
* Implement ListenBrainz Agent and Auth Router
* Implement frontend for ListenBrainz linking
* Update listenBrainzRequest
- Don't marshal Player to json
- Rename Track to Title
* Return ErrRetryLater on ListenBrainz server errors
* Add tests for listenBrainzAgent
* Add tests for ListenBrainz Client
* Adjust ListenBrainzTokenDialog to handle errors better
* Refactor listenbrainz.formatListen and listenBrainzRequest structs
* Refactor agent auth_routers
* Refactor session_keys to agents package
* Add test for listenBrainzResponse
* Add tests for ListenBrainz auth_router
* Update ListenBrainzTokenDialog and auth_router
* Adjust player scrobble toggle
* Extract version from directory name if .git dir is missing
* Avoid using shell
* Remove .gitinfo build from pipeline
* Fix git-detecting rule to be robust in presence of setup-git
* Add function 'isSynced' that identifies if lyrics are synced or not and add tests for the same
* implement 'getLyrics' which returns lyrics if they exist
Signed-off-by: Dheeraj Lalwani <lalwanidheeraj1234@gmail.com>
* remove timestamps frorom the the lyrics if they are synced, fix filters & clean up code
Signed-off-by: Dheeraj Lalwani <lalwanidheeraj1234@gmail.com>
* add snapshot tests for the 'Lyrics' response & add some clean up
Signed-off-by: Dheeraj Lalwani <lalwanidheeraj1234@gmail.com>
* add tests for 'GetLyrics' function
Signed-off-by: Dheeraj Lalwani <lalwanidheeraj1234@gmail.com>
* update the snapshot test & the test for 'GetLyrics' function
Signed-off-by: Dheeraj Lalwani <lalwanidheeraj1234@gmail.com>
* Seperate mobile desktop components
* Fix err
* Rename classes and fix some styles
* Add lastFM button and remove console log
* Add Mbiz Icon
* render bio as dangerouslySetInnerHTML and remove unused css classes
* Add Fav and Stars
* Remove unstandardised class selector
* Remove ext link from m view
* Fix naming and simplify rounded styling
* Refactor ArtistShow:
- Extracted DesktopArtistDetails to its own file
- Removed album count as it was incorrect, it is not considering compilations
- Show bio and image from Native API, if it is available, before calling `getArtistInfo`
Co-authored-by: Deluan <deluan@navidrome.org>
* Rename manifest.json to manifest.webmanifest
browser consoles keep complaining that the manifest doesn't have the `.webmanifest` extension.
* FIx manifest.webmanifest references
Co-authored-by: Deluan <deluan@navidrome.org>
* Check goimports in the pipeline
* Check goimports in the pipeline
* Check goimports in the pipeline
* go mod tidy
* wip
* wip
* Fix goimports and go:build tags
* Run golangci-lint before goimports
* Use local copy of workbox service worker scripts
* Refactor workbox integration:
- Only add prod js, without maps. Reduces the size from 170k to 24k
- Removed it from build. As it is small now, we can add it to source, and have a script to just update it whenever it is required
- Fixed relative paths in navidrome-service-worker.js, should now work with BaseUrl != ''
Co-authored-by: Deluan <deluan@navidrome.org>
* Configure fetching from API and route
* pretty
* Remove errors
* Remove errors
* Remove errors
* Complete page for Desktop view
* Fix error
* Add xs Artist page
* Remove unused import
* Add styles for theme
* Change route path
* Remove artId useEffect array
* Remove array
* Fix cover load err
* Add redirect on err
* Remove route
* What's in a name? consistency :)
* Fix err
* Fix UI changes
* Fetch album from resource
* Renaming done
* Review changes
* Some touch-up
* Small refactor, to make naming and structure more consistent with AlbumShow
* Make artist's album list similar to original implementation
* Reuse AlbumGridView, to avoid duplication
* Add feature flag to enable new Artist Page, default false
* Better biography styling. Small refactorings,
* Don't encode quotes and other symbols
* Moved AlbumShow to correct folder
Co-authored-by: Deluan <deluan@navidrome.org>
Syntax is Ant-style Globs, with support for '**' (any subfolder). Default: '.:**' (or '.;**' in Windows`, meaning all folders and subfolders under `MusicFolder`
* Show playlists in sidebar menu
* Fix menu
* Refresh playlist submenu when adding new playlist
* Group shared playlists below user's playlists
* Fix text overflow in menu options
* Add button in playlist menu to go to Playlists list
* Add config option `DevSidebarPlaylists` to enable this feature (default false)
* Added back button
* Added back button
* Added back button
* Fixed Album size overflow
* Fixed Album size overflow
* Fixed album size overflowing
* Fixed album size overflowing
* Fixed album size overflowing
* Fixed album size overflow on small screen
* Changes reverted in PlayerEdit.js
* prettier formatting issue resolved
Co-authored-by: Deluan <deluan@navidrome.org>
* Don't include updatedAt field when fetching album art placeholder. This will allow browers to cache the place holder
* Apply resizing to placeholder image
* Fix issues discovered by CI linter and prettier
* Updates from PR review
* Use wchar_t for tagLib filenames on Windows
* Make TagLib default extractor for all platforms.
* Organize imports
Co-authored-by: Deluan <deluan@navidrome.org>
* Disable mobile player cover animation when EnableCoverAnimation is set to false. Also increase cover art size and remove rounded borders.
* Display song album and year in mobile player view
* Remove default singer element from mobile player and reduce vertical white space
* Only add song year if it exists
* Add song year to desktop player when present
* Increase non-animated cover size to 85% and set a limit on the width of 600px.
* Explain what what the styles impact
* Remove unused style for songArtist
* Apply prettier
* Adjust player styles to handle nonsquare album art better. Should probably push this upstream too
* Also fix desktop player's handling of non square cover art.
* added a dependency npm was complaining about
added playlist to album actions
* removed chokidar dependency
Co-authored-by: Skrtansh Rajput <srajput@alienvault.com>
* Make authentication part of the server, so it can be reused outside the Native API
This commit has broken tests after a rebase
* Serve frontend assets from `server`, and not from Native API
* Change Native API URL
* Fix auth tests
* Refactor server authentication
* Simplify authProvider, now subsonic token+salt comes from the server
* Don't send JWT token to UI when authenticated via Request Header
* Enable ReverseProxyWhitelist to be read from environment
* Call Last.FM's getInfo again without mbid when artist is not found
* Call Last.FM's getSimilar again without mbid when artist is not found
* Call Last.FM's getTopTracks again without mbid when artist is not found
* Upgrade to CRA 4.0.3
* Try to fix tests. No lucky
* Fix new ESLint errors
* Fix JS tests and remove unwanted dependency. (#1106)
* Fix tests
* Fix lint
* Remove React v16 workaround (fixed in v17)
* Force eslint to break on warnings
* Lint now needs to be called explicitly in the pipeline
Co-authored-by: Yash Jipkate <34203227+YashJipkate@users.noreply.github.com>
* Swedish translation
* Updated and renamed to sv.json
Added further lines/translations from the english.json and corrected some of the previous translations
* Update sv.json
* Update sv.json
Ok now i'm done! :P
* Show more descriptive success messages for User actions
* Check username uniqueness when creating/updating User
* Adjust translations
* Add tests for `validateUsernameUnique()`
Co-authored-by: Deluan <deluan@navidrome.org>
See https://pkg.go.dev/github.com/robfig/cron#hdr-CRON_Expression_Format for expression syntax.
`ScanInterval` will still work for the time being. The only situation it does not work is when you want to disable periodic scanning by setting `ScanInterval=0`. If you want to disable it, please set `ScanSchedule=""`
Closes#1085
* BPM metadata enhancement
Related to #1036.
Adds BPM to the stored metadata about MediaFiles.
Displays BPM in the following locations:
- Listing songs in the song list (desktop, sortable)
- Listing songs in playlists (desktop, sortable)
- Listing songs in albums (desktop)
- Expanding song details
When listing, shows a blank field if no BPM is present. When showing song details, shows a question mark.
Updates test MP3 file to have BPM tag. Updated test to ensure tag is read correctly.
Updated localization files. Most languages just use "BPM" as discovered during research on Wikipedia. However, a couple use some different nomenclature. Spanish uses PPM and Japanese uses M.M.
* Enhances support for BPM metadata extraction
- Supports reading floating point BPM (still storing it as an integer) and FFmpeg as the extractor
- Replaces existing .ogg test file with one that shouldn't fail randomly
- Adds supporting tests for both FFmpeg and TagLib
* Addresses various issues with PR #1087.
- Adds index for BPM. Removes drop column as it's not supported by SQLite (duh).
- Removes localizations for BPM as those will be done in POEditor.
- Moves BPM before Comment in Song Details and removes BPM altogether if it's empty.
- Omits empty BPM in JSON responses, eliminating need for FunctionField.
- Fixes copy/paste error in ffmpeg_test.
Imported redacting code from https://github.com/whuang8/redactrus (thanks William Huang)
Didn't use it as a dependency as it was too small and we want to keep dependencies at a minimum
* Handle subdirectories without rx permission correctly
Allow ogg files w/o metadata, having taglib behave more like ffmpeg
* Fix test for walk_dir_tree, fix full reading of files in permission-
constrained directories, allow directories with leading ellipses
* Sorted directory traversal is preferred, and cleanup tests
* Small refactoring to clean-up `loadDir` function and to remove some "warnings" from IntelliJ
Co-authored-by: Deluan <deluan@navidrome.org>
This gives more space for the song and artist names in the player
* fix min-width of AlbumDetails
* Fix song play time display
* Song duration display fix#2
* Removed important
* Resolve conflicts
* Update Player.js
* Change breakdown and hide volume
Co-authored-by: Deluan <deluan@navidrome.org>
* Add support for multiple playlists
* Fix lint
* Remove console log comment
* Disable 'check' when loading
* Fix lint
* reset playlists on closeAddToPlaylist
* new playlist: accomodate string type on enter
* Fix lint
* multiple new playlists are added correctly
* use makestyle()
* Add tests
* Fix lint
* refactored some styles in jinkieplayer
* fix: refactored some styles in jinkie player and removed br tag - #865
* fix: refactored some styles in jinkie player and removed br tag - #865
Signed-off-by: armedev <epiratesdev@gmail.com>
* add icons
* add logic to change the icon
* make the active menu bold
* Encapsulate the dynamic icon behaviour into a self-contained component
Co-authored-by: Deluan <deluan@navidrome.org>
* Added Star Rating functionality for Songs
* Added Star Rating functionality for Artists
* Added Star Rating functionality for AlbumListView
* Added Star Rating functionality for AlbumDetails and improved typography for title
* Added functionality to turn on/off Star Rating functionality for Songs
* Added functionality to turn on/off Star Rating functionality for Artists
* Added functionality to turn on/off Star Rating functionality for Albums
* Added enableStarRating to server config
* Resolved the bugs and improved the ratings functionality.
* synced repo and removed duplicate key
* changed the default rating size to small, and changed the color to match the theme.
* Added translations for ratings, and Top Rated tab in side menu.
* Changed rating translation to topRated in albumLists, and added has_rating filter to topRated.
* Added empty stars icon to RatingField.
* Added sortable=false in AlbumSongs and added sortByOrder=DESC in all List components.
* Added translations for rating, for artists and albums, and removed the sortByOrder=DESC from SimpleLists.
* added quality info
* fixed formatting
* implemented various suggestions
* npm run prettier
* applied suggestions
* npm run prettier
* corrected lossless formats and other suggestions
* moved losslessformats into consts.js
* added some test
* typo while resolving conflicts
* fetch
* removed a bug causing component (as suggested)
* Update PlayerToolbar.js
* implemented suggestions
* added few more tests
* npm run prettier
* added size
* updated qualityInfo
* implemented suggestions
* added test for when no record is recieved
* Update QualityInfo.js
* fix(ui/src/album): White play button on hover for all themes - #960
* fix(PlayButton) : White play button for light theme - #960
* fix(PlayButton) : White play button for light theme - #960
* bug(AlbumGridView.js) - Album play button defaults to white, can be overridden - #960
Signed-off-by: Shishir <shishir.srik@gmail.com>
* bug(AlbumGridView.js) - Album play button defaults to white, can be overridden - #960
* Reverted package.json and package-lock.json - #960
Signed-off-by: Shishir <shishir.srik@gmail.com>
* Missing lint script added - #960
Signed-off-by: Shishir <shishir.srik@gmail.com>
* Removed color, added className and made record required in PlayButton.propTypes - #960
* added new theme - night
* removed a unused field
* fixed a typo from previous change
* night theme in login window
* changed name
changed the theme name from "Night" to "Extra Dark"
* changed the theme name
* Update index.js
* Rename night.js to extradark.js
* trying something
* formatted
the JS build was failing because I haven't formatted the index.js file with prettier. I got to know about this now.
I think now it will be resolved.
* Fix the Album Details UI to look similar to Song Details UI
* Remove the unused components
* Fix the gap between row and the first field in the details view
* Fix the width of the row of Album Details UI
* [Theme] Allow customising album and player parts
* [Theme] Allow customizing song lists view
* Make spotify-ish more spotify-ish
* Fix responsive issues in spotify-ish
* Spotify-ish login page
* Add back the previous "Spotify-ish" theme as "Green"
Co-authored-by: Deluan <deluan@navidrome.org>
* Added option to enable/disable favorites in Song
* Added option to enable/disable favorites in Artist
* Added option to enable/disable favorites in Albums and Favorites tab in sidebar
* Added option to enable/disable favorites in Player
* Set default value of enableFavourites as true
* Improved the functionality to enable/disable Favorites
* Add `EnableFavourites` config option
Co-authored-by: Deluan <deluan@navidrome.org>
* Added setRating feature to AlbumListView
* Refactored the iconography from ⭐ to ❤️
* Refactored the current component from StarButton to LoveButton
* Refactored all translations from Starred to Loved, and all props from showStar to showLove
* Refactored useToggleStar hook to useToggleLove
* rebased repository from master and removed stray commmits
* Refactored handler name from TOGGLE_STAR to TOGGLE_LOVE in PlayerToolbar.js
* Change "starred" translation to "Favorite"
Co-authored-by: Deluan <deluan@navidrome.org>
* added new component SONGSIMPLELIST for smaller displays
* added new component SONGSIMPLELIST for smaller displays
* added new component SONGSIMPLELIST for smaller displays
* Updated songsimplelist
Removed truncation
* removed garbage code
* refactored some issues of overlapping
* refactored some issues of overlapping
* changed the song ui design
* refactored some bugs in artist display
* refactored some bugs in artist display
* removed garbage dependencies
* removed div bugs
* added all the logic to the component itself
* Make the version number clickable for the SNAPSHOT version while using development docker build
* Update the snapshot version link in to view list of commits since the release
* Create a new component for the link to the version
* Add tests and refactored a bit
Co-authored-by: Deluan <deluan@navidrome.org>
* Auto theme preference added
* Fix lint
* Add and use AUTO from consts
* Add shared custom hook to get current theme
* Moved up 'Auto' choice
* AUTO -> AUTO_THEME_ID & extract useCurrentTheme to file
* Liberalise theme setting
* Add tests
* Use new embed functionality for serving UI assets
* Use new embed functionality for serving resources. Remove dependency on go-bindata
* Remove Go 1.15
This will allow to use 'embed' and 'fs' packages.
This also makes the check for the Go environment when running the
Makefile fail if Golang version isn't 1.16.x
This caused a panic and needs more investigation:
http: superfluous response.WriteHeader call from github.com/go-chi/chi/middleware.Recoverer.func1.1 (recoverer.go:33)
panic: interface conversion: *middleware.compressResponseWriter is not io.ReaderFrom: missing method ReadFrom
-> github.com/go-chi/chi/middleware.(*httpFancyWriter).ReadFrom
-> /Users/deluan/go/pkg/mod/github.com/go-chi/chi@v1.5.2/middleware/wrap_writer.go:135
If files cannot be sorted by disc and track id, try by artist then
title.
One use case is a loose compilation of files with same album, album
artist, and no track numbers. File order was then undetermined, in
practice depended on insertion order in the database.
This is a workaround for rclone not changing the directory modtime when you delete all folders from it (happens when you are moveing things around with beets)
External services do not use these unicode chars. Ex:
- “Weird Al” Yankovic
- Bachman–Turner Overdrive
- The Go‐Go’s
are not found in Last.FM and Spotify
* add size to album details
for #534
* addressing review comments:
* create index album(size)
* remove unneeded Size field from refresh struct
* add whitespace to album details
* add size to album list view
* prettier
Not sure the reason, but I got this error:
```
Cannot read property 'id' of undefined
at tn (SongTitleField.js:35)
at Ka (react-dom.production.min.js:153)
at vl (react-dom.production.min.js:261)
at sc (react-dom.production.min.js:246)
at lc (react-dom.production.min.js:246)
```
This implements basic tests for functionality related to loading and
processing external album covers, both on the scanning size, and on the
display side.
Files that match the `CoverArtPriority` setting will now be considered
eligible only if their extensions are of an 'image/*' MIME type (e.g.
'.png' for 'image/png', '.jpg' for 'image/jpeg'). This prevents matching
files that will likely not be valid during display.
In addition to the above, code for returning the cover image file from
scanned data will also check against the MIME type for the path stored,
instead of attempting to re-trace `CoverArtPriority` matches. This
simplifies the code and bypasses a number of edge-cases related to
inconsistent matching.
When checking stored references to cover images (whether embedded or
external), it's possible that configured patterns do no match, and a
valid error should be returned in those cases.
This commit adds support for loading cover art from media file
directories, according to configured filename priorities (of which an
additional, special choice of `embedded` is given).
Cover art paths are resolved during scanning and stored in the database
as part of the `album.cover_art_path` column; if embedded cover art is
matched, this will default to the path of the media file itself, and if
no cover art is matched at all.
Similarly, the `album.cover_art_id` column will default to a reference
to `media_file.id` if embedded cover art is wanted, but if an external
cover art file is matched, this will instead be set to a reference to
the `album.id` value itself, prefixed with the `al-` constant.
Stored cover art paths are once again resolved and matched against
configuration when covers are requested; that is, any change in
configuration between scanning and requesting cover art may not return
correct data until a re-scan is complete.
Tests will be added in future commits.
description:Before opening a new issue, please search to see if an issue already exists for the bug you encountered.
title:"[Bug]: "
labels:["bug","triage"]
#assignees:
# - deluan
body:
- type:markdown
attributes:
value:|
### Thanks for taking the time to fill out this bug report!
- type:checkboxes
id:requirements
attributes:
label:"I confirm that:"
options:
- label:I have searched the existing [open AND closed issues](https://github.com/navidrome/navidrome/issues?q=is%3Aissue) to see if an issue already exists for the bug I've encountered
required:true
- label:I'm using the latest version (your issue may have been fixed already)
required:false
- type:input
id:version
attributes:
label:Version
description:What version of Navidrome are you running? (please try upgrading first, as your issue may have been fixed already).
validations:
required:true
- type:textarea
attributes:
label:Current Behavior
description:A concise description of what you're experiencing.
validations:
required:true
- type:textarea
attributes:
label:Expected Behavior
description:A concise description of what you expected to happen.
validations:
required:true
- type:textarea
attributes:
label:Steps To Reproduce
description:Steps to reproduce the behavior.
placeholder:|
1. In this scenario...
2. With this config...
3. Click (or Execute) '...'
4. See error...
validations:
required:false
- type:textarea
id:env
attributes:
label:Environment
description:|
examples:
- **OS**: Ubuntu 20.04
- **Browser**: Chrome 110.0.5481.177 on Windows 11
- **Client**: DSub 5.5.1
value:|
- OS:
- Browser:
- Client:
render:markdown
- type:dropdown
id:distribution
attributes:
label:How Navidrome is installed?
multiple:false
options:
- Docker
- Binary (from downloads page)
- Package
- Built from sources
validations:
required:true
- type:textarea
id:config
attributes:
label:Configuration
description:Please copy and paste your `navidrome.toml` (and/or `docker-compose.yml`) configuration. This will be automatically formatted into code, so no need for backticks.
render:toml
- type:textarea
id:logs
attributes:
label:Relevant log output
description:Please copy and paste any relevant log output (change your `LogLevel` (`ND_LOGLEVEL`) to debug). This will be automatically formatted into code, so no need for backticks. ([Where I can find the logs?](https://www.navidrome.org/docs/faq/#where-are-the-logs))
render:shell
- type:textarea
attributes:
label:Anything else?
description:|
Links? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach screenshots by clicking this area to highlight it and then dragging files in.
- type:checkboxes
id:terms
attributes:
label:Code of Conduct
description:By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/navidrome/navidrome/blob/master/CODE_OF_CONDUCT.md).
options:
- label:I agree to follow Navidrome's Code of Conduct
This issue has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.
pr-comment:>
This pull request has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.
- uses:actions/stale@v9
with:
operations-per-run:999
days-before-issue-stale:180
days-before-pr-stale:180
days-before-issue-close:30
days-before-pr-close:30
stale-issue-message:>
This issue has been automatically marked as stale because it has not had
recent activity. The resources of the Navidrome team are limited, and so we are asking for your help.
If this is a **bug** and you can still reproduce this error on the <code>master</code> branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a **feature request**, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.
stale-pr-message:This PR has been automatically marked as stale because it has not had
recent activity. The resources of the Navidrome team are limited, and so we are asking for your help.
Please check https://github.com/navidrome/navidrome/blob/master/CONTRIBUTING.md#pull-requests and verify that this code contribution fits with the description. If yes, tell it in a comment.
This PR will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.
Navidrome is a streaming service which allows you to enjoy your music collection from anywhere. We'd welcome you to contribute to our open source project and make Navidrome even better. There are some basic guidelines which you need to follow if you like to contribute to Navidrome.
- [Asking Support Questions](#asking-support-questions)
- [Code of Conduct](#code-of-conduct)
- [Issues](#issues)
- [Pull Requests](#pull-requests)
## Asking Support Questions
We have an active [discussion forum](https://github.com/navidrome/navidrome/discussions) where users and developers can ask questions. Please don't use the GitHub issue tracker to ask questions.
## Code of Conduct
Please read the following [Code of Conduct](https://github.com/navidrome/navidrome/blob/master/CODE_OF_CONDUCT.md).
## Issues
Found any issue or bug in our codebase? Have a great idea you want to propose or discuss with
the developers? You can help by submitting an [issue](https://github.com/navidrome/navidrome/issues/new/choose)
to the GitHub repository.
**Before opening a new issue, please check if the issue has not been already made by searching
the [issues](https://github.com/navidrome/navidrome/issues)**
## Pull requests
Before submitting a pull request, ensure that you go through the following:
- Open a corresponding issue for the Pull Request, if not existing. The issue can be opened following [these guidelines](#issues)
- Ensure that there is no open or closed Pull Request corresponding to your submission to avoid duplication of effort.
- Setup the [development environment](https://www.navidrome.org/docs/developers/dev-environment/)
- Create a new branch on your forked repo and make the changes in it. Naming conventions for branch are: `<Issue Title>/<Issue Number>`. Example:
```
git checkout -b adding-docs/834 master
```
- The commits should follow a [specific convention](#commit-conventions)
- Ensure that a DCO sign-off for commits is provided via `--signoff` option of git commit
- Provide a link to the issue that will be closed via your Pull request.
### Commit Conventions
Each commit message must adhere to the following format:
```
<type>(scope): <description> - <issue number>
[optional body]
```
This improves the readability of the messages
#### Type
It can be one of the following:
1.**feat**: Addition of a new feature
2.**fix**: Bug fix
3.**sec**: Fixing security issues
4.**docs**: Documentation Changes
5.**style**: Changes to styling
6.**refactor**: Refactoring of code
7.**perf**: Code that affects performance
8.**test**: Updating or improving the current tests
9.**build**: Changes to Build process
10.**revert**: Reverting to a previous commit
11.**chore** : updating grunt tasks etc
If there is a breaking change in your Pull Request, please add `BREAKING CHANGE` in the optional body section
#### Scope
The file or folder where the changes are made. If there are more than one, you can mention any
#### Description
A short description of the issue
#### Issue number
The issue fixed by this Pull Request.
The body is optional. It may contain short description of changes made.
Following all the guidelines an ideal commit will look like:
docker-image:##@Cross_Compilation Build Docker image, tagged as `deluan/navidrome:develop`, override with DOCKER_TAG var. Use IMAGE_PLATFORMS to specify target platforms
@echo $(IMAGE_PLATFORMS)| grep -q "windows"&&echo"ERROR: Windows is not supported for Docker builds"&&exit1||true
@echo $(IMAGE_PLATFORMS)| grep -q "darwin"&&echo"ERROR: macOS is not supported for Docker builds"&&exit1||true
@echo $(IMAGE_PLATFORMS)| grep -q "arm/v5"&&echo"ERROR: Linux ARMv5 is not supported for Docker builds"&&exit1||true
[](https://discord.gg/xh7j7yF)
# Navidrome Music Server [](https://twitter.com/intent/tweet?text=Tired%20of%20paying%20for%20music%20subscriptions%2C%20and%20not%20finding%20what%20you%20really%20like%3F%20Roll%20your%20own%20streaming%20service%21&url=https://navidrome.org&via=navidrome)
Navidrome is an open source web-based music collection server and streamer. It gives you freedom to listen to your
pruneCmd.Flags().IntVarP(&backupCount,"keep-count","k",-1,"specify the number of backups to keep. 0 remove ALL backups, and negative values mean to use the default from configuration")
pruneCmd.Flags().BoolVarP(&force,"force","f",false,"bypass warning when backup count is zero")
backupRoot.AddCommand(pruneCmd)
restoreCommand.Flags().StringVarP(&restorePath,"backup-file","b","","path of backup database to restore")
rootCmd.PersistentFlags().BoolVarP(&noBanner,"nobanner","n",false,`don't show banner`)
rootCmd.PersistentFlags().String("musicfolder",viper.GetString("musicfolder"),"folder where your music is stored")
rootCmd.PersistentFlags().String("datafolder",viper.GetString("datafolder"),"folder to store application data (DB), needs write access")
rootCmd.PersistentFlags().String("cachefolder",viper.GetString("cachefolder"),"folder to store cache data (transcoding, images...), needs write access")
rootCmd.PersistentFlags().StringP("loglevel","l",viper.GetString("loglevel"),"log level, possible values: error, info, debug, trace")
rootCmd.PersistentFlags().String("logfile",viper.GetString("logfile"),"log file path, if not set logs will be printed to stderr")
rootCmd.Flags().String("transcodingcachesize",viper.GetString("transcodingcachesize"),"size of transcoding cache")
rootCmd.Flags().String("imagecachesize",viper.GetString("imagecachesize"),"size of image (art work) cache. set to 0 to disable cache")
rootCmd.Flags().String("albumplaycountmode",viper.GetString("albumplaycountmode"),"how to compute playcount for albums. absolute (default) or normalized")
scanCmd.Flags().BoolVarP(&fullScan,"full","f",false,"check all subfolders, ignoring timestamps")
scanCmd.Flags().BoolVarP(&subprocess,"subprocess","",false,"run as subprocess (internal use)")
scanCmd.Flags().StringArrayVarP(&targets,"target","t",[]string{},"list of libraryID:folderPath pairs, can be repeated (e.g., \"-t 1:Music/Rock -t 1:Music/Jazz -t 2:Classical\")")
scanCmd.Flags().StringVar(&targetFile,"target-file","","path to file containing targets (one libraryID:folderPath per line)")
userCreateCommand.Flags().StringVarP(&email,"email","e","","New user email")
userCreateCommand.Flags().IntSliceVarP(&libraryIds,"library-ids","i",[]int{},"Comma-separated list of library IDs. Set the user's accessible libraries. If empty, the user can access all libraries. This is incompatible with admin, as admin can always access all libraries")
userCreateCommand.Flags().BoolVarP(&setAdmin,"admin","a",false,"If set, make the user an admin. This user will have access to every library")
userCreateCommand.Flags().StringVar(&name,"name","","New user's name (this is separate from username used to log in)")
_=userCreateCommand.MarkFlagRequired("username")
userRoot.AddCommand(userCreateCommand)
userDeleteCommand.Flags().StringVarP(&userID,"user","u","","username or id")
_=userDeleteCommand.MarkFlagRequired("user")
userRoot.AddCommand(userDeleteCommand)
userEditCommand.Flags().StringVarP(&userID,"user","u","","username or id")
userEditCommand.Flags().BoolVar(&setAdmin,"set-admin",false,"If set, make the user an admin")
userEditCommand.Flags().BoolVar(&setRegularUser,"set-regular",false,"If set, make the user a non-admin")
userEditCommand.Flags().BoolVar(&setPassword,"set-password",false,"If set, the user's new password will be prompted on the CLI")
userEditCommand.Flags().IntSliceVarP(&libraryIds,"library-ids","i",[]int{},"Comma-separated list of library IDs. Set the user's accessible libraries by id")
_=userEditCommand.MarkFlagRequired("user")
userRoot.AddCommand(userEditCommand)
userListCommand.Flags().StringVarP(&outputFormat,"format","f","csv","output format [supported values: csv, json]")
userRoot.AddCommand(userListCommand)
}
var(
userRoot=&cobra.Command{
Use:"user",
Short:"Administer users",
Long:"Create, delete, list, or update users",
}
userCreateCommand=&cobra.Command{
Use:"create",
Aliases:[]string{"c"},
Short:"Create a new user",
Run:func(cmd*cobra.Command,args[]string){
runCreateUser(cmd.Context())
},
}
userDeleteCommand=&cobra.Command{
Use:"delete",
Aliases:[]string{"d"},
Short:"Deletes an existing user",
Run:func(cmd*cobra.Command,args[]string){
runDeleteUser(cmd.Context())
},
}
userEditCommand=&cobra.Command{
Use:"edit",
Aliases:[]string{"e"},
Short:"Edit a user",
Long:"Edit the password, admin status, and/or library access",
Run:func(cmd*cobra.Command,args[]string){
runUserEdit(cmd.Context())
},
}
userListCommand=&cobra.Command{
Use:"list",
Short:"List users",
Run:func(cmd*cobra.Command,args[]string){
runUserList(cmd.Context())
},
}
)
funcpromptPassword()string{
for{
fmt.Print("Enter new password (press enter with no password to cancel): ")
log.Info("No configuration file found. Loaded configuration only from environment variables")
}else{
log.Warn("No configuration file found. Using default values. To specify a config file, use the --configfile flag or set the ND_CONFIGFILE environment variable.")
}
// Print current configuration if log level is Debug
log.Error(fmt.Sprintf("Invalid %s. Please read format spec at https://pkg.go.dev/github.com/robfig/cron#hdr-CRON_Expression_Format",field),"schedule",schedule,err)
}else{
c.Remove(id)
}
returnschedule,err
}
// AddHook is used to register initialization code that should run as soon as the config is loaded
funcAddHook(hookfunc()){
hooks=append(hooks,hook)
}
// hasNDEnvVars checks if any ND_ prefixed environment variables are set (excluding ND_CONFIGFILE)
A couple things to keep in mind with this manifest:
1. This creates a namespace called `navidrome`. Adjust this as needed.
1. This manifest was created on [K3s](https://github.com/k3s-io/k3s), which uses its own storage provisioner called [local-path-provisioner](https://github.com/rancher/local-path-provisioner). Be sure to change the `storageClassName` of the `PersistentVolumeClaim` as needed.
1. The `PersistentVolumeClaim` sets up a 2Gi volume for Navidrome's database. Adjust this as needed.
1. Be sure to change the `image` tag from `ghcr.io/navidrome/navidrome:0.49.3` to whatever the newest version is.
1. This assumes your music is mounted on the host using `hostPath` at `/path/to/your/music/on/the/host`. Adjust this as needed.
1. The `Ingress` is already configured for `cert-manager` to obtain a Let's Encrypt TLS certificate and uses Traefik for routing. Adjust this as needed.
1. The `Ingress` presents the service at `navidrome.${SECRET_INTERNAL_DOMAIN_NAME}`, which needs to already be setup in DNS.
This folder abstracts metadata lookup into "agents". Each agent can be implemented to get as
much info as the external source provides, by using a granular set of interfaces
(see [interfaces](interfaces.go)).
A new agent must comply with these simple implementation rules:
1) Implement the `AgentName()` method. It just returns the name of the agent for logging purposes.
2) Implement one or more of the `*Retriever()` interfaces. That's where the agent's logic resides.
3) Register itself (in its `init()` function).
For an agent to be used it needs to be listed in the `Agents` config option (default is `"lastfm,spotify"`). The order dictates the priority of the agents
For a simple Agent example, look at the [local_agent](local_agent.go) agent source code.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.