commit 11c68f21c7d92c7b7118f4e435e25ecbedc623cc Author: Jeffrey Serio <23226432+hyperreal64@users.noreply.github.com> Date: Fri Jun 23 21:33:24 2023 -0500 Initial commit diff --git a/almalinux/main.go b/almalinux/main.go new file mode 100644 index 0000000..1ff8615 --- /dev/null +++ b/almalinux/main.go @@ -0,0 +1,48 @@ +package almalinux + +import ( + "fmt" + "log" + + "codeberg.org/hyperreal/go-torrent-helper/common" + "github.com/hekmon/transmissionrpc" +) + +type AlmaLinux struct { + NameSubstr string + Relver string + URL string +} + +func (a AlmaLinux) AddNewTorrents(transmissionbt *transmissionrpc.Client) error { + // Set torrentURLs for AlmaLinux mirror + a.URL = "https://almalinux-mirror.dal1.hivelocity.net/" + torrentURLs := []string{ + fmt.Sprintf("%s/%s/isos/aarch64/AlmaLinux-%s-aarch64.torrent", a.URL, a.Relver, a.Relver), + fmt.Sprintf("%s/%s/isos/ppc64le/AlmaLinux-%s-ppc64le.torrent", a.URL, a.Relver, a.Relver), + fmt.Sprintf("%s/%s/isos/s390x/AlmaLinux-%s-s390x.torrent", a.URL, a.Relver, a.Relver), + fmt.Sprintf("%s/%s/isos/x86_64/AlmaLinux-%s-x86_64.torrent", a.URL, a.Relver, a.Relver), + } + + // Add torrents to Transmission instance + for _, torrentURL := range torrentURLs { + torrent, err := transmissionbt.TorrentAdd(&transmissionrpc.TorrentAddPayload{ + Filename: &torrentURL, + }) + if err != nil { + return err + } + + log.Printf("%s added\n", *torrent.Name) + } + + return nil +} + +func (a AlmaLinux) RemoveOldTorrents(transmissionbt *transmissionrpc.Client) error { + if err := common.RemoveTorrents(a.NameSubstr, a.Relver, transmissionbt); err != nil { + return err + } + + return nil +} diff --git a/command/main.go b/command/main.go new file mode 100644 index 0000000..249ee1a --- /dev/null +++ b/command/main.go @@ -0,0 +1,163 @@ +package command + +import ( + "errors" + "flag" + "fmt" + "os" + + "codeberg.org/hyperreal/go-torrent-helper/almalinux" + "codeberg.org/hyperreal/go-torrent-helper/debian" + "codeberg.org/hyperreal/go-torrent-helper/fedora" + "codeberg.org/hyperreal/go-torrent-helper/nixos" + "codeberg.org/hyperreal/go-torrent-helper/parrot" + "codeberg.org/hyperreal/go-torrent-helper/qubes" + "codeberg.org/hyperreal/go-torrent-helper/rocky" + "github.com/hekmon/transmissionrpc" +) + +type Distro interface { + AddNewTorrents(client *transmissionrpc.Client) error + RemoveOldTorrents(client *transmissionrpc.Client) error +} + +func NewAddCmd() *AddCmd { + addCmd := &AddCmd{ + fs: flag.NewFlagSet("add", flag.ExitOnError), + } + + addCmd.fs.StringVar(&addCmd.distro, "distro", "", "Distro to add torrents for") + addCmd.fs.StringVar(&addCmd.relver, "relver", "", "Release version to add") + + return addCmd +} + +func NewRemoveCmd() *RemoveCmd { + removeCmd := &RemoveCmd{ + fs: flag.NewFlagSet("remove", flag.ExitOnError), + } + + removeCmd.fs.StringVar(&removeCmd.distro, "distro", "", "Distro to remove torrents for") + removeCmd.fs.StringVar(&removeCmd.relver, "relver", "", "Release version to remove") + + return removeCmd +} + +type AddCmd struct { + fs *flag.FlagSet + + distro string + relver string +} + +type RemoveCmd struct { + fs *flag.FlagSet + + distro string + relver string +} + +func (a *AddCmd) Name() string { + return a.fs.Name() +} + +func (r *RemoveCmd) Name() string { + return r.fs.Name() +} + +func (a *AddCmd) Init(args []string) error { + return a.fs.Parse(args) +} + +func (r *RemoveCmd) Init(args []string) error { + return r.fs.Parse(args) +} + +func (a *AddCmd) Run(d Distro) error { + client, err := transmissionrpc.New(os.Getenv("TRANSMISSION_RPC_URL"), "", "", nil) + if err != nil { + return err + } + + if err := d.AddNewTorrents(client); err != nil { + return err + } + + return nil +} + +func (r *RemoveCmd) Run(d Distro) error { + client, err := transmissionrpc.New(os.Getenv("TRANSMISSION_RPC_URL"), "", "", nil) + if err != nil { + return err + } + + if err := d.RemoveOldTorrents(client); err != nil { + return err + } + + return nil +} + +type Runner interface { + Init([]string) error + Run(d Distro) error + Name() string +} + +func Root(args []string) error { + if len(args) < 1 { + return errors.New("You must pass a sub-command") + } + + cmds := []Runner{ + NewAddCmd(), + NewRemoveCmd(), + } + + subcmd := os.Args[1] + + for _, cmd := range cmds { + if cmd.Name() == subcmd { + cmd.Init(os.Args[2:]) + + distro := os.Args[3] + relver := os.Args[5] + + switch distro { + case "almalinux": + a := &almalinux.AlmaLinux{NameSubstr: "AlmaLinux", Relver: relver} + return cmd.Run(a) + + case "debian": + d := &debian.Debian{NameSubstr: "debian", Relver: relver} + return cmd.Run(d) + + case "fedora": + f := &fedora.Fedora{NameSubstr: "Fedora", Relver: relver} + return cmd.Run(f) + + case "nixos": + n := &nixos.Nixos{NameSubstr: "nixos"} + return cmd.Run(n) + + case "parrot": + p := &parrot.Parrot{NameSubstr: "Parrot", Relver: relver} + return cmd.Run(p) + + case "qubes": + q := &qubes.Qubes{NameSubstr: "Qubes", Relver: relver} + return cmd.Run(q) + + case "rocky": + r := &rocky.Rocky{NameSubstr: "Rocky", Relver: relver} + return cmd.Run(r) + + default: + return fmt.Errorf("Unknown distro: %s", distro) + } + } + } + + return fmt.Errorf("Unknown subcommand: %s", subcmd) +} diff --git a/common/main.go b/common/main.go new file mode 100644 index 0000000..e8ab79d --- /dev/null +++ b/common/main.go @@ -0,0 +1,67 @@ +package common + +import ( + "fmt" + "io/ioutil" + "net/http" + "strings" + + "github.com/hekmon/transmissionrpc" +) + +func GetResponse(url string) ([]byte, error) { + req, _ := http.NewRequest("GET", url, nil) + req.Header.Add("User-Agent", "go-torrent-helper") + + // Add required headers for GitHub API + if strings.Contains(url, "github") { + req.Header.Add("Accept", "application/vnd.github.v3.text-match+json") + req.Header.Add("Accept", "application/vnd.github.moondragon+json") + } + + // Carry out the request and receive response + client := http.Client{} + + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("Error while making request: %s\n", err) + } + + // Status in <200 or >299 + if resp.StatusCode < 200 || resp.StatusCode > 299 { + return nil, fmt.Errorf("Error: %d %s\n", resp.StatusCode, resp.Status) + } + + // Return response as bytes + dataInBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("Error reading response: %s\n", err) + } + + return dataInBytes, nil +} + +func RemoveTorrents(nameSubstr string, relver string, transmissionbt *transmissionrpc.Client) error { + var oldTorrents []int64 + torrents, err := transmissionbt.TorrentGet([]string{"id", "name"}, nil) + if err != nil { + return err + } else { + for _, torrent := range torrents { + if strings.Contains(*torrent.Name, nameSubstr) && strings.Contains(*torrent.Name, relver) { + oldTorrents = append(oldTorrents, *torrent.ID) + } + } + } + + rmPayload := &transmissionrpc.TorrentRemovePayload{ + IDs: oldTorrents, + DeleteLocalData: false, + } + + if err := transmissionbt.TorrentRemove(rmPayload); err != nil { + return err + } + + return nil +} diff --git a/debian/main.go b/debian/main.go new file mode 100644 index 0000000..73234c2 --- /dev/null +++ b/debian/main.go @@ -0,0 +1,48 @@ +package debian + +import ( + "fmt" + "log" + + thelper "codeberg.org/hyperreal/go-torrent-helper/common" + "github.com/hekmon/transmissionrpc" +) + +type Debian struct { + NameSubstr string + Relver string + URL string +} + +func (d Debian) AddNewTorrents(transmissionbt *transmissionrpc.Client) error { + // Set torrentURLs for Debian GNU/Linux mirror + d.URL = "https://cdimage.debian.org/debian-cd/current/" + torrentURLs := []string{ + fmt.Sprintf("%s/amd64/bt-dvd/debian-%s-amd64-DVD-1.iso.torrent", d.URL, d.Relver), + fmt.Sprintf("%s/arm64/bt-dvd/debian-%s-arm64-DVD-1.iso.torrent", d.URL, d.Relver), + fmt.Sprintf("%s/ppc64el/bt-dvd/debian-%s-ppc64el-DVD-1.iso.torrent", d.URL, d.Relver), + fmt.Sprintf("%s/s390x/bt-dvd/debian-%s-s390x-DVD-1.iso.torrent", d.URL, d.Relver), + } + + // Add torrents to Transmission instance + for _, torrentURL := range torrentURLs { + torrent, err := transmissionbt.TorrentAdd(&transmissionrpc.TorrentAddPayload{ + Filename: &torrentURL, + }) + if err != nil { + return err + } + + log.Printf("%s added\n", *torrent.Name) + } + + return nil +} + +func (d Debian) RemoveOldTorrents(transmissionbt *transmissionrpc.Client) error { + if err := thelper.RemoveTorrents(d.NameSubstr, d.Relver, transmissionbt); err != nil { + return err + } + + return nil +} diff --git a/fedora/main.go b/fedora/main.go new file mode 100644 index 0000000..c1e41e7 --- /dev/null +++ b/fedora/main.go @@ -0,0 +1,61 @@ +package fedora + +import ( + "fmt" + "log" + "regexp" + "strings" + + "codeberg.org/hyperreal/go-torrent-helper/common" + "github.com/hekmon/transmissionrpc" +) + +type Fedora struct { + NameSubstr string + Relver string + URL string +} + +func (f Fedora) AddNewTorrents(transmissionbt *transmissionrpc.Client) error { + // Send HTTP GET request and receive response + f.URL = "https://torrent.fedoraproject.org/" + torrentSubstr := fmt.Sprintf("%s.torrent", f.Relver) + dataInBytes, err := common.GetResponse(f.URL) + if err != nil { + return err + } + + bodyText := string(dataInBytes) + + // Extract torrent URLs from web page contents + var torrentURLs []string + re := regexp.MustCompile(`(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])`) + match := re.FindAllString(bodyText, 1000) + for _, v := range match { + if strings.Contains(v, torrentSubstr) { + torrentURLs = append(torrentURLs, v) + } + } + + // Add torrents to Transmission instance + for _, torrentURL := range torrentURLs { + torrent, err := transmissionbt.TorrentAdd(&transmissionrpc.TorrentAddPayload{ + Filename: &torrentURL, + }) + if err != nil { + return err + } + + log.Printf("%s added\n", *torrent.Name) + } + + return nil +} + +func (f Fedora) RemoveOldTorrents(transmissionbt *transmissionrpc.Client) error { + if err := common.RemoveTorrents(f.NameSubstr, f.Relver, transmissionbt); err != nil { + return err + } + + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b5880c8 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module codeberg.org/hyperreal/go-torrent-helper + +go 1.20 + +require github.com/hekmon/transmissionrpc v1.1.0 + +require ( + github.com/hashicorp/go-cleanhttp v0.5.1 // indirect + github.com/hekmon/cunits/v2 v2.0.2 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d45d26e --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hekmon/cunits/v2 v2.0.2 h1:qnZMfVxBiTgtAXVSMLKxzV1nihS6KzdjDHgh+nS4RgI= +github.com/hekmon/cunits/v2 v2.0.2/go.mod h1:9r1TycXYXaTmEWlAIfFV8JT+Xo59U96yUJAYHxzii2M= +github.com/hekmon/transmissionrpc v1.1.0 h1:58xY27x2JYxaMlIj7ycKnxqgCm3IjvTxfB7cHPLxOfs= +github.com/hekmon/transmissionrpc v1.1.0/go.mod h1:qkwhsyD/MQSlWvOE1AC92xajwEveAuGsOvTuOBZEuHc= diff --git a/main.go b/main.go new file mode 100644 index 0000000..a2b7b37 --- /dev/null +++ b/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "log" + "os" + + "codeberg.org/hyperreal/go-torrent-helper/command" +) + +func main() { + if err := command.Root(os.Args[1:]); err != nil { + log.Fatalln(err) + } +} diff --git a/nixos/main.go b/nixos/main.go new file mode 100644 index 0000000..aae239b --- /dev/null +++ b/nixos/main.go @@ -0,0 +1,57 @@ +package nixos + +import ( + "encoding/json" + "log" + + "codeberg.org/hyperreal/go-torrent-helper/common" + "github.com/hekmon/transmissionrpc" +) + +type Nixos struct { + NameSubstr string + URL string +} + +func (n Nixos) AddNewTorrents(transmissionbt *transmissionrpc.Client) error { + // Send GET request and receive HTTP response + n.URL = "https://api.github.com/repos/AnimMouse/NixOS-ISO-Torrents/releases/latest" + dataInBytes, err := common.GetResponse(n.URL) + if err != nil { + return err + } + + result := make(map[string]interface{}) + if err := json.Unmarshal(dataInBytes, &result); err != nil { + return err + } + + // Get torrent URLs from HTTP response result + var torrentURLs []interface{} + for _, asset := range result["assets"].([]interface{}) { + torrentURLs = append(torrentURLs, asset.(map[string]interface{})["browser_download_url"]) + } + + // Add URLs to Transmission + for _, torrentURL := range torrentURLs { + strTorrentURL := torrentURL.(string) + torrent, err := transmissionbt.TorrentAdd(&transmissionrpc.TorrentAddPayload{ + Filename: &strTorrentURL, + }) + if err != nil { + return err + } + + log.Printf("%s added\n", *torrent.Name) + } + + return nil +} + +func (n Nixos) RemoveOldTorrents(transmissionbt *transmissionrpc.Client) error { + if err := common.RemoveTorrents(n.NameSubstr, "", transmissionbt); err != nil { + return err + } + + return nil +} diff --git a/parrot/main.go b/parrot/main.go new file mode 100644 index 0000000..0e3c0ac --- /dev/null +++ b/parrot/main.go @@ -0,0 +1,53 @@ +package parrot + +import ( + "fmt" + "log" + + "codeberg.org/hyperreal/go-torrent-helper/common" + "github.com/hekmon/transmissionrpc" +) + +type Parrot struct { + NameSubstr string + Relver string + URL string +} + +func (p Parrot) AddNewTorrents(transmissionbt *transmissionrpc.Client) error { + // Set torrentURLs for Parrot Security + p.URL = "https://deb.parrot.sh/parrot/" + torrentURLs := []string{ + fmt.Sprintf("%s/iso/%s/Parrot-security-%s_amd64.iso.torrent", p.URL, p.Relver, p.Relver), + fmt.Sprintf("%s/iso/%s/Parrot-security-%s_amd64.ova.torrent", p.URL, p.Relver, p.Relver), + fmt.Sprintf("%s/iso/%s/Parrot-security-%s_arm64.utm.torrent", p.URL, p.Relver, p.Relver), + fmt.Sprintf("%s/iso/%s/Parrot-home-%s_amd64.iso.torrent", p.URL, p.Relver, p.Relver), + fmt.Sprintf("%s/iso/%s/Parrot-home-%s_amd64.ova.torrent", p.URL, p.Relver, p.Relver), + fmt.Sprintf("%s/iso/%s/Parrot-home-%s_arm64.utm.torrent", p.URL, p.Relver, p.Relver), + fmt.Sprintf("%s/iso/%s/Parrot-htb-%s_amd64.iso.torrent", p.URL, p.Relver, p.Relver), + fmt.Sprintf("%s/iso/%s/Parrot-architect-%s_arm64.iso.torrent", p.URL, p.Relver, p.Relver), + fmt.Sprintf("%s/iso/%s/Parrot-architect-%s_amd64.iso.torrent", p.URL, p.Relver, p.Relver), + } + + // Add torrents to Transmission instance + for _, torrentURL := range torrentURLs { + torrent, err := transmissionbt.TorrentAdd(&transmissionrpc.TorrentAddPayload{ + Filename: &torrentURL, + }) + if err != nil { + return err + } + + log.Printf("%s added\n", *torrent.Name) + } + + return nil +} + +func (p Parrot) RemoveOldTorrents(transmissionbt *transmissionrpc.Client) error { + if err := common.RemoveTorrents(p.NameSubstr, p.Relver, transmissionbt); err != nil { + return err + } + + return nil +} diff --git a/qubes/main.go b/qubes/main.go new file mode 100644 index 0000000..bdb13f8 --- /dev/null +++ b/qubes/main.go @@ -0,0 +1,41 @@ +package qubes + +import ( + "fmt" + "log" + + "codeberg.org/hyperreal/go-torrent-helper/common" + "github.com/hekmon/transmissionrpc" +) + +type Qubes struct { + NameSubstr string + Relver string + URL string +} + +func (q Qubes) AddNewTorrents(transmissionbt *transmissionrpc.Client) error { + // Set torrentURLs for Qubes OS + q.URL = "https://mirrors.edge.kernel.org/qubes/iso/Qubes" + torrentURL := fmt.Sprintf("%s-%s-x86_64.torrent", q.URL, q.Relver) + + // Add torrent to Transmission instance + torrent, err := transmissionbt.TorrentAdd(&transmissionrpc.TorrentAddPayload{ + Filename: &torrentURL, + }) + if err != nil { + return err + } + + log.Printf("%s added\n", *torrent.Name) + + return nil +} + +func (q Qubes) RemoveOldTorrents(transmissionbt *transmissionrpc.Client) error { + if err := common.RemoveTorrents(q.NameSubstr, q.Relver, transmissionbt); err != nil { + return err + } + + return nil +} diff --git a/rocky/main.go b/rocky/main.go new file mode 100644 index 0000000..afb6ba9 --- /dev/null +++ b/rocky/main.go @@ -0,0 +1,48 @@ +package rocky + +import ( + "fmt" + "log" + + "codeberg.org/hyperreal/go-torrent-helper/common" + "github.com/hekmon/transmissionrpc" +) + +type Rocky struct { + NameSubstr string + Relver string + URL string +} + +func (r Rocky) AddNewTorrents(transmissionbt *transmissionrpc.Client) error { + // Set torrentURLs for Rocky Linux mirror + r.URL = "https://download.rockylinux.org/pub/rocky/" + torrentURLs := []string{ + fmt.Sprintf("%s/%s/isos/x86_64/Rocky-%s-x86_64-dvd.torrent", r.URL, r.Relver, r.Relver), + fmt.Sprintf("%s/%s/isos/aarch64/Rocky-%s-aarch64-dvd.torrent", r.URL, r.Relver, r.Relver), + fmt.Sprintf("%s/%s/isos/ppc64le/Rocky-%s-ppc64le-dvd.torrent", r.URL, r.Relver, r.Relver), + fmt.Sprintf("%s/%s/isos/s390x/Rocky-%s-s390x-dvd.torrent", r.URL, r.Relver, r.Relver), + } + + // Add torrents to Transmission instance + for _, torrentURL := range torrentURLs { + torrent, err := transmissionbt.TorrentAdd(&transmissionrpc.TorrentAddPayload{ + Filename: &torrentURL, + }) + if err != nil { + return err + } + + log.Printf("%s added\n", *torrent.Name) + } + + return nil +} + +func (r Rocky) RemoveOldTorrents(transmissionbt *transmissionrpc.Client) error { + if err := common.RemoveTorrents(r.NameSubstr, r.Relver, transmissionbt); err != nil { + return err + } + + return nil +}