diff --git a/internal/lidarr/client.go b/internal/lidarr/client.go index 3c6b7d4b..9d90cc51 100644 --- a/internal/lidarr/client.go +++ b/internal/lidarr/client.go @@ -274,13 +274,20 @@ func (c *Client) LookupTrack(ctx context.Context, term string) ([]LookupResult, return out, nil } -// AddArtist posts to POST /api/v1/artist. MonitorAll=true sends monitor="all"; -// false sends "future". Returns nil on 2xx; typed error otherwise. +// AddArtist posts to POST /api/v1/artist. MonitorAll=true monitors every +// album ("all"); false monitors only releases from now on ("future"). New +// releases are monitored either way. Returns nil on 2xx; typed error +// otherwise. // // All four of artistName, foreignArtistId, qualityProfileId, and // metadataProfileId are required by Lidarr. Omitting any one produces a // 400 with field-level validation messages (e.g. "'Metadata Profile Id' // must be greater than '0'"). +// +// The monitor choice belongs in addOptions (AddArtistOptions, a +// MonitoringOptions). ArtistResource has no top-level `monitor`, so a +// choice sent there is dropped, AddOptions.Monitor stays Unknown and +// Lidarr skips applying it (#5239). func (c *Client) AddArtist(ctx context.Context, p AddArtistParams) error { monitor := "future" if p.MonitorAll { @@ -293,8 +300,12 @@ func (c *Client) AddArtist(ctx context.Context, p AddArtistParams) error { "metadataProfileId": p.MetadataProfileID, "rootFolderPath": p.RootFolderPath, "monitored": true, - "monitor": monitor, - "addOptions": map[string]any{"searchForMissingAlbums": true}, + "monitorNewItems": "all", + "addOptions": map[string]any{ + "monitor": monitor, + "monitored": true, + "searchForMissingAlbums": true, + }, }) if err != nil { return fmt.Errorf("%w: marshal: %v", ErrInvalidPayload, err) diff --git a/internal/lidarr/client_test.go b/internal/lidarr/client_test.go index c797af00..43e7b0af 100644 --- a/internal/lidarr/client_test.go +++ b/internal/lidarr/client_test.go @@ -288,13 +288,24 @@ func TestAddArtist_PostsCorrectBody(t *testing.T) { if decoded["monitored"] != true { t.Errorf("monitored = %v, want true", decoded["monitored"]) } - if decoded["monitor"] != "all" { - t.Errorf("monitor = %v, want all (MonitorAll=true)", decoded["monitor"]) + if decoded["monitorNewItems"] != "all" { + t.Errorf("monitorNewItems = %v, want all", decoded["monitorNewItems"]) + } + // #5239: ArtistResource has no top-level monitor; Lidarr reads the + // choice from addOptions and silently drops it anywhere else. + if _, set := decoded["monitor"]; set { + t.Errorf("monitor sent at top level (%v), where Lidarr ignores it", decoded["monitor"]) } opts, ok := decoded["addOptions"].(map[string]any) if !ok { t.Fatalf("addOptions missing or wrong type: %T", decoded["addOptions"]) } + if opts["monitor"] != "all" { + t.Errorf("addOptions.monitor = %v, want all (MonitorAll=true)", opts["monitor"]) + } + if opts["monitored"] != true { + t.Errorf("addOptions.monitored = %v, want true", opts["monitored"]) + } if opts["searchForMissingAlbums"] != true { t.Errorf("addOptions.searchForMissingAlbums = %v, want true", opts["searchForMissingAlbums"]) } @@ -309,8 +320,8 @@ func TestAddArtist_MonitorFuture(t *testing.T) { defer srv.Close() _ = c.AddArtist(context.Background(), AddArtistParams{MonitorAll: false}) - if decoded["monitor"] != "future" { - t.Errorf("monitor = %v, want future (MonitorAll=false)", decoded["monitor"]) + if opts, _ := decoded["addOptions"].(map[string]any); opts["monitor"] != "future" { + t.Errorf("addOptions.monitor = %v, want future (MonitorAll=false)", opts["monitor"]) } } diff --git a/internal/lidarr/types.go b/internal/lidarr/types.go index 7a5858f7..3fd9db36 100644 --- a/internal/lidarr/types.go +++ b/internal/lidarr/types.go @@ -57,7 +57,7 @@ type AddArtistParams struct { QualityProfileID int MetadataProfileID int RootFolderPath string - MonitorAll bool // true => monitor="all"; false => "future" + MonitorAll bool // true => addOptions.monitor="all"; false => "future" } // AddAlbumParams identify the album to add and carry the settings Lidarr