]> Sergey Matveev's repositories - btrtrc.git/blob - cmd/torrent/metainfo.go
d40596b641d32c1ebf79655e48457f4904d77b33
[btrtrc.git] / cmd / torrent / metainfo.go
1 package main
2
3 import (
4         "encoding/hex"
5         "encoding/json"
6         "fmt"
7         "os"
8
9         "github.com/anacrolix/args"
10         "github.com/anacrolix/torrent/metainfo"
11         "github.com/bradfitz/iter"
12 )
13
14 type pprintMetainfoFlags struct {
15         JustName    bool
16         PieceHashes bool
17         Files       bool
18 }
19
20 func metainfoCmd(ctx args.SubCmdCtx) (err error) {
21         var metainfoPath string
22         var mi *metainfo.MetaInfo
23         // TODO: Treat no subcommand as a failure.
24         return ctx.NewParser().AddParams(
25                 args.Pos("torrent file", &metainfoPath, args.AfterParse(func() (err error) {
26                         mi, err = metainfo.LoadFromFile(metainfoPath)
27                         return
28                 })),
29                 args.Subcommand("magnet", func(ctx args.SubCmdCtx) (err error) {
30                         info, err := mi.UnmarshalInfo()
31                         if err != nil {
32                                 return
33                         }
34                         fmt.Fprintf(os.Stdout, "%s\n", mi.Magnet(nil, &info).String())
35                         return nil
36                 }),
37                 args.Subcommand("pprint", func(ctx args.SubCmdCtx) (err error) {
38                         var flags pprintMetainfoFlags
39                         err = ctx.NewParser().AddParams(args.FromStruct(&flags)...).Parse()
40                         if err != nil {
41                                 return
42                         }
43                         err = pprintMetainfo(mi, flags)
44                         if err != nil {
45                                 return
46                         }
47                         if !flags.JustName {
48                                 os.Stdout.WriteString("\n")
49                         }
50                         return
51                 }),
52                 args.Subcommand("infohash", func(ctx args.SubCmdCtx) (err error) {
53                         fmt.Printf("%s: %s\n", mi.HashInfoBytes().HexString(), metainfoPath)
54                         return nil
55                 }),
56                 args.Subcommand("list-files", func(ctx args.SubCmdCtx) (err error) {
57                         info, err := mi.UnmarshalInfo()
58                         if err != nil {
59                                 return fmt.Errorf("unmarshalling info from metainfo at %q: %v", metainfoPath, err)
60                         }
61                         for _, f := range info.UpvertedFiles() {
62                                 fmt.Println(f.DisplayPath(&info))
63                         }
64                         return nil
65                 }),
66         ).Parse()
67 }
68
69 func pprintMetainfo(metainfo *metainfo.MetaInfo, flags pprintMetainfoFlags) error {
70         info, err := metainfo.UnmarshalInfo()
71         if err != nil {
72                 return fmt.Errorf("error unmarshalling info: %s", err)
73         }
74         if flags.JustName {
75                 fmt.Printf("%s\n", info.Name)
76                 return nil
77         }
78         d := map[string]interface{}{
79                 "Name":         info.Name,
80                 "NumPieces":    info.NumPieces(),
81                 "PieceLength":  info.PieceLength,
82                 "InfoHash":     metainfo.HashInfoBytes().HexString(),
83                 "NumFiles":     len(info.UpvertedFiles()),
84                 "TotalLength":  info.TotalLength(),
85                 "Announce":     metainfo.Announce,
86                 "AnnounceList": metainfo.AnnounceList,
87                 "UrlList":      metainfo.UrlList,
88         }
89         if len(metainfo.Nodes) > 0 {
90                 d["Nodes"] = metainfo.Nodes
91         }
92         if flags.Files {
93                 d["Files"] = info.UpvertedFiles()
94         }
95         if flags.PieceHashes {
96                 d["PieceHashes"] = func() (ret []string) {
97                         for i := range iter.N(info.NumPieces()) {
98                                 ret = append(ret, hex.EncodeToString(info.Pieces[i*20:(i+1)*20]))
99                         }
100                         return
101                 }()
102         }
103         b, _ := json.MarshalIndent(d, "", "  ")
104         _, err = os.Stdout.Write(b)
105         return err
106 }