208 Commits
Author SHA1 Message Date
Deluan ba3974ee59 refactor(shellquote): replace go-shellquote with custom shell quoting implementation 2026-03-14 10:23:45 -04:00
Deluan 8939f31d55 refactor(jsoncommentstrip): replace go-jsoncommentstrip with custom JSON comment stripping 2026-03-14 10:18:56 -04:00
Deluan d79b812467 refactor(natural): replace maruel/natural with custom natural sort implementation 2026-03-14 10:18:56 -04:00
Deluan d042fc138c refactor(nanoid): replace gonanoid with custom nanoid implementation for ID generation
Signed-off-by: Deluan <[email protected]>
2026-03-13 21:06:26 -04:00
Deluan QuintãoandGitHub 4ddb0774ec perf(artwork): improve image serving performance with WebP encoding and optimized pipeline (#5181)
* test(artwork): add benchmark helpers for generating test images

* test(artwork): add image decode benchmarks for JPEG/PNG at various sizes

* test(artwork): add image resize benchmarks for Lanczos at various sizes

* test(artwork): add image encode benchmarks for JPEG quality levels and PNG

* test(artwork): add full resize pipeline benchmark (decode+resize+encode)

* test(artwork): add tag extraction benchmark for embedded art

* test(cache): add file cache benchmarks for read, write, and concurrent access

* test(artwork): add E2E benchmarks for artwork.Get with cache on/off and concurrency

* fix(test): use absolute path for tag extraction benchmark fixture

* test(artwork): add resize alternatives benchmark comparing resamplers

* perf(artwork): switch to CatmullRom resampler and JPEG for square images

Replace imaging.Lanczos with imaging.CatmullRom for image resizing
(30% faster, indistinguishable quality at thumbnail sizes). Stop forcing
PNG encoding for square images when the source is JPEG — JPEG is smaller
and faster to encode. Square images from JPEG sources went from 52ms to
10ms (80% improvement). Add sync.Pool for encode buffers to reduce GC
pressure under concurrent load.

* perf(artwork): increase cache warmer concurrency from 2 to 4 workers

Resize is CPU-bound, so more workers improve throughput on multi-core
systems. Doubled worker count to better utilize available cores during
background cache warming.

* perf(artwork): switch to xdraw.ApproxBiLinear and always encode as JPEG

Replace disintegration/imaging with golang.org/x/image/draw for image
resizing. This eliminates ~92K allocations per resize (from imaging's
internal goroutine parallelism) down to ~20, reducing GC pressure under
concurrent load.

Always encode resized artwork as JPEG regardless of source format, since
cover art doesn't need transparency. This is ~5x faster than PNG encode
and produces much smaller output (e.g. 18KB JPEG vs 124KB PNG).

* perf(artwork): skip external API call when artist image URL is cached

ArtistImage() was always calling the external agent (Spotify/Last.fm)
to get the image URL, even when the artist already had URLs stored in
the database. This caused every artist image request to block on an
external API call, creating severe serialization when loading artist
grids (5-20 seconds for the first page).

Now use the stored URL directly when available. Artists with no stored
URL still fetch synchronously. Background refresh via UpdateArtistInfo
handles TTL-based URL updates.

* perf(artwork): increase getCoverArt throttle from NumCPU/3 to NumCPU

The previous default of max(2, NumCPU/3) was too aggressive for artist
images which are I/O-bound (downloading from external CDNs), not
CPU-bound. On an 8-core machine this meant only 2 concurrent requests,
causing a staircase pattern where 12 images took ~2.4s wall-clock.

Bumping to max(4, NumCPU) cuts wall-clock time by ~50% for artist image
grids while still preventing unbounded concurrency for CPU-bound resizes.

* perf(artwork): encode resized images as WebP instead of JPEG

Switch from JPEG to WebP encoding for resized artwork using gen2brain/webp
(libwebp via WASM, no CGo). WebP produces ~74% smaller output at the same
quality with only ~25% slower full-pipeline encode time (cached, so only
paid once per artwork+size).

Use NRGBA image type to preserve alpha channel in WebP output, and
transparent padding for square canvas instead of black.

Also removes the disintegration/imaging dependency entirely by replacing
imaging.Fill in playlist tile generation with a custom fillCenter function
using xdraw.ApproxBiLinear.

* perf(artwork): switch from ApproxBiLinear to BiLinear scaling for improved image processing

Signed-off-by: Deluan <[email protected]>

* refactor(configuration): rename CoverJpegQuality to CoverArtQuality and update references

Signed-off-by: Deluan <[email protected]>

* feat(artwork): add DevJpegCoverArt option to control JPEG encoding for cover art

Signed-off-by: Deluan <[email protected]>

* fix(artwork): remove redundant transparent fill and handle encode errors in resizeImage

Removed a no-op draw.Draw call that filled the NRGBA canvas with
transparent pixels — NewNRGBA already zero-initializes to fully
transparent. Also added an early return on encode failure to avoid
allocating and copying potentially corrupt buffer data before returning
the error.

* fix(configuration): reorder default agents (deezer is faster)

Signed-off-by: Deluan <[email protected]>

* fix(test): resolve dogsled lint warning in tag extraction benchmark

Use all return values from runtime.Caller instead of discarding three
with blank identifiers, which triggered the dogsled linter.

* fix(artwork): revert cache key format

Signed-off-by: Deluan <[email protected]>

* fix(configuration): remove deprecated CoverJpegQuality field and update references to CoverArtQuality

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2026-03-13 09:35:59 -04:00
Deluan 3cd5d16b0a chore: upgrade golangci-lint to 2.11 and fix lint issues
Signed-off-by: Deluan <[email protected]>
2026-03-06 19:23:47 -05:00
Deluan QuintãoandGitHub acd69f6a4f feat(playlist): support #EXTALBUMARTURL directive and sidecar images (#5131)
* feat(playlist): add migration for playlist image field rename and external URL

* refactor(playlist): rename ImageFile to UploadedImage and ArtworkPath to UploadedImagePath

Rename playlist model fields and methods for clarity in preparation for
adding external image URL and sidecar image support. Add the new
ExternalImageURL field to the Playlist model.

* feat(playlist): parse #EXTALBUMARTURL directive in M3U imports

* feat(playlist): always sync ExternalImageURL on re-scan, preserve UploadedImage

* feat(artwork): add sidecar image discovery and cache invalidation for playlists

Add playlist sidecar image support to the artwork reader fallback chain.
A sidecar image (e.g., MyPlaylist.jpg next to MyPlaylist.m3u) is discovered
via case-insensitive base name matching using model.IsImageFile(). Cache
invalidation uses max(playlist.UpdatedAt, imageFile.ModTime()) to bust
stale artwork when sidecar or ExternalImageURL local files change.

* feat(artwork): add external image URL source to playlist artwork reader

Add fromPlaylistExternalImage source function that resolves playlist
cover art from ExternalImageURL, supporting both HTTP(S) URLs (via
the existing fromURL helper) and local file paths (via os.Open).
Insert it in the Reader() fallback chain between sidecar and tiled cover.

* refactor(artwork): simplify playlist artwork source functions

Extract shared fromLocalFile helper, use url.Parse for scheme check,
and collapse sidecar directory scan conditions.

* test(artwork): remove redundant fromPlaylistSidecar tests

These tests duplicated scenarios already covered by findPlaylistSidecarPath
tests combined with fromLocalFile (tested via fromPlaylistExternalImage).
After refactoring fromPlaylistSidecar to a one-liner composing those two
functions, the wrapper tests add no value.

* fix(playlist): address security review comments from PR #5131:

- Use url.PathUnescape instead of url.QueryUnescape for file:// URLs so
  that '+' in filenames is preserved (not decoded as space).
- Validate all local image paths (file://, absolute, relative) against
  known library boundaries via libraryMatcher, rejecting paths outside
  any configured library.
- Harden #EXTALBUMARTURL against path traversal and SSRF by adding EnableM3UExternalAlbumArt config flag (default false, also
  disabled by EnableExternalServices=false) to gate HTTP(S) URL storage
  at parse time and fetching at read time (defense in depth).
- Log a warning when os.ReadDir fails in findPlaylistSidecarPath for
  diagnosability.
- Extract resolveLocalPath helper to simplify resolveImageURL.

Signed-off-by: Deluan <[email protected]>

* feat(playlist): implement human-friendly filename generation for uploaded playlist cover images

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2026-03-02 11:39:59 -05:00
MaximilianandGitHub a704e86ac1 refactor: run Go modernize (#5002) 2026-02-08 09:57:30 -05:00
Deluan 735c0d9103 chore(deps): remove direct dependency on golang.org/x/exp
Signed-off-by: Deluan <[email protected]>
2025-12-31 17:03:44 -05:00
28d5299ffc feat(scanner): implement selective folder scanning and file system watcher improvements (#4674)
* 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 <[email protected]>

* test: update parseTargets test to handle folder names with spaces

Signed-off-by: Deluan <[email protected]>

* refactor(folder): remove unused LibraryPath struct and update GC logging message

Signed-off-by: Deluan <[email protected]>

* refactor(folder): enhance external scanner to support target-specific scanning

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): simplify scanner methods

Signed-off-by: Deluan <[email protected]>

* feat(watcher): implement folder scanning notifications with deduplication

Signed-off-by: Deluan <[email protected]>

* refactor(watcher): add resolveFolderPath function for testability

Signed-off-by: Deluan <[email protected]>

* feat(watcher): implement path ignoring based on .ndignore patterns

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): implement IgnoreChecker for managing .ndignore patterns

Signed-off-by: Deluan <[email protected]>

* refactor(ignore_checker): rename scanner to lineScanner for clarity

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): enhance ScanTarget struct with String method for better target representation

Signed-off-by: Deluan <[email protected]>

* fix(scanner): validate library ID to prevent negative values

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): simplify GC method by removing library ID parameter

Signed-off-by: Deluan <[email protected]>

* feat(scanner): update folder scanning to include all descendants of specified folders

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): allow selective scan in the /startScan endpoint

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): update CallScan to handle specific library/folder pairs

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): streamline scanning logic by removing scanAll method

Signed-off-by: Deluan <[email protected]>

* test: enhance mockScanner for thread safety and improve test reliability

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): move scanner.ScanTarget to model.ScanTarget

Signed-off-by: Deluan <[email protected]>

* refactor: move scanner types to model,implement MockScanner

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): update scanner interface and implementations to use model.Scanner

Signed-off-by: Deluan <[email protected]>

* refactor(folder_repository): normalize target path handling by using filepath.Clean

Signed-off-by: Deluan <[email protected]>

* test(folder_repository): add comprehensive tests for folder retrieval and child exclusion

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): simplify selective scan logic using slice.Filter

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): streamline phase folder and album creation by removing unnecessary library parameter

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): move initialization logic from phase_1 to the scanner itself

Signed-off-by: Deluan <[email protected]>

* refactor(tests): rename selective scan test file to scanner_selective_test.go

Signed-off-by: Deluan <[email protected]>

* feat(configuration): add DevSelectiveWatcher configuration option

Signed-off-by: Deluan <[email protected]>

* feat(watcher): enhance .ndignore handling for folder deletions and file changes

Signed-off-by: Deluan <[email protected]>

* docs(scanner): comments

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): enhance walkDirTree to support target folder scanning

Signed-off-by: Deluan <[email protected]>

* fix(scanner, watcher): handle errors when pushing ignore patterns for folders

Signed-off-by: Deluan <[email protected]>

* Update scanner/phase_1_folders.go

Co-authored-by: Copilot <[email protected]>

* refactor(scanner): replace parseTargets function with direct call to scanner.ParseTargets

Signed-off-by: Deluan <[email protected]>

* test(scanner): add tests for ScanBegin and ScanEnd functionality

Signed-off-by: Deluan <[email protected]>

* fix(library): update PRAGMA optimize to check table sizes without ANALYZE

Signed-off-by: Deluan <[email protected]>

* test(scanner): refactor tests

Signed-off-by: Deluan <[email protected]>

* feat(ui): add selective scan options and update translations

Signed-off-by: Deluan <[email protected]>

* feat(ui): add quick and full scan options for individual libraries

Signed-off-by: Deluan <[email protected]>

* feat(ui): add Scan buttonsto the LibraryList

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* feat(scan): add '@Recycle' (QNAP) to ignored directories list

Signed-off-by: Deluan <[email protected]>

* fix(log): improve thread safety in logging level management

* test(scan): move unit tests for ParseTargets function

Signed-off-by: Deluan <[email protected]>

* review

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: deluan <[email protected]>
2025-11-14 22:15:43 -05:00
Deluan 58b5ed86df refactor: extract TruncateRunes function for safe string truncation with suffix
Signed-off-by: Deluan <[email protected]>

# Conflicts:
#	core/share.go
#	core/share_test.go
2025-11-06 14:27:38 -05:00
Deluan QuintãoandGitHub 91fab68578 fix: handle UTF BOM in lyrics and playlist files (#4637)
* 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 <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2025-10-31 09:07:23 -04:00
Deluan QuintãoandGitHub 00c83af170 feat: Multi-library support (#4181)
* feat(database): add user_library table and library access methods

Signed-off-by: Deluan <[email protected]>

# Conflicts:
#	tests/mock_library_repo.go

* feat(database): enhance user retrieval with library associations

Signed-off-by: Deluan <[email protected]>

* feat(api): implement library management and user-library association endpoints

Signed-off-by: Deluan <[email protected]>

* feat(api): restrict access to library and config endpoints to admin users

Signed-off-by: Deluan <[email protected]>

* refactor(library): implement library management service and update API routes

Signed-off-by: Deluan <[email protected]>

* feat(database): add library filtering to album, folder, and media file queries

Signed-off-by: Deluan <[email protected]>

* refactor library service to use REST repository pattern and remove CRUD operations

Signed-off-by: Deluan <[email protected]>

* add total_duration column to library and update user_library table

Signed-off-by: Deluan <[email protected]>

* fix migration file name

Signed-off-by: Deluan <[email protected]>

* feat(library): add library management features including create, edit, delete, and list functionalities - WIP

Signed-off-by: Deluan <[email protected]>

* feat(library): enhance library validation and management with path checks and normalization - WIP

Signed-off-by: Deluan <[email protected]>

* feat(library): improve library path validation and error handling - WIP

Signed-off-by: Deluan <[email protected]>

* use utils/formatBytes

Signed-off-by: Deluan <[email protected]>

* simplify DeleteLibraryButton.jsx

Signed-off-by: Deluan <[email protected]>

* feat(library): enhance validation messages and error handling for library paths

Signed-off-by: Deluan <[email protected]>

* lint

Signed-off-by: Deluan <[email protected]>

* test(scanner): add tests for multi-library scanning and validation

Signed-off-by: Deluan <[email protected]>

* test(scanner): improve handling of filesystem errors and ensure warnings are returned

Signed-off-by: Deluan <[email protected]>

* feat(controller): add function to retrieve the most recent scan time across all libraries

Signed-off-by: Deluan <[email protected]>

* feat(library): add additional fields and restructure LibraryEdit component for enhanced statistics display

Signed-off-by: Deluan <[email protected]>

* feat(library): enhance LibraryCreate and LibraryEdit components with additional props and styling

Signed-off-by: Deluan <[email protected]>

* feat(mediafile): add LibraryName field and update queries to include library name

Signed-off-by: Deluan <[email protected]>

* feat(missingfiles): add library filter and display in MissingFilesList component

Signed-off-by: Deluan <[email protected]>

* feat(library): implement scanner interface for triggering library scans on create/update

Signed-off-by: Deluan <[email protected]>

# 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 <[email protected]>

* rename migration file for user library table to maintain versioning order

Signed-off-by: Deluan <[email protected]>

* refactor: move scan triggering logic into a helper method for clarity

Signed-off-by: Deluan <[email protected]>

* feat(library): add library path and name fields to album and mediafile models

Signed-off-by: Deluan <[email protected]>

* feat(library): add/remove watchers on demand, not only when server starts

Signed-off-by: Deluan <[email protected]>

* refactor(scanner): streamline library handling by using state-libraries for consistency

Signed-off-by: Deluan <[email protected]>

* fix: track processed libraries by updating state with scan timestamps

Signed-off-by: Deluan <[email protected]>

* prepend libraryID for track and album PIDs

Signed-off-by: Deluan <[email protected]>

* feat(repository): apply library filtering in CountAll methods for albums, folders, and media files

Signed-off-by: Deluan <[email protected]>

* feat(user): add library selection for user creation and editing

Signed-off-by: Deluan <[email protected]>

* feat(library): implement library selection functionality with reducer and UI component

Signed-off-by: Deluan <[email protected]>

# Conflicts:
#	.github/copilot-instructions.md

# Conflicts:
#	.gitignore

* feat(library): add tests for LibrarySelector and library selection hooks

Signed-off-by: Deluan <[email protected]>

* test: add unit tests for file utility functions

Signed-off-by: Deluan <[email protected]>

* feat(library): add library ID filtering for album resources

Signed-off-by: Deluan <[email protected]>

* feat(library): streamline library ID filtering in repositories and update resource filtering logic

Signed-off-by: Deluan <[email protected]>

* fix(repository): add table name handling in filter functions for SQL queries

Signed-off-by: Deluan <[email protected]>

* feat(library): add refresh functionality on LibrarySelector close

Signed-off-by: Deluan <[email protected]>

* feat(artist): add library ID filtering for artists in repository and update resource filtering logic

Signed-off-by: Deluan <[email protected]>

# 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 <[email protected]>

* feat(library): enhance LibrarySelectionField to extract library IDs from record

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): update GetIndexes and GetArtists method to support library ID filtering

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* feat: enhance selectedMusicFolderIds function to handle valid music folder IDs and improve fallback logic

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* feat: add library access methods to User model

Signed-off-by: Deluan <[email protected]>

* feat: implement library access filtering for artist queries based on user permissions

Signed-off-by: Deluan <[email protected]>

* feat: enhance artist library filtering based on user permissions and optimize library ID retrieval

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* feat: refresh LibraryList on scan end

Signed-off-by: Deluan <[email protected]>

* fix: allow editing name of main library

Signed-off-by: Deluan <[email protected]>

* refactor: implement SendBroadcastMessage method for event broadcasting

Signed-off-by: Deluan <[email protected]>

* feat: add event broadcasting for library creation, update, and deletion

Signed-off-by: Deluan <[email protected]>

* feat: add useRefreshOnEvents hook for custom refresh logic on event changes

Signed-off-by: Deluan <[email protected]>

* feat: enhance library management with refresh event broadcasting

Signed-off-by: Deluan <[email protected]>

* feat: replace AddUserLibrary and RemoveUserLibrary with SetUserLibraries for better library management

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* fix: correct updated_at assignment in library repository

Signed-off-by: Deluan <[email protected]>

* fix: improve cache buffering logic

Refactored the cache buffering logic to ensure thread safety when checking
the buffer length

Signed-off-by: Deluan <[email protected]>

* fix formating

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* feat: add multi-library support with per-library tag statistics - WIP

Signed-off-by: Deluan <[email protected]>

* refactor: genre and tag repositories. add comprehensive tests

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* refactor: rename search_test.go to searching_test.go for consistency

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* refactor: cleanup

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2025-07-18 18:41:12 -04:00
Deluan QuintãoandGitHub aab3223e00 fix(subsonic): clearing playlist comment and public in Subsonic API (#4258)
* fix(subsonic): allow clearing playlist comment

* fix(playlists): simplify comment and public parameter handling

Signed-off-by: Deluan <[email protected]>

* refactor(playlists): streamline fakePlaylists implementation in tests

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2025-06-24 08:50:06 -04:00
Deluan QuintãoGitHubellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
f1fc2cd9b9 feat(plugins): experimental support for plugins (#3998)
* feat(plugins): add minimal test agent plugin with API definitions

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* feat(plugins): implement persistent compilation cache for WASM agent plugins

Signed-off-by: Deluan <[email protected]>

* feat(plugins): implement instance pooling for wasmAgent to improve resource management

Signed-off-by: Deluan <[email protected]>

* feat(plugins): enhance logging for wasmAgent and plugin manager operations

Signed-off-by: Deluan <[email protected]>

* feat(plugins): implement HttpService for handling HTTP requests in WASM plugins

Also add a sample Wikimedia plugin

Signed-off-by: Deluan <[email protected]>

* feat(plugins): standardize error handling in wasmAgent and MinimalAgent

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* refactor(plugins): rename wasmAgent to wasmArtistAgent

Signed-off-by: Deluan <[email protected]>

* feat(api): add AlbumMetadataService with AlbumInfo and AlbumImages requests

Signed-off-by: Deluan <[email protected]>

* refactor(plugin): rename MinimalAgent for artist metadata service

Signed-off-by: Deluan <[email protected]>

* feat(api): implement wasmAlbumAgent for album metadata service with GetAlbumInfo and GetAlbumImages methods

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): simplify wasmAlbumAgent and wasmArtistAgent by using wasmBasePlugin

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add support for ArtistMetadataService and AlbumMetadataService in plugin manager

Signed-off-by: Deluan <[email protected]>

* feat(plugins): enhance plugin pool creation with custom runtime and precompilation support

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): implement generic plugin pool and agent factory for improved service handling

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): reorganize plugin management

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): improve function signatures for clarity and consistency

Signed-off-by: Deluan <[email protected]>

* feat(plugins): implement background precompilation for plugins and agent factory creation

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): include instanceID in logging for better traceability

Signed-off-by: Deluan <[email protected]>

* test(plugins): add tests for plugin pre-compilation and agent factory synchronization

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add minimal album test agent plugin for AlbumMetadataService

Signed-off-by: Deluan <[email protected]>

* feat(plugins): rename fake artist and album test agent plugins for metadata services

Signed-off-by: Deluan <[email protected]>

* feat(makefile): add Makefile for building plugin WASM binaries

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add FakeMultiAgent plugin implementing Artist and Album metadata services

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): remove log statements from FakeArtistAgent and FakeMultiAgent methods

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* refactor: remove wasm module pooling

it was causing issues with the GC and the Close methods

Signed-off-by: Deluan <[email protected]>

* refactor: rename metadata service files to adapter naming convention

Signed-off-by: Deluan <[email protected]>

* refactor: unify album and artist method calls by introducing callMethod function

Signed-off-by: Deluan <[email protected]>

* refactor: unify album and artist method calls by introducing callMethod function

Signed-off-by: Deluan <[email protected]>

* fix: handle nil values in data redaction process

Signed-off-by: Deluan <[email protected]>

* fix: add timeout for plugin compilation to prevent indefinite blocking

Signed-off-by: Deluan <[email protected]>

* feat: implement ScrobblerService plugin with authorization and scrobbling capabilities

Signed-off-by: Deluan <[email protected]>

* refactor: simplify generalization

Signed-off-by: Deluan <[email protected]>

* fix: tests

Signed-off-by: Deluan <[email protected]>

* refactor: enhance plugin management by improving scanning and loading mechanisms

Signed-off-by: Deluan <[email protected]>

* refactor: update plugin creation functions to return specific interfaces for better type safety

Signed-off-by: Deluan <[email protected]>

* refactor: enhance wasmBasePlugin to support specific plugin types for improved type safety

Signed-off-by: Deluan <[email protected]>

* refactor: implement MediaMetadataService with combined artist and album methods

Signed-off-by: Deluan <[email protected]>

* refactor: improve MediaMetadataService plugin implementation and testing structure

Signed-off-by: Deluan <[email protected]>

* refactor: add tests for Adapter Media Agent and improve plugin documentation

Signed-off-by: Deluan <[email protected]>

* docs: add README for Navidrome Plugin System with detailed architecture and usage guidelines

Signed-off-by: Deluan <[email protected]>

* refactor: enhance agent management with plugin loading and caching

Signed-off-by: Deluan <[email protected]>

* refactor: update agent discovery logic to include only local agent when no config is specified

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* fix: correct file extension filter in goimports command

Signed-off-by: Deluan <[email protected]>

* refactor: use defer to unlock the mutex

Signed-off-by: Deluan <[email protected]>

* chore: move Cover Art Archive AlbumMetadataService plugins to an example folder

Signed-off-by: Deluan <[email protected]>

* fix: handle errors when creating media metadata and scrobbler service plugins

Signed-off-by: Deluan <[email protected]>

* fix: increase compilation timeout to one minute

Signed-off-by: Deluan <[email protected]>

* feat: add configurable plugin compilation timeout

Signed-off-by: Deluan <[email protected]>

* feat: implement plugin scrobbler support in PlayTracker

Signed-off-by: Deluan <[email protected]>

* feat: add context management and Stop method to buffered scrobbler

Signed-off-by: Deluan <[email protected]>

* feat: add username field to scrobbler requests and update logging

Signed-off-by: Deluan <[email protected]>

* fix: data race in test

Signed-off-by: Deluan <[email protected]>

* refactor: rename http proto files to host and update references

Signed-off-by: Deluan <[email protected]>

* refactor: remove unused plugin registration methods from manager

Signed-off-by: Deluan <[email protected]>

* feat: extend plugin manifests and implement plugin management commands

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* feat(plugins): implement timer service with register and cancel functionality - WIP

Signed-off-by: Deluan <[email protected]>

* feat(plugins): implement timer service with register and cancel functionality - WIP

Signed-off-by: Deluan <[email protected]>

* feat(plugins): implement timer service with register and cancel functionality - WIP

Signed-off-by: Deluan <[email protected]>

* feat(plugins): implement timer service with register and cancel functionality

Signed-off-by: Deluan <[email protected]>

* fix: lint errors

Signed-off-by: Deluan <[email protected]>

* feat(README): update documentation to include TimerCallbackService and its functionality

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add InitService with OnInit method and initialization tracking - WIP

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add tests for InitService and plugin initialization tracking

Signed-off-by: Deluan <[email protected]>

* feat(plugins): expand documentation on plugin system implementation and architecture

Signed-off-by: Deluan <[email protected]>

* fix: panic

Signed-off-by: Deluan <[email protected]>

* feat(plugins): redirect plugins' stderr to logs

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add safe accessor methods for TimerService

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add plugin-specific configuration support in InitRequest and documentation

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add TimerCallbackService plugin adapter and integration

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): rename services for consistency and clarity

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add mutex for configuration access and clone plugin config

Signed-off-by: Deluan <[email protected]>

* refactor(tests): remove configtest dependency to prevent data races in integration tests

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): remove PluginName method from WASM plugin implementations and update LoadPlugin to accept service type

Signed-off-by: Deluan <[email protected]>

* feat(plugins): implement instance pooling for wasmBasePlugin to improve performance - WIP

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add wasmInstancePool for managing WASM plugin instances with TTL and max size

Signed-off-by: Deluan <[email protected]>

* fix(plugins): correctly pass error to done function in wasmBasePlugin

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): rename service types to capabilities for consistency

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): simplify instance management in wasmBasePlugin by removing error handling in closure

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): update wasmBasePlugin and wasmInstancePool to return errors for better error handling

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): rename InitService to LifecycleManagement for consistency

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): fix instance ID logging in wasmBasePlugin

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): extract instance ID logging to a separate function in wasmBasePlugin, to avoid vet error

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): make timers be isolated per plugin

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): make timers be isolated per plugin

Signed-off-by: Deluan <[email protected]>

* refactor(plugins): rename HttpServiceImpl to httpServiceImpl for consistency and improve logging

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add config service for plugin-specific configuration management

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* fix(singleton): fix deadlock issue when a constructor calls GetSingleton again

Signed-off-by: Deluan <[email protected]> (+1 squashed commit)
Squashed commits:
[325a96ea2] fix(singleton): fix deadlock issue when a constructor calls GetSingleton again

Signed-off-by: Deluan <[email protected]>

* feat(scheduler): implement Scheduler for one-time and recurring job scheduling, merging CrontabService and TimerService

Signed-off-by: Deluan <[email protected]>

* fix(scheduler): race condition in the scheduleOneTime and scheduleRecurring methods when replacing jobs with the same ID

Signed-off-by: Deluan <[email protected]>

* refactor(scheduler): consolidate job scheduling logic into a single helper function

Signed-off-by: Deluan <[email protected]>

* refactor(plugin): rename GetInstance method to Instantiate for clarity

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add WebSocket service for handling connections and messages

Signed-off-by: Deluan <[email protected]>

* feat(crypto-ticker): add WebSocket plugin for real-time cryptocurrency price tracking

Signed-off-by: Deluan <[email protected]>

* feat(websocket): enhance connection management and callback handling

Signed-off-by: Deluan <[email protected]>

* feat(manager): only create one adapter instance for each adapter/capability pair

Signed-off-by: Deluan <[email protected]>

* fix(websocket): ensure proper resource management by closing response body and use defer to unlocking mutexes

Signed-off-by: Deluan <[email protected]>

* fix: flaky test

Signed-off-by: Deluan <[email protected]>

* feat(plugin): refactor WebSocket service integration and improve error logging

Signed-off-by: Deluan <[email protected]>

* feat(plugin): add SchedulerCallback support and improve reconnection logic

Signed-off-by: Deluan <[email protected]>

* fix: test panic

Signed-off-by: Deluan <[email protected]>

* docs: add crypto-ticker plugin example to README

Signed-off-by: Deluan <[email protected]>

* feat(manager): add LoadAllPlugins and LoadAllMediaAgents methods with slice.Map integration

Signed-off-by: Deluan <[email protected]>

* feat(api): add Timestamp field to ScrobblerNowPlayingRequest and update related methods

Signed-off-by: Deluan <[email protected]>

* feat(websocket): add error field to response messages for better error handling

Signed-off-by: Deluan <[email protected]>

* feat(cache): implement CacheService with string, int, float, and byte operations

Signed-off-by: Deluan <[email protected]>

* feat(tests): update buffered scrobbler tests for improved scrobble verification and use RWMutex in mock repo

Signed-off-by: Deluan <[email protected]>

* refactor(cache): simplify cache service implementation and remove unnecessary synchronization

Signed-off-by: Deluan <[email protected]>

* feat(tests): add build step for test plugins in the test suite

Signed-off-by: Deluan <[email protected]>

* wip

Signed-off-by: Deluan <[email protected]>

* feat(scheduler): implement named scheduler callbacks and enhance Discord plugin integration

Signed-off-by: Deluan <[email protected]>

* feat(rpc): enhance activity image processing and improve error handling in Discord integration

Signed-off-by: Deluan <[email protected]>

* feat(discord): enhance activity state with artist list and add large text asset

Signed-off-by: Deluan <[email protected]>

* fix tests

Signed-off-by: Deluan <[email protected]>

* feat(artwork): implement ArtworkService for retrieving artwork URLs

Signed-off-by: Deluan <[email protected]>

* Add playback position to scrobble NowPlaying (#4089)

* test(playtracker): cover playback position

* address review comment

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>

* fix merge

Signed-off-by: Deluan <[email protected]>

* refactor: remove unnecessary check for empty slice in Map function

Signed-off-by: Deluan <[email protected]>

* fix: update reflex.conf to include .wasm file extension

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* test(ui): fix warnings (#4187)

* fix(ui): address test warnings

* ignore lint error in test

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* test: add cases for fallback to title matching and combined MBID/title matching

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* fix(test): test all themes

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>

* chore(deps): update TagLib to version 2.1 (#4185)

* chore: update cross-taglib

* fix(taglib): add logging for TagLib version

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* fix tests

Signed-off-by: Deluan <[email protected]>

* feat(runtime): implement pooled WASM runtime and module for better instance management

Signed-off-by: Deluan <[email protected]>

* fix(discord-plugin): adjust timer delay calculation for track completion

Signed-off-by: Deluan <[email protected]>

* resolve PR comments

Signed-off-by: Deluan <[email protected]>

* feat(plugins): implement cache cleanup by size functionality

Signed-off-by: Deluan <[email protected]>

* fix(manager): return error from getCompilationCache and handle it in ScanPlugins

Signed-off-by: Deluan <[email protected]>

* fix possible rce condition

Signed-off-by: Deluan <[email protected]>

* feat(docs): update README to include Cache and Artwork services

Signed-off-by: Deluan <[email protected]>

* feat(manager): add permissions support for host services in custom runtime - WIP

Signed-off-by: Deluan <[email protected]>

* feat(manifest): add permissions field to plugin manifests - WIP

Signed-off-by: Deluan <[email protected]>

* test(permissions): implement permission validation and testing for plugins - WIP

Signed-off-by: Deluan <[email protected]>

* feat(plugins): add unauthorized_plugin to test permission enforcement - WIP

Signed-off-by: Deluan <[email protected]>

* feat(docs): add Plugin Permission System section to README - WIP

Signed-off-by: Deluan <[email protected]>

* feat(manifest): add detailed reasons for permissions in plugin manifests - WIP

Signed-off-by: Deluan <[email protected]>

* feat(permissions): implement granular HTTP permissions for plugins - WIP

Signed-off-by: Deluan <[email protected]>

* feat(permissions): implement HTTP and WebSocket permissions for plugins - WIP

Signed-off-by: Deluan <[email protected]>

* refactor

Signed-off-by: Deluan <[email protected]>

* refactor: unexport all plugins package private symbols

Signed-off-by: Deluan <[email protected]>

* update docs

Signed-off-by: Deluan <[email protected]>

* refactor: rename plugin_lifecycle_manager

Signed-off-by: Deluan <[email protected]>

* docs: add discord-rich-presence plugin example to README

Signed-off-by: Deluan <[email protected]>

* feat: add support for PATCH, HEAD, and OPTIONS HTTP methods

Signed-off-by: Deluan <[email protected]>

* feat: use folder names as unique identifiers for plugins

Signed-off-by: Deluan <[email protected]>

* fix: read config just once, to avoid data race in tests

Signed-off-by: Deluan <[email protected]>

* refactor: rename pluginName to pluginID for consistency across services

Signed-off-by: Deluan <[email protected]>

* fix: use symlink name instead of folder name for plugin registration

Signed-off-by: Deluan <[email protected]>

* feat: update plugin output format to include ID and enhance README with symlink usage

Signed-off-by: Deluan <[email protected]>

* refactor: implement shared plugin discovery function to streamline plugin scanning and error handling

Signed-off-by: Deluan <[email protected]>

* feat: show plugin permissions in `plugin info`

Signed-off-by: Deluan <[email protected]>

* feat: add JSON schema for Navidrome Plugin manifest and generate corresponding Go types - WIP

Signed-off-by: Deluan <[email protected]>

* feat: implement typed permissions for plugins to enhance permission handling

Signed-off-by: Deluan <[email protected]>

* feat: refactor plugin permissions to use typed schema and improve validation - WIP

Signed-off-by: Deluan <[email protected]>

* feat: update HTTP permissions handling to use typed schema for allowed URLs - WIP

Signed-off-by: Deluan <[email protected]>

* feat: remove unused JSON schema validation for plugin manifests

Signed-off-by: Deluan <[email protected]>

* feat: remove unused fields from PluginPackage struct in package.go

Signed-off-by: Deluan <[email protected]>

* feat: update file permissions in tests and remove unused permission parsing function

Signed-off-by: Deluan <[email protected]>

* feat: refactor test plugin creation to use typed permissions and remove legacy helper

Signed-off-by: Deluan <[email protected]>

* feat: add website field to plugin manifests and update test cases

Signed-off-by: Deluan <[email protected]>

* refactor: permission schema to use basePermission structure for consistency

Signed-off-by: Deluan <[email protected]>

* feat: enhance host service management by adding permission checks for each service

Signed-off-by: Deluan <[email protected]>

* refactor: reorganize code files

Signed-off-by: Deluan <[email protected]>

* refactor: simplify custom runtime creation by removing compilation cache parameter

Signed-off-by: Deluan <[email protected]>

* doc: add WebSocketService and update ConfigService for plugin-specific configuration

Signed-off-by: Deluan <[email protected]>

* feat: implement WASM loading optimization to enhance plugin instance creation speed

Signed-off-by: Deluan <[email protected]>

* refactor: rename custom runtime functions and update related tests for clarity

Signed-off-by: Deluan <[email protected]>

* refactor: enhance plugin structure with compilation handling and error reporting

Signed-off-by: Deluan <[email protected]>

* refactor: improve logging and context tracing in runtime and wasm base plugin

Signed-off-by: Deluan <[email protected]>

* refactor: enhance runtime management with scoped runtime and caching improvements

Signed-off-by: Deluan <[email protected]>

* refactor: implement EnsureCompiled method for improved plugin compilation handling

Signed-off-by: Deluan <[email protected]>

* refactor: implement cached module management with TTL for improved performance

Signed-off-by: Deluan <[email protected]>

* refactor: replace map with sync.Map

Signed-off-by: Deluan <[email protected]>

* refactor: adjust time tolerance in scrobble buffer repository tests to avoid flakiness

Signed-off-by: Deluan <[email protected]>

* refactor: enhance image processing with fallback mechanism for improved error handling

Signed-off-by: Deluan <[email protected]>

* docs: review test plugins readme

Signed-off-by: Deluan <[email protected]>

* feat: set default timeout for HTTP client to 10 seconds

Signed-off-by: Deluan <[email protected]>

* feat: enhance wasm instance pool with concurrency limits and timeout settings

Signed-off-by: Deluan <[email protected]>

* feat(discordrp): implement caching for processed image URLs with configurable TTL

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
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>
2025-06-22 20:45:38 -04:00
Deluan 65029968ab refactor: rename chain package to run and update references
Signed-off-by: Deluan <[email protected]>
2025-06-14 17:19:06 -04:00
Deluan QuintãoandGitHub 76042ba173 feat(ui): add Now Playing panel for admins (#4209)
* feat(ui): add Now Playing panel and integrate now playing count updates

Signed-off-by: Deluan <[email protected]>

* 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 <[email protected]>

* feat(ui): refactor Now Playing panel with new components and error handling

Signed-off-by: Deluan <[email protected]>

* fix(ui): adjust padding and height in Now Playing panel for improved layout

Signed-off-by: Deluan <[email protected]>

* fix(cache): add automatic cleanup to prevent goroutine leak on cache garbage collection

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2025-06-10 17:22:13 -04:00
Deluan de698918ac Revert "fix(server): failed transcoded files should not be cached (#4124)"
This reverts commit 9dd5a8c334.
2025-05-27 19:53:10 -04:00
Deluan QuintãoandGitHub 9dd5a8c334 fix(server): failed transcoded files should not be cached (#4124)
* Close stream on caching errors

* fix(test): replace errPartialReader with errFakeReader to fix lint error

Signed-off-by: Deluan <[email protected]>

* fix(test): update error assertion to check for substring in closed file error

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2025-05-26 20:30:26 -04:00
Deluan 0cb02bce06 test: improve test reliability with longer sleep durations and generous tolerances
Signed-off-by: Deluan <[email protected]>
2025-05-25 22:03:55 -04:00
Deluan QuintãoandGitHub 6731787053 fix(server): memory leak in cache warmer (#4095)
* Prevent cache warmer memory leak when cache disabled

* refactor(tests): replace disabledCache with mockFileCache in CacheWarmer tests

Signed-off-by: Deluan <[email protected]>

* test(cache): enhance CacheWarmer tests for initialization, buffer management, and error handling

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2025-05-21 21:48:49 -04:00
Deluan QuintãoandGitHub 5ab345c83e chore(server): add more info to scrobble errors logs (#3889)
* chore(server): add more info to scrobble errors

Signed-off-by: Deluan <[email protected]>

* chore(server): add more info to scrobble errors

Signed-off-by: Deluan <[email protected]>

* chore(server): add more info to scrobble errors

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2025-03-27 18:57:06 -04:00
36ed880e61 fix(scanner): always refresh folder image time when adding first image (#3764)
* 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 <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
Co-authored-by: Deluan <[email protected]>
2025-03-06 22:16:37 -05:00
Deluan QuintãoandGitHub 0c4c223127 fix(server): import absolute paths in m3u (#3756)
* fix(server): import playlists with absolute paths

Signed-off-by: Deluan <[email protected]>

* fix(server): optimize playlist import

Signed-off-by: Deluan <[email protected]>

* fix(server): add test with multiple libraries

Signed-off-by: Deluan <[email protected]>

* fix(server): refactor

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2025-02-26 22:26:38 -05:00
c795bcfcf7 feat(bfr): Big Refactor: new scanner, lots of new fields and tags, improvements and DB schema changes (#2709)
* fix(server): more race conditions when updating artist/album from external sources

Signed-off-by: Deluan <[email protected]>

* feat(scanner): add .gitignore syntax to .ndignore. Resolves #1394

Signed-off-by: Deluan <[email protected]>

* fix(ui): null

Signed-off-by: Deluan <[email protected]>

* fix(scanner): pass configfile option to child process

Signed-off-by: Deluan <[email protected]>

* fix(scanner): resume interrupted fullScans

Signed-off-by: Deluan <[email protected]>

* fix(scanner): remove old scanner code

Signed-off-by: Deluan <[email protected]>

* fix(scanner): rename old metadata package

Signed-off-by: Deluan <[email protected]>

* fix(scanner): move old metadata package

Signed-off-by: Deluan <[email protected]>

* fix: tests

Signed-off-by: Deluan <[email protected]>

* chore(deps): update Go to 1.23.4

Signed-off-by: Deluan <[email protected]>

* fix: logs

Signed-off-by: Deluan <[email protected]>

* fix(test):

Signed-off-by: Deluan <[email protected]>

* fix: log level

Signed-off-by: Deluan <[email protected]>

* fix: remove log message

Signed-off-by: Deluan <[email protected]>

* feat: add config for scanner watcher

Signed-off-by: Deluan <[email protected]>

* refactor: children playlists

Signed-off-by: Deluan <[email protected]>

* refactor: replace `interface{}` with `any`

Signed-off-by: Deluan <[email protected]>

* fix: smart playlists with genres

Signed-off-by: Deluan <[email protected]>

* fix: allow any tags in smart playlists

Signed-off-by: Deluan <[email protected]>

* fix: artist names in playlists

Signed-off-by: Deluan <[email protected]>

* fix: smart playlist's sort by tags

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add moods to child

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add moods to AlbumID3

Signed-off-by: Deluan <[email protected]>

* refactor(subsonic): use generic JSONArray for OS arrays

Signed-off-by: Deluan <[email protected]>

* refactor(subsonic): use https in test

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add releaseTypes to AlbumID3

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add recordLabels to AlbumID3

Signed-off-by: Deluan <[email protected]>

* refactor(subsonic): rename JSONArray to Array

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add artists to AlbumID3

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add artists to Child

Signed-off-by: Deluan <[email protected]>

* fix(scanner): do not pre-populate smart playlists

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): implement a simplified version of ArtistID3.

See https://github.com/opensubsonic/open-subsonic-api/discussions/120

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add artists to album child

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add contributors to mediafile Child

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add albumArtists to mediafile Child

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add displayArtist and displayAlbumArtist

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add displayComposer to Child

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add roles to ArtistID3

Signed-off-by: Deluan <[email protected]>

* fix(subsonic): use " • " separator for displayComposer

Signed-off-by: Deluan <[email protected]>

* refactor:

Signed-off-by: Deluan <[email protected]>

* fix(subsonic):

Signed-off-by: Deluan <[email protected]>

* fix(subsonic): respect `PreferSortTags` config option

Signed-off-by: Deluan <[email protected]>

* refactor(subsonic):

Signed-off-by: Deluan <[email protected]>

* refactor: optimize purging non-unused tags

Signed-off-by: Deluan <[email protected]>

* refactor: don't run 'refresh artist stats' concurrently with other transactions

Signed-off-by: Deluan <[email protected]>

* refactor:

Signed-off-by: Deluan <[email protected]>

* fix: log message

Signed-off-by: Deluan <[email protected]>

* feat: add Scanner.ScanOnStartup config option, default true

Signed-off-by: Deluan <[email protected]>

* feat: better json parsing error msg when importing NSPs

Signed-off-by: Deluan <[email protected]>

* fix: don't update album's imported_time when updating external_metadata

Signed-off-by: Deluan <[email protected]>

* fix: handle interrupted scans and full scans after migrations

Signed-off-by: Deluan <[email protected]>

* feat: run `analyze` when migration requires a full rescan

Signed-off-by: Deluan <[email protected]>

* feat: run `PRAGMA optimize` at the end of the scan

Signed-off-by: Deluan <[email protected]>

* fix: don't update artist's updated_at when updating external_metadata

Signed-off-by: Deluan <[email protected]>

* feat: handle multiple artists and roles in smart playlists

Signed-off-by: Deluan <[email protected]>

* feat(ui): dim missing tracks

Signed-off-by: Deluan <[email protected]>

* fix: album missing logic

Signed-off-by: Deluan <[email protected]>

* fix: error encoding in gob

Signed-off-by: Deluan <[email protected]>

* feat: separate warnings from errors

Signed-off-by: Deluan <[email protected]>

* fix: mark albums as missing if they were contained in a deleted folder

Signed-off-by: Deluan <[email protected]>

* refactor: add participant names to media_file and album tables

Signed-off-by: Deluan <[email protected]>

* refactor: use participations in criteria, instead of m2m relationship

Signed-off-by: Deluan <[email protected]>

* refactor: rename participations to participants

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add moods to album child

Signed-off-by: Deluan <[email protected]>

* fix: albumartist role case

Signed-off-by: Deluan <[email protected]>

* feat(scanner): run scanner as an external process by default

Signed-off-by: Deluan <[email protected]>

* fix(ui): show albumArtist names

Signed-off-by: Deluan <[email protected]>

* fix(ui): dim out missing albums

Signed-off-by: Deluan <[email protected]>

* fix: flaky test

Signed-off-by: Deluan <[email protected]>

* fix(server): scrobble buffer mapping. fix #3583

Signed-off-by: Deluan <[email protected]>

* refactor: more participations renaming

Signed-off-by: Deluan <[email protected]>

* fix: listenbrainz scrobbling

Signed-off-by: Deluan <[email protected]>

* feat: send release_group_mbid to listenbrainz

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): implement OpenSubsonic explicitStatus field (#3597)

* feat: implement OpenSubsonic explicitStatus field

* fix(subsonic): fix failing snapshot tests

* refactor: create helper for setting explicitStatus

* fix: store smaller values for explicit-status on database

* test: ToAlbum explicitStatus

* refactor: rename explicitStatus helper function

---------

Co-authored-by: Deluan Quintão <[email protected]>

* fix: handle album and track tags in the DB based on the mappings.yaml file

Signed-off-by: Deluan <[email protected]>

* save similar artists as JSONB

Signed-off-by: Deluan <[email protected]>

* fix: getAlbumList byGenre

Signed-off-by: Deluan <[email protected]>

* detect changes in PID configuration

Signed-off-by: Deluan <[email protected]>

* set default album PID to legacy_pid

Signed-off-by: Deluan <[email protected]>

* fix tests

Signed-off-by: Deluan <[email protected]>

* fix SIGSEGV

Signed-off-by: Deluan <[email protected]>

* fix: don't lose album stars/ratings when migrating

Signed-off-by: Deluan <[email protected]>

* store full PID conf in properties

Signed-off-by: Deluan <[email protected]>

* fix: keep album annotations when changing PID.Album config

Signed-off-by: Deluan <[email protected]>

* fix: reassign album annotations

Signed-off-by: Deluan <[email protected]>

* feat: use (display) albumArtist and add links to each artist

Signed-off-by: Deluan <[email protected]>

* fix: not showing albums by albumartist

Signed-off-by: Deluan <[email protected]>

* fix: error msgs

Signed-off-by: Deluan <[email protected]>

* fix: hide PID from Native API

Signed-off-by: Deluan <[email protected]>

* fix: album cover art resolution

Signed-off-by: Deluan <[email protected]>

* fix: trim participant names

Signed-off-by: Deluan <[email protected]>

* fix: reduce watcher log spam

Signed-off-by: Deluan <[email protected]>

* fix: panic when initializing the watcher

Signed-off-by: Deluan <[email protected]>

* fix: various artists

Signed-off-by: Deluan <[email protected]>

* fix: don't store empty lyrics in the DB

Signed-off-by: Deluan <[email protected]>

* remove unused methods

Signed-off-by: Deluan <[email protected]>

* drop full_text indexes, as they are not being used by SQLite

Signed-off-by: Deluan <[email protected]>

* keep album created_at when upgrading

Signed-off-by: Deluan <[email protected]>

* fix(ui): null pointer

Signed-off-by: Deluan <[email protected]>

* fix: album artwork cache

Signed-off-by: Deluan <[email protected]>

* fix: don't expose missing files in Subsonic API

Signed-off-by: Deluan <[email protected]>

* refactor: searchable interface

Signed-off-by: Deluan <[email protected]>

* fix: filter out missing items from subsonic search

* fix: filter out missing items from playlists

* fix: filter out missing items from shares

Signed-off-by: Deluan <[email protected]>

* feat(ui): add filter by artist role

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): only return albumartists in getIndexes and getArtists endpoints

Signed-off-by: Deluan <[email protected]>

* sort roles alphabetically

Signed-off-by: Deluan <[email protected]>

* fix: artist playcounts

Signed-off-by: Deluan <[email protected]>

* change default Album PID conf

Signed-off-by: Deluan <[email protected]>

* fix albumartist link when it does not match any albumartists values

Signed-off-by: Deluan <[email protected]>

* fix `Ignoring filter not whitelisted` (role) message

Signed-off-by: Deluan <[email protected]>

* fix: trim any names/titles being imported

Signed-off-by: Deluan <[email protected]>

* remove unused genre code

Signed-off-by: Deluan <[email protected]>

* serialize calls to Last.fm's getArtist

Signed-off-by: Deluan <[email protected]>

xxx

Signed-off-by: Deluan <[email protected]>

* add counters to genres

Signed-off-by: Deluan <[email protected]>

* nit: fix migration `notice` message

Signed-off-by: Deluan <[email protected]>

* optimize similar artists query

Signed-off-by: Deluan <[email protected]>

* fix: last.fm.getInfo when mbid does not exist

Signed-off-by: Deluan <[email protected]>

* ui only show missing items for admins

Signed-off-by: Deluan <[email protected]>

* don't allow interaction with missing items

Signed-off-by: Deluan <[email protected]>

* Add Missing Files view (WIP)

Signed-off-by: Deluan <[email protected]>

* refactor: merged tag_counts into tag table

Signed-off-by: Deluan <[email protected]>

* add option to completely disable automatic scanner

Signed-off-by: Deluan <[email protected]>

* add delete missing files functionality

Signed-off-by: Deluan <[email protected]>

* fix: playlists not showing for regular users

Signed-off-by: Deluan <[email protected]>

* reduce updateLastAccess frequency to once every minute

Signed-off-by: Deluan <[email protected]>

* reduce update player frequency to once every minute

Signed-off-by: Deluan <[email protected]>

* add timeout when updating player

Signed-off-by: Deluan <[email protected]>

* remove dead code

Signed-off-by: Deluan <[email protected]>

* fix duplicated roles in stats

Signed-off-by: Deluan <[email protected]>

* add `; ` to artist splitters

Signed-off-by: Deluan <[email protected]>

* fix stats query

Signed-off-by: Deluan <[email protected]>

* more logs

Signed-off-by: Deluan <[email protected]>

* fix: support legacy clients (DSub) by removing OpenSubsonic extra fields - WIP

Signed-off-by: Deluan <[email protected]>

* fix: support legacy clients (DSub) by removing OpenSubsonic extra fields - WIP

Signed-off-by: Deluan <[email protected]>

* fix: support legacy clients (DSub) by removing OpenSubsonic extra fields - WIP

Signed-off-by: Deluan <[email protected]>

* fix: support legacy clients (DSub) by removing OpenSubsonic extra fields - WIP

Signed-off-by: Deluan <[email protected]>

* add record label filter

Signed-off-by: Deluan <[email protected]>

* add release type filter

Signed-off-by: Deluan <[email protected]>

* fix purgeUnused tags

Signed-off-by: Deluan <[email protected]>

* add grouping filter to albums

Signed-off-by: Deluan <[email protected]>

* allow any album tags to be used in as filters in the API

Signed-off-by: Deluan <[email protected]>

* remove empty tags from album info

Signed-off-by: Deluan <[email protected]>

* comments in the migration

Signed-off-by: Deluan <[email protected]>

* fix: Cannot read properties of undefined

Signed-off-by: Deluan <[email protected]>

* fix: listenbrainz scrobbling (#3640)

Signed-off-by: Deluan <[email protected]>

* fix: remove duplicated tag values

Signed-off-by: Deluan <[email protected]>

* fix: don't ignore the taglib folder!

Signed-off-by: Deluan <[email protected]>

* feat: show track subtitle tag

Signed-off-by: Deluan <[email protected]>

* fix: show artists stats based on selected role

Signed-off-by: Deluan <[email protected]>

* fix: inspect

Signed-off-by: Deluan <[email protected]>

* add media type to album info/filters

Signed-off-by: Deluan <[email protected]>

* fix: change format of subtitle in the UI

Signed-off-by: Deluan <[email protected]>

* fix: subtitle in Subsonic API and search

Signed-off-by: Deluan <[email protected]>

* fix: subtitle in UI's player

Signed-off-by: Deluan <[email protected]>

* fix: split strings should be case-insensitive

Signed-off-by: Deluan <[email protected]>

* disable ScanSchedule

Signed-off-by: Deluan <[email protected]>

* increase default sessiontimeout

Signed-off-by: Deluan <[email protected]>

* add sqlite command line tool to docker image

Signed-off-by: Deluan <[email protected]>

* fix: resources override

Signed-off-by: Deluan <[email protected]>

* fix: album PID conf

Signed-off-by: Deluan <[email protected]>

* change migration to mark current artists as albumArtists

Signed-off-by: Deluan <[email protected]>

* feat(ui): Allow filtering on multiple genres (#3679)

* feat(ui): Allow filtering on multiple genres

Signed-off-by: Henrik Nordvik <[email protected]>
Signed-off-by: Deluan <[email protected]>

* add multi-genre filter in Album list

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Henrik Nordvik <[email protected]>
Signed-off-by: Deluan <[email protected]>
Co-authored-by: Henrik Nordvik <[email protected]>

* add more multi-valued tag filters to Album and Song views

Signed-off-by: Deluan <[email protected]>

* fix(ui): unselect missing files after removing

Signed-off-by: Deluan <[email protected]>

* fix(ui): song filter

Signed-off-by: Deluan <[email protected]>

* fix sharing tracks. fix #3687

Signed-off-by: Deluan <[email protected]>

* use rowids when using search for sync (ex: Symfonium)

Signed-off-by: Deluan <[email protected]>

* fix "Report Real Paths" option for subsonic clients

Signed-off-by: Deluan <[email protected]>

* fix "Report Real Paths" option for subsonic clients for search

Signed-off-by: Deluan <[email protected]>

* add libraryPath to Native API /songs endpoint

Signed-off-by: Deluan <[email protected]>

* feat(subsonic): add album version

Signed-off-by: Deluan <[email protected]>

* made all tags lowercase as they are case-insensitive anyways.

Signed-off-by: Deluan <[email protected]>

* feat(ui): Show full paths, extended properties for album/song (#3691)

* feat(ui): Show full paths, extended properties for album/song

- uses library path + os separator + path
- show participants (album/song) and tags (song)
- make album/participant clickable in show info

* add source to path

* fix pathSeparator in UI

Signed-off-by: Deluan <[email protected]>

* fix local artist artwork (#3695)

Signed-off-by: Deluan <[email protected]>

* fix: parse vorbis performers

Signed-off-by: Deluan <[email protected]>

* refactor: clean function into smaller functions

Signed-off-by: Deluan <[email protected]>

* fix translations for en and pt

Signed-off-by: Deluan <[email protected]>

* add trace log to show annotations reassignment

Signed-off-by: Deluan <[email protected]>

* add trace log to show annotations reassignment

Signed-off-by: Deluan <[email protected]>

* fix: allow performers without instrument/subrole

Signed-off-by: Deluan <[email protected]>

* refactor: metadata clean function again

Signed-off-by: Deluan <[email protected]>

* refactor: optimize split function

Signed-off-by: Deluan <[email protected]>

* refactor: split function is now a method of TagConf

Signed-off-by: Deluan <[email protected]>

* fix: humanize Artist total size

Signed-off-by: Deluan <[email protected]>

* add album version to album details

Signed-off-by: Deluan <[email protected]>

* don't display album-level tags in SongInfo

Signed-off-by: Deluan <[email protected]>

* fix genre clicking in Album Page

Signed-off-by: Deluan <[email protected]>

* don't use mbids in Last.fm api calls.

From https://discord.com/channels/671335427726114836/704303730660737113/1337574018143879248:

With MBID:
```
GET https://ws.audioscrobbler.com/2.0/?api_key=XXXX&artist=Van+Morrison&format=json&lang=en&mbid=a41ac10f-0a56-4672-9161-b83f9b223559&method=artist.getInfo

{
artist: {
name: "Bee Gees",
mbid: "bf0f7e29-dfe1-416c-b5c6-f9ebc19ea810",
url: "https://www.last.fm/music/Bee+Gees",
}
```

Without MBID:
```
GET https://ws.audioscrobbler.com/2.0/?api_key=XXXX&artist=Van+Morrison&format=json&lang=en&method=artist.getInfo

{
artist: {
name: "Van Morrison",
mbid: "a41ac10f-0a56-4672-9161-b83f9b223559",
url: "https://www.last.fm/music/Van+Morrison",
}
```

Signed-off-by: Deluan <[email protected]>

* better logging for when the artist folder is not found

Signed-off-by: Deluan <[email protected]>

* fix various issues with artist image resolution

Signed-off-by: Deluan <[email protected]>

* hide "Additional Tags" header if there are none.

Signed-off-by: Deluan <[email protected]>

* simplify tag rendering

Signed-off-by: Deluan <[email protected]>

* enhance logging for artist folder detection

Signed-off-by: Deluan <[email protected]>

* make folderID consistent for relative and absolute folderPaths

Signed-off-by: Deluan <[email protected]>

* handle more folder paths scenarios

Signed-off-by: Deluan <[email protected]>

* filter out other roles when SubsonicArtistParticipations = true

Signed-off-by: Deluan <[email protected]>

* fix "Cannot read properties of undefined"

Signed-off-by: Deluan <[email protected]>

* fix lyrics and comments being truncated (#3701)

* fix lyrics and comments being truncated

* specifically test for lyrics and comment length

* reorder assertions

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
Co-authored-by: Deluan <[email protected]>

* fix(server): Expose library_path for playlist (#3705)

Allows showing absolute path for UI, and makes "report real path" work for playlists (Subsonic)

* fix BFR on Windows (#3704)

* fix potential reflected cross-site scripting vulnerability

Signed-off-by: Deluan <[email protected]>

* hack to make it work on Windows

* ignore windows executables

* try fixing the pipeline

Signed-off-by: Deluan <[email protected]>

* allow MusicFolder in other drives

* move windows local drive logic to local storage implementation

---------

Signed-off-by: Deluan <[email protected]>

* increase pagination sizes for missing files

Signed-off-by: Deluan <[email protected]>

* reduce level of "already scanning" watcher log message

Signed-off-by: Deluan <[email protected]>

* only count folders with audio files in it

See https://github.com/navidrome/navidrome/discussions/3676#discussioncomment-11990930

Signed-off-by: Deluan <[email protected]>

* add album version and catalog number to search

Signed-off-by: Deluan <[email protected]>

* add `organization` alias for `recordlabel`

Signed-off-by: Deluan <[email protected]>

* remove mbid from Last.fm agent

Signed-off-by: Deluan <[email protected]>

* feat: support inspect in ui (#3726)

* inspect in ui

* address round 1

* add catalogNum to AlbumInfo

Signed-off-by: Deluan <[email protected]>

* remove dependency on metadata_old (deprecated) package

Signed-off-by: Deluan <[email protected]>

* add `RawTags` to model

Signed-off-by: Deluan <[email protected]>

* support parsing MBIDs for roles (from the https://github.com/kgarner7/picard-all-mbids plugin) (#3698)


* parse standard roles, vorbis/m4a work for now

* fix djmixer

* working roles, use DJ-mix

* add performers to file

* map mbids

* add a few more tests

* add test

Signed-off-by: Deluan <[email protected]>

* try to simplify the performers logic

Signed-off-by: Deluan <[email protected]>

* stylistic changes

---------

Signed-off-by: Deluan <[email protected]>
Co-authored-by: Deluan <[email protected]>

* remove param mutation

Signed-off-by: Deluan <[email protected]>

* run automated SQLite optimizations

Signed-off-by: Deluan <[email protected]>

* fix playlists import/export on Windows

* fix import playlists

* fix export playlists

* better handling of Windows volumes

Signed-off-by: Deluan <[email protected]>

* handle more album ID reassignments

Signed-off-by: Deluan <[email protected]>

* allow adding/overriding tags in the config file

Signed-off-by: Deluan <[email protected]>

* fix(ui): Fix playlist track id, handle missing tracks better (#3734)

- Use `mediaFileId` instead of `id` for playlist tracks
- Only fetch if the file is not missing
- If extractor fails to get the file, also error (rather than panic)

* optimize DB after each scan.

Signed-off-by: Deluan <[email protected]>

* remove sortable from AlbumSongs columns

Signed-off-by: Deluan <[email protected]>

* simplify query to get missing tracks

Signed-off-by: Deluan <[email protected]>

* mark Scanner.Extractor as deprecated

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
Signed-off-by: Henrik Nordvik <[email protected]>
Co-authored-by: Caio Cotts <[email protected]>
Co-authored-by: Henrik Nordvik <[email protected]>
Co-authored-by: Kendall Garner <[email protected]>
2025-02-19 20:35:17 -05:00
Deluan 7f030b0859 fix(server): encrypt jwt secret at rest
Signed-off-by: Deluan <[email protected]>
2024-12-05 21:52:15 -05:00
Deluan d229ff39e5 refactor: reduce GC pressure by pre-allocating slices
Signed-off-by: Deluan <[email protected]>
2024-11-19 18:41:50 -05:00
Deluan QuintãoandGitHub cd0cf7c12b feat: cache login background images (#3462)
* feat: use direct links to unsplash for background images

Signed-off-by: Deluan <[email protected]>

* feat: cache images from unsplash

Signed-off-by: Deluan <[email protected]>

* refactor: use cache.HTTPClient to reduce complexity

Signed-off-by: Deluan <[email protected]>

* refactor: remove magic numbers

Signed-off-by: Deluan <[email protected]>

---------

Signed-off-by: Deluan <[email protected]>
2024-11-08 20:23:30 -05:00
Deluan QuintãoandGitHub a557f37834 refactor: small improvements and clean up (#3423)
* refactor: replace custom map functions with slice.Map

* refactor: extract StringerValue function

* refactor: removed unnecessary if

* chore: removed invalid comment

* refactor: replace more map functions

* chore: fix FFmpeg typo
2024-10-22 22:54:31 -04:00
Deluan QuintãoandGitHub 669c8f4c49 refactor(server): replace RangeByChunks with Go 1.23 iterators (#3292)
* 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
2024-09-22 11:47:10 -04:00
Deluan ecf934feab fix(subsonic): random albums not reshuffling.
See: https://github.com/navidrome/navidrome/issues/3277#issuecomment-2364269787
2024-09-20 16:59:46 -04:00
Deluan 46be041e7b fix(scanner): improve M3U playlist import times (#2706) 2024-09-18 20:12:12 -04:00
Deluan e8d0f2ec2c Allow searching songs by filepath, for songs without Title 2024-09-13 18:04:21 -04:00
Deluan c95fa11a2f Remove potential integer overflow conversion uint64 -> int64 2024-08-22 19:28:22 -04:00
Deluan QuintãoandGitHub c4bd0e67fa Upgrade Go to 1.23 (#3190)
* Upgrade to Golang 1.23rc1

* Fix imports

* Go 1.23 final version

* Fix lint compatibility with ci-goreleaser
2024-08-19 17:47:54 -04:00
Deluan 76c3f5131a Use SHA256 in Gravatar URLs 2024-07-23 17:49:46 -04:00
Deluan d046c180bf Fix race condition 2024-07-22 14:27:02 -04:00
Deluan 3bc9e75b28 Evict expired items from SimpleCache 2024-06-24 17:32:34 -04:00
Deluan 3993c4d17f Upgrade to ttlcache/v3 2024-06-21 18:09:34 -04:00
Deluan 29b7b740ce Also use SimpleCache in cache.HTTPClient 2024-06-21 17:40:18 -04:00
Deluan 29bc17acd7 Wrap ttlcache in our own SimpleCache implementation 2024-06-21 17:21:09 -04:00
Deluan 0f7d6b5bc4 More micro-optimizations 2024-06-06 07:11:43 -04:00
Deluan 939f3eee97 Initialize Index Groups regex just once 2024-06-05 23:00:36 -04:00
Deluan b4ef1b1e38 Replace gg.If with cmp.Or 2024-06-05 22:48:00 -04:00
Deluan 11bef060a3 Small refactoring 2024-06-05 22:40:22 -04:00
Deluan abe5690018 Refactor string utilities into its own package str 2024-06-05 22:09:27 -04:00
Deluan 46fc38bf61 Fix tests expectations 2024-06-05 19:54:25 -04:00
Deluan b2ecc1d16f Fix G404 gosec lint error 2024-05-19 21:55:19 -04:00
Deluan bcaa180fc7 Fix 32 bits builds 2024-05-19 13:03:13 -04:00
Deluan 3977ef6e0f Make first WebUI random page stick 2024-05-19 12:35:30 -04:00