dipole/main.go

200 lines
5.2 KiB
Go

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
}