Skip to content

Commit

Permalink
feat(export): export torrents by category (#35)
Browse files Browse the repository at this point in the history
* feat(export): export torrents by category

* feat: use pipe as replace separator

* fix(import): traling slash path handling (#41)

* chore: update go mod version

* fix: trailing slash in paths

* feat(export): export torrents by category

* feat: use pipe as replace separator

* chore: improve error handling and logs

* feat: check both torrent and fastresume
  • Loading branch information
ludviglundgren committed Jan 17, 2023
1 parent 868f3d2 commit d1332f6
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 5 deletions.
143 changes: 143 additions & 0 deletions cmd/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package cmd

import (
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"strings"

"github.com/ludviglundgren/qbittorrent-cli/internal/config"
"github.com/ludviglundgren/qbittorrent-cli/pkg/qbittorrent"
"github.com/ludviglundgren/qbittorrent-cli/pkg/torrent"

"github.com/pkg/errors"
"github.com/spf13/cobra"
)

func RunExport() *cobra.Command {
var command = &cobra.Command{
Use: "export",
Short: "export torrents",
Long: "Export torrents and fastresume by category",
}

var (
dry bool
sourceDir string
exportDir string
categories []string
)

command.Flags().BoolVar(&dry, "dry-run", false, "dry run")
command.Flags().StringVar(&sourceDir, "source", "", "Dir with torrent and fast-resume files")
command.Flags().StringVar(&exportDir, "export-dir", "", "Dir to export files to")
command.Flags().StringSliceVar(&categories, "categories", []string{}, "Export torrents from categories")
command.MarkFlagRequired("categories")

command.RunE = func(cmd *cobra.Command, args []string) error {
// get torrents from client by categories
config.InitConfig()

qbtSettings := qbittorrent.Settings{
Hostname: config.Qbit.Host,
Port: config.Qbit.Port,
Username: config.Qbit.Login,
Password: config.Qbit.Password,
}

qb := qbittorrent.NewClient(qbtSettings)
if err := qb.Login(); err != nil {
return errors.Wrapf(err, "connection failed")
}

hashes := map[string]struct{}{}

for _, category := range categories {
torrents, err := qb.GetTorrentsByCategory(category)
if err != nil {
return errors.Wrapf(err, "could not get torrents for category: %s", category)
}

for _, t := range torrents {
// only grab completed torrents
if t.Progress != 1 {
continue
}

// append hash to map of hashes to gather
hashes[t.Hash] = struct{}{}
}
}

if len(hashes) == 0 {
fmt.Printf("Could not find any matching torrents to export from (%s)\n", strings.Join(categories, ","))
os.Exit(0)
}

fmt.Printf("Found '%d' matching torrents\n", len(hashes))

if err := processHashes(sourceDir, exportDir, hashes, dry); err != nil {
return errors.Wrapf(err, "could not process torrents")
}

fmt.Println("Successfully exported torrents!")

return nil
}

return command
}
func processHashes(sourceDir, exportDir string, hashes map[string]struct{}, dry bool) error {
exportCount := 0
// check BT_backup dir, pick torrent and fastresume files by id
err := filepath.Walk(sourceDir, func(dirPath string, info fs.FileInfo, err error) error {
if err != nil {
return err
}

if !!info.IsDir() {
return nil //
}

fileName := info.Name()

if filepath.Ext(fileName) != ".torrent" || filepath.Ext(fileName) != ".fastresume" {
return nil
}

torrentHash := fileNameTrimExt(fileName)

// if filename not in hashes return and check next
_, ok := hashes[torrentHash]
if !ok {
return nil
}

fmt.Printf("processing: %s\n", fileName)

if !dry {
outFile := filepath.Join(exportDir, fileName)
if err := torrent.CopyFile(dirPath, outFile); err != nil {
return errors.Wrapf(err, "could not copy file: %s to %s", dirPath, outFile)
}
}

exportCount++

return nil
})
if err != nil {
log.Printf("error reading files: %q", err)
return err
}

fmt.Printf("Found and exported '%d' torrents\n", exportCount)

return nil
}

func fileNameTrimExt(fileName string) string {
return strings.TrimSuffix(fileName, filepath.Ext(fileName))
}
35 changes: 35 additions & 0 deletions cmd/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cmd

import "testing"

func Test_processHashes(t *testing.T) {
type args struct {
sourceDir string
exportDir string
hashes map[string]struct{}
replace []string
dry bool
}
tests := []struct {
name string
args args
wantErr bool
}{
{name: "test_1", args: args{
sourceDir: "../test/config/qBittorrent/BT_backup",
exportDir: "../test/export",
hashes: map[string]struct{}{
"5ba4939a00a9b21629a0ad7d376898b768d997a3": {},
},
replace: []string{"https://academictorrents.com/announce.php|https://test.com/announce.php?test"},
dry: false,
}, wantErr: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := processHashes(tt.args.sourceDir, tt.args.exportDir, tt.args.hashes, tt.args.replace, tt.args.dry); (err != nil) != tt.wantErr {
t.Errorf("processHashes() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
11 changes: 6 additions & 5 deletions cmd/qbt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ Documentation is available at https://github.com/ludviglundgren/qbittorrent-cli`
rootCmd.PersistentFlags().StringVar(&config.CfgFile, "config", "", "config file (default is $HOME/.config/qbt/.qbt.toml)")

rootCmd.AddCommand(cmd.RunVersion(version, commit, date))
rootCmd.AddCommand(cmd.RunList())
rootCmd.AddCommand(cmd.RunAdd())
rootCmd.AddCommand(cmd.RunImport())
rootCmd.AddCommand(cmd.RunPause())
rootCmd.AddCommand(cmd.RunResume())
rootCmd.AddCommand(cmd.RunMove())
rootCmd.AddCommand(cmd.RunCompare())
rootCmd.AddCommand(cmd.RunEdit())
rootCmd.AddCommand(cmd.RunExport())
rootCmd.AddCommand(cmd.RunHash())
rootCmd.AddCommand(cmd.RunImport())
rootCmd.AddCommand(cmd.RunList())
rootCmd.AddCommand(cmd.RunMove())
rootCmd.AddCommand(cmd.RunPause())
rootCmd.AddCommand(cmd.RunRemove())
rootCmd.AddCommand(cmd.RunResume())

if err := rootCmd.Execute(); err != nil {
os.Exit(1)
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d8:announce41:https://academictorrents.com/announce.php13:announce-listll41:https://academictorrents.com/announce.phpel34:udp://tracker.coppersurfer.tk:6969el42:udp://tracker.opentrackr.org:1337/announceel44:udp://tracker.openbittorrent.com:80/announceee10:created by23:py3createtorrent v0.9.513:creation datei1398649389e4:infod6:lengthi42310e4:name44:Scikit-learn: Machine Learning in Python.pdf12:piece lengthi16384e6:pieces60:l�3��M]d=��"T[]�,*ƫ9ˢ:��ho7Bd?v�C��٩`Ƨ��%}��h��e8:url-listl65:http://www.jmlr.org/papers/volume12/pedregosa11a/pedregosa11a.pdf93:https://web.archive.org/web/http://www.jmlr.org/papers/volume12/pedregosa11a/pedregosa11a.pdfee

0 comments on commit d1332f6

Please sign in to comment.