mirror of
https://github.com/celogeek/go-qbittorrent-sync.git
synced 2025-05-24 16:02:37 +02:00
206 lines
3.3 KiB
Go
206 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/go-resty/resty/v2"
|
|
)
|
|
|
|
type QBitTorrentOptions struct {
|
|
Uri string
|
|
Username string
|
|
Password string
|
|
PasswordFile string
|
|
SyncTag string
|
|
SyncedTag string
|
|
}
|
|
|
|
type QBittorrentCli struct {
|
|
SyncTag string
|
|
SyncedTag string
|
|
cli *resty.Client
|
|
}
|
|
|
|
type Torrent struct {
|
|
Name string `json:"name"`
|
|
Path string `json:"content_path"`
|
|
Hash string `json:"hash"`
|
|
|
|
Progress int `json:"-"`
|
|
}
|
|
|
|
func NewQBittorrentCli(options *QBitTorrentOptions) (*QBittorrentCli, error) {
|
|
r := resty.New().SetBaseURL(fmt.Sprintf("%s/api/v2", options.Uri))
|
|
r.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
|
|
if r.StatusCode() == http.StatusForbidden {
|
|
return errors.New("forbidden")
|
|
}
|
|
return nil
|
|
})
|
|
|
|
result, err := r.
|
|
R().
|
|
SetFormData(map[string]string{
|
|
"username": options.Username,
|
|
"password": options.Password,
|
|
}).
|
|
Post("/auth/login")
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !bytes.Equal(result.Body(), []byte("Ok.")) {
|
|
return nil, errors.New("auth failed")
|
|
}
|
|
|
|
cli := &QBittorrentCli{
|
|
SyncTag: options.SyncTag,
|
|
SyncedTag: options.SyncedTag,
|
|
cli: r,
|
|
}
|
|
|
|
cli.ClearTags()
|
|
|
|
return cli, nil
|
|
}
|
|
|
|
func (c *QBittorrentCli) Logout() error {
|
|
_, err := c.cli.R().Post("/auth/logout")
|
|
return err
|
|
}
|
|
|
|
func (c *QBittorrentCli) List() ([]*Torrent, error) {
|
|
result := make([]*Torrent, 0)
|
|
|
|
_, err := c.cli.R().
|
|
SetQueryParam("filter", "completed").
|
|
SetQueryParam("tag", c.SyncTag).
|
|
SetResult(&result).
|
|
Get("/torrents/info")
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, t := range result {
|
|
t.Progress = -1
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (c *QBittorrentCli) ClearTags() error {
|
|
// fetch tags
|
|
tags := []string{}
|
|
_, err := c.cli.
|
|
R().
|
|
SetResult(&tags).
|
|
Get("/torrents/tags")
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// check existing tags
|
|
hasSync := false
|
|
toDeleteTags := []string{}
|
|
for _, t := range tags {
|
|
if t == c.SyncTag {
|
|
hasSync = true
|
|
}
|
|
if strings.HasPrefix(t, "Progress:") {
|
|
toDeleteTags = append(toDeleteTags, t)
|
|
}
|
|
}
|
|
|
|
// create missing sync
|
|
if !hasSync {
|
|
_, err := c.cli.
|
|
R().
|
|
SetFormData(map[string]string{
|
|
"tags": c.SyncTag,
|
|
}).
|
|
Post("/torrents/createTags")
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// remove progress
|
|
if len(toDeleteTags) > 0 {
|
|
_, err := c.cli.
|
|
R().
|
|
SetFormData(map[string]string{
|
|
"tags": strings.Join(toDeleteTags, ","),
|
|
}).
|
|
Post("/torrents/deleteTags")
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *QBittorrentCli) SetTag(t *Torrent, tag string) error {
|
|
_, err := c.cli.
|
|
R().
|
|
SetFormData(map[string]string{
|
|
"hashes": t.Hash,
|
|
"tags": tag,
|
|
}).
|
|
Post("/torrents/addTags")
|
|
|
|
return err
|
|
}
|
|
|
|
func (c *QBittorrentCli) SetProgress(t *Torrent, p int) error {
|
|
if t.Progress == p {
|
|
return nil
|
|
}
|
|
|
|
err := c.ClearTags()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.SetTag(t, fmt.Sprintf("Progress:%d%%", p))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
t.Progress = p
|
|
return nil
|
|
}
|
|
|
|
func (c *QBittorrentCli) SetDone(t *Torrent) error {
|
|
err := c.ClearTags()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = c.cli.
|
|
R().
|
|
SetFormData(map[string]string{
|
|
"hashes": t.Hash,
|
|
"tags": c.SyncTag,
|
|
}).
|
|
Post("/torrents/removeTags")
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.SyncedTag != "" {
|
|
return c.SetTag(t, c.SyncedTag)
|
|
}
|
|
return nil
|
|
}
|