8 "github.com/anacrolix/bargle"
9 "github.com/anacrolix/log"
11 "github.com/anacrolix/torrent"
12 "github.com/anacrolix/torrent/bencode"
13 "github.com/anacrolix/torrent/metainfo"
14 "github.com/anacrolix/torrent/storage"
17 func serve() (cmd bargle.Command) {
18 var filePaths []string
19 cmd.Positionals = append(cmd.Positionals, &bargle.Positional{
20 Value: bargle.AutoUnmarshaler(&filePaths),
22 cmd.Desc = "creates and seeds a torrent from a filepath"
23 cmd.DefaultAction = func() error {
24 cfg := torrent.NewDefaultClientConfig()
26 cl, err := torrent.NewClient(cfg)
28 return fmt.Errorf("new torrent client: %w", err)
31 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
34 for _, filePath := range filePaths {
35 totalLength, err := totalLength(filePath)
37 return fmt.Errorf("calculating total length of %q: %v", filePath, err)
39 pieceLength := metainfo.ChoosePieceLength(totalLength)
40 info := metainfo.Info{
41 PieceLength: pieceLength,
43 err = info.BuildFromFilePath(filePath)
45 return fmt.Errorf("building info from path %q: %w", filePath, err)
47 for _, fi := range info.UpvertedFiles() {
48 log.Printf("added %q", fi.Path)
50 mi := metainfo.MetaInfo{
51 InfoBytes: bencode.MustMarshal(info),
53 pc, err := storage.NewDefaultPieceCompletionForDir(".")
55 return fmt.Errorf("new piece completion: %w", err)
58 ih := mi.HashInfoBytes()
59 to, _ := cl.AddTorrentOpt(torrent.AddTorrentOpts{
61 Storage: storage.NewFileOpts(storage.NewFileClientOpts{
62 ClientBaseDir: filePath,
63 FilePathMaker: func(opts storage.FilePathMakerOpts) string {
64 return filepath.Join(opts.File.Path...)
71 err = to.MergeSpec(&torrent.TorrentSpec{
72 InfoBytes: mi.InfoBytes,
73 Trackers: [][]string{{
74 `wss://tracker.btorrent.xyz`,
75 `wss://tracker.openwebtorrent.com`,
76 "http://p4p.arenabg.com:1337/announce",
77 "udp://tracker.opentrackr.org:1337/announce",
78 "udp://tracker.openbittorrent.com:6969/announce",
82 return fmt.Errorf("setting trackers: %w", err)
84 fmt.Printf("%v: %v\n", to, to.Metainfo().Magnet(&ih, &info))