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("- %s
", filepath.Join(requestPath, url.PathEscape(name)), name)
+ htmlDoc += fmt.Sprintf("- %s
", 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
}