Files
zurg/internal/torrent/manager.go
2023-10-18 02:06:01 +02:00

149 lines
3.2 KiB
Go

package torrent
import (
"log"
"strings"
"sync"
"github.com/debridmediamanager.com/zurg/pkg/realdebrid"
)
type TorrentManager struct {
token string
torrents []Torrent
workerPool chan bool
}
// NewTorrentManager creates a new torrent manager
// it will fetch all torrents and their info in the background
// and store them in-memory
func NewTorrentManager(token string) *TorrentManager {
handler := &TorrentManager{
token: token,
workerPool: make(chan bool, 10),
}
handler.torrents = handler.getAll()
for _, torrent := range handler.torrents {
go func(id string) {
handler.workerPool <- true
handler.getInfo(id)
// sleep for 1 second to avoid rate limiting
<-handler.workerPool
}(torrent.ID)
}
return handler
}
func (t *TorrentManager) getAll() []Torrent {
torrents, err := realdebrid.GetTorrents(t.token)
if err != nil {
log.Printf("Cannot get torrents: %v\n", err.Error())
return nil
}
var torrentsV2 []Torrent
for _, torrent := range torrents {
torrentsV2 = append(torrentsV2, Torrent{
Torrent: torrent,
SelectedFiles: nil,
})
}
return torrentsV2
}
func (t *TorrentManager) GetAll() []Torrent {
return t.torrents
}
func (t *TorrentManager) getInfo(torrentID string) *Torrent {
info, err := realdebrid.GetTorrentInfo(t.token, torrentID)
if err != nil {
log.Printf("Cannot get info: %v\n", err.Error())
return nil
}
var selectedFiles []File
for _, file := range info.Files {
if file.Selected == 0 {
continue
}
selectedFiles = append(selectedFiles, File{
File: file,
Link: "",
})
}
if len(selectedFiles) != len(info.Links) {
type Result struct {
Filename string
Link string
}
resultsChan := make(chan Result, len(info.Links))
var wg sync.WaitGroup
// Limit concurrency
sem := make(chan struct{}, 10) // e.g., 10 concurrent requests
for _, link := range info.Links {
wg.Add(1)
sem <- struct{}{} // Acquire semaphore
go func(lnk string) {
defer wg.Done()
defer func() { <-sem }() // Release semaphore
unrestrictFn := func() (*realdebrid.UnrestrictResponse, error) {
return realdebrid.UnrestrictLink(t.token, lnk)
}
resp := realdebrid.RetryUntilOk(unrestrictFn)
if resp != nil {
resultsChan <- Result{Filename: resp.Filename, Link: resp.Link}
}
}(link)
}
go func() {
wg.Wait()
close(resultsChan)
}()
for result := range resultsChan {
for i := range selectedFiles {
if strings.HasSuffix(selectedFiles[i].Path, result.Filename) {
selectedFiles[i].Link = result.Link
}
}
}
} else {
for i, link := range info.Links {
selectedFiles[i].Link = link
}
}
torrent := t.getByID(torrentID)
if torrent != nil {
torrent.SelectedFiles = selectedFiles
}
log.Println("Fetched info for", info.Filename)
return torrent
}
func (t *TorrentManager) GetInfo(torrentID string) *Torrent {
for _, torrent := range t.torrents {
if torrent.ID == torrentID {
if torrent.SelectedFiles != nil {
return t.getInfo(torrentID)
}
}
}
return nil
}
func (t *TorrentManager) getByID(torrentID string) *Torrent {
for _, torrent := range t.torrents {
if torrent.ID == torrentID {
return &torrent
}
}
return nil
}