|
1 | | -package main |
| 1 | +package builtin |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "context" |
| 4 | + "bufio" |
| 5 | + "crypto/rand" |
5 | 6 | "fmt" |
6 | | - "log" |
| 7 | + "net/http" |
| 8 | + "runtime/debug" |
7 | 9 | "time" |
8 | 10 |
|
| 11 | + CFG "github.com/NullpointerW/anicat/conf" |
| 12 | + "github.com/NullpointerW/anicat/log" |
9 | 13 | "github.com/anacrolix/torrent" |
| 14 | + "github.com/anacrolix/torrent/storage" |
10 | 15 | ) |
11 | 16 |
|
12 | | -func main() { |
13 | | - // Create a new torrent client with default configuration |
14 | | - client, err := torrent.NewClient(nil) |
15 | | - if err != nil { |
16 | | - log.Fatalf("error creating torrent client: %v", err) |
| 17 | +var DefaultDownLoader *Downloader |
| 18 | + |
| 19 | +func init() { |
| 20 | + if CFG.Env.BuiltinDownloader { |
| 21 | + log.Info(log.Struct{"github", "https://github.com/anacrolix/torrent"}, "builtin-enabled, using anacrolix/torrent") |
| 22 | + InitDownloader() |
| 23 | + } |
| 24 | +} |
| 25 | +func InitDownloader() { |
| 26 | + cfg := &DownloaderConfig{ |
| 27 | + BaseDir: "./.db", |
| 28 | + FakePeerID: true, |
| 29 | + NopUpload: true, |
| 30 | + Seeker: NewHttpSeeker(), |
17 | 31 | } |
18 | | - defer client.Close() |
| 32 | + DefaultDownLoader = NewDownloader(cfg) |
| 33 | +} |
| 34 | + |
| 35 | +type Downloader struct { |
| 36 | + client *torrent.Client |
| 37 | + TorrentSeeker |
| 38 | + extraTrackers [][]string |
| 39 | +} |
| 40 | +type FileName interface { |
| 41 | + Name() storage.FilePathMaker |
| 42 | +} |
19 | 43 |
|
20 | | - // Define the magnet link |
21 | | - magnetLink := "magnet:?xt=urn:btih:fbc74348498175b4caec790054e922d28312a106&tr=http%3a%2f%2ft.nyaatracker.com%2fannounce&tr=http%3a%2f%2ftracker.kamigami.org%3a2710%2fannounce&tr=http%3a%2f%2fshare.camoe.cn%3a8080%2fannounce&tr=http%3a%2f%2fopentracker.acgnx.se%2fannounce&tr=http%3a%2f%2fanidex.moe%3a6969%2fannounce&tr=http%3a%2f%2ft.acg.rip%3a6699%2fannounce&tr=https%3a%2f%2ftr.bangumi.moe%3a9696%2fannounce&tr=udp%3a%2f%2ftr.bangumi.moe%3a6969%2fannounce&tr=http%3a%2f%2fopen.acgtracker.com%3a1096%2fannounce&tr=udp%3a%2f%2ftracker.opentrackr.org%3a1337%2fannounce" |
| 44 | +type FileOption interface { |
| 45 | + FileName |
| 46 | + Dir() storage.TorrentDirFilePathMaker |
| 47 | +} |
| 48 | +type DownloaderConfig struct { |
| 49 | + BaseDir string |
| 50 | + Seeker TorrentSeeker |
| 51 | + NopUpload bool |
| 52 | + FakePeerID bool |
| 53 | +} |
22 | 54 |
|
23 | | - // Add the magnet link to the client |
24 | | - t, err := client.AddMagnet(magnetLink) |
| 55 | +func NewDownloader(c *DownloaderConfig) *Downloader { |
| 56 | + cfg := torrent.NewDefaultClientConfig() |
| 57 | + cfg.Seed = !c.NopUpload |
| 58 | + cfg.NoUpload = c.NopUpload |
| 59 | + fop := storage.NewFileClientOpts{} |
| 60 | + fop.ClientBaseDir = c.BaseDir |
| 61 | + cfg.DefaultStorage = storage.NewFileOpts(fop) |
| 62 | + if c.Seeker == nil { |
| 63 | + c.Seeker = NewHttpSeeker() |
| 64 | + } |
| 65 | + if c.FakePeerID { |
| 66 | + f := "-qB419E-" // qBittorrent |
| 67 | + var b [20]byte |
| 68 | + n := copy(b[:], ([]byte)(f)) |
| 69 | + _, err := rand.Read(b[n:]) |
| 70 | + if err != nil { |
| 71 | + panic("builtin-downloader: error generating peer id") |
| 72 | + } |
| 73 | + cfg.PeerID = (string)(b[:]) |
| 74 | + cfg.HTTPUserAgent = "qBittorrent/v4.1.9.14" |
| 75 | + mainPath := "github.com/NullpointerW/anicat" |
| 76 | + mainVersion := "unknown" |
| 77 | + if buildInfo, ok := debug.ReadBuildInfo(); ok { |
| 78 | + mainPath = buildInfo.Main.Path |
| 79 | + mainVersion = buildInfo.Main.Version |
| 80 | + } |
| 81 | + exhskVer := fmt.Sprintf( |
| 82 | + "%v %v (%v %v)", |
| 83 | + mainPath, |
| 84 | + mainVersion, |
| 85 | + "qBittorrent", |
| 86 | + "v4.1.9.14", |
| 87 | + ) |
| 88 | + cfg.ExtendedHandshakeClientVersion = exhskVer |
| 89 | + } |
| 90 | + client, err := torrent.NewClient(cfg) |
25 | 91 | if err != nil { |
26 | | - log.Fatalf("error adding magnet link: %v", err) |
| 92 | + panic(err) |
| 93 | + } |
| 94 | + peerIDStr := func(p torrent.PeerID) string { |
| 95 | + b := ([20]byte)(p) |
| 96 | + // fmt.Println((string)(b[:])) |
| 97 | + return string(b[:]) |
27 | 98 | } |
28 | 99 |
|
29 | | - // Wait for the torrent information to be fetched or timeout |
30 | | - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) |
31 | | - defer cancel() |
32 | | - |
33 | | - <-t.GotInfo() |
34 | | - t.DownloadAll() |
| 100 | + log.Info(log.Struct{"version", cfg.ExtendedHandshakeClientVersion, "userAgent", cfg.HTTPUserAgent, "peerID", peerIDStr(client.PeerID()), "upnpID", cfg.UpnpID}, "torrent-client initialized") |
| 101 | + return &Downloader{client, c.Seeker, extraTrackers()} |
35 | 102 |
|
36 | | - go func() { |
37 | | - for { |
38 | | - fmt.Printf(" w %d", t.BytesCompleted()) |
39 | | - time.Sleep(1 * time.Second) |
40 | | - } |
41 | | - }() |
| 103 | +} |
42 | 104 |
|
43 | | - select { |
44 | | - case <-t.Complete.On(): |
45 | | - log.Println("torrent download complete") |
46 | | - case <-ctx.Done(): |
47 | | - log.Println("torrent download timeout") |
| 105 | +func (d *Downloader) Download(s string, fOp FileOption, seeker TorrentSeeker) (t *torrent.Torrent, err error) { |
| 106 | + var ts *torrent.TorrentSpec |
| 107 | + if seeker == nil { |
| 108 | + ts, err = d.Seek(s) |
| 109 | + } else { |
| 110 | + ts, err = seeker.Seek(s) |
| 111 | + } |
| 112 | + if err != nil { |
| 113 | + return nil, err |
48 | 114 | } |
49 | 115 |
|
50 | | - // Stream the torrent content to stdout or handle it as needed |
51 | | - //reader := t.NewReader() |
52 | | - //io.Copy(os.Stdout, reader) |
| 116 | + fop := storage.NewFileClientOpts{} |
| 117 | + fop.TorrentDirMaker = fOp.Dir() |
| 118 | + fop.FilePathMaker = fOp.Name() |
| 119 | + fop.PieceCompletion = storage.NewMapPieceCompletion() |
| 120 | + ts.Storage = storage.NewFileOpts(fop) |
| 121 | + t, _, err = d.client.AddTorrentSpec(ts) |
| 122 | + t.AddTrackers(d.extraTrackers) |
| 123 | + return |
| 124 | +} |
| 125 | +func extraTrackers() (trackers [][]string) { |
| 126 | + provider := "https://cdn.jsdelivr.net/gh/DeSireFire/animeTrackerList/AT_all.txt" |
| 127 | + h := http.Client{Timeout: time.Second * 5} |
| 128 | + get, err := h.Get(provider) |
| 129 | + if err != nil { |
| 130 | + log.Error(log.Struct{"err", err}, "builtin-downloader: set tracker failed") |
| 131 | + return nil |
| 132 | + } |
| 133 | + defer get.Body.Close() |
| 134 | + r := bufio.NewScanner(get.Body) |
| 135 | + var trackerURLs []string |
| 136 | + for r.Scan() { |
| 137 | + trackerURLs = append(trackerURLs, r.Text()) |
| 138 | + } |
| 139 | + return append(trackers, trackerURLs) |
53 | 140 | } |
0 commit comments