Added add endpoint
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
package torrent
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -75,34 +77,63 @@ func (c *QbittorrentClient) Login(username string, password string) (string, err
|
||||
}
|
||||
|
||||
func (c *QbittorrentClient) List() ([]TorrentInfo, error) {
|
||||
log.Trace().Msg("qbittorrent listing torrents")
|
||||
return c.Find(FindOptions{})
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", c.baseURL+"/api/v2/torrents/info", nil)
|
||||
func (c *QbittorrentClient) Find(opts FindOptions) ([]TorrentInfo, error) {
|
||||
log.Trace().
|
||||
Str("hash", opts.Hash).
|
||||
Str("name", opts.Name).
|
||||
Str("category", opts.Category).
|
||||
Str("tag", opts.Tag).
|
||||
Str("state", opts.State).
|
||||
Msg("qbittorrent finding torrents")
|
||||
|
||||
params := url.Values{}
|
||||
if opts.Hash != "" {
|
||||
params.Set("hashes", opts.Hash)
|
||||
}
|
||||
if opts.Category != "" {
|
||||
params.Set("category", opts.Category)
|
||||
}
|
||||
if opts.Tag != "" {
|
||||
params.Set("tag", opts.Tag)
|
||||
}
|
||||
if opts.State != "" {
|
||||
params.Set("filter", opts.State)
|
||||
}
|
||||
|
||||
reqURL := c.baseURL + "/api/v2/torrents/info"
|
||||
if len(params) > 0 {
|
||||
reqURL += "?" + params.Encode()
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", reqURL, nil)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("qbittorrent creating list request failed")
|
||||
return nil, fmt.Errorf("creating list request: %w", err)
|
||||
log.Error().Err(err).Msg("qbittorrent creating find request failed")
|
||||
return nil, fmt.Errorf("creating find request: %w", err)
|
||||
}
|
||||
req.AddCookie(&http.Cookie{Name: "SID", Value: c.sid})
|
||||
|
||||
start := time.Now()
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("qbittorrent list request failed")
|
||||
return nil, fmt.Errorf("list request failed: %w", err)
|
||||
log.Error().Err(err).Msg("qbittorrent find request failed")
|
||||
return nil, fmt.Errorf("find request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Trace().Int("status", resp.StatusCode).Dur("duration", time.Since(start)).Msg("qbittorrent list response")
|
||||
log.Trace().Int("status", resp.StatusCode).Dur("duration", time.Since(start)).Msg("qbittorrent find response")
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Error().Int("status", resp.StatusCode).Msg("qbittorrent list returned non-OK status")
|
||||
return nil, fmt.Errorf("list request returned status %d", resp.StatusCode)
|
||||
log.Error().Int("status", resp.StatusCode).Msg("qbittorrent find returned non-OK status")
|
||||
return nil, fmt.Errorf("find request returned status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var items []QbittorrentListItem
|
||||
if err := json.NewDecoder(resp.Body).Decode(&items); err != nil {
|
||||
log.Error().Err(err).Msg("qbittorrent decoding list response failed")
|
||||
return nil, fmt.Errorf("decoding list response: %w", err)
|
||||
log.Error().Err(err).Msg("qbittorrent decoding find response failed")
|
||||
return nil, fmt.Errorf("decoding find response: %w", err)
|
||||
}
|
||||
|
||||
torrents := make([]TorrentInfo, len(items))
|
||||
@@ -110,11 +141,93 @@ func (c *QbittorrentClient) List() ([]TorrentInfo, error) {
|
||||
torrents[i] = item.toTorrentInfo()
|
||||
}
|
||||
|
||||
log.Debug().Int("count", len(torrents)).Msg("qbittorrent torrents listed")
|
||||
torrents = filterLocally(torrents, opts)
|
||||
|
||||
log.Debug().Int("count", len(torrents)).Msg("qbittorrent find results")
|
||||
|
||||
return torrents, nil
|
||||
}
|
||||
|
||||
func filterLocally(torrents []TorrentInfo, opts FindOptions) []TorrentInfo {
|
||||
var result []TorrentInfo
|
||||
|
||||
for _, t := range torrents {
|
||||
if opts.Name != "" && !strings.Contains(strings.ToLower(t.Name), strings.ToLower(opts.Name)) {
|
||||
continue
|
||||
}
|
||||
if opts.Hash != "" && !strings.EqualFold(t.Hash, opts.Hash) {
|
||||
continue
|
||||
}
|
||||
if opts.Category != "" && !strings.EqualFold(t.Category, opts.Category) {
|
||||
continue
|
||||
}
|
||||
if opts.Tag != "" && !strings.Contains(strings.ToLower(t.Tags), strings.ToLower(opts.Tag)) {
|
||||
continue
|
||||
}
|
||||
if opts.State != "" && !strings.EqualFold(t.State, opts.State) {
|
||||
continue
|
||||
}
|
||||
result = append(result, t)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *QbittorrentClient) Add(file TorrentFile) error {
|
||||
log.Trace().Str("filename", file.Filename).Int("size", len(file.Data)).Msg("qbittorrent adding torrent")
|
||||
|
||||
var buf bytes.Buffer
|
||||
writer := multipart.NewWriter(&buf)
|
||||
|
||||
part, err := writer.CreateFormFile("torrents", file.Filename)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("qbittorrent creating multipart form failed")
|
||||
return fmt.Errorf("creating multipart form: %w", err)
|
||||
}
|
||||
|
||||
if _, err := part.Write(file.Data); err != nil {
|
||||
log.Error().Err(err).Msg("qbittorrent writing torrent data failed")
|
||||
return fmt.Errorf("writing torrent data: %w", err)
|
||||
}
|
||||
|
||||
if err := writer.Close(); err != nil {
|
||||
return fmt.Errorf("closing multipart writer: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", c.baseURL+"/api/v2/torrents/add", &buf)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("qbittorrent creating add request failed")
|
||||
return fmt.Errorf("creating add request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
req.AddCookie(&http.Cookie{Name: "SID", Value: c.sid})
|
||||
|
||||
start := time.Now()
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("qbittorrent add request failed")
|
||||
return fmt.Errorf("add request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("qbittorrent reading add response failed")
|
||||
return fmt.Errorf("reading add response: %w", err)
|
||||
}
|
||||
|
||||
log.Trace().Int("status", resp.StatusCode).Dur("duration", time.Since(start)).Msg("qbittorrent add response")
|
||||
|
||||
if resp.StatusCode != http.StatusOK || string(body) != "Ok." {
|
||||
log.Error().Int("status", resp.StatusCode).Str("body", string(body)).Msg("qbittorrent add torrent failed")
|
||||
return fmt.Errorf("add torrent failed: status %d, body: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
log.Info().Str("filename", file.Filename).Msg("qbittorrent torrent added")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type QbittorrentListItem struct {
|
||||
Hash string `json:"hash"`
|
||||
Name string `json:"name"`
|
||||
|
||||
Reference in New Issue
Block a user