package client import ( "bytes" "encoding/json" "fmt" "net/http" "github.com/fjurmanovic/sugarr/internal/utl/configs" ) type RadarrMovie struct { Title string `json:"title"` TmdbId int `json:"tmdbId"` QualityProfileId int `json:"qualityProfileId"` RootFolderPath string `json:"rootFolderPath"` Monitored bool `json:"monitored"` AddOptions radarrAddOptions `json:"addOptions"` } type radarrAddOptions struct { SearchForMovie bool `json:"searchForMovie"` } type RadarrClient struct { url string apiKey string qualityProfile int rootFolder string http *http.Client } func NewRadarrClient(cfg *configs.Config) *RadarrClient { return &RadarrClient{ url: cfg.RadarrURL, apiKey: cfg.RadarrAPIKey, qualityProfile: cfg.RadarrQualityProfile, rootFolder: cfg.RadarrRootFolder, http: &http.Client{}, } } func (c *RadarrClient) newRequest(method, path string, body []byte) (*http.Request, error) { var req *http.Request var err error if body != nil { req, err = http.NewRequest(method, c.url+path, bytes.NewReader(body)) } else { req, err = http.NewRequest(method, c.url+path, nil) } if err != nil { return nil, err } req.Header.Set("X-Api-Key", c.apiKey) req.Header.Set("Accept", "application/json") if body != nil { req.Header.Set("Content-Type", "application/json") } return req, nil } func (c *RadarrClient) Lookup(tmdbID int) (*RadarrMovie, error) { req, err := c.newRequest(http.MethodGet, fmt.Sprintf("/api/v3/movie/lookup/tmdb?tmdbId=%d", tmdbID), nil) if err != nil { return nil, err } resp, err := c.http.Do(req) if err != nil { return nil, fmt.Errorf("radarr lookup failed: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("radarr lookup returned status %d", resp.StatusCode) } var movie RadarrMovie if err := json.NewDecoder(resp.Body).Decode(&movie); err != nil { return nil, fmt.Errorf("decoding radarr lookup response: %w", err) } movie.QualityProfileId = c.qualityProfile movie.RootFolderPath = c.rootFolder movie.Monitored = true movie.AddOptions = radarrAddOptions{SearchForMovie: true} return &movie, nil } // AddMovie adds a movie to Radarr. Treats HTTP 400 (already exists) as success. func (c *RadarrClient) AddMovie(movie RadarrMovie) error { body, err := json.Marshal(movie) if err != nil { return err } req, err := c.newRequest(http.MethodPost, "/api/v3/movie", body) if err != nil { return err } resp, err := c.http.Do(req) if err != nil { return fmt.Errorf("radarr add movie failed: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusBadRequest { return fmt.Errorf("radarr add movie returned status %d", resp.StatusCode) } return nil } func (c *RadarrClient) GetExisting() ([]RadarrMovie, error) { req, err := c.newRequest(http.MethodGet, "/api/v3/movie", nil) if err != nil { return nil, err } resp, err := c.http.Do(req) if err != nil { return nil, fmt.Errorf("radarr get existing failed: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("radarr get existing returned status %d", resp.StatusCode) } var movies []RadarrMovie if err := json.NewDecoder(resp.Body).Decode(&movies); err != nil { return nil, fmt.Errorf("decoding radarr movies: %w", err) } return movies, nil }