From 4c8fdd956f95b9fe52db124ee4ddd15b56a4aa9c Mon Sep 17 00:00:00 2001 From: celogeek <65178+celogeek@users.noreply.github.com> Date: Tue, 15 Aug 2023 16:19:25 +0200 Subject: [PATCH] qbit read/update --- main.go | 52 +++++++++++++++ qbittorent.go | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 main.go create mode 100644 qbittorent.go diff --git a/main.go b/main.go new file mode 100644 index 0000000..8ead52b --- /dev/null +++ b/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "flag" + "log" + "time" +) + +type Options struct { + Qbittorent QBitTorrentOptions +} + +func main() { + options := &Options{} + flag.StringVar(&options.Qbittorent.Uri, "qbittorrent-uri", "http://localhost:8080", "URI of qbittorrent") + flag.StringVar(&options.Qbittorent.Username, "qbittorrent-username", "", "Username of qbittorrent") + flag.StringVar(&options.Qbittorent.Password, "qbittorrent-password", "", "Password of qbittorrent") + flag.StringVar(&options.Qbittorent.SyncTag, "qbittorrent-sync-tag", "Sync", "Tag of qbittorrent to copy") + flag.StringVar(&options.Qbittorent.SyncedTag, "qbittorrent-synced-tag", "", "Tag of qbittorrent when copy finished") + flag.Parse() + + if options.Qbittorent.Uri == "" || + options.Qbittorent.Username == "" || + options.Qbittorent.Password == "" || + options.Qbittorent.SyncTag == "" { + log.Fatal("missing qbittorrent parameters") + } + + qcli, err := NewQBittorrentCli(&options.Qbittorent) + if err != nil { + log.Fatal(err) + } + defer qcli.Logout() + + torrents, err := qcli.List() + if err != nil { + log.Fatal(err) + } + + for _, t := range torrents { + for p := 0; p <= 100; p += 20 { + qcli.ClearTags() + qcli.SetProgress(&t, p) + time.Sleep(time.Second) + } + qcli.SetDone(&t) + } +} + +func init() { + log.SetFlags(0) +} diff --git a/qbittorent.go b/qbittorent.go new file mode 100644 index 0000000..c68ed26 --- /dev/null +++ b/qbittorent.go @@ -0,0 +1,181 @@ +package main + +import ( + "fmt" + "strings" + + "github.com/go-resty/resty/v2" +) + +type QBitTorrentOptions struct { + Uri string + Username string + Password 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)) + + _, err := r. + R(). + SetFormData(map[string]string{ + "username": options.Username, + "password": options.Password, + }). + Post("/auth/login") + + if err != nil { + return nil, err + } + + 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 + } + + t.Progress = p + return c.SetTag(t, fmt.Sprintf("Progress:%d%%", p)) +} + +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/deleteTags") + + if err != nil { + return err + } + + if c.SyncedTag != "" { + return c.SetTag(t, c.SyncedTag) + } + return nil +}