mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 16:59:12 +00:00
feat(download-clients): improve errors for starr apps (#250)
* feat(actions): improve errors for starr apps * fix: tests expected error * feat: radarr improve logging * feat: sonarr improve logging and errors * feat: lidarr improve logging and errors
This commit is contained in:
parent
e5a95415a1
commit
3d018404a9
8 changed files with 279 additions and 107 deletions
|
@ -4,6 +4,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
@ -11,7 +13,7 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *client) get(endpoint string) (*http.Response, error) {
|
func (c *client) get(endpoint string) (int, []byte, error) {
|
||||||
u, err := url.Parse(c.config.Hostname)
|
u, err := url.Parse(c.config.Hostname)
|
||||||
u.Path = path.Join(u.Path, "/api/v1/", endpoint)
|
u.Path = path.Join(u.Path, "/api/v1/", endpoint)
|
||||||
reqUrl := u.String()
|
reqUrl := u.String()
|
||||||
|
@ -19,27 +21,29 @@ func (c *client) get(endpoint string) (*http.Response, error) {
|
||||||
req, err := http.NewRequest(http.MethodGet, reqUrl, http.NoBody)
|
req, err := http.NewRequest(http.MethodGet, reqUrl, http.NoBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("lidarr client request error : %v", reqUrl)
|
log.Error().Err(err).Msgf("lidarr client request error : %v", reqUrl)
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.config.BasicAuth {
|
if c.config.BasicAuth {
|
||||||
req.SetBasicAuth(c.config.Username, c.config.Password)
|
req.SetBasicAuth(c.config.Username, c.config.Password)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Add("X-Api-Key", c.config.APIKey)
|
c.setHeaders(req)
|
||||||
req.Header.Set("User-Agent", "autobrr")
|
|
||||||
|
|
||||||
res, err := c.http.Do(req)
|
resp, err := c.http.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("lidarr client request error : %v", reqUrl)
|
log.Error().Err(err).Msgf("lidarr client.get request error: %v", reqUrl)
|
||||||
return nil, err
|
return 0, nil, fmt.Errorf("lidarr.http.Do(req): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.StatusCode == http.StatusUnauthorized {
|
defer resp.Body.Close()
|
||||||
return nil, errors.New("unauthorized: bad credentials")
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err = io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return resp.StatusCode, nil, fmt.Errorf("lidarr.io.Copy: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return resp.StatusCode, buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) post(endpoint string, data interface{}) (*http.Response, error) {
|
func (c *client) post(endpoint string, data interface{}) (*http.Response, error) {
|
||||||
|
@ -85,3 +89,56 @@ func (c *client) post(endpoint string, data interface{}) (*http.Response, error)
|
||||||
// return raw response and let the caller handle json unmarshal of body
|
// return raw response and let the caller handle json unmarshal of body
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *client) postBody(endpoint string, data interface{}) (int, []byte, error) {
|
||||||
|
u, err := url.Parse(c.config.Hostname)
|
||||||
|
u.Path = path.Join(u.Path, "/api/v1/", endpoint)
|
||||||
|
reqUrl := u.String()
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("lidarr client could not marshal data: %v", reqUrl)
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, reqUrl, bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("lidarr client request error: %v", reqUrl)
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.config.BasicAuth {
|
||||||
|
req.SetBasicAuth(c.config.Username, c.config.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.setHeaders(req)
|
||||||
|
|
||||||
|
resp, err := c.http.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("lidarr client request error: %v", reqUrl)
|
||||||
|
return 0, nil, fmt.Errorf("lidarr.http.Do(req): %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err = io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return resp.StatusCode, nil, fmt.Errorf("lidarr.io.Copy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||||
|
return resp.StatusCode, buf.Bytes(), fmt.Errorf("lidarr: bad request: %v (status: %s): %s", resp.Request.RequestURI, resp.Status, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.StatusCode, buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) setHeaders(req *http.Request) {
|
||||||
|
if req.Body != nil {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("User-Agent", "autobrr")
|
||||||
|
|
||||||
|
req.Header.Set("X-Api-Key", c.config.APIKey)
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package lidarr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -67,60 +67,44 @@ type SystemStatusResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) Test() (*SystemStatusResponse, error) {
|
func (c *client) Test() (*SystemStatusResponse, error) {
|
||||||
res, err := c.get("system/status")
|
status, res, err := c.get("system/status")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("lidarr client get error")
|
log.Error().Stack().Err(err).Msg("lidarr client get error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer res.Body.Close()
|
if status == http.StatusUnauthorized {
|
||||||
|
return nil, errors.New("unauthorized: bad credentials")
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("lidarr client error reading body")
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace().Msgf("lidarr system/status response status: %v body: %v", status, string(res))
|
||||||
|
|
||||||
response := SystemStatusResponse{}
|
response := SystemStatusResponse{}
|
||||||
err = json.Unmarshal(body, &response)
|
err = json.Unmarshal(res, &response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("lidarr client error json unmarshal")
|
log.Error().Stack().Err(err).Msg("lidarr client error json unmarshal")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("lidarr system/status response: %+v", response)
|
|
||||||
|
|
||||||
return &response, nil
|
return &response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) Push(release Release) ([]string, error) {
|
func (c *client) Push(release Release) ([]string, error) {
|
||||||
res, err := c.post("release/push", release)
|
status, res, err := c.postBody("release/push", release)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("lidarr client post error")
|
log.Error().Stack().Err(err).Msg("lidarr client post error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == nil {
|
log.Trace().Msgf("lidarr release/push response status: %v body: %v", status, string(res))
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("lidarr client error reading body")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pushResponse := PushResponse{}
|
pushResponse := PushResponse{}
|
||||||
err = json.Unmarshal(body, &pushResponse)
|
err = json.Unmarshal(res, &pushResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("lidarr client error json unmarshal")
|
log.Error().Stack().Err(err).Msg("lidarr client error json unmarshal")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("lidarr release/push response body: %+v", string(body))
|
|
||||||
|
|
||||||
// log and return if rejected
|
// log and return if rejected
|
||||||
if pushResponse.Rejected {
|
if pushResponse.Rejected {
|
||||||
rejections := strings.Join(pushResponse.Rejections, ", ")
|
rejections := strings.Join(pushResponse.Rejections, ", ")
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
@ -11,7 +13,7 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *client) get(endpoint string) (*http.Response, error) {
|
func (c *client) get(endpoint string) (int, []byte, error) {
|
||||||
u, err := url.Parse(c.config.Hostname)
|
u, err := url.Parse(c.config.Hostname)
|
||||||
u.Path = path.Join(u.Path, "/api/v3/", endpoint)
|
u.Path = path.Join(u.Path, "/api/v3/", endpoint)
|
||||||
reqUrl := u.String()
|
reqUrl := u.String()
|
||||||
|
@ -19,27 +21,29 @@ func (c *client) get(endpoint string) (*http.Response, error) {
|
||||||
req, err := http.NewRequest(http.MethodGet, reqUrl, http.NoBody)
|
req, err := http.NewRequest(http.MethodGet, reqUrl, http.NoBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("radarr client request error : %v", reqUrl)
|
log.Error().Err(err).Msgf("radarr client request error : %v", reqUrl)
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.config.BasicAuth {
|
if c.config.BasicAuth {
|
||||||
req.SetBasicAuth(c.config.Username, c.config.Password)
|
req.SetBasicAuth(c.config.Username, c.config.Password)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Add("X-Api-Key", c.config.APIKey)
|
c.setHeaders(req)
|
||||||
req.Header.Set("User-Agent", "autobrr")
|
|
||||||
|
|
||||||
res, err := c.http.Do(req)
|
resp, err := c.http.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("radarr client request error : %v", reqUrl)
|
log.Error().Err(err).Msgf("radarr client.get request error: %v", reqUrl)
|
||||||
return nil, err
|
return 0, nil, fmt.Errorf("radarr.http.Do(req): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.StatusCode == http.StatusUnauthorized {
|
defer resp.Body.Close()
|
||||||
return nil, errors.New("unauthorized: bad credentials")
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err = io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return resp.StatusCode, nil, fmt.Errorf("radarr.io.Copy: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return resp.StatusCode, buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) post(endpoint string, data interface{}) (*http.Response, error) {
|
func (c *client) post(endpoint string, data interface{}) (*http.Response, error) {
|
||||||
|
@ -77,6 +81,9 @@ func (c *client) post(endpoint string, data interface{}) (*http.Response, error)
|
||||||
if res.StatusCode == http.StatusUnauthorized {
|
if res.StatusCode == http.StatusUnauthorized {
|
||||||
log.Error().Err(err).Msgf("radarr client bad request: %v", reqUrl)
|
log.Error().Err(err).Msgf("radarr client bad request: %v", reqUrl)
|
||||||
return nil, errors.New("unauthorized: bad credentials")
|
return nil, errors.New("unauthorized: bad credentials")
|
||||||
|
} else if res.StatusCode == http.StatusBadRequest {
|
||||||
|
log.Error().Err(err).Msgf("radarr client request error: %v", reqUrl)
|
||||||
|
return nil, errors.New("radarr: bad request")
|
||||||
} else if res.StatusCode != http.StatusOK {
|
} else if res.StatusCode != http.StatusOK {
|
||||||
log.Error().Err(err).Msgf("radarr client request error: %v", reqUrl)
|
log.Error().Err(err).Msgf("radarr client request error: %v", reqUrl)
|
||||||
return nil, errors.New("radarr: bad request")
|
return nil, errors.New("radarr: bad request")
|
||||||
|
@ -85,3 +92,56 @@ func (c *client) post(endpoint string, data interface{}) (*http.Response, error)
|
||||||
// return raw response and let the caller handle json unmarshal of body
|
// return raw response and let the caller handle json unmarshal of body
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *client) postBody(endpoint string, data interface{}) (int, []byte, error) {
|
||||||
|
u, err := url.Parse(c.config.Hostname)
|
||||||
|
u.Path = path.Join(u.Path, "/api/v3/", endpoint)
|
||||||
|
reqUrl := u.String()
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("radarr client could not marshal data: %v", reqUrl)
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, reqUrl, bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("radarr client request error: %v", reqUrl)
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.config.BasicAuth {
|
||||||
|
req.SetBasicAuth(c.config.Username, c.config.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.setHeaders(req)
|
||||||
|
|
||||||
|
resp, err := c.http.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("radarr client request error: %v", reqUrl)
|
||||||
|
return 0, nil, fmt.Errorf("radarr.http.Do(req): %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err = io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return resp.StatusCode, nil, fmt.Errorf("radarr.io.Copy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||||
|
return resp.StatusCode, buf.Bytes(), fmt.Errorf("radarr: bad request: %v (status: %s): %s", resp.Request.RequestURI, resp.Status, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.StatusCode, buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) setHeaders(req *http.Request) {
|
||||||
|
if req.Body != nil {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("User-Agent", "autobrr")
|
||||||
|
|
||||||
|
req.Header.Set("X-Api-Key", c.config.APIKey)
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package radarr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -66,22 +66,18 @@ type SystemStatusResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) Test() (*SystemStatusResponse, error) {
|
func (c *client) Test() (*SystemStatusResponse, error) {
|
||||||
res, err := c.get("system/status")
|
status, res, err := c.get("system/status")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("radarr client get error")
|
log.Error().Stack().Err(err).Msg("radarr client get error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer res.Body.Close()
|
if status == http.StatusUnauthorized {
|
||||||
|
return nil, errors.New("unauthorized: bad credentials")
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("radarr client error reading body")
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response := SystemStatusResponse{}
|
response := SystemStatusResponse{}
|
||||||
err = json.Unmarshal(body, &response)
|
err = json.Unmarshal(res, &response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("radarr client error json unmarshal")
|
log.Error().Stack().Err(err).Msg("radarr client error json unmarshal")
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -93,32 +89,20 @@ func (c *client) Test() (*SystemStatusResponse, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) Push(release Release) ([]string, error) {
|
func (c *client) Push(release Release) ([]string, error) {
|
||||||
res, err := c.post("release/push", release)
|
status, res, err := c.postBody("release/push", release)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("radarr client post error")
|
log.Error().Stack().Err(err).Msgf("radarr client post error. status: %d", status)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if res == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("radarr client error reading body")
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pushResponse := make([]PushResponse, 0)
|
pushResponse := make([]PushResponse, 0)
|
||||||
err = json.Unmarshal(body, &pushResponse)
|
err = json.Unmarshal(res, &pushResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("radarr client error json unmarshal")
|
log.Error().Stack().Err(err).Msg("radarr client error json unmarshal")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("radarr release/push response body: %+v", string(body))
|
log.Trace().Msgf("radarr release/push response status: %v body: %+v", status, string(res))
|
||||||
|
|
||||||
// log and return if rejected
|
// log and return if rejected
|
||||||
if pushResponse[0].Rejected {
|
if pushResponse[0].Rejected {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -33,6 +34,20 @@ func Test_client_Push(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
data, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected error to be nil got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(string(data), "Minx 1 epi 9 2160p") {
|
||||||
|
jsonPayload, _ := ioutil.ReadFile("testdata/release_push_parse_error.json")
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Write(jsonPayload)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// read json response
|
// read json response
|
||||||
jsonPayload, _ := ioutil.ReadFile("testdata/release_push_response.json")
|
jsonPayload, _ := ioutil.ReadFile("testdata/release_push_response.json")
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
@ -102,6 +117,29 @@ func Test_client_Push(t *testing.T) {
|
||||||
//err: errors.New("radarr push rejected Could not find Some Old Movie"),
|
//err: errors.New("radarr push rejected Could not find Some Old Movie"),
|
||||||
//wantErr: true,
|
//wantErr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "push_parse_error",
|
||||||
|
fields: fields{
|
||||||
|
config: Config{
|
||||||
|
Hostname: ts.URL,
|
||||||
|
APIKey: key,
|
||||||
|
BasicAuth: false,
|
||||||
|
Username: "",
|
||||||
|
Password: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: args{release: Release{
|
||||||
|
Title: "Minx 1 epi 9 2160p",
|
||||||
|
DownloadUrl: "https://www.test.org/rss/download/0000001/00000000000000000000/Minx.1.epi.9.2160p.torrent",
|
||||||
|
Size: 0,
|
||||||
|
Indexer: "test",
|
||||||
|
DownloadProtocol: "torrent",
|
||||||
|
Protocol: "torrent",
|
||||||
|
PublishDate: "2021-08-21T15:36:00Z",
|
||||||
|
}},
|
||||||
|
err: errors.New("radarr: bad request: (status: 400 Bad Request): [\n {\n \"propertyName\": \"Title\",\n \"errorMessage\": \"Unable to parse\",\n \"attemptedValue\": \"Minx 1 epi 9 2160p\",\n \"severity\": \"error\"\n }\n]\n"),
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
8
pkg/radarr/testdata/release_push_parse_error.json
vendored
Normal file
8
pkg/radarr/testdata/release_push_parse_error.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"propertyName": "Title",
|
||||||
|
"errorMessage": "Unable to parse",
|
||||||
|
"attemptedValue": "Minx 1 epi 9 2160p",
|
||||||
|
"severity": "error"
|
||||||
|
}
|
||||||
|
]
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
@ -11,7 +13,7 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *client) get(endpoint string) (*http.Response, error) {
|
func (c *client) get(endpoint string) (int, []byte, error) {
|
||||||
u, err := url.Parse(c.config.Hostname)
|
u, err := url.Parse(c.config.Hostname)
|
||||||
u.Path = path.Join(u.Path, "/api/v3/", endpoint)
|
u.Path = path.Join(u.Path, "/api/v3/", endpoint)
|
||||||
reqUrl := u.String()
|
reqUrl := u.String()
|
||||||
|
@ -19,27 +21,29 @@ func (c *client) get(endpoint string) (*http.Response, error) {
|
||||||
req, err := http.NewRequest(http.MethodGet, reqUrl, http.NoBody)
|
req, err := http.NewRequest(http.MethodGet, reqUrl, http.NoBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("sonarr client request error : %v", reqUrl)
|
log.Error().Err(err).Msgf("sonarr client request error : %v", reqUrl)
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.config.BasicAuth {
|
if c.config.BasicAuth {
|
||||||
req.SetBasicAuth(c.config.Username, c.config.Password)
|
req.SetBasicAuth(c.config.Username, c.config.Password)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Add("X-Api-Key", c.config.APIKey)
|
c.setHeaders(req)
|
||||||
req.Header.Set("User-Agent", "autobrr")
|
|
||||||
|
|
||||||
res, err := c.http.Do(req)
|
resp, err := c.http.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("sonarr client request error : %v", reqUrl)
|
log.Error().Err(err).Msgf("sonarr client.get request error: %v", reqUrl)
|
||||||
return nil, err
|
return 0, nil, fmt.Errorf("sonarr.http.Do(req): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.StatusCode == http.StatusUnauthorized {
|
defer resp.Body.Close()
|
||||||
return nil, errors.New("unauthorized: bad credentials")
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err = io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return resp.StatusCode, nil, fmt.Errorf("sonarr.io.Copy: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return resp.StatusCode, buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) post(endpoint string, data interface{}) (*http.Response, error) {
|
func (c *client) post(endpoint string, data interface{}) (*http.Response, error) {
|
||||||
|
@ -85,3 +89,56 @@ func (c *client) post(endpoint string, data interface{}) (*http.Response, error)
|
||||||
// return raw response and let the caller handle json unmarshal of body
|
// return raw response and let the caller handle json unmarshal of body
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *client) postBody(endpoint string, data interface{}) (int, []byte, error) {
|
||||||
|
u, err := url.Parse(c.config.Hostname)
|
||||||
|
u.Path = path.Join(u.Path, "/api/v3/", endpoint)
|
||||||
|
reqUrl := u.String()
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("sonarr client could not marshal data: %v", reqUrl)
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, reqUrl, bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("sonarr client request error: %v", reqUrl)
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.config.BasicAuth {
|
||||||
|
req.SetBasicAuth(c.config.Username, c.config.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.setHeaders(req)
|
||||||
|
|
||||||
|
resp, err := c.http.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msgf("sonarr client request error: %v", reqUrl)
|
||||||
|
return 0, nil, fmt.Errorf("sonarr.http.Do(req): %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err = io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return resp.StatusCode, nil, fmt.Errorf("sonarr.io.Copy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||||
|
return resp.StatusCode, buf.Bytes(), fmt.Errorf("sonarr: bad request: %v (status: %s): %s", resp.Request.RequestURI, resp.Status, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.StatusCode, buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) setHeaders(req *http.Request) {
|
||||||
|
if req.Body != nil {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("User-Agent", "autobrr")
|
||||||
|
|
||||||
|
req.Header.Set("X-Api-Key", c.config.APIKey)
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package sonarr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -67,60 +67,44 @@ type SystemStatusResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) Test() (*SystemStatusResponse, error) {
|
func (c *client) Test() (*SystemStatusResponse, error) {
|
||||||
res, err := c.get("system/status")
|
status, res, err := c.get("system/status")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("sonarr client get error")
|
log.Error().Stack().Err(err).Msg("sonarr client get error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer res.Body.Close()
|
if status == http.StatusUnauthorized {
|
||||||
|
return nil, errors.New("unauthorized: bad credentials")
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("sonarr client error reading body")
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace().Msgf("sonarr system/status response: %v", string(res))
|
||||||
|
|
||||||
response := SystemStatusResponse{}
|
response := SystemStatusResponse{}
|
||||||
err = json.Unmarshal(body, &response)
|
err = json.Unmarshal(res, &response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("sonarr client error json unmarshal")
|
log.Error().Stack().Err(err).Msg("sonarr client error json unmarshal")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("sonarr system/status response: %+v", response)
|
|
||||||
|
|
||||||
return &response, nil
|
return &response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) Push(release Release) ([]string, error) {
|
func (c *client) Push(release Release) ([]string, error) {
|
||||||
res, err := c.post("release/push", release)
|
status, res, err := c.postBody("release/push", release)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("sonarr client post error")
|
log.Error().Stack().Err(err).Msg("sonarr client post error")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == nil {
|
log.Trace().Msgf("sonarr release/push response status: (%v) body: %v", status, string(res))
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Stack().Err(err).Msg("sonarr client error reading body")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pushResponse := make([]PushResponse, 0)
|
pushResponse := make([]PushResponse, 0)
|
||||||
err = json.Unmarshal(body, &pushResponse)
|
err = json.Unmarshal(res, &pushResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Stack().Err(err).Msg("sonarr client error json unmarshal")
|
log.Error().Stack().Err(err).Msg("sonarr client error json unmarshal")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("sonarr release/push response body: %+v", string(body))
|
|
||||||
|
|
||||||
// log and return if rejected
|
// log and return if rejected
|
||||||
if pushResponse[0].Rejected {
|
if pushResponse[0].Rejected {
|
||||||
rejections := strings.Join(pushResponse[0].Rejections, ", ")
|
rejections := strings.Join(pushResponse[0].Rejections, ", ")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue