This commit is contained in:
firebadnofire 2025-05-04 13:30:55 -04:00
parent 4bbddc1579
commit 4a0d1a288b
Signed by: firebadnofire
SSH key fingerprint: SHA256:bnN1TGRauJN84CxL1IZ/2uHNvJualwYkFjOKaaOilJE

77
main.go
View file

@ -1,31 +1,47 @@
package main package main
import ( import (
"context"
"flag"
"fmt" "fmt"
"log" "log"
"os" "os"
"strings" "path/filepath"
"regexp"
"time" "time"
"github.com/anacrolix/torrent" "github.com/anacrolix/torrent"
) )
var invalidFilenameChars = regexp.MustCompile(`[<>:"/\\|?*\x00-\x1F]`)
// sanitizeFilename replaces invalid filesystem characters with underscores.
func sanitizeFilename(name string) string {
return invalidFilenameChars.ReplaceAllString(name, "_")
}
func main() { func main() {
if len(os.Args) < 2 { // Command-line flags
fmt.Println("Usage: ./magnet-to-torrent \"magnet_link\" [output.torrent]") output := flag.String("o", "", "Output .torrent filename (optional)")
timeout := flag.Duration("timeout", 5*time.Minute, "Timeout for metadata retrieval")
upload := flag.Bool("upload", false, "Allow uploading (seeding) after metadata retrieval")
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] magnet_link\nOptions:\n", os.Args[0])
flag.PrintDefaults()
}
flag.Parse()
if flag.NArg() < 1 {
flag.Usage()
os.Exit(1) os.Exit(1)
} }
magnetLink := flag.Arg(0)
magnetLink := os.Args[1] // Configure torrent client
outputFile := ""
if len(os.Args) == 3 {
outputFile = os.Args[2]
}
clientConfig := torrent.NewDefaultClientConfig() clientConfig := torrent.NewDefaultClientConfig()
clientConfig.DataDir = os.TempDir() clientConfig.DataDir = os.TempDir()
clientConfig.NoUpload = true clientConfig.NoUpload = !*upload
client, err := torrent.NewClient(clientConfig) client, err := torrent.NewClient(clientConfig)
if err != nil { if err != nil {
@ -33,35 +49,46 @@ func main() {
} }
defer client.Close() defer client.Close()
// Add magnet link
t, err := client.AddMagnet(magnetLink) t, err := client.AddMagnet(magnetLink)
if err != nil { if err != nil {
log.Fatalf("Error adding magnet link: %v", err) log.Fatalf("Error adding magnet link: %v", err)
} }
<-t.GotInfo() // Wait for metadata with timeout
info := t.Metainfo() ctx, cancel := context.WithTimeout(context.Background(), *timeout)
defer cancel()
if outputFile == "" { select {
outputFile = strings.ReplaceAll(t.Name(), " ", "_") + ".torrent" case <-t.GotInfo():
// Metadata received
case <-ctx.Done():
log.Fatalf("Timeout waiting for metadata after %v", *timeout)
} }
f, err := os.Create(outputFile) info := t.Metainfo()
// Determine output filename
outFile := *output
if outFile == "" {
base := sanitizeFilename(t.Name())
outFile = base + ".torrent"
}
outFile = filepath.Clean(outFile)
// Write .torrent file
f, err := os.Create(outFile)
if err != nil { if err != nil {
log.Fatalf("Error creating file: %v", err) log.Fatalf("Error creating file %s: %v", outFile, err)
} }
defer f.Close() defer f.Close()
err = info.Write(f) if err := info.Write(f); err != nil {
if err != nil {
log.Fatalf("Error writing torrent file: %v", err) log.Fatalf("Error writing torrent file: %v", err)
} }
fmt.Printf("Torrent metadata saved to %s\n", outputFile) fmt.Printf("Torrent metadata saved to %s\n", outFile)
// Drop the torrent handle; client will close via defer
t.Drop() t.Drop()
client.Close()
// Give client some time to gracefully close
time.Sleep(2 * time.Second)
} }