initial commit
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"git.sbstp.ca/sbstp/qbittorrent-sentinel/api"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
var rxExecutable = regexp.MustCompile(`\.(exe|scr|lnk|bat|vbs|js|cmd)$`)
|
||||
|
||||
func isExecutable(t *api.TorrentFile) bool {
|
||||
// - File has extension commonly used for viruses/executables
|
||||
return rxExecutable.MatchString(t.Name)
|
||||
}
|
||||
|
||||
func isCandidate(t *api.TorrentInfo) bool {
|
||||
// - Less downloaded than total size, indicates it's stalled
|
||||
// - Size is less than total size, indicates some files have been filtered out
|
||||
return t.Downloaded < t.TotalSize && t.Size < t.TotalSize && time.Since(t.AddedOn.Time) > time.Minute*15
|
||||
}
|
||||
|
||||
func checkTorrents(baseURL, username, password string) error {
|
||||
client, err := api.NewClient(baseURL, username, password)
|
||||
if err != nil {
|
||||
slog.Error("Could not connect to qBittorrent", slog.String("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
list, err := client.LisTorrents()
|
||||
if err != nil {
|
||||
slog.Error("Could not list torrents", slog.String("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
slog.Info("Successfully listed torrents", slog.Int("num", len(list)))
|
||||
|
||||
for _, t := range list {
|
||||
if isCandidate(&t) {
|
||||
slog.Info("Torrent is a candidate", slog.String("hash", t.Hash), slog.String("name", t.Name))
|
||||
files, err := client.TorrentFiles(t.Hash)
|
||||
if err != nil {
|
||||
slog.Error("Could not get torrent files", slog.String("error", err.Error()))
|
||||
continue
|
||||
}
|
||||
|
||||
executables := lo.Filter(files, func(f api.TorrentFile, _ int) bool {
|
||||
return isExecutable(&f)
|
||||
})
|
||||
if len(executables) > 0 {
|
||||
slog.Info("Torrent contains executables")
|
||||
for _, exe := range executables {
|
||||
slog.Info("Torrent file is executable", slog.String("name", exe.Name))
|
||||
}
|
||||
slog.Info("Deleting torrent...")
|
||||
if err := client.DeleteTorrent(t.Hash, true); err != nil {
|
||||
slog.Error("Failed to delete torrent", slog.String("error", err.Error()))
|
||||
} else {
|
||||
slog.Info("Torrent deleted successfully")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
slog.Info("Done")
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
baseURL := os.Getenv("QBITTORRENT_BASE_URL")
|
||||
username := os.Getenv("QBITTORRENT_USERNAME")
|
||||
password := os.Getenv("QBITTORRENT_PASSWORD")
|
||||
|
||||
if len(baseURL) == 0 {
|
||||
slog.Error("QBITTORRENT_BASE_URL environment variable is required")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if err := checkTorrents(baseURL, username, password); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user