From 527cbebfce096f8f2ab046b236f859961d7de0f0 Mon Sep 17 00:00:00 2001 From: Steven Polley Date: Sat, 22 Apr 2023 18:00:41 -0600 Subject: [PATCH] initial commit --- .gitignore | 2 + README.md | 12 +++- go.mod | 5 ++ go.sum | 2 + main.go | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1fc6035 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dipole.exe +dipole \ No newline at end of file diff --git a/README.md b/README.md index 6dc942d..60bdd7a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ # dipole -A magnet link handler for rutorrent \ No newline at end of file +A magnet link handler for rutorrent. + +Download your linux ISO's with style. + +### Usage + +Run the executable manually once, it will register itself as the handler for magnet links. If you move the exectuable, you will need to run it again to reregister its new path. It will also prompt you for the URL of your rutorrent instance. + +If you need to change the URL of the rutorrent instance, delete the folder located at %appdata%\dipole, then run it again. + +Then, click on magnet links in your web browser and they will automatically be added to your rutorrent instance. \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1693413 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module deadbeef.codes/steven/dipole + +go 1.20 + +require golang.org/x/sys v0.7.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7c22a2b --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/main.go b/main.go new file mode 100644 index 0000000..39bc874 --- /dev/null +++ b/main.go @@ -0,0 +1,199 @@ +package main + +import ( + "bufio" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/url" + "os" + "time" + + "golang.org/x/sys/windows/registry" +) + +func main() { + + ex, err := os.Executable() + if err != nil { + log.Fatalf("failed to get executable path: %v", err) + } + programFullPath := fmt.Sprintf("\"%s\"", ex) + + ruTorrentURL, err := getRUTorrentURL() + if err != nil { + log.Fatalf("failed to get ruTorrent URL: %v", err) + } + + if len(os.Args[1:]) < 1 { + err := registerProtocolHandler(programFullPath) + if err != nil { + log.Fatalf("failed to register protocol handler for magnet URLs: %v", err) + } + log.Printf("successfully set registry handler for magnet links") + return + } + + magnetLink := os.Args[1] + + if len(magnetLink) > 7 { + if magnetLink[:7] != "magnet:" { + log.Fatalf("unexpected argument '%s', expected a magnet link", os.Args[1:]) + } + } + + err = addRuTorrent(ruTorrentURL, magnetLink) + if err != nil { + log.Printf("failed to add magnet link to rutorrent: %v", err) + + fmt.Println(ruTorrentURL) + fmt.Println(magnetLink) + time.Sleep(time.Minute) + } +} + +func addRuTorrent(ruTorrentURL, magnetLink string) error { + + addTorrentEndpoint := fmt.Sprintf("%s/php/addtorrent.php", ruTorrentURL) + + /* + magnetLink, err := url.QueryUnescape(magnetLink) + if err != nil { + return fmt.Errorf("failed to URL decode magnet link: %v", err) + }*/ + + form := url.Values{} + form.Add("url", magnetLink) + + client := http.Client{} + + resp, err := client.PostForm(addTorrentEndpoint, form) + if err != nil { + return fmt.Errorf("failed to do POST request to '%s': %v", addTorrentEndpoint, err) + } + + if resp.StatusCode != http.StatusOK { + body, _ := ioutil.ReadAll(resp.Body) + defer resp.Body.Close() + fmt.Println(string(body)) + return fmt.Errorf("unexpected HTTP status code '%d', expected '%d'", resp.StatusCode, http.StatusOK) + } + + return nil +} + +func getRUTorrentURL() (string, error) { + + userConfigDir, err := os.UserConfigDir() + if err != nil { + return "", fmt.Errorf("failed to get user config dir: %v", err) + } + + configDir := fmt.Sprintf("%s/dipole", userConfigDir) + configFile := fmt.Sprintf("%s/dipole.conf", configDir) + + if _, err := os.Stat(configDir); os.IsNotExist(err) { + if err := os.Mkdir(configDir, 0700); err != nil { + return "", fmt.Errorf("failed to make config dir '%s': %v", configDir, err) + } + } + + var ruTorrentURL string + if _, err := os.Stat(configFile); os.IsNotExist(err) { + // collect + fmt.Println("Enter your rutorrent instance URL: ") + _, err = fmt.Scanln(&ruTorrentURL) + if err != nil { + return "", fmt.Errorf("failed to scan line while collecting rutorrent URL: %v", err) + } + + f, err := os.OpenFile(configFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + return "", fmt.Errorf("failed to open config file '%s' for writing: %v", configFile, err) + } + + _, err = f.Write([]byte(ruTorrentURL)) + if err != nil { + return "", fmt.Errorf("failed to write ruTorrentURL to config file '%s': %v", configFile, err) + } + if err := f.Close(); err != nil { + return "", fmt.Errorf("failed to close config file '%s': %v", configFile, err) + } + } else { + f, err := os.Open(configFile) + if err != nil { + return "", fmt.Errorf("failed to open config file '%s': %v", configFile, err) + } + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + ruTorrentURL = scanner.Text() + } + if err := scanner.Err(); err != nil { + return "", fmt.Errorf("failed to scan config file: %v", err) + } + + if err := f.Close(); err != nil { + return "", fmt.Errorf("failed to close config file '%s': %v", configFile, err) + } + } + + return ruTorrentURL, err +} + +func registerProtocolHandler(programFullPath string) error { + + prefix := "SOFTWARE\\Classes\\" + urlScheme := "magnet" + basePath := prefix + urlScheme + permission := uint32(registry.QUERY_VALUE | registry.SET_VALUE) + baseKey := registry.CURRENT_USER + + // create key + k, _, err := registry.CreateKey(baseKey, basePath, permission) + if err != nil { + return fmt.Errorf("failed to create base key: %v", err) + } + + // set description + err = k.SetStringValue("", "Dipole Magnet Link Handler") + if err != nil { + return fmt.Errorf("failed to set description string value: %v", err) + } + err = k.SetStringValue("URL Protocol", "") + if err != nil { + return fmt.Errorf("failed to set description url protocol value: %v", err) + } + + // set icon + k, _, err = registry.CreateKey(registry.CURRENT_USER, "lumiere\\DefaultIcon", registry.ALL_ACCESS) + if err != nil { + return fmt.Errorf("failed to set icon key: %v", err) + } + err = k.SetStringValue("", programFullPath+",1") + if err != nil { + return fmt.Errorf("failed to set programFullPath value for icon: %v", err) + } + + // create tree + _, _, err = registry.CreateKey(baseKey, basePath+"\\shell", permission) + if err != nil { + return fmt.Errorf("failed to create shell key: %v", err) + } + _, _, err = registry.CreateKey(baseKey, basePath+"\\shell\\open", permission) + if err != nil { + return fmt.Errorf("failed to create shell/open key: %v", err) + } + k, _, err = registry.CreateKey(baseKey, basePath+"\\shell\\open\\command", permission) + if err != nil { + return fmt.Errorf("failed to create shell/open/command key: %v", err) + } + + // set open command + err = k.SetStringValue("", programFullPath+" \"%1\"") + if err != nil { + return fmt.Errorf("failed to set programFullPath for open command: %v", err) + } + return nil +}