97 lines
3.1 KiB
Go
97 lines
3.1 KiB
Go
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"`
|
|
Resolution int `json:"resolution"`
|
|
} `json:"quality"`
|
|
} `json:"quality"`
|
|
Languages []struct {
|
|
Name string `json:"name"`
|
|
} `json:"languages"`
|
|
CustomFormats []struct {
|
|
Name string `json:"name"`
|
|
} `json:"customFormats"`
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// Attrs derives the filterable properties from what the release announces:
|
|
// its title, quality, custom formats and languages. Codec and HDR only show up
|
|
// when the uploader put them into the title.
|
|
func (r Release) Attrs() FileAttrs {
|
|
names := []string{r.Title, r.Quality.Quality.Name}
|
|
for _, cf := range r.CustomFormats {
|
|
names = append(names, cf.Name)
|
|
}
|
|
text := strings.Join(names, " ")
|
|
|
|
a := FileAttrs{Resolution: r.Quality.Quality.Resolution, Codec: codecOf(text)}
|
|
if a.Resolution == 0 {
|
|
if m := reRes.FindStringSubmatch(text); m != nil {
|
|
a.Resolution = atoi(m[1])
|
|
}
|
|
}
|
|
a.DV = reDV.MatchString(text)
|
|
a.HDR = reHDR.MatchString(text)
|
|
for _, l := range r.Languages {
|
|
if l.Name != "" {
|
|
a.Languages = append(a.Languages, l.Name)
|
|
}
|
|
}
|
|
return a
|
|
}
|