Adds internal/arr with a shared HTTP layer and per-service clients that look up candidates and POST the chosen one back with monitored=true and search-on-add enabled. Lidarr requires metadata_profile_id, now part of ArrConfig and validated when lidarr is set.
61 lines
1.4 KiB
Go
61 lines
1.4 KiB
Go
package arr
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"bellhop/internal/config"
|
|
)
|
|
|
|
// Radarr drives a Radarr v3 instance.
|
|
type Radarr struct {
|
|
h *httpClient
|
|
qualityProfileID int
|
|
rootFolder string
|
|
}
|
|
|
|
func NewRadarr(cfg *config.ArrConfig) *Radarr {
|
|
return &Radarr{
|
|
h: newHTTP(cfg.URL, cfg.APIKey),
|
|
qualityProfileID: cfg.QualityProfileID,
|
|
rootFolder: cfg.RootFolder,
|
|
}
|
|
}
|
|
|
|
func (r *Radarr) Search(ctx context.Context, term string) ([]Result, error) {
|
|
body, err := r.h.get(ctx, "/api/v3/movie/lookup", map[string]string{"term": term})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseLookup(body, "title")
|
|
}
|
|
|
|
func (r *Radarr) Add(ctx context.Context, res Result) error {
|
|
if len(res.raw) == 0 {
|
|
return fmt.Errorf("radarr: empty result")
|
|
}
|
|
body, err := buildAddBody(res.raw, map[string]any{
|
|
"qualityProfileId": r.qualityProfileID,
|
|
"rootFolderPath": r.rootFolder,
|
|
"monitored": true,
|
|
"addOptions": map[string]any{
|
|
"searchForMovie": true,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = r.h.post(ctx, "/api/v3/movie", body)
|
|
return err
|
|
}
|
|
|
|
// compile-time interface check
|
|
var _ Client = (*Radarr)(nil)
|
|
|
|
// makeResult is a tiny helper used by tests in this package to construct a
|
|
// Result from arbitrary JSON without going through the network.
|
|
func makeResult(title string, year int, raw string) Result {
|
|
return Result{Title: title, Year: year, raw: json.RawMessage(raw)}
|
|
}
|