Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add torrent selection for Pause & Resume commands #33

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 68 additions & 4 deletions cmd/pause.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package cmd
import (
"fmt"
"os"
"log"
"time"

"github.com/ludviglundgren/qbittorrent-cli/internal/config"
"github.com/ludviglundgren/qbittorrent-cli/pkg/qbittorrent"
Expand All @@ -12,12 +14,34 @@ import (

// RunPause cmd to pause torrents
func RunPause() *cobra.Command {
var (
pauseAll bool
hashes bool
names bool
)

var command = &cobra.Command{
Use: "pause",
Short: "Pause all torrents",
Long: `Pause all torrents`,
Short: "Pause specified torrents",
Long: `Pauses torrents indicated by hash, name or a prefix of either;
whitespace indicates next prefix unless argument is surrounded by quotes`,
}

command.Flags().BoolVar(&pauseAll, "all", false, "Pauses all torrents")
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.Run = func(cmd *cobra.Command, args []string) {
if !pauseAll && len(args) < 1 {
log.Printf("Please provide atleast one torrent hash/name as an argument")
return
}

if !pauseAll && !hashes && !names {
log.Printf("Please specifiy if arguments are to be read as hashes or names (--hashes / --names)")
return
}

config.InitConfig()
qbtSettings := qbittorrent.Settings{
Hostname: config.Qbit.Host,
Expand All @@ -33,11 +57,51 @@ func RunPause() *cobra.Command {
os.Exit(1)
}

err = qb.Pause(nil)
if pauseAll {
qb.Pause([]string{"all"})
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not pause torrents: %v\n", err)
os.Exit(1)
}

log.Printf("All torrents paused successfully")
return
}

foundTorrents, err := qb.GetTorrentsByPrefixes(args, hashes, names)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not pause torrents %v\n", err)
fmt.Fprintf(os.Stderr, "ERROR: failed to retrieve torrents: %v\n", err)
os.Exit(1)
}

hashesToPause := []string{}
for _, torrent := range foundTorrents {
hashesToPause = append(hashesToPause, torrent.Hash)
}

if len(hashesToPause) < 1 {
log.Printf("No torrents found to pause with provided search terms")
return
}

// Split the hashes to pause into groups of 20 to avoid flooding qbittorrent
batch := 20
for i := 0; i < len(hashesToPause); i += batch {
j := i + batch
if j > len(hashesToPause) {
j = len(hashesToPause)
}

qb.Pause(hashesToPause[i:j])
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not pause torrents: %v\n", err)
os.Exit(1)
}

time.Sleep(time.Second * 1)
}

log.Printf("torrent(s) successfully paused")
}

return command
Expand Down
67 changes: 34 additions & 33 deletions cmd/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package cmd
import (
"fmt"
"os"
"strings"
"log"
"time"

"github.com/ludviglundgren/qbittorrent-cli/internal/config"
"github.com/ludviglundgren/qbittorrent-cli/pkg/qbittorrent"
Expand Down Expand Up @@ -58,48 +58,49 @@ func RunRemove() *cobra.Command {
fmt.Fprintf(os.Stderr, "ERROR: connection failed: %v\n", err)
os.Exit(1)
}

if removeAll {
qb.DeleteTorrents([]string{"all"}, deleteFiles)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not delete torrents: %v\n", err)
os.Exit(1)
}

log.Printf("All torrents removed successfully")
return
}

torrents, err := qb.GetTorrents()
foundTorrents, err := qb.GetTorrentsByPrefixes(args, hashes, names)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not retrieve torrents: %v\n", err)
fmt.Fprintf(os.Stderr, "ERROR: failed to retrieve torrents: %v\n", err)
os.Exit(1)
}

foundHashes := map[string]bool{}
for _, torrent := range torrents {
if removeAll {
foundHashes[torrent.Hash] = true
continue
}
hashesToRemove := []string{}
for _, torrent := range foundTorrents {
hashesToRemove = append(hashesToRemove, torrent.Hash)
}

if hashes {
for _, targetHash := range args {
if strings.HasPrefix(torrent.Hash, targetHash) {
foundHashes[torrent.Hash] = true
break
}
}
}
if len(hashesToRemove) < 1 {
log.Printf("No torrents found to remove with provided search terms")
return
}

if names {
for _, targetName := range args {
if strings.HasPrefix(torrent.Name, targetName) {
foundHashes[torrent.Hash] = true
break
}
}
// Split the hashes to remove into groups of 20 to avoid flooding qbittorrent
batch := 20
for i := 0; i < len(hashesToRemove); i += batch {
j := i + batch
if j > len(hashesToRemove) {
j = len(hashesToRemove)
}
}

hashesToRemove := []string{}
for hash := range foundHashes {
hashesToRemove = append(hashesToRemove, hash)
}
qb.DeleteTorrents(hashesToRemove[i:j], deleteFiles)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not delete torrents: %v\n", err)
os.Exit(1)
}

err = qb.DeleteTorrents(hashesToRemove, deleteFiles)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not delete torrents: %v\n", err)
os.Exit(1)
time.Sleep(time.Second * 1)
}

log.Printf("torrent(s) successfully deleted")
Expand Down
72 changes: 68 additions & 4 deletions cmd/resume.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package cmd
import (
"fmt"
"os"
"log"
"time"

"github.com/ludviglundgren/qbittorrent-cli/internal/config"
"github.com/ludviglundgren/qbittorrent-cli/pkg/qbittorrent"
Expand All @@ -12,13 +14,34 @@ import (

// RunResume cmd to resume torrents
func RunResume() *cobra.Command {
var (
resumeAll bool
hashes bool
names bool
)

var command = &cobra.Command{
Use: "resume",
Short: "Resume all torrents",
Long: `Resume all torrents`,
Short: "resume specified torrents",
Long: `resumes torrents indicated by hash, name or a prefix of either;
whitespace indicates next prefix unless argument is surrounded by quotes`,
}

command.Flags().BoolVar(&resumeAll, "all", false, "resumes all torrents")
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.Run = func(cmd *cobra.Command, args []string) {
if !resumeAll && len(args) < 1 {
log.Printf("Please provide atleast one torrent hash/name as an argument")
return
}

if !resumeAll && !hashes && !names {
log.Printf("Please specifiy if arguments are to be read as hashes or names (--hashes / --names)")
return
}

config.InitConfig()
qbtSettings := qbittorrent.Settings{
Hostname: config.Qbit.Host,
Expand All @@ -34,11 +57,52 @@ func RunResume() *cobra.Command {
os.Exit(1)
}

err = qb.Resume(nil)

if resumeAll {
qb.Resume([]string{"all"})
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not resume torrents: %v\n", err)
os.Exit(1)
}

log.Printf("All torrents resumed successfully")
return
}

foundTorrents, err := qb.GetTorrentsByPrefixes(args, hashes, names)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not resume torrents %v\n", err)
fmt.Fprintf(os.Stderr, "ERROR: failed to retrieve torrents: %v\n", err)
os.Exit(1)
}

hashesToResume := []string{}
for _, torrent := range foundTorrents {
hashesToResume = append(hashesToResume, torrent.Hash)
}

if len(hashesToResume) < 1 {
log.Printf("No torrents found to resume with provided search terms")
return
}

// Split the hashes to resume into groups of 20 to avoid flooding qbittorrent
batch := 20
for i := 0; i < len(hashesToResume); i += batch {
j := i + batch
if j > len(hashesToResume) {
j = len(hashesToResume)
}

qb.Resume(hashesToResume[i:j])
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not resume torrents: %v\n", err)
os.Exit(1)
}

time.Sleep(time.Second * 1)
}

log.Printf("torrent(s) successfully resumed")
}

return command
Expand Down
62 changes: 48 additions & 14 deletions pkg/qbittorrent/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,46 @@ func (c *Client) GetTorrentByHash(hash string) (string, error) {
return string(data), nil
}

// Search for torrents using provided prefixes; checks against either hashes, names, or both
func (c *Client) GetTorrentsByPrefixes(terms []string, hashes bool, names bool) ([]Torrent, error) {
torrents, err := c.GetTorrents()
if err != nil {
log.Fatalf("ERROR: could not retrieve torrents: %v\n", err)
}

matchedTorrents := map[Torrent]bool{}
for _, torrent := range torrents {
if hashes {
for _, targetHash := range terms {
if strings.HasPrefix(torrent.Hash, targetHash) {
matchedTorrents[torrent] = true
break
}
}

if matchedTorrents[torrent] {
continue
}
}

if names {
for _, targetName := range terms {
if strings.HasPrefix(torrent.Name, targetName) {
matchedTorrents[torrent] = true
break
}
}
}
}

var foundTorrents []Torrent
for torrent := range matchedTorrents {
foundTorrents = append(foundTorrents, torrent)
}

return foundTorrents, nil
}

func (c *Client) GetTorrentTrackers(hash string) ([]TorrentTracker, error) {
var trackers []TorrentTracker

Expand Down Expand Up @@ -253,15 +293,12 @@ func (c *Client) ReAnnounceTorrents(hashes []string) error {

func (c *Client) Pause(hashes []string) error {
v := url.Values{}
encodedHashes := "all"

if len(hashes) > 0 {
// Add hashes together with | separator
encodedHashes = strings.Join(hashes, "|")
}
// Add hashes together with | separator
hv := strings.Join(hashes, "|")
v.Add("hashes", hv)

v.Add("hashes", encodedHashes)
encodedHashes = v.Encode()
encodedHashes := v.Encode()

resp, err := c.get("torrents/pause?"+encodedHashes, nil)
if err != nil {
Expand All @@ -277,15 +314,12 @@ func (c *Client) Pause(hashes []string) error {

func (c *Client) Resume(hashes []string) error {
v := url.Values{}
encodedHashes := "all"

if len(hashes) > 0 {
// Add hashes together with | separator
encodedHashes = strings.Join(hashes, "|")
}
// Add hashes together with | separator
hv := strings.Join(hashes, "|")
v.Add("hashes", hv)

v.Add("hashes", encodedHashes)
encodedHashes = v.Encode()
encodedHashes := v.Encode()

resp, err := c.get("torrents/resume?"+encodedHashes, nil)
if err != nil {
Expand Down