Refactor with ordered maps
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -65,13 +65,15 @@ func handleListOfTorrents(requestPath string, w http.ResponseWriter, r *http.Req
|
||||
for _, directory := range c.GetDirectories() {
|
||||
if basePath == directory {
|
||||
htmlDoc := "<ol>"
|
||||
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("<li><a href=\"%s/\">%s</a></li>", filepath.Join(requestPath, url.PathEscape(name)), name)
|
||||
htmlDoc += fmt.Sprintf("<li><a href=\"%s/\">%s</a></li>", 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 := "<ol>"
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user