6 g "github.com/anacrolix/generics"
8 "github.com/anacrolix/torrent/metainfo"
9 pp "github.com/anacrolix/torrent/peer_protocol"
10 "github.com/anacrolix/torrent/storage"
11 infohash_v2 "github.com/anacrolix/torrent/types/infohash-v2"
14 // Specifies a new torrent for adding to a client, or additions to an existing Torrent. There are
15 // constructor functions for magnet URIs and torrent metainfo files. TODO: This type should be
16 // dismantled into a new Torrent option type, and separate Torrent mutate method(s).
17 type TorrentSpec struct {
18 // The tiered tracker URIs.
20 // TODO: Move into a "new" Torrent opt type.
21 InfoHash metainfo.Hash
22 InfoHashV2 g.Option[infohash_v2.T]
24 // The name to use if the Name field from the Info isn't available.
26 // WebSeed URLs. For additional options add the URLs separately with Torrent.AddWebSeeds
31 // The combination of the "xs" and "as" fields in magnet links, for now.
33 // BEP 52 "piece layers" from metainfo
34 PieceLayers map[string]string
36 // The chunk size to use for outbound requests. Defaults to 16KiB if not set. Can only be set
37 // for new Torrents. TODO: Move into a "new" Torrent opt type.
39 // TODO: Move into a "new" Torrent opt type.
40 Storage storage.ClientImpl
42 DisableInitialPieceCheck bool
44 // Whether to allow data download or upload
45 DisallowDataUpload bool
46 DisallowDataDownload bool
49 func TorrentSpecFromMagnetUri(uri string) (spec *TorrentSpec, err error) {
50 m, err := metainfo.ParseMagnetV2Uri(uri)
55 Trackers: [][]string{m.Trackers},
56 DisplayName: m.DisplayName,
57 InfoHash: m.InfoHash.UnwrapOrZeroValue(),
58 InfoHashV2: m.V2InfoHash,
59 Webseeds: m.Params["ws"],
60 Sources: append(m.Params["xs"], m.Params["as"]...),
61 PeerAddrs: m.Params["x.pe"], // BEP 9
62 // TODO: What's the parameter for DHT nodes?
67 // The error will be from unmarshalling the info bytes. The TorrentSpec is still filled out as much
68 // as possible in this case.
69 func TorrentSpecFromMetaInfoErr(mi *metainfo.MetaInfo) (*TorrentSpec, error) {
70 info, err := mi.UnmarshalInfo()
72 err = fmt.Errorf("unmarshalling info: %w", err)
74 var v1Ih metainfo.Hash
76 v1Ih = mi.HashInfoBytes()
78 var v2Infohash g.Option[infohash_v2.T]
80 v2Infohash.Set(infohash_v2.HashBytes(mi.InfoBytes))
84 Trackers: mi.UpvertedAnnounceList(),
86 InfoHashV2: v2Infohash,
87 PieceLayers: mi.PieceLayers,
88 InfoBytes: mi.InfoBytes,
89 DisplayName: info.Name,
91 DhtNodes: func() (ret []string) {
92 ret = make([]string, 0, len(mi.Nodes))
93 for _, node := range mi.Nodes {
94 ret = append(ret, string(node))
101 // Panics if there was anything missing from the metainfo.
102 func TorrentSpecFromMetaInfo(mi *metainfo.MetaInfo) *TorrentSpec {
103 ts, err := TorrentSpecFromMetaInfoErr(mi)