2024-05-19 21:24:09 +00:00
|
|
|
package torrent
|
2024-03-17 21:00:34 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"git.kmsign.ru/royalcat/tstor/pkg/uuid"
|
|
|
|
"github.com/anacrolix/torrent"
|
|
|
|
"github.com/anacrolix/torrent/types/infohash"
|
|
|
|
)
|
|
|
|
|
2024-05-19 21:24:09 +00:00
|
|
|
type DownloadTask struct {
|
2024-03-17 21:00:34 +00:00
|
|
|
ID uuid.UUID
|
|
|
|
InfoHash infohash.T
|
|
|
|
File string
|
|
|
|
}
|
|
|
|
|
2024-05-19 21:24:09 +00:00
|
|
|
func (s *Service) Download(ctx context.Context, task *DownloadTask) error {
|
2024-05-18 07:24:14 +00:00
|
|
|
t, ok := s.client.Torrent(task.InfoHash)
|
2024-03-17 21:00:34 +00:00
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("torrent with IH %s not found", task.InfoHash.HexString())
|
|
|
|
}
|
|
|
|
|
|
|
|
if task.File != "" {
|
|
|
|
var file *torrent.File
|
|
|
|
for _, tf := range t.Files() {
|
|
|
|
if tf.Path() == task.File {
|
|
|
|
file = tf
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if file == nil {
|
|
|
|
return fmt.Errorf("file %s not found in torrent torrent with IH %s", task.File, task.InfoHash.HexString())
|
|
|
|
}
|
|
|
|
|
|
|
|
file.Download()
|
2024-04-24 17:36:33 +00:00
|
|
|
} else {
|
|
|
|
for _, file := range t.Files() {
|
|
|
|
file.Download()
|
|
|
|
}
|
2024-03-17 21:00:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// func (s *Service) DownloadAndWait(ctx context.Context, task *TorrentDownloadTask) error {
|
|
|
|
// t, ok := s.c.Torrent(task.InfoHash)
|
|
|
|
// if !ok {
|
|
|
|
// return fmt.Errorf("torrent with IH %s not found", task.InfoHash.HexString())
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if task.File != "" {
|
|
|
|
// var file *torrent.File
|
|
|
|
// for _, tf := range t.Files() {
|
|
|
|
// if tf.Path() == task.File {
|
|
|
|
// file = tf
|
|
|
|
// break
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if file == nil {
|
|
|
|
// return fmt.Errorf("file %s not found in torrent torrent with IH %s", task.File, task.InfoHash.HexString())
|
|
|
|
// }
|
|
|
|
|
|
|
|
// file.Download()
|
|
|
|
// return waitPieceRange(ctx, t, file.BeginPieceIndex(), file.EndPieceIndex())
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// t.DownloadAll()
|
|
|
|
// select {
|
|
|
|
// case <-ctx.Done():
|
|
|
|
// return ctx.Err()
|
|
|
|
// case <-t.Complete.On():
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// func waitPieceRange(ctx context.Context, t *torrent.Torrent, start, end int) error {
|
|
|
|
// for i := start; i < end; i++ {
|
|
|
|
// timer := time.NewTimer(time.Millisecond)
|
|
|
|
// for {
|
|
|
|
// select {
|
|
|
|
// case <-ctx.Done():
|
|
|
|
// return ctx.Err()
|
|
|
|
// case <-timer.C:
|
|
|
|
// if t.PieceState(i).Complete {
|
|
|
|
// continue
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
|
|
|
|
type TorrentProgress struct {
|
2024-05-19 21:24:09 +00:00
|
|
|
Torrent *Controller
|
2024-03-17 21:00:34 +00:00
|
|
|
Current int64
|
|
|
|
Total int64
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) DownloadProgress(ctx context.Context) (<-chan TorrentProgress, error) {
|
|
|
|
torrents, err := s.ListTorrents(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out := make(chan TorrentProgress, 1)
|
|
|
|
go func() {
|
|
|
|
defer close(out)
|
|
|
|
for _, t := range torrents {
|
|
|
|
sub := t.Torrent().SubscribePieceStateChanges()
|
2024-05-19 21:24:09 +00:00
|
|
|
go func(t *Controller) {
|
2024-04-24 17:36:33 +00:00
|
|
|
for stateChange := range sub.Values {
|
|
|
|
if !stateChange.Complete && !stateChange.Partial {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-03-17 21:00:34 +00:00
|
|
|
out <- TorrentProgress{
|
|
|
|
Torrent: t,
|
|
|
|
Current: t.BytesCompleted(),
|
|
|
|
Total: t.Length(),
|
|
|
|
}
|
|
|
|
}
|
2024-04-24 17:36:33 +00:00
|
|
|
}(t)
|
2024-03-17 21:00:34 +00:00
|
|
|
defer sub.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
<-ctx.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|