mirror of
https://github.com/celogeek/go-qbittorrent-sync.git
synced 2025-05-24 16:02:37 +02:00
rsync with progress
This commit is contained in:
parent
4c8fdd956f
commit
8827aca192
62
main.go
62
main.go
@ -2,31 +2,49 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type RsyncOptions struct {
|
||||||
Qbittorent QBitTorrentOptions
|
Username string
|
||||||
|
Hostname string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RsyncOptions) Uri(path string) string {
|
||||||
|
result := fmt.Sprintf("%s:%s", r.Hostname, path)
|
||||||
|
if r.Username == "" {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s@%s", r.Username, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
options := &Options{}
|
qbitoptions := &QBitTorrentOptions{}
|
||||||
flag.StringVar(&options.Qbittorent.Uri, "qbittorrent-uri", "http://localhost:8080", "URI of qbittorrent")
|
rsyncoptions := &RsyncOptions{}
|
||||||
flag.StringVar(&options.Qbittorent.Username, "qbittorrent-username", "", "Username of qbittorrent")
|
dest := ""
|
||||||
flag.StringVar(&options.Qbittorent.Password, "qbittorrent-password", "", "Password of qbittorrent")
|
flag.StringVar(&qbitoptions.Uri, "qbittorrent-uri", "http://localhost:8080", "URI of qbittorrent")
|
||||||
flag.StringVar(&options.Qbittorent.SyncTag, "qbittorrent-sync-tag", "Sync", "Tag of qbittorrent to copy")
|
flag.StringVar(&qbitoptions.Username, "qbittorrent-username", "", "Username of qbittorrent")
|
||||||
flag.StringVar(&options.Qbittorent.SyncedTag, "qbittorrent-synced-tag", "", "Tag of qbittorrent when copy finished")
|
flag.StringVar(&qbitoptions.Password, "qbittorrent-password", "", "Password of qbittorrent")
|
||||||
|
flag.StringVar(&qbitoptions.SyncTag, "qbittorrent-sync-tag", "Sync", "Tag of qbittorrent to copy")
|
||||||
|
flag.StringVar(&qbitoptions.SyncedTag, "qbittorrent-synced-tag", "", "Tag of qbittorrent when copy finished")
|
||||||
|
flag.StringVar(&rsyncoptions.Hostname, "rsync-hostname", "", "Rsync host")
|
||||||
|
flag.StringVar(&rsyncoptions.Username, "rsync-username", "", "Rsync username")
|
||||||
|
flag.StringVar(&dest, "dest", ".", "Destination directory")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if options.Qbittorent.Uri == "" ||
|
if qbitoptions.Uri == "" ||
|
||||||
options.Qbittorent.Username == "" ||
|
qbitoptions.Username == "" ||
|
||||||
options.Qbittorent.Password == "" ||
|
qbitoptions.Password == "" ||
|
||||||
options.Qbittorent.SyncTag == "" {
|
qbitoptions.SyncTag == "" {
|
||||||
log.Fatal("missing qbittorrent parameters")
|
log.Fatal("missing qbittorrent parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
qcli, err := NewQBittorrentCli(&options.Qbittorent)
|
if rsyncoptions.Hostname == "" {
|
||||||
|
log.Fatal("missing rsync parameters")
|
||||||
|
}
|
||||||
|
|
||||||
|
qcli, err := NewQBittorrentCli(qbitoptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -38,12 +56,20 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range torrents {
|
for _, t := range torrents {
|
||||||
for p := 0; p <= 100; p += 20 {
|
rtask := NewRsync(
|
||||||
|
rsyncoptions.Uri(t.Path),
|
||||||
|
dest,
|
||||||
|
func(p int) {
|
||||||
|
qcli.SetProgress(t, p)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := rtask.Run(); err != nil {
|
||||||
qcli.ClearTags()
|
qcli.ClearTags()
|
||||||
qcli.SetProgress(&t, p)
|
log.Fatal(err)
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
}
|
||||||
qcli.SetDone(&t)
|
|
||||||
|
qcli.SetDone(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
@ -60,8 +61,8 @@ func (c *QBittorrentCli) Logout() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QBittorrentCli) List() ([]Torrent, error) {
|
func (c *QBittorrentCli) List() ([]*Torrent, error) {
|
||||||
result := make([]Torrent, 0)
|
result := make([]*Torrent, 0)
|
||||||
|
|
||||||
_, err := c.cli.R().
|
_, err := c.cli.R().
|
||||||
SetQueryParam("filter", "completed").
|
SetQueryParam("filter", "completed").
|
||||||
@ -152,8 +153,19 @@ func (c *QBittorrentCli) SetProgress(t *Torrent, p int) error {
|
|||||||
return nil
|
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
|
t.Progress = p
|
||||||
return c.SetTag(t, fmt.Sprintf("Progress:%d%%", p))
|
log.Printf("Downloading [%s]: %d%%", t.Name, p)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QBittorrentCli) SetDone(t *Torrent) error {
|
func (c *QBittorrentCli) SetDone(t *Torrent) error {
|
||||||
|
89
rsync.go
Normal file
89
rsync.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Rsync struct {
|
||||||
|
Source string
|
||||||
|
Destination string
|
||||||
|
OnProgress func(p int)
|
||||||
|
|
||||||
|
progress int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRsync(source, destination string, onProgress func(p int)) *Rsync {
|
||||||
|
return &Rsync{
|
||||||
|
Source: source,
|
||||||
|
Destination: destination,
|
||||||
|
OnProgress: onProgress,
|
||||||
|
progress: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScanCR(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
if atEOF && len(data) == 0 {
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
if i := bytes.IndexByte(data, '\r'); i >= 0 {
|
||||||
|
// We have a full newline-terminated line.
|
||||||
|
return i + 1, data[0:i], nil
|
||||||
|
}
|
||||||
|
// If we're at EOF, we have a final, non-terminated line. Return it.
|
||||||
|
if atEOF {
|
||||||
|
return len(data), data, nil
|
||||||
|
}
|
||||||
|
// Request more data.
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rsync) Run() error {
|
||||||
|
cmd := exec.Command(
|
||||||
|
"rsync",
|
||||||
|
"--archive",
|
||||||
|
"--partial",
|
||||||
|
"--inplace",
|
||||||
|
"--no-inc-recursive",
|
||||||
|
"--info=progress2",
|
||||||
|
r.Source,
|
||||||
|
r.Destination,
|
||||||
|
)
|
||||||
|
out, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
scanner := bufio.NewScanner(out)
|
||||||
|
scanner.Split(ScanCR)
|
||||||
|
progressMatch := regexp.MustCompile(`(\d+)%`)
|
||||||
|
for scanner.Scan() {
|
||||||
|
progress := scanner.Text()
|
||||||
|
if progressMatch.MatchString(progress) {
|
||||||
|
m := progressMatch.FindStringSubmatch(progress)
|
||||||
|
if p, err := strconv.Atoi(m[1]); err == nil {
|
||||||
|
r.OnProgress(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user