package arr import ( "context" "fmt" "net/http" "net/url" "strings" ) // Release is an indexer search result from an interactive search. type Release struct { GUID string `json:"guid"` Title string `json:"title"` Indexer string `json:"indexer"` IndexerID int `json:"indexerId"` Protocol string `json:"protocol"` // usenet or torrent Size int64 `json:"size"` AgeMinutes float64 `json:"ageMinutes"` QualityWeight int `json:"qualityWeight"` CustomFormatScore int `json:"customFormatScore"` ReleaseGroup string `json:"releaseGroup"` Approved bool `json:"approved"` Rejected bool `json:"rejected"` TemporarilyRejected bool `json:"temporarilyRejected"` Rejections []string `json:"rejections"` FullSeason bool `json:"fullSeason"` Quality struct { Quality struct { Name string `json:"name"` } `json:"quality"` } `json:"quality"` Languages []struct { Name string `json:"name"` } `json:"languages"` } // QualityName returns the release's quality, e.g. "Bluray-1080p". func (r Release) QualityName() string { return r.Quality.Quality.Name } // LanguageNames returns the release's languages joined by commas. func (r Release) LanguageNames() string { names := make([]string, len(r.Languages)) for i, l := range r.Languages { names[i] = l.Name } return strings.Join(names, ", ") } // Releases runs an interactive search with the given query, e.g. movieId=12. // Searching queries every indexer and can take a while; use a generous timeout. func (c *Client) Releases(ctx context.Context, query url.Values) ([]Release, error) { var releases []Release err := c.Do(ctx, http.MethodGet, "release", query, nil, &releases) return releases, err } // Grab sends a release found by a previous search to the download client. // Releases that were rejected can be grabbed as well. func (c *Client) Grab(ctx context.Context, r Release) error { if r.GUID == "" { return fmt.Errorf("release has no guid") } body := map[string]any{"guid": r.GUID, "indexerId": r.IndexerID} return c.Do(ctx, http.MethodPost, "release", nil, body, nil) }