magnet-to-torrent/main.go
2025-05-04 13:30:55 -04:00

94 lines
2.1 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"time"
"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() {
// Command-line flags
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)
}
magnetLink := flag.Arg(0)
// Configure torrent client
clientConfig := torrent.NewDefaultClientConfig()
clientConfig.DataDir = os.TempDir()
clientConfig.NoUpload = !*upload
client, err := torrent.NewClient(clientConfig)
if err != nil {
log.Fatalf("Error creating torrent client: %v", err)
}
defer client.Close()
// Add magnet link
t, err := client.AddMagnet(magnetLink)
if err != nil {
log.Fatalf("Error adding magnet link: %v", err)
}
// Wait for metadata with timeout
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
defer cancel()
select {
case <-t.GotInfo():
// Metadata received
case <-ctx.Done():
log.Fatalf("Timeout waiting for metadata after %v", *timeout)
}
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 {
log.Fatalf("Error creating file %s: %v", outFile, err)
}
defer f.Close()
if err := info.Write(f); err != nil {
log.Fatalf("Error writing torrent file: %v", err)
}
fmt.Printf("Torrent metadata saved to %s\n", outFile)
// Drop the torrent handle; client will close via defer
t.Drop()
}