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  }