github.com/anacrolix/torrent@v1.61.0/cmd/torrent/metainfo.go (about) 1 package main 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "os" 9 "strings" 10 11 "github.com/anacrolix/bargle" 12 "github.com/bradfitz/iter" 13 14 "github.com/anacrolix/torrent/metainfo" 15 ) 16 17 type pprintMetainfoFlags struct { 18 JustName bool 19 PieceHashes bool 20 Files bool 21 } 22 23 func metainfoCmd() (cmd bargle.Command) { 24 var metainfoPath string 25 var mi *metainfo.MetaInfo 26 // TODO: Test if bargle treats no subcommand as a failure. 27 cmd.Positionals = append(cmd.Positionals, 28 &bargle.Positional{ 29 Name: "torrent file", 30 Value: &bargle.String{Target: &metainfoPath}, 31 AfterParseFunc: func(ctx bargle.Context) error { 32 ctx.AfterParse(func() (err error) { 33 if strings.HasPrefix(metainfoPath, "http://") || strings.HasPrefix(metainfoPath, "https://") { 34 response, err := http.Get(metainfoPath) 35 if err != nil { 36 return nil 37 } 38 mi, err = metainfo.Load(response.Body) 39 if err != nil { 40 return nil 41 } 42 } else { 43 mi, err = metainfo.LoadFromFile(metainfoPath) 44 } 45 return 46 }) 47 return nil 48 }, 49 }, 50 bargle.Subcommand{Name: "magnet", Command: func() (cmd bargle.Command) { 51 cmd.DefaultAction = func() (err error) { 52 m, err := mi.MagnetV2() 53 if err != nil { 54 return 55 } 56 fmt.Fprintf(os.Stdout, "%v\n", m.String()) 57 return nil 58 } 59 return 60 }()}, 61 bargle.Subcommand{Name: "pprint", Command: func() (cmd bargle.Command) { 62 var flags pprintMetainfoFlags 63 cmd = bargle.FromStruct(&flags) 64 cmd.DefaultAction = func() (err error) { 65 err = pprintMetainfo(mi, flags) 66 if err != nil { 67 return 68 } 69 if !flags.JustName { 70 os.Stdout.WriteString("\n") 71 } 72 return 73 } 74 return 75 }()}, 76 //bargle.Subcommand{Name: "infohash", Command: func(ctx args.SubCmdCtx) (err error) { 77 // fmt.Printf("%s: %s\n", mi.HashInfoBytes().HexString(), metainfoPath) 78 // return nil 79 //}}, 80 //bargle.Subcommand{Name: "list-files", Command: func(ctx args.SubCmdCtx) (err error) { 81 // info, err := mi.UnmarshalInfo() 82 // if err != nil { 83 // return fmt.Errorf("unmarshalling info from metainfo at %q: %v", metainfoPath, err) 84 // } 85 // for _, f := range info.UpvertedFiles() { 86 // fmt.Println(f.DisplayPath(&info)) 87 // } 88 // return nil 89 //}}, 90 ) 91 return 92 } 93 94 func pprintMetainfo(metainfo *metainfo.MetaInfo, flags pprintMetainfoFlags) error { 95 info, err := metainfo.UnmarshalInfo() 96 if err != nil { 97 return fmt.Errorf("error unmarshalling info: %s", err) 98 } 99 if flags.JustName { 100 fmt.Printf("%s\n", info.BestName()) 101 return nil 102 } 103 d := map[string]interface{}{ 104 "Name": info.Name, 105 "Name.Utf8": info.NameUtf8, 106 "NumPieces": info.NumPieces(), 107 "PieceLength": info.PieceLength, 108 "InfoHash": metainfo.HashInfoBytes().HexString(), 109 "NumFiles": len(info.UpvertedFiles()), 110 "TotalLength": info.TotalLength(), 111 "Announce": metainfo.Announce, 112 "AnnounceList": metainfo.AnnounceList, 113 "UrlList": metainfo.UrlList, 114 } 115 if len(metainfo.Nodes) > 0 { 116 d["Nodes"] = metainfo.Nodes 117 } 118 if flags.Files { 119 d["Files"] = info.UpvertedFiles() 120 } 121 if flags.PieceHashes { 122 d["PieceHashes"] = func() (ret []string) { 123 for i := range iter.N(info.NumPieces()) { 124 ret = append(ret, hex.EncodeToString(info.Pieces[i*20:(i+1)*20])) 125 } 126 return 127 }() 128 } 129 b, _ := json.MarshalIndent(d, "", " ") 130 _, err = os.Stdout.Write(b) 131 return err 132 }