"strings"
"syscall"
"time"
- "math"
"github.com/anacrolix/sync"
"github.com/anacrolix/utp"
t.cl.raisePiecePriority(t.torrent, t.numPieces()-1, piecePriorityReadahead)
}
-// Marks the entire torrent for download. Requires the info first, see
-// GotInfo.
-func (t Torrent) DownloadFile(Path []string) {
- t.cl.mu.Lock()
- defer t.cl.mu.Unlock()
-
- // log.Printf("File to Download: %s", Path)
-
- // log.Printf("Pieces: %s", t.torrent.Info.NumPieces())
- // log.Printf("Length: %s", t.torrent.Info.TotalLength())
- // log.Printf("Torrent info: %s", t.torrent.Info.UpvertedFiles())
-
- var offset int64
- var pickedFile metainfo.FileInfo
-
- found := false
- pathStr := strings.Join(Path, "")
-
- for _, file := range t.torrent.Info.UpvertedFiles() {
- if strings.Join(file.Path, "/") == pathStr {
- log.Printf("Found file: %s", file)
-
- found = true
- pickedFile = file
- break
- }
- // log.Printf("%d %d `%s` `%s`", len(file.Path), len(Path), strings.Join(file.Path, "/"), strings.Join(Path, ""))
- log.Printf("File: %s", strings.Join(file.Path, "/"))
- offset += file.Length;
- }
-
- if !found {
- panic(fmt.Sprintf("File not found"))
- }
-
- log.Printf("Donwloading file: `%s`", Path)
- log.Printf("Calculated offset: %s", offset)
- log.Printf("File length: %s", pickedFile.Length)
- log.Printf("Piece length: %s", t.torrent.Info.PieceLength)
-
-
- firstChunk := int(offset/t.torrent.Info.PieceLength)
- nChunks := int(math.Ceil(float64(pickedFile.Length) / float64(t.torrent.Info.PieceLength)))
-
- log.Printf("First chunk: %s", offset/t.torrent.Info.PieceLength)
- log.Printf("Number of chunks: %s", nChunks)
- log.Printf("Total chunks: %s", t.torrent.Info.NumPieces())
-
-
- for chunk := firstChunk; chunk < firstChunk + nChunks; chunk++ {
- log.Printf("Piece #%d: %s %s", chunk, t.torrent.Info.Piece(chunk).Length(), t.torrent.Info.Piece(chunk).Offset())
- t.cl.raisePiecePriority(t.torrent, chunk, piecePriorityNormal)
- }
-}
// Returns nil metainfo if it isn't in the cache. Checks that the retrieved
"net/http"
_ "net/http/pprof"
"os"
+ "io"
+ "io/ioutil"
"strings"
"time"
+ "bufio"
+
_ "github.com/anacrolix/envpprof"
"github.com/dustin/go-humanize"
return fmt.Sprintf("\033[K%s / %s\r", humanize.Bytes(uint64(bytesCompleted(tc))), humanize.Bytes(uint64(totalBytesEstimate(tc))))
}
+func dstFileName(picked string) string {
+ parts := strings.Split(picked, "/")
+ return parts[len(parts)-1]
+}
+
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
var rootGroup struct {
Client torrent.Config `group:"Client Options"`
Seed bool `long:"seed" description:"continue seeding torrents after completed"`
TestPeers []string `long:"test-peer" description:"address of peer to inject to every torrent"`
- Pick []string `long:"pick" description:"filename to pick"`
+ Pick string `long:"pick" description:"filename to pick"`
}
// Don't pass flags.PrintError because it's inconsistent with printing.
// https://github.com/jessevdk/go-flags/issues/132
fmt.Fprintln(os.Stderr, "no torrents specified")
return
}
+
+ tmpdir, err := ioutil.TempDir("", "torrent-pick-")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ defer os.RemoveAll(tmpdir)
+
+ rootGroup.Client.DataDir = tmpdir
+
client, err := torrent.NewClient(&rootGroup.Client)
if err != nil {
log.Fatalf("error creating client: %s", err)
client.WriteStatus(w)
})
defer client.Close()
+
+
+ dstName := dstFileName(rootGroup.Pick)
+
+ f, err := os.Create(dstName)
+ if err != nil {
+ log.Fatal(err)
+ }
+ dstWriter := bufio.NewWriter(f)
+
+
for _, arg := range posArgs {
t := func() torrent.Torrent {
if strings.HasPrefix(arg, "magnet:") {
if err != nil {
log.Fatal(err)
}
+
go func() {
<-t.GotInfo()
- t.DownloadFile(rootGroup.Pick)
+ files := t.Files()
+ for _, file := range files {
+ if file.Path() == rootGroup.Pick {
+
+ log.Printf("Downloading file: %s", file.Path())
+
+ srcReader := io.NewSectionReader(t.NewReader(), file.Offset(), file.Length())
+ io.Copy(dstWriter, srcReader)
+ break
+ }
+ }
}()
}
+
done := make(chan struct{})
go func() {
defer close(done)