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 }