fix(qbittorrent): params url parsing (#286)

* fix(qbittorrent): params url parsing

* feat: add more logging

* refactor: qbit tracker status check
This commit is contained in:
Ludvig Lundgren 2022-06-01 19:37:44 +02:00 committed by GitHub
parent 52fad1da95
commit a5ade5ef24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 144 additions and 60 deletions

View file

@ -88,7 +88,7 @@ func (c *Client) get(endpoint string, opts map[string]string) (*http.Response, e
var err error
var resp *http.Response
reqUrl := buildUrl(c.settings, endpoint)
reqUrl := buildUrlOpts(c.settings, endpoint, opts)
req, err := http.NewRequest("GET", reqUrl, nil)
if err != nil {
@ -296,7 +296,8 @@ func (c *Client) postFile(endpoint string, fileName string, opts map[string]stri
}
func (c *Client) setCookies(cookies []*http.Cookie) {
cookieURL, _ := url.Parse(fmt.Sprintf("%v://%v:%v", c.settings.protocol, c.settings.Hostname, c.settings.Port))
cookieURL, _ := url.Parse(buildUrl(c.settings, ""))
c.http.Jar.SetCookies(cookieURL, cookies)
}
@ -346,3 +347,58 @@ func buildUrl(settings Settings, endpoint string) string {
// make into new string and return
return u.String()
}
func buildUrlOpts(settings Settings, endpoint string, opts map[string]string) string {
// parse url
u, _ := url.Parse(settings.Hostname)
// reset Opaque
u.Opaque = ""
// set scheme
scheme := "http"
if u.Scheme == "http" || u.Scheme == "https" {
if settings.TLS {
scheme = "https"
}
u.Scheme = scheme
} else {
if settings.TLS {
scheme = "https"
}
u.Scheme = scheme
}
// if host is empty lets use one from settings
if u.Host == "" {
u.Host = settings.Hostname
}
// reset Path
if u.Host == u.Path {
u.Path = ""
}
// handle ports
if settings.Port > 0 {
if settings.Port == 80 || settings.Port == 443 {
// skip for regular http and https
} else {
u.Host = fmt.Sprintf("%v:%v", u.Host, settings.Port)
}
}
// add query params
q := u.Query()
for k, v := range opts {
q.Set(k, v)
}
u.RawQuery = q.Encode()
// join path
u.Path = path.Join(u.Path, "/api/v2/", endpoint)
// make into new string and return
return u.String()
}

View file

@ -50,12 +50,12 @@ type TorrentTrackersResponse struct {
}
type TorrentTracker struct {
//Tier uint `json:"tier"` // can be both empty "" and int
//Tier int `json:"tier"` // can be both empty "" and int
Url string `json:"url"`
Status TrackerStatus `json:"status"`
NumPeers int `json:"num_peers"`
NumSeeds int `json:"num_seeds"`
NumLeechers int `json:"num_leechers"`
NumLeechers int `json:"num_leeches"`
NumDownloaded int `json:"num_downloaded"`
Message string `json:"msg"`
}

View file

@ -5,7 +5,7 @@ import (
"errors"
"io/ioutil"
"net/http"
"net/url"
"net/http/httputil"
"strconv"
"strings"
@ -14,11 +14,12 @@ import (
// Login https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#authentication
func (c *Client) Login() error {
credentials := make(map[string]string)
credentials["username"] = c.settings.Username
credentials["password"] = c.settings.Password
opts := map[string]string{
"username": c.settings.Username,
"password": c.settings.Password,
}
resp, err := c.postBasic("auth/login", credentials)
resp, err := c.postBasic("auth/login", opts)
if err != nil {
log.Error().Err(err).Msg("login error")
return err
@ -57,7 +58,6 @@ func (c *Client) Login() error {
}
func (c *Client) GetTorrents() ([]Torrent, error) {
var torrents []Torrent
resp, err := c.get("torrents/info", nil)
if err != nil {
@ -73,6 +73,7 @@ func (c *Client) GetTorrents() ([]Torrent, error) {
return nil, readErr
}
var torrents []Torrent
err = json.Unmarshal(body, &torrents)
if err != nil {
log.Error().Err(err).Msg("get torrents unmarshal error")
@ -83,13 +84,11 @@ func (c *Client) GetTorrents() ([]Torrent, error) {
}
func (c *Client) GetTorrentsFilter(filter TorrentFilter) ([]Torrent, error) {
var torrents []Torrent
opts := map[string]string{
"filter": string(filter),
}
v := url.Values{}
v.Add("filter", string(filter))
params := v.Encode()
resp, err := c.get("torrents/info?"+params, nil)
resp, err := c.get("torrents/info", opts)
if err != nil {
log.Error().Err(err).Msgf("get filtered torrents error: %v", filter)
return nil, err
@ -103,6 +102,7 @@ func (c *Client) GetTorrentsFilter(filter TorrentFilter) ([]Torrent, error) {
return nil, readErr
}
var torrents []Torrent
err = json.Unmarshal(body, &torrents)
if err != nil {
log.Error().Err(err).Msgf("get filtered torrents unmarshal error: %v", filter)
@ -115,11 +115,11 @@ func (c *Client) GetTorrentsFilter(filter TorrentFilter) ([]Torrent, error) {
func (c *Client) GetTorrentsActiveDownloads() ([]Torrent, error) {
var filter = TorrentFilterDownloading
v := url.Values{}
v.Add("filter", string(filter))
params := v.Encode()
opts := map[string]string{
"filter": string(filter),
}
resp, err := c.get("torrents/info?"+params, nil)
resp, err := c.get("torrents/info", opts)
if err != nil {
log.Error().Err(err).Msgf("get filtered torrents error: %v", filter)
return nil, err
@ -167,14 +167,11 @@ func (c *Client) GetTorrentsRaw() (string, error) {
}
func (c *Client) GetTorrentTrackers(hash string) ([]TorrentTracker, error) {
var trackers []TorrentTracker
opts := map[string]string{
"hash": hash,
}
params := url.Values{}
params.Add("hash", hash)
p := params.Encode()
resp, err := c.get("torrents/trackers?"+p, nil)
resp, err := c.get("torrents/trackers", opts)
if err != nil {
log.Error().Err(err).Msgf("get torrent trackers error: %v", hash)
return nil, err
@ -182,12 +179,30 @@ func (c *Client) GetTorrentTrackers(hash string) ([]TorrentTracker, error) {
defer resp.Body.Close()
dump, err := httputil.DumpResponse(resp, true)
if err != nil {
log.Error().Err(err).Msgf("get torrent trackers dump response error: %v", err)
}
log.Trace().Msgf("get torrent trackers response dump: %v", string(dump))
if resp.StatusCode == http.StatusNotFound {
//return nil, fmt.Errorf("torrent not found: %v", hash)
return nil, nil
} else if resp.StatusCode == http.StatusForbidden {
//return nil, fmt.Errorf("torrent not found: %v", hash)
return nil, nil
}
body, readErr := ioutil.ReadAll(resp.Body)
if readErr != nil {
log.Error().Err(err).Msgf("get torrent trackers read error: %v", hash)
return nil, readErr
}
log.Trace().Msgf("get torrent trackers body: %v", string(body))
var trackers []TorrentTracker
err = json.Unmarshal(body, &trackers)
if err != nil {
log.Error().Err(err).Msgf("get torrent trackers: %v", hash)
@ -215,16 +230,15 @@ func (c *Client) AddTorrentFromFile(file string, options map[string]string) erro
}
func (c *Client) DeleteTorrents(hashes []string, deleteFiles bool) error {
v := url.Values{}
// Add hashes together with | separator
hv := strings.Join(hashes, "|")
v.Add("hashes", hv)
v.Add("deleteFiles", strconv.FormatBool(deleteFiles))
encodedHashes := v.Encode()
opts := map[string]string{
"hashes": hv,
"deleteFiles": strconv.FormatBool(deleteFiles),
}
resp, err := c.get("torrents/delete?"+encodedHashes, nil)
resp, err := c.get("torrents/delete", opts)
if err != nil {
log.Error().Err(err).Msgf("delete torrents error: %v", hashes)
return err
@ -239,15 +253,13 @@ func (c *Client) DeleteTorrents(hashes []string, deleteFiles bool) error {
}
func (c *Client) ReAnnounceTorrents(hashes []string) error {
v := url.Values{}
// Add hashes together with | separator
hv := strings.Join(hashes, "|")
v.Add("hashes", hv)
opts := map[string]string{
"hashes": hv,
}
encodedHashes := v.Encode()
resp, err := c.get("torrents/reannounce?"+encodedHashes, nil)
resp, err := c.get("torrents/reannounce", opts)
if err != nil {
log.Error().Err(err).Msgf("re-announce error: %v", hashes)
return err
@ -262,8 +274,6 @@ func (c *Client) ReAnnounceTorrents(hashes []string) error {
}
func (c *Client) GetTransferInfo() (*TransferInfo, error) {
var info TransferInfo
resp, err := c.get("transfer/info", nil)
if err != nil {
log.Error().Err(err).Msg("get torrents error")
@ -278,6 +288,7 @@ func (c *Client) GetTransferInfo() (*TransferInfo, error) {
return nil, readErr
}
var info TransferInfo
err = json.Unmarshal(body, &info)
if err != nil {
log.Error().Err(err).Msg("get torrents unmarshal error")