From 2ad1f17a5b8c96a647412e71a06f59e7145dbd4a Mon Sep 17 00:00:00 2001 From: soup Date: Tue, 23 May 2023 16:23:25 +0000 Subject: [PATCH 1/4] add option to remove paused --- cmd/remove.go | 35 ++++++++++++++++++++++++++++++----- pkg/qbittorrent/methods.go | 22 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/cmd/remove.go b/cmd/remove.go index 98c495e..d3d6037 100644 --- a/cmd/remove.go +++ b/cmd/remove.go @@ -16,10 +16,11 @@ import ( // RunRemove cmd to remove torrents func RunRemove() *cobra.Command { var ( - removeAll bool - deleteFiles bool - hashes bool - names bool + removeAll bool + removePaused bool + deleteFiles bool + hashes bool + names bool ) var command = &cobra.Command{ @@ -30,6 +31,7 @@ func RunRemove() *cobra.Command { } command.Flags().BoolVar(&removeAll, "all", false, "Removes all torrents") + command.Flags().BoolVar(&removePaused, "paused", false, "Removes all paused torrents") command.Flags().BoolVar(&deleteFiles, "delete-files", false, "Also delete downloaded files from torrent(s)") command.Flags().BoolVar(&hashes, "hashes", false, "Provided arguments will be read as torrent hashes") command.Flags().BoolVar(&names, "names", false, "Provided arguments will be read as torrent names") @@ -66,7 +68,30 @@ func RunRemove() *cobra.Command { } if removeAll { - if err := qb.DeleteTorrents(ctx, []string{"all"}, deleteFiles); err != nil { + if removePaused { + pausedTorrents, err := qb.GetPausedTorrents(ctx) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to retrieve paused torrents: %v\n", err) + os.Exit(1) + } + + hashesToRemove := []string{} + for _, torrent := range pausedTorrents { + hashesToRemove = append(hashesToRemove, torrent.Hash) + } + + if len(hashesToRemove) < 1 { + log.Printf("No paused torrents found to remove") + return + } + + if err := qb.DeleteTorrents(ctx, hashesToRemove, deleteFiles); err != nil { + fmt.Fprintf(os.Stderr, "ERROR: could not delete paused torrents: %v\n", err) + os.Exit(1) + } + + log.Print("Paused torrents removed successfully") + } else if err := qb.DeleteTorrents(ctx, []string{"all"}, deleteFiles); err != nil { fmt.Fprintf(os.Stderr, "ERROR: could not delete torrents: %v\n", err) os.Exit(1) } diff --git a/pkg/qbittorrent/methods.go b/pkg/qbittorrent/methods.go index 2fcb5a2..024d577 100644 --- a/pkg/qbittorrent/methods.go +++ b/pkg/qbittorrent/methods.go @@ -2,6 +2,7 @@ package qbittorrent import ( "encoding/json" + "fmt" "io" "log" "net/http" @@ -329,6 +330,27 @@ func (c *Client) ReAnnounceTorrents(ctx context.Context, hashes []string) error return nil } +func (c *Client) GetPausedTorrents(ctx context.Context) ([]Torrent, error) { + // Initiate request to appropriate endpoint to fetch all paused torrent info. + resp, err := c.getCtx(ctx, "torrents/info?filter=paused", nil) + if err != nil { + log.Printf("Error retrieving paused torrent info: %v", err) + return nil, fmt.Errorf("error retrieving paused torrent info: %v", err) + } + defer resp.Body.Close() + + // Parse response. + var torrents []Torrent + if err := json.NewDecoder(resp.Body).Decode(&torrents); err != nil { + log.Printf("Error decoding response: %v", err) + return nil, fmt.Errorf("error decoding response: %v", err) + } + + log.Printf("Found %d paused torrents", len(torrents)) + + return torrents, nil +} + func (c *Client) Pause(ctx context.Context, hashes []string) error { v := url.Values{} From 7c4815b33124a90be65da8a630affcaaa6a7bae7 Mon Sep 17 00:00:00 2001 From: soup Date: Tue, 23 May 2023 18:00:36 +0000 Subject: [PATCH 2/4] use GetTorrentsWithFilters --- cmd/remove.go | 42 ++++++++++++++++++++++++-------------- pkg/qbittorrent/methods.go | 22 -------------------- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/cmd/remove.go b/cmd/remove.go index d3d6037..fd8c31a 100644 --- a/cmd/remove.go +++ b/cmd/remove.go @@ -21,6 +21,7 @@ func RunRemove() *cobra.Command { deleteFiles bool hashes bool names bool + dryRun bool ) var command = &cobra.Command{ @@ -35,15 +36,16 @@ func RunRemove() *cobra.Command { command.Flags().BoolVar(&deleteFiles, "delete-files", false, "Also delete downloaded files from torrent(s)") command.Flags().BoolVar(&hashes, "hashes", false, "Provided arguments will be read as torrent hashes") command.Flags().BoolVar(&names, "names", false, "Provided arguments will be read as torrent names") + command.Flags().BoolVar(&dryRun, "dry-run", false, "Display what would be done without actually doing it") command.Run = func(cmd *cobra.Command, args []string) { - if !removeAll && len(args) < 1 { - log.Printf("Please provide atleast one torrent hash/name as an argument") + if !removeAll && !removePaused && len(args) < 1 { + log.Printf("Please provide at least one torrent hash/name as an argument") return } - if !removeAll && !hashes && !names { - log.Printf("Please specifiy if arguments are to be read as hashes or names (--hashes / --names)") + if !removeAll && !removePaused && !hashes && !names { + log.Printf("Please specify if arguments are to be read as hashes or names (--hashes / --names)") return } @@ -69,7 +71,7 @@ func RunRemove() *cobra.Command { if removeAll { if removePaused { - pausedTorrents, err := qb.GetPausedTorrents(ctx) + pausedTorrents, err := qb.GetTorrentsWithFilters(ctx, &qbittorrent.GetTorrentsRequest{Filter: "paused"}) if err != nil { fmt.Fprintf(os.Stderr, "ERROR: failed to retrieve paused torrents: %v\n", err) os.Exit(1) @@ -85,18 +87,28 @@ func RunRemove() *cobra.Command { return } - if err := qb.DeleteTorrents(ctx, hashesToRemove, deleteFiles); err != nil { - fmt.Fprintf(os.Stderr, "ERROR: could not delete paused torrents: %v\n", err) - os.Exit(1) - } + if dryRun { + log.Printf("Paused torrents to be removed: %v", hashesToRemove) + } else { + if err := qb.DeleteTorrents(ctx, hashesToRemove, deleteFiles); err != nil { + fmt.Fprintf(os.Stderr, "ERROR: could not delete paused torrents: %v\n", err) + os.Exit(1) + } - log.Print("Paused torrents removed successfully") - } else if err := qb.DeleteTorrents(ctx, []string{"all"}, deleteFiles); err != nil { - fmt.Fprintf(os.Stderr, "ERROR: could not delete torrents: %v\n", err) - os.Exit(1) + log.Print("Paused torrents removed successfully") + } + } else { + if dryRun { + log.Printf("Would remove all torrents") + } else { + if err := qb.DeleteTorrents(ctx, []string{"all"}, deleteFiles); err != nil { + fmt.Fprintf(os.Stderr, "ERROR: could not delete torrents: %v\n", err) + os.Exit(1) + } + + log.Printf("All torrents removed successfully") + } } - - log.Printf("All torrents removed successfully") return } diff --git a/pkg/qbittorrent/methods.go b/pkg/qbittorrent/methods.go index 024d577..2fcb5a2 100644 --- a/pkg/qbittorrent/methods.go +++ b/pkg/qbittorrent/methods.go @@ -2,7 +2,6 @@ package qbittorrent import ( "encoding/json" - "fmt" "io" "log" "net/http" @@ -330,27 +329,6 @@ func (c *Client) ReAnnounceTorrents(ctx context.Context, hashes []string) error return nil } -func (c *Client) GetPausedTorrents(ctx context.Context) ([]Torrent, error) { - // Initiate request to appropriate endpoint to fetch all paused torrent info. - resp, err := c.getCtx(ctx, "torrents/info?filter=paused", nil) - if err != nil { - log.Printf("Error retrieving paused torrent info: %v", err) - return nil, fmt.Errorf("error retrieving paused torrent info: %v", err) - } - defer resp.Body.Close() - - // Parse response. - var torrents []Torrent - if err := json.NewDecoder(resp.Body).Decode(&torrents); err != nil { - log.Printf("Error decoding response: %v", err) - return nil, fmt.Errorf("error decoding response: %v", err) - } - - log.Printf("Found %d paused torrents", len(torrents)) - - return torrents, nil -} - func (c *Client) Pause(ctx context.Context, hashes []string) error { v := url.Values{} From 2a70ce668a598190121e2e16fd7064a2bb39917e Mon Sep 17 00:00:00 2001 From: soup Date: Tue, 23 May 2023 23:37:11 +0200 Subject: [PATCH 3/4] refactor DeleteTorrents for proper params --- pkg/qbittorrent/methods.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/qbittorrent/methods.go b/pkg/qbittorrent/methods.go index 2fcb5a2..fef7d05 100644 --- a/pkg/qbittorrent/methods.go +++ b/pkg/qbittorrent/methods.go @@ -3,10 +3,10 @@ package qbittorrent import ( "encoding/json" "io" + "io/ioutil" "log" "net/http" "net/url" - "strconv" "strings" "github.com/anacrolix/torrent/metainfo" @@ -287,19 +287,23 @@ func (c *Client) AddTorrentFromMagnet(ctx context.Context, u string, options map } func (c *Client) DeleteTorrents(ctx context.Context, hashes []string, deleteFiles bool) error { - v := url.Values{} + opts := make(map[string]string) // Add hashes together with | separator hv := strings.Join(hashes, "|") - v.Add("hashes", hv) - v.Add("deleteFiles", strconv.FormatBool(deleteFiles)) + opts["hashes"] = hv - encodedHashes := v.Encode() + // Only include the deleteFiles parameter if it's set to true + if deleteFiles { + opts["deleteFiles"] = "true" + } - resp, err := c.postCtx(ctx, "torrents/delete?"+encodedHashes, nil) + resp, err := c.postCtx(ctx, "torrents/delete", opts) if err != nil { log.Fatalf("error deleting torrents: %v", err) } else if resp.StatusCode != http.StatusOK { + bodyBytes, _ := ioutil.ReadAll(resp.Body) + log.Printf("Unexpected response status: %d. Body: %s", resp.StatusCode, string(bodyBytes)) return err } From bff978be3c31aa877d8f46e5223937576dee9f36 Mon Sep 17 00:00:00 2001 From: soup Date: Tue, 23 May 2023 23:37:38 +0200 Subject: [PATCH 4/4] split removeAll and removePaused --- cmd/remove.go | 61 ++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/cmd/remove.go b/cmd/remove.go index fd8c31a..20f13a5 100644 --- a/cmd/remove.go +++ b/cmd/remove.go @@ -70,44 +70,45 @@ func RunRemove() *cobra.Command { } if removeAll { - if removePaused { - pausedTorrents, err := qb.GetTorrentsWithFilters(ctx, &qbittorrent.GetTorrentsRequest{Filter: "paused"}) - if err != nil { - fmt.Fprintf(os.Stderr, "ERROR: failed to retrieve paused torrents: %v\n", err) + if dryRun { + log.Printf("Would remove all torrents") + } else { + if err := qb.DeleteTorrents(ctx, []string{"all"}, deleteFiles); err != nil { + fmt.Fprintf(os.Stderr, "ERROR: could not delete torrents: %v\n", err) os.Exit(1) } - hashesToRemove := []string{} - for _, torrent := range pausedTorrents { - hashesToRemove = append(hashesToRemove, torrent.Hash) - } + log.Printf("All torrents removed successfully") + } + return + } - if len(hashesToRemove) < 1 { - log.Printf("No paused torrents found to remove") - return - } + if removePaused { + pausedTorrents, err := qb.GetTorrentsWithFilters(ctx, &qbittorrent.GetTorrentsRequest{Filter: "paused"}) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: failed to retrieve paused torrents: %v\n", err) + os.Exit(1) + } - if dryRun { - log.Printf("Paused torrents to be removed: %v", hashesToRemove) - } else { - if err := qb.DeleteTorrents(ctx, hashesToRemove, deleteFiles); err != nil { - fmt.Fprintf(os.Stderr, "ERROR: could not delete paused torrents: %v\n", err) - os.Exit(1) - } + hashesToRemove := []string{} + for _, torrent := range pausedTorrents { + hashesToRemove = append(hashesToRemove, torrent.Hash) + } - log.Print("Paused torrents removed successfully") - } + if len(hashesToRemove) < 1 { + log.Printf("No paused torrents found to remove") + return + } + + if dryRun { + log.Printf("Paused torrents to be removed: %v", hashesToRemove) } else { - if dryRun { - log.Printf("Would remove all torrents") - } else { - if err := qb.DeleteTorrents(ctx, []string{"all"}, deleteFiles); err != nil { - fmt.Fprintf(os.Stderr, "ERROR: could not delete torrents: %v\n", err) - os.Exit(1) - } - - log.Printf("All torrents removed successfully") + if err := qb.DeleteTorrents(ctx, hashesToRemove, deleteFiles); err != nil { + fmt.Fprintf(os.Stderr, "ERROR: could not delete paused torrents: %v\n", err) + os.Exit(1) } + + log.Print("Paused torrents removed successfully") } return }