-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(reannounce): add missing reannounce handler (#53)
- Loading branch information
1 parent
71644e2
commit beff510
Showing
1 changed file
with
135 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package cmd | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"github.com/ludviglundgren/qbittorrent-cli/internal/config" | ||
"github.com/ludviglundgren/qbittorrent-cli/pkg/qbittorrent" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
// RunReannounce cmd to reannounce torrents | ||
func RunReannounce() *cobra.Command { | ||
var ( | ||
dry bool | ||
hash string | ||
category string | ||
tag string | ||
attempts int | ||
interval int | ||
) | ||
|
||
var command = &cobra.Command{ | ||
Use: "reannounce", | ||
Short: "Reannounce torrent(s)", | ||
Long: `Reannounce torrents if needed.`, | ||
} | ||
|
||
command.Flags().BoolVar(&dry, "dry-run", false, "Run without doing anything") | ||
command.Flags().StringVar(&hash, "hash", "", "Reannounce torrent with hash") | ||
command.Flags().StringVar(&category, "category", "", "Reannounce torrents with category") | ||
command.Flags().StringVar(&tag, "tag", "", "Reannounce torrents with tag") | ||
command.Flags().IntVar(&attempts, "attempts", 50, "Reannounce torrents X times") | ||
command.Flags().IntVar(&interval, "interval", 7000, "Reannounce torrents X times with interval Y. In MS") | ||
|
||
command.Run = func(cmd *cobra.Command, args []string) { | ||
config.InitConfig() | ||
|
||
if !dry { | ||
qbtSettings := qbittorrent.Settings{ | ||
Addr: config.Qbit.Addr, | ||
Hostname: config.Qbit.Host, | ||
Port: config.Qbit.Port, | ||
Username: config.Qbit.Login, | ||
Password: config.Qbit.Password, | ||
BasicUser: config.Qbit.BasicUser, | ||
BasicPass: config.Qbit.BasicPass, | ||
} | ||
|
||
qb := qbittorrent.NewClient(qbtSettings) | ||
|
||
ctx := context.Background() | ||
|
||
if err := qb.Login(ctx); err != nil { | ||
fmt.Fprintf(os.Stderr, "ERROR: connection failed: %v\n", err) | ||
os.Exit(1) | ||
} | ||
|
||
req := &qbittorrent.GetTorrentsRequest{ | ||
Filter: string(qbittorrent.TorrentFilterDownloading), | ||
Category: category, | ||
Tag: tag, | ||
Hashes: hash, | ||
} | ||
|
||
activeDownloads, err := qb.GetTorrentsWithFilters(ctx, req) | ||
if err != nil { | ||
log.Fatalf("could not fetch torrents: err: %q", err) | ||
} | ||
|
||
for _, torrent := range activeDownloads { | ||
if torrent.Progress == 0 && torrent.TimeActive < 120 { | ||
go func() { | ||
log.Printf("torrent %s %s not working, active for %ds, re-announcing...\n", torrent.Hash, torrent.Name, torrent.TimeActive) | ||
|
||
// some trackers are bugged or slow, so we need to re-announce the torrent until it works | ||
if err = reannounceTorrent(ctx, qb, interval, attempts, torrent.Hash); err != nil { | ||
log.Printf("could not re-announce torrent: %s %s err: %q\n", torrent.Hash, torrent.Name, err) | ||
} | ||
|
||
log.Printf("successfully re-announced torrent: %s %s err: %q\n", torrent.Hash, torrent.Name, err) | ||
|
||
}() | ||
} | ||
} | ||
|
||
log.Println("torrents successfully re-announced") | ||
} else { | ||
log.Println("dry-run: torrents successfully re-announced!") | ||
} | ||
} | ||
|
||
return command | ||
} | ||
|
||
func reannounceTorrent(ctx context.Context, qb *qbittorrent.Client, interval, attempts int, hash string) error { | ||
announceOK := false | ||
attempt := 0 | ||
|
||
time.Sleep(time.Duration(interval) * time.Millisecond) | ||
|
||
for attempt < attempts { | ||
trackers, err := qb.GetTorrentTrackers(ctx, hash) | ||
if err != nil { | ||
log.Fatalf("could not get trackers of torrent: %s err: %q", hash, err) | ||
} | ||
|
||
// check if status not working or something else | ||
_, working := findTrackerStatus(trackers, 2) | ||
if working { | ||
announceOK = true | ||
break | ||
} | ||
|
||
if err = qb.ReAnnounceTorrents(ctx, []string{hash}); err != nil { | ||
return err | ||
} | ||
|
||
time.Sleep(time.Duration(interval) * time.Millisecond) | ||
attempt++ | ||
continue | ||
} | ||
|
||
if !announceOK { | ||
log.Println("announce still not ok") | ||
return errors.New("announce still not ok") | ||
} | ||
|
||
return nil | ||
} |