diff --git a/cmd/zurg/main.go b/cmd/zurg/main.go index 33f9e7d..392d7f6 100644 --- a/cmd/zurg/main.go +++ b/cmd/zurg/main.go @@ -37,7 +37,7 @@ func main() { cache := expirable.NewLRU[string, string](1e4, nil, time.Hour) - torrentMgr := torrent.NewTorrentManager(config, cache, db) + torrentMgr := torrent.NewTorrentManager(config, db) mux := http.NewServeMux() net.Router(mux, config, torrentMgr, cache) diff --git a/go.mod b/go.mod index 1b30310..d588ff3 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/elliotchance/orderedmap/v2 v2.2.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/nutsdb/nutsdb v0.14.1 // indirect diff --git a/go.sum b/go.sum index 6061d0f..99f954e 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk= +github.com/elliotchance/orderedmap/v2 v2.2.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= diff --git a/internal/dav/listing.go b/internal/dav/listing.go index 0a9dae5..69bbca9 100644 --- a/internal/dav/listing.go +++ b/internal/dav/listing.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "path" + "path/filepath" "strings" "github.com/debridmediamanager.com/zurg/internal/config" @@ -69,10 +70,28 @@ func handleListOfTorrents(requestPath string, w http.ResponseWriter, r *http.Req for _, directory := range c.GetDirectories() { if basePath == directory { - torrents := t.GetByDirectory(basePath) - resp, err := createMultiTorrentResponse("/"+basePath, torrents) - if err != nil { - return nil, fmt.Errorf("cannot read directory (%s): %w", basePath, err) + var responses []dav.Response + + responses = append(responses, dav.Directory(basePath)) + + for el := t.TorrentMap.Front(); el != nil; el = el.Next() { + accessKey := el.Key + torrent := el.Value + if torrent.InProgress { + continue + } + for _, dir := range torrent.Directories { + if dir == basePath { + path := filepath.Join(basePath, accessKey) + responses = append(responses, dav.Directory(path)) + break + } + } + } + + resp := &dav.MultiStatus{ + XMLNS: "DAV:", + Response: responses, } return xml.Marshal(resp) } @@ -82,17 +101,37 @@ func handleListOfTorrents(requestPath string, w http.ResponseWriter, r *http.Req } func handleSingleTorrent(requestPath string, w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager) ([]byte, error) { - directory := path.Dir(requestPath) - torrentName := path.Base(requestPath) - - sameNameTorrents := t.FindAllTorrentsWithName(directory, torrentName) - if len(sameNameTorrents) == 0 { - return nil, fmt.Errorf("cannot find directory when generating single torrent: %s", requestPath) + accessKey := path.Base(requestPath) + torrent, exists := t.TorrentMap.Get(accessKey) + if !exists { + return nil, fmt.Errorf("cannot find torrent %s", requestPath) } - resp, err := createSingleTorrentResponse("/"+directory, sameNameTorrents) - if err != nil { - return nil, fmt.Errorf("cannot read directory (%s): %w", requestPath, err) + var responses []dav.Response + + // initial response is the directory itself + responses = append(responses, dav.Directory(requestPath)) + + for el := torrent.SelectedFiles.Front(); el != nil; el = el.Next() { + file := el.Value + if file.Link == "" { + // will be caught by torrent manager's repairAll + // just skip it for now + continue + } + filename := filepath.Base(file.Path) + filePath := filepath.Join(requestPath, filename) + responses = append(responses, dav.File( + filePath, + file.Bytes, + convertRFC3339toRFC1123(torrent.LatestAdded), + file.Link, + )) + } + + resp := &dav.MultiStatus{ + XMLNS: "DAV:", + Response: responses, } return xml.Marshal(resp) } diff --git a/internal/dav/response.go b/internal/dav/response.go deleted file mode 100644 index 15d00b8..0000000 --- a/internal/dav/response.go +++ /dev/null @@ -1,79 +0,0 @@ -package dav - -import ( - "path/filepath" - - "github.com/debridmediamanager.com/zurg/internal/torrent" - "github.com/debridmediamanager.com/zurg/pkg/dav" -) - -// createMultiTorrentResponse creates a WebDAV response for a list of torrents -func createMultiTorrentResponse(basePath string, torrents []torrent.Torrent) (*dav.MultiStatus, error) { - var responses []dav.Response - responses = append(responses, dav.Directory(basePath)) - - seen := make(map[string]bool) - - for _, item := range torrents { - if item.InProgress { - continue - } - if _, exists := seen[item.AccessKey]; exists { - continue - } - seen[item.AccessKey] = true - - path := filepath.Join(basePath, item.AccessKey) - responses = append(responses, dav.Directory(path)) - } - - return &dav.MultiStatus{ - XMLNS: "DAV:", - Response: responses, - }, nil -} - -// createTorrentResponse creates a WebDAV response for a single torrent -// but it also handles the case where there are many torrents with the same name -func createSingleTorrentResponse(basePath string, torrents []torrent.Torrent) (*dav.MultiStatus, error) { - var responses []dav.Response - - // initial response is the directory itself - currentPath := filepath.Join(basePath, torrents[0].AccessKey) - responses = append(responses, dav.Directory(currentPath)) - - finalName := make(map[string]bool) - - var torrentResponses []dav.Response - - for _, torrent := range torrents { - for _, file := range torrent.SelectedFiles { - if file.Link == "" { - // TODO: fix the file? - // log.Println("File has no link, skipping (repairing links take time)", file.Path) - continue - } - - filename := filepath.Base(file.Path) - if finalName[filename] { - continue - } - finalName[filename] = true - - filePath := filepath.Join(currentPath, filename) - torrentResponses = append(torrentResponses, dav.File( - filePath, - file.Bytes, - convertRFC3339toRFC1123(torrent.LatestAdded), - file.Link, - )) - } - } - - responses = append(responses, torrentResponses...) - - return &dav.MultiStatus{ - XMLNS: "DAV:", - Response: responses, - }, nil -} diff --git a/internal/http/listing.go b/internal/http/listing.go index 6e39b9b..096c8f8 100644 --- a/internal/http/listing.go +++ b/internal/http/listing.go @@ -65,13 +65,15 @@ func handleListOfTorrents(requestPath string, w http.ResponseWriter, r *http.Req for _, directory := range c.GetDirectories() { if basePath == directory { htmlDoc := "
    " - for name, torrent := range t.TorrentMap { - if len(torrent.SelectedFiles) == 0 { + for el := t.TorrentMap.Front(); el != nil; el = el.Next() { + accessKey := el.Key + torrent := el.Value + if torrent.InProgress { continue } for _, dir := range torrent.Directories { if dir == basePath { - htmlDoc += fmt.Sprintf("
  1. %s
  2. ", filepath.Join(requestPath, url.PathEscape(name)), name) + htmlDoc += fmt.Sprintf("
  3. %s
  4. ", filepath.Join(requestPath, url.PathEscape(accessKey)), accessKey) break } } @@ -84,12 +86,18 @@ func handleListOfTorrents(requestPath string, w http.ResponseWriter, r *http.Req } func handleSingleTorrent(requestPath string, w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager) (*string, error) { - torrentName := path.Base(requestPath) + accessKey := path.Base(requestPath) + torrent, _ := t.TorrentMap.Get(accessKey) + if torrent == nil { + return nil, fmt.Errorf("cannot find torrent %s", requestPath) + } + htmlDoc := "
      " - for _, file := range t.TorrentMap[torrentName].SelectedFiles { + for el := torrent.SelectedFiles.Front(); el != nil; el = el.Next() { + file := el.Value if file.Link == "" { - // TODO: fix the file? - fmt.Printf("File %s has no link, skipping\n", file.Path) + // will be caught by torrent manager's repairAll + // just skip it for now continue } filename := filepath.Base(file.Path) diff --git a/internal/torrent/manager.go b/internal/torrent/manager.go index 21c6667..a1919d9 100644 --- a/internal/torrent/manager.go +++ b/internal/torrent/manager.go @@ -3,7 +3,9 @@ package torrent import ( "encoding/gob" "fmt" + "math" "os" + "path/filepath" "strings" "sync" "time" @@ -11,18 +13,17 @@ import ( "github.com/debridmediamanager.com/zurg/internal/config" "github.com/debridmediamanager.com/zurg/pkg/logutil" "github.com/debridmediamanager.com/zurg/pkg/realdebrid" - "github.com/hashicorp/golang-lru/v2/expirable" + "github.com/elliotchance/orderedmap/v2" "github.com/nutsdb/nutsdb" "go.uber.org/zap" ) type TorrentManager struct { - TorrentMap map[string]*Torrent + TorrentMap *orderedmap.OrderedMap[string, *Torrent] // accessKey -> Torrent requiredVersion string rd *realdebrid.RealDebrid checksum string config config.ConfigInterface - cache *expirable.LRU[string, string] db *nutsdb.DB workerPool chan bool directoryMap map[string][]string @@ -34,13 +35,12 @@ type TorrentManager struct { // NewTorrentManager creates a new torrent manager // it will fetch all torrents and their info in the background // and store them in-memory and cached in files -func NewTorrentManager(config config.ConfigInterface, cache *expirable.LRU[string, string], db *nutsdb.DB) *TorrentManager { +func NewTorrentManager(config config.ConfigInterface, db *nutsdb.DB) *TorrentManager { t := &TorrentManager{ - TorrentMap: make(map[string]*Torrent), - requiredVersion: fmt.Sprintf("8.11.2023 - retain:%v", config.EnableRetainFolderNameExtension()), + TorrentMap: orderedmap.NewOrderedMap[string, *Torrent](), + requiredVersion: fmt.Sprintf("10.11.2023/retain=%t", config.EnableRetainFolderNameExtension()), rd: realdebrid.NewRealDebrid(config.GetToken(), logutil.NewLogger().Named("realdebrid")), config: config, - cache: cache, db: db, workerPool: make(chan bool, config.GetNumOfWorkers()), directoryMap: make(map[string][]string), @@ -74,10 +74,11 @@ func NewTorrentManager(config config.ConfigInterface, cache *expirable.LRU[strin if newTorrent == nil { continue } - if _, exists := t.TorrentMap[newTorrent.AccessKey]; exists { - t.TorrentMap[newTorrent.AccessKey] = t.mergeToMain(t.TorrentMap[newTorrent.AccessKey], newTorrent) + torrent, _ := t.TorrentMap.Get(newTorrent.AccessKey) + if torrent != nil { + t.TorrentMap.Set(newTorrent.AccessKey, t.mergeToMain(torrent, newTorrent)) } else { - t.TorrentMap[newTorrent.AccessKey] = newTorrent + t.TorrentMap.Set(newTorrent.AccessKey, newTorrent) } } t.checksum = t.getChecksum() @@ -95,15 +96,11 @@ func (t *TorrentManager) mergeToMain(t1, t2 *Torrent) *Torrent { merged := t1 // Merge SelectedFiles - fileMap := make(map[int]File) - for _, f := range append(t1.SelectedFiles, t2.SelectedFiles...) { - if _, exists := fileMap[f.ID]; !exists { - fileMap[f.ID] = f + for el := t2.SelectedFiles.Front(); el != nil; el = el.Next() { + if _, ok := merged.SelectedFiles.Get(el.Key); !ok { + merged.SelectedFiles.Set(el.Key, el.Value) } } - for _, f := range fileMap { - merged.SelectedFiles = append(merged.SelectedFiles, f) - } // Merge Instances merged.Instances = append(t1.Instances, t2.Instances...) @@ -113,7 +110,7 @@ func (t *TorrentManager) mergeToMain(t1, t2 *Torrent) *Torrent { merged.LatestAdded = t2.LatestAdded } - // InProgress + // InProgress - if one of the instances is in progress, then the whole torrent is in progress for _, instance := range merged.Instances { if instance.Progress != 100 { merged.InProgress = true @@ -124,36 +121,6 @@ func (t *TorrentManager) mergeToMain(t1, t2 *Torrent) *Torrent { return merged } -// GetByDirectory returns all torrents that have a file in the specified directory -func (t *TorrentManager) GetByDirectory(directory string) []Torrent { - var torrents []Torrent - for k, v := range t.TorrentMap { - found := false - for _, dir := range v.Directories { - if dir == directory { - found = true - break - } - } - if found { - torrents = append(torrents, *t.TorrentMap[k]) - } - } - return torrents -} - -// FindAllTorrentsWithName finds all torrents in a given directory with a given name -func (t *TorrentManager) FindAllTorrentsWithName(directory, torrentName string) []Torrent { - var matchingTorrents []Torrent - torrents := t.GetByDirectory(directory) - for i := range torrents { - if torrents[i].AccessKey == torrentName || strings.Contains(torrents[i].AccessKey, torrentName) { - matchingTorrents = append(matchingTorrents, torrents[i]) - } - } - return matchingTorrents -} - // proxy func (t *TorrentManager) UnrestrictUntilOk(link string) *realdebrid.UnrestrictResponse { return t.rd.UnrestrictUntilOk(link) @@ -244,16 +211,33 @@ func (t *TorrentManager) startRefreshJob() { <-t.workerPool }(i) } + + // deletes + // for el := t.TorrentMap.Front(); el != nil; el = el.Next() { + // found := false + // for _, newTorrent := range newTorrents { + // if newTorrent.ID == el.Value.AccessKey { + // found = true + // break + // } + // } + // if !found { + // t.log.Infof("Torrent id=%s is no longer found", accessKey) + // t.TorrentMap.Delete(accessKey) + // } + // } + wg.Wait() close(torrentsChan) for newTorrent := range torrentsChan { if newTorrent == nil { continue } - if _, exists := t.TorrentMap[newTorrent.AccessKey]; exists { - t.TorrentMap[newTorrent.AccessKey] = t.mergeToMain(t.TorrentMap[newTorrent.AccessKey], newTorrent) + torrent, _ := t.TorrentMap.Get(newTorrent.AccessKey) + if torrent != nil { + t.TorrentMap.Set(newTorrent.AccessKey, t.mergeToMain(torrent, newTorrent)) } else { - t.TorrentMap[newTorrent.AccessKey] = newTorrent + t.TorrentMap.Set(newTorrent.AccessKey, newTorrent) } } t.checksum = t.getChecksum() @@ -288,7 +272,7 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { // it also has a Link field, which can be empty // if it is empty, it means the file is no longer available // Files+Links together are the same as SelectedFiles - var selectedFiles []File + selectedFiles := orderedmap.NewOrderedMap[string, *File]() streamableCount := 0 // if some Links are empty, we need to repair it forRepair := false @@ -299,22 +283,26 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { if file.Selected == 0 { continue } - selectedFiles = append(selectedFiles, File{ + selectedFiles.Set(filepath.Base(file.Path), &File{ File: file, Link: "", // no link yet }) } - if len(selectedFiles) > len(info.Links) && info.Progress == 100 { - t.log.Debugf("Some links has expired for %s %s: %d selected but only %d link(s)", info.ID, info.Name, len(selectedFiles), len(info.Links)) + if selectedFiles.Len() > len(info.Links) && info.Progress == 100 { + t.log.Debugf("Some links has expired for %s %s: %d selected but only %d link(s)", info.ID, info.Name, selectedFiles.Len(), len(info.Links)) // chaotic file means RD will not output the desired file selection // e.g. even if we select just a single mkv, it will output a rar var isChaotic bool selectedFiles, isChaotic = t.organizeChaos(&rdTorrent, selectedFiles) - if isChaotic { + if isChaotic && selectedFiles.Len() == 1 { t.log.Infof("Torrent %s %s is unfixable, it's always returning an unstreamable link, ignoring", info.ID, info.Name) t.log.Debugf("You can try fixing it yourself magnet:?xt=urn:btih:%s", info.Hash) } else { if streamableCount > 1 { + // case for repair 1: it's missing some links (or all links) + // if we download it as is, we might get the same file over and over again + // so we need to redownload it with other files selected + // that is why we check if there are other streamable files t.log.Infof("Torrent %s %s marked for repair", info.ID, info.Name) forRepair = true } else { @@ -322,10 +310,16 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { t.log.Debugf("You can try fixing it yourself magnet:?xt=urn:btih:%s", info.Hash) } } - } else if len(selectedFiles) > 0 { + } else if selectedFiles.Len() == len(info.Links) { // all links are still intact! good! - for i, link := range info.Links { - selectedFiles[i].Link = link + i := 0 + for el := selectedFiles.Front(); el != nil; el = el.Next() { + if i < len(info.Links) { + file := el.Value + file.Link = info.Links[i] + selectedFiles.Set(el.Key, file) + i++ + } } } @@ -338,7 +332,7 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { InProgress: info.Progress != 100, Instances: []realdebrid.TorrentInfo{*info}, } - if len(selectedFiles) > 0 && torrentFromFile == nil { + if selectedFiles.Len() > 0 && torrentFromFile == nil { t.writeToFile(info) // only when there are selected files, else it's useless } return &torrent @@ -429,7 +423,7 @@ func (t *TorrentManager) readFromFile(torrentID string) *realdebrid.TorrentInfo return &torrent } -func (t *TorrentManager) organizeChaos(info *realdebrid.Torrent, selectedFiles []File) ([]File, bool) { +func (t *TorrentManager) organizeChaos(info *realdebrid.Torrent, selectedFiles *orderedmap.OrderedMap[string, *File]) (*orderedmap.OrderedMap[string, *File], bool) { type Result struct { Response *realdebrid.UnrestrictResponse } @@ -465,84 +459,61 @@ func (t *TorrentManager) organizeChaos(info *realdebrid.Torrent, selectedFiles [ continue } found := false - for i := range selectedFiles { - if strings.Contains(selectedFiles[i].Path, result.Response.Filename) { + for el := selectedFiles.Front(); el != nil; el = el.Next() { + if file, _ := selectedFiles.Get(el.Key); strings.Contains(file.Path, result.Response.Filename) { t.log.Debugf("Found a file that is in the selection for torrent id=%s: %s", info.ID, result.Response.Filename) - selectedFiles[i].Link = result.Response.Link + file.Link = result.Response.Link found = true } } if !found { - isChaotic = result.Response.Streamable == 0 - t.log.Debugf("Found a file that is not in the selection for torrent id=%s: %s %v", info.ID, result.Response.Filename, result.Response.Streamable) - selectedFiles = append(selectedFiles, File{ - File: realdebrid.File{ - Path: result.Response.Filename, - Bytes: result.Response.Filesize, - Selected: 1, - }, - Link: result.Response.Link, - }) + t.log.Debugf("Found a file that is NOT in the selection for torrent id=%s: %s %v", info.ID, result.Response.Filename, result.Response.Streamable) + if result.Response.Streamable == 1 { + selectedFiles.Set(filepath.Base(result.Response.Filename), &File{ + File: realdebrid.File{ + ID: math.MaxInt32, + Path: result.Response.Filename, + Bytes: result.Response.Filesize, + Selected: 1, + }, + Link: result.Response.Link, + }) + } } } return selectedFiles, isChaotic } -// HideTheFile marks a file as deleted -// func (t *TorrentManager) HideTheFile(torrent *Torrent, file *File) { -// file.Unavailable = true -// t.repair(torrent, false) -// } - // func (t *TorrentManager) repairAll() { -// for _, torrent := range t.torrentMap { -// // do not repair if: -// // in progress -// hasInProgress := false -// for _, info := range torrent.Instances { -// if info.Progress != 100 { -// hasInProgress = true -// break -// } -// } -// if hasInProgress { +// for el := t.TorrentMap.Front(); el != nil; el = el.Next() { +// torrent := el.Value +// // do not repair if: in progress +// if torrent.InProgress { // continue // } -// // already repaired based on other instances + // var missingFiles []File -// for _, file := range torrent.SelectedFiles { -// if file.Link == "" || file.Unavailable { -// missingFiles = append(missingFiles, file) +// for el2 := torrent.SelectedFiles.Front(); el2 != nil; el2 = el2.Next() { +// file, ok := torrent.SelectedFiles.Get(el2.Key) +// if !ok { +// continue // } -// } -// for _, sFile := range selectedFiles { -// if sFile.Link == "" || sFile.Unavailable { -// found := false -// for _, fFile := range foundFiles { -// // same file but different link, then yes it has been repaired -// if sFile.Path == fFile.Path && sFile.Link != fFile.Link { -// found = true -// break -// } -// } -// if !found { -// missingFiles = append(missingFiles, sFile) -// } +// // check for case of repairs like +// // case 1: missing links +// // case 2: unrestrictable links TODO +// if file.Link == "" { +// missingFiles = append(missingFiles, *file) // } // } // if len(missingFiles) == 0 { -// t.log.Infof("Torrent id=%s is already repaired", info.ID) -// return +// continue // } // for _, info := range torrent.Instances { -// if info.Progress != 100 { -// continue -// } // if info.ForRepair { // t.log.Infof("There were less links than was expected on %s %s; fixing...", info.ID, info.Name) -// t.repair(&info, true) +// // t.repair(&info, true) // break // only repair the first one for repair and then move on // } // if len(info.Links) == 0 && info.Progress == 100 { @@ -557,6 +528,7 @@ func (t *TorrentManager) organizeChaos(info *realdebrid.Torrent, selectedFiles [ // } // func (t *TorrentManager) repair(info *realdebrid.TorrentInfo, tryReinsertionFirst bool) { +// // file.Link == "" should be repaired // // then we repair it! // t.log.Infof("Repairing torrent id=%s", info.ID) // // check if we can still add more downloads @@ -576,6 +548,9 @@ func (t *TorrentManager) organizeChaos(info *realdebrid.Torrent, selectedFiles [ // var otherStreamableFileIDs []int // for _, file := range info.Files { // found := false +// for el := selectedFiles.Front(); el != nil; el = el.Next() { + +// } // for _, selectedFile := range selectedFiles { // if selectedFile.ID == file.ID { // found = true diff --git a/internal/torrent/types.go b/internal/torrent/types.go index a1e4641..f4c35a7 100644 --- a/internal/torrent/types.go +++ b/internal/torrent/types.go @@ -2,11 +2,12 @@ package torrent import ( "github.com/debridmediamanager.com/zurg/pkg/realdebrid" + "github.com/elliotchance/orderedmap/v2" ) type Torrent struct { AccessKey string - SelectedFiles []File + SelectedFiles *orderedmap.OrderedMap[string, *File] Directories []string LatestAdded string InProgress bool @@ -16,6 +17,5 @@ type Torrent struct { type File struct { realdebrid.File - Link string - Unavailable bool + Link string } diff --git a/internal/universal/get.go b/internal/universal/get.go index 4b5f95a..f699433 100644 --- a/internal/universal/get.go +++ b/internal/universal/get.go @@ -47,17 +47,17 @@ func HandleGetRequest(w http.ResponseWriter, r *http.Request, t *torrent.Torrent } baseDirectory := segments[len(segments)-3] - torrentName := segments[len(segments)-2] + accessKey := segments[len(segments)-2] filename := segments[len(segments)-1] - torrents := t.FindAllTorrentsWithName(baseDirectory, torrentName) - if torrents == nil { - log.Errorf("Cannot find torrent %s in the directory %s", requestPath, baseDirectory) + torrent, _ := t.TorrentMap.Get(accessKey) + if torrent == nil { + log.Errorf("Cannot find torrent %s in the directory %s", accessKey, baseDirectory) http.Error(w, "File not found", http.StatusNotFound) return } - _, file := getFile(torrents, filename) + file, _ := torrent.SelectedFiles.Get(filename) if file == nil { log.Errorf("Cannot find file from path %s", requestPath) http.Error(w, "File not found", http.StatusNotFound) @@ -73,10 +73,7 @@ func HandleGetRequest(w http.ResponseWriter, r *http.Request, t *torrent.Torrent resp := t.UnrestrictUntilOk(link) if resp == nil { - if !file.Unavailable { - log.Errorf("Cannot unrestrict file %s %s", filename, link) - // t.HideTheFile(torrent, file) - } + // TODO: maybe repair the torrent? streamErrorVideo("https://www.youtube.com/watch?v=gea_FJrtFVA", w, r, t, c, log) return } else if resp.Filename != filename { diff --git a/internal/universal/head.go b/internal/universal/head.go index 65211fe..a623fb8 100644 --- a/internal/universal/head.go +++ b/internal/universal/head.go @@ -41,17 +41,17 @@ func HandleHeadRequest(w http.ResponseWriter, r *http.Request, t *torrent.Torren } baseDirectory := segments[len(segments)-3] - torrentName := segments[len(segments)-2] + accessKey := segments[len(segments)-2] filename := segments[len(segments)-1] - torrents := t.FindAllTorrentsWithName(baseDirectory, torrentName) - if torrents == nil { - log.Errorf("Cannot find torrent %s in the directory %s", requestPath, baseDirectory) - http.Error(w, "Cannot find file", http.StatusNotFound) + torrent, _ := t.TorrentMap.Get(accessKey) + if torrent == nil { + log.Errorf("Cannot find torrent %s in the directory %s", accessKey, baseDirectory) + http.Error(w, "File not found", http.StatusNotFound) return } - _, file := getFile(torrents, filename) + file, _ := torrent.SelectedFiles.Get(filename) if file == nil { log.Errorf("Cannot find file from path %s", requestPath) http.Error(w, "Cannot find file", http.StatusNotFound) diff --git a/internal/universal/util.go b/internal/universal/util.go index e9d5351..897888b 100644 --- a/internal/universal/util.go +++ b/internal/universal/util.go @@ -1,20 +1 @@ package universal - -import ( - "path/filepath" - - "github.com/debridmediamanager.com/zurg/internal/torrent" -) - -// getFile finds a link by a fragment, it might be wrong -func getFile(torrents []torrent.Torrent, filename string) (*torrent.Torrent, *torrent.File) { - for t := range torrents { - for f, file := range torrents[t].SelectedFiles { - fname := filepath.Base(file.Path) - if filename == fname { - return &torrents[t], &torrents[t].SelectedFiles[f] - } - } - } - return nil, nil -} diff --git a/pkg/realdebrid/types.go b/pkg/realdebrid/types.go index d0ce0f5..230cf19 100644 --- a/pkg/realdebrid/types.go +++ b/pkg/realdebrid/types.go @@ -44,20 +44,20 @@ type TorrentInfo struct { Version string `json:"-"` } -func (t *Torrent) UnmarshalJSON(data []byte) error { - type Alias Torrent +func (i *TorrentInfo) UnmarshalJSON(data []byte) error { + type Alias TorrentInfo aux := &struct { Progress float64 `json:"progress"` *Alias }{ - Alias: (*Alias)(t), + Alias: (*Alias)(i), } if err := json.Unmarshal(data, &aux); err != nil { return err } - t.Progress = int(math.Round(aux.Progress)) + i.Progress = int(math.Round(aux.Progress)) return nil }