Created
December 3, 2024 04:07
-
-
Save yegle/25e3d02a65a73f31438ef5162005c373 to your computer and use it in GitHub Desktop.
qBittorrent: list torrents of which all trackers are failing
This file contains hidden or 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
package main | |
import ( | |
"context" | |
"encoding/json" | |
"io" | |
"log" | |
"net/http" | |
"strconv" | |
"time" | |
"github.com/pkg/errors" | |
) | |
const api = "http://qbittorrent:8080/api/v2" | |
type Torrent struct { | |
Hash string | |
Name string | |
} | |
const ( | |
DISABLED = iota | |
NOT_CONNECTED | |
WORKING | |
UPDATING | |
NOT_WORKING | |
) | |
type Status int | |
func (s *Status) MarshalJSON() ([]byte, error) { | |
return json.Marshal(strconv.Itoa(int(*s))) | |
} | |
func (s *Status) UnmarshalJSON(data []byte) error { | |
i, err := strconv.Atoi(string(data)) | |
*s = Status(i) | |
return err | |
} | |
func (s Status) String() string { | |
return map[Status]string{ | |
0: "DISABLED", | |
1: "NOT_CONTACTED", | |
2: "WORKING", | |
3: "UPDATING", | |
4: "NOT_WORKING", | |
}[s] | |
} | |
type Tracker struct { | |
URL string | |
Status Status | |
Msg string | |
} | |
var client = http.DefaultClient | |
func torrents(ctx context.Context) ([]Torrent, error) { | |
req, err := http.NewRequestWithContext(ctx, "GET", api+"/torrents/info", nil) | |
if err != nil { | |
return nil, errors.WithStack(err) | |
} | |
resp, err := client.Do(req) | |
if err != nil { | |
return nil, errors.WithStack(err) | |
} | |
defer resp.Body.Close() | |
var ret []Torrent | |
if bytes, err := io.ReadAll(resp.Body); err != nil { | |
return nil, errors.WithStack(err) | |
} else if err := json.Unmarshal(bytes, &ret); err != nil { | |
return nil, errors.WithStack(err) | |
} | |
return ret, nil | |
} | |
func (t Torrent) Trackers(ctx context.Context) ([]Tracker, error) { | |
req, err := http.NewRequestWithContext(ctx, "GET", api+"/torrents/trackers?hash="+t.Hash, nil) | |
if err != nil { | |
return nil, errors.WithStack(err) | |
} | |
resp, err := client.Do(req) | |
if err != nil { | |
return nil, errors.WithStack(err) | |
} | |
defer resp.Body.Close() | |
var ret []Tracker | |
if bytes, err := io.ReadAll(resp.Body); err != nil { | |
return nil, errors.WithStack(err) | |
} else if err := json.Unmarshal(bytes, &ret); err != nil { | |
return nil, errors.WithStack(err) | |
} | |
return ret, nil | |
} | |
func run() error { | |
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) | |
defer cancel() | |
ts, err := torrents(ctx) | |
if err != nil { | |
return err | |
} | |
for _, t := range ts { | |
trackers, err := t.Trackers(ctx) | |
if err != nil { | |
return err | |
} | |
working := false | |
for _, tracker := range trackers { | |
if tracker.Status == WORKING { | |
working = true | |
break | |
} | |
} | |
if !working { | |
log.Printf("%s", t.Name) | |
for _, tracker := range trackers { | |
log.Printf("\t%v", tracker) | |
} | |
} | |
} | |
return nil | |
} | |
func main() { | |
if err := run(); err != nil { | |
log.Fatalf("%+v", err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment