Changelog 0.5.0
This commit is contained in:
+47
-11
@@ -2,13 +2,16 @@ package arr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/sirrobot01/debrid-blackhole/internal/config"
|
||||
"github.com/sirrobot01/debrid-blackhole/internal/request"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Type is a type of arr
|
||||
@@ -21,51 +24,84 @@ const (
|
||||
Readarr Type = "readarr"
|
||||
)
|
||||
|
||||
var (
|
||||
client *request.RLHTTPClient = request.NewRLHTTPClient(nil, nil)
|
||||
)
|
||||
|
||||
type Arr struct {
|
||||
Name string `json:"name"`
|
||||
Host string `json:"host"`
|
||||
Token string `json:"token"`
|
||||
Type Type `json:"type"`
|
||||
Cleanup bool `json:"cleanup"`
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func New(name, host, token string, cleanup bool) *Arr {
|
||||
return &Arr{
|
||||
Name: name,
|
||||
Host: host,
|
||||
Token: token,
|
||||
Token: strings.TrimSpace(token),
|
||||
Type: InferType(host, name),
|
||||
Cleanup: cleanup,
|
||||
client: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Arr) Request(method, endpoint string, payload interface{}) (*http.Response, error) {
|
||||
if a.Token == "" || a.Host == "" {
|
||||
return nil, nil
|
||||
return nil, fmt.Errorf("arr not configured")
|
||||
}
|
||||
url, err := request.JoinURL(a.Host, endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var jsonPayload []byte
|
||||
|
||||
var body io.Reader
|
||||
if payload != nil {
|
||||
jsonPayload, err = json.Marshal(payload)
|
||||
b, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body = bytes.NewReader(b)
|
||||
}
|
||||
req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonPayload))
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-Api-Key", a.Token)
|
||||
return client.Do(req)
|
||||
if a.client == nil {
|
||||
a.client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
|
||||
for attempts := 0; attempts < 5; attempts++ {
|
||||
resp, err = a.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If we got a 401, wait briefly and retry
|
||||
if resp.StatusCode == http.StatusUnauthorized {
|
||||
resp.Body.Close() // Don't leak response bodies
|
||||
if attempts < 4 { // Don't sleep on the last attempt
|
||||
time.Sleep(time.Duration(attempts+1) * 100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (a *Arr) Validate() error {
|
||||
|
||||
+31
-11
@@ -7,25 +7,38 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (a *Arr) GetMedia(tvId string) ([]Content, error) {
|
||||
type episode struct {
|
||||
Id int `json:"id"`
|
||||
EpisodeFileID int `json:"episodeFileId"`
|
||||
}
|
||||
|
||||
func (a *Arr) GetMedia(mediaId string) ([]Content, error) {
|
||||
// Get series
|
||||
resp, err := a.Request(http.MethodGet, fmt.Sprintf("api/v3/series?tvdbId=%s", tvId), nil)
|
||||
if a.Type == Radarr {
|
||||
return GetMovies(a, mediaId)
|
||||
}
|
||||
// This is likely Sonarr
|
||||
resp, err := a.Request(http.MethodGet, fmt.Sprintf("api/v3/series?tvdbId=%s", mediaId), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
// This is likely Radarr
|
||||
return GetMovies(a, tvId)
|
||||
return GetMovies(a, mediaId)
|
||||
}
|
||||
a.Type = Sonarr
|
||||
defer resp.Body.Close()
|
||||
|
||||
type series struct {
|
||||
Title string `json:"title"`
|
||||
Id int `json:"id"`
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to get series: %s", resp.Status)
|
||||
}
|
||||
var data []series
|
||||
if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to decode series: %v", err)
|
||||
}
|
||||
// Get series files
|
||||
contents := make([]Content, 0)
|
||||
@@ -43,11 +56,6 @@ func (a *Arr) GetMedia(tvId string) ([]Content, error) {
|
||||
Title: d.Title,
|
||||
Id: d.Id,
|
||||
}
|
||||
|
||||
type episode struct {
|
||||
Id int `json:"id"`
|
||||
EpisodeFileID int `json:"episodeFileId"`
|
||||
}
|
||||
resp, err = a.Request(http.MethodGet, fmt.Sprintf("api/v3/episode?seriesId=%d", d.Id), nil)
|
||||
if err != nil {
|
||||
continue
|
||||
@@ -67,12 +75,20 @@ func (a *Arr) GetMedia(tvId string) ([]Content, error) {
|
||||
if !ok {
|
||||
eId = 0
|
||||
}
|
||||
if file.Id == 0 || file.Path == "" {
|
||||
// Skip files without path
|
||||
continue
|
||||
}
|
||||
files = append(files, ContentFile{
|
||||
FileId: file.Id,
|
||||
Path: file.Path,
|
||||
Id: eId,
|
||||
})
|
||||
}
|
||||
if len(files) == 0 {
|
||||
// Skip series without files
|
||||
continue
|
||||
}
|
||||
ct.Files = files
|
||||
contents = append(contents, ct)
|
||||
}
|
||||
@@ -92,7 +108,7 @@ func GetMovies(a *Arr, tvId string) ([]Content, error) {
|
||||
defer resp.Body.Close()
|
||||
var movies []Movie
|
||||
if err = json.NewDecoder(resp.Body).Decode(&movies); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to decode movies: %v", err)
|
||||
}
|
||||
contents := make([]Content, 0)
|
||||
for _, movie := range movies {
|
||||
@@ -101,6 +117,10 @@ func GetMovies(a *Arr, tvId string) ([]Content, error) {
|
||||
Id: movie.Id,
|
||||
}
|
||||
files := make([]ContentFile, 0)
|
||||
if movie.MovieFile.Id == 0 || movie.MovieFile.Path == "" {
|
||||
// Skip movies without files
|
||||
continue
|
||||
}
|
||||
files = append(files, ContentFile{
|
||||
FileId: movie.MovieFile.Id,
|
||||
Id: movie.Id,
|
||||
|
||||
@@ -8,7 +8,6 @@ type Movie struct {
|
||||
MovieId int `json:"movieId"`
|
||||
RelativePath string `json:"relativePath"`
|
||||
Path string `json:"path"`
|
||||
Size int `json:"size"`
|
||||
Id int `json:"id"`
|
||||
} `json:"movieFile"`
|
||||
Id int `json:"id"`
|
||||
|
||||
Reference in New Issue
Block a user