diff --git a/internal/dav/infuse.go b/internal/dav/infuse.go index 2fc75a9..492a258 100644 --- a/internal/dav/infuse.go +++ b/internal/dav/infuse.go @@ -47,7 +47,7 @@ func ServeTorrentsListForInfuse(directory string, torMgr *torrent.TorrentManager if !ok || tor.AllInProgress() { continue } - buf.WriteString(dav.BaseDirectory(torMgr.GetKey(tor), tor.LatestAdded)) + buf.WriteString(dav.BaseDirectory(torMgr.GetKey(tor), tor.Added)) } buf.WriteString("") return buf.Bytes(), nil diff --git a/internal/dav/listing.go b/internal/dav/listing.go index d66fbc3..4e7e25b 100644 --- a/internal/dav/listing.go +++ b/internal/dav/listing.go @@ -50,7 +50,7 @@ func ServeTorrentsList(directory string, torMgr *torrent.TorrentManager) ([]byte if !ok || tor.AllInProgress() { continue } - buf.WriteString(dav.Directory(torMgr.GetKey(tor), tor.LatestAdded)) + buf.WriteString(dav.Directory(torMgr.GetKey(tor), tor.Added)) } buf.WriteString("") return buf.Bytes(), nil @@ -74,7 +74,7 @@ func ServeFilesList(directory, torrentName string, torMgr *torrent.TorrentManage var buf bytes.Buffer buf.WriteString("") - buf.WriteString(dav.BaseDirectory(filepath.Join(directory, torMgr.GetKey(tor)), tor.LatestAdded)) + buf.WriteString(dav.BaseDirectory(filepath.Join(directory, torMgr.GetKey(tor)), tor.Added)) filenames := tor.SelectedFiles.Keys() sort.Strings(filenames) for _, filename := range filenames { @@ -113,7 +113,7 @@ func HandleSingleFile(directory, torrentName, fileName string, torMgr *torrent.T var buf bytes.Buffer buf.WriteString("") - buf.WriteString(dav.BaseDirectory(filepath.Join(directory, torMgr.GetKey(tor)), tor.LatestAdded)) + buf.WriteString(dav.BaseDirectory(filepath.Join(directory, torMgr.GetKey(tor)), tor.Added)) buf.WriteString(dav.File(fileName, file.Bytes, file.Ended)) buf.WriteString("") return buf.Bytes(), nil diff --git a/internal/torrent/delete.go b/internal/torrent/delete.go index d36def4..938aacd 100644 --- a/internal/torrent/delete.go +++ b/internal/torrent/delete.go @@ -23,7 +23,7 @@ func (t *TorrentManager) CheckDeletedStatus(torrent *Torrent) bool { } } }) - t.writeTorrentToFile(id, info, false) + t.writeTorrentToFile(id, info) return false }) } diff --git a/internal/torrent/manager.go b/internal/torrent/manager.go index ff1a0db..8f535c2 100644 --- a/internal/torrent/manager.go +++ b/internal/torrent/manager.go @@ -185,7 +185,7 @@ func (t *TorrentManager) GetKey(torrent *Torrent) string { } } -func (t *TorrentManager) writeTorrentToFile(instanceID string, torrent *Torrent, overwriteNames bool) { +func (t *TorrentManager) writeTorrentToFile(instanceID string, torrent *Torrent) { filePath := "data/" + instanceID + ".json" file, err := os.Create(filePath) if err != nil { @@ -194,13 +194,6 @@ func (t *TorrentManager) writeTorrentToFile(instanceID string, torrent *Torrent, } defer file.Close() - if !overwriteNames { - infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE) - if cachedTorrent, exists := infoCache.Get(instanceID); exists { - torrent.Name = cachedTorrent.Name - torrent.OriginalName = cachedTorrent.OriginalName - } - } torrent.Version = t.requiredVersion jsonData, err := json.Marshal(torrent) diff --git a/internal/torrent/refresh.go b/internal/torrent/refresh.go index 3ce93c6..113ed17 100644 --- a/internal/torrent/refresh.go +++ b/internal/torrent/refresh.go @@ -114,13 +114,29 @@ func (t *TorrentManager) startRefreshJob() { // getMoreInfo gets original name, size and files for a torrent func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE) - if torrentFromCache, exists := infoCache.Get(rdTorrent.ID); exists && !torrentFromCache.AnyInProgress() && torrentFromCache.SelectedFiles.Count() == len(rdTorrent.Links) { + if torrentFromCache, exists := infoCache.Get(rdTorrent.ID); exists && + !torrentFromCache.AnyInProgress() && + torrentFromCache.SelectedFiles.Count() == len(rdTorrent.Links) { + return torrentFromCache } + torrentFromFile := t.readTorrentFromFile(rdTorrent.ID) - if torrentFromFile != nil && !torrentFromFile.AnyInProgress() && torrentFromFile.SelectedFiles.Count() == len(rdTorrent.Links) { - infoCache.Set(rdTorrent.ID, torrentFromFile) - return torrentFromFile + if torrentFromFile != nil && + !torrentFromFile.AnyInProgress() && + torrentFromFile.SelectedFiles.Count() == len(rdTorrent.Links) { + + hasBrokenFiles := false + torrentFromFile.SelectedFiles.IterCb(func(filepath string, file *File) { + if !strings.HasPrefix(file.Link, "http") && file.Link != "unselect" { + hasBrokenFiles = true + } + }) + + if !hasBrokenFiles { + infoCache.Set(rdTorrent.ID, torrentFromFile) + return torrentFromFile + } } info, err := t.Api.GetTorrentInfo(rdTorrent.ID) @@ -132,7 +148,7 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { torrent := Torrent{ Name: info.Name, OriginalName: info.OriginalName, - LatestAdded: info.Added, + Added: info.Added, Hash: info.Hash, } // SelectedFiles is a subset of Files with only the selected ones @@ -182,8 +198,8 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { } torrent.BrokenLinks = mapset.NewSet[string]() - t.writeTorrentToFile(rdTorrent.ID, &torrent, true) infoCache.Set(rdTorrent.ID, &torrent) + t.writeTorrentToFile(rdTorrent.ID, &torrent) return &torrent } @@ -198,6 +214,7 @@ func (t *TorrentManager) mergeToMain(existing, toMerge *Torrent) Torrent { InProgressIDs: mapset.NewSet[string](), Unfixable: existing.Unfixable || toMerge.Unfixable, UnassignedLinks: existing.UnassignedLinks.Union(toMerge.UnassignedLinks), + BrokenLinks: existing.BrokenLinks.Union(toMerge.BrokenLinks), } // this function triggers only when we have a new DownloadedID @@ -219,8 +236,8 @@ func (t *TorrentManager) mergeToMain(existing, toMerge *Torrent) Torrent { // if it doesn't exist in the main torrent, add it mainTorrent.SelectedFiles.Set(filepath, fileToMerge) } else if originalFile.Link != "unselect" { - // if it exists, compare the LatestAdded property and the link - if existing.LatestAdded < toMerge.LatestAdded { + // if it exists, compare the Added property and the link + if existing.Added < toMerge.Added { // && strings.HasPrefix(fileToMerge.Link, "http") // if torrentToMerge is more recent and its file has a link, update the main torrent's file mainTorrent.SelectedFiles.Set(filepath, fileToMerge) @@ -229,10 +246,10 @@ func (t *TorrentManager) mergeToMain(existing, toMerge *Torrent) Torrent { } }) - if existing.LatestAdded < toMerge.LatestAdded { - mainTorrent.LatestAdded = toMerge.LatestAdded + if existing.Added < toMerge.Added { + mainTorrent.Added = toMerge.Added } else { - mainTorrent.LatestAdded = existing.LatestAdded + mainTorrent.Added = existing.Added } return mainTorrent diff --git a/internal/torrent/repair.go b/internal/torrent/repair.go index 0ee2677..f8d2471 100644 --- a/internal/torrent/repair.go +++ b/internal/torrent/repair.go @@ -113,7 +113,7 @@ func (t *TorrentManager) Repair(torrent *Torrent) { return file.Link == link }) }) - t.writeTorrentToFile(id, info, false) + t.writeTorrentToFile(id, info) return false }) _ = t.workerPool.Submit(func() { @@ -129,7 +129,6 @@ func (t *TorrentManager) repair(torrent *Torrent) { t.log.Infof("Torrent %s is in progress, skipping repair until download is done", t.GetKey(torrent)) return } - torrent.InProgressIDs.Add(REPAIR_SEMAPHORE) proceed := t.canCapacityHandle() // blocks for approx 45 minutes if active torrents are full @@ -158,28 +157,33 @@ func (t *TorrentManager) repair(torrent *Torrent) { assignedCount := 0 rarCount := 0 unassignedDownloads := make([]*realdebrid.Download, 0) + assignedLinks := make([]string, 0) torrent.UnassignedLinks.Each(func(link string) bool { unrestrict := t.UnrestrictUntilOk(link) - if unrestrict != nil { - // assign to a selected file - assigned := false - torrent.SelectedFiles.IterCb(func(_ string, file *File) { - // if strings.HasSuffix(file.Path, unrestrict.Filename) { - if file.Bytes == unrestrict.Filesize { - file.Link = unrestrict.Link - assigned = true - assignedCount++ - } - }) - if !assigned { - if strings.HasSuffix(unrestrict.Filename, ".rar") { - rarCount++ - } - unassignedDownloads = append(unassignedDownloads, unrestrict) + if unrestrict == nil { + return false + } + // assign to a selected file + assigned := false + torrent.SelectedFiles.IterCb(func(_ string, file *File) { + // if strings.HasSuffix(file.Path, unrestrict.Filename) { + if file.Bytes == unrestrict.Filesize { + file.Link = unrestrict.Link + assigned = true + assignedCount++ } + }) + if !assigned { + if strings.HasSuffix(unrestrict.Filename, ".rar") { + rarCount++ + } + unassignedDownloads = append(unassignedDownloads, unrestrict) + } else { + assignedLinks = append(assignedLinks, unrestrict.Link) } return false }) + torrent.UnassignedLinks = torrent.UnassignedLinks.Difference(mapset.NewSet(assignedLinks...)) if assignedCount > 0 { t.log.Infof("Assigned %d links to selected files for torrent %s", assignedCount, t.GetKey(torrent)) @@ -197,7 +201,7 @@ func (t *TorrentManager) repair(torrent *Torrent) { Bytes: unassigned.Filesize, Selected: 1, }, - Ended: torrent.LatestAdded, + Ended: torrent.Added, Link: unassigned.Link, } torrent.SelectedFiles.Set(unassigned.Filename, newFile) @@ -377,7 +381,7 @@ func (t *TorrentManager) markAsUnfixable(torrent *Torrent) { torrent.DownloadedIDs.Each(func(id string) bool { info, _ := infoCache.Get(id) info.Unfixable = true - t.writeTorrentToFile(id, info, false) + t.writeTorrentToFile(id, info) return false }) } diff --git a/internal/torrent/types.go b/internal/torrent/types.go index a2dad34..27d3f37 100644 --- a/internal/torrent/types.go +++ b/internal/torrent/types.go @@ -14,17 +14,17 @@ import ( var json = jsoniter.ConfigCompatibleWithStandardLibrary type Torrent struct { - Name string `json:"Name"` - OriginalName string `json:"OriginalName"` - Rename string `json:"Rename"` - Hash string `json:"Hash"` - SelectedFiles cmap.ConcurrentMap[string, *File] `json:"-"` - LatestAdded string `json:"LatestAdded"` - Unfixable bool `json:"Unfixable"` - DownloadedIDs mapset.Set[string] `json:"DownloadedIDs"` - InProgressIDs mapset.Set[string] `json:"InProgressIDs"` - UnassignedLinks mapset.Set[string] `json:"UnassignedLinks"` - BrokenLinks mapset.Set[string] `json:"BrokenLinks"` + Hash string `json:"Hash"` // immutable + Added string `json:"Added"` // immutable + UnassignedLinks mapset.Set[string] `json:"UnassignedLinks"` // immutable + DownloadedIDs mapset.Set[string] `json:"DownloadedIDs"` // immutable + InProgressIDs mapset.Set[string] `json:"InProgressIDs"` // immutable + Name string `json:"Name"` // immutable + OriginalName string `json:"OriginalName"` // immutable + Rename string `json:"Rename"` // modified over time + SelectedFiles cmap.ConcurrentMap[string, *File] `json:"-"` // modified over time + Unfixable bool `json:"Unfixable"` // modified over time + BrokenLinks mapset.Set[string] `json:"BrokenLinks"` // only relevant on repair Version string `json:"Version"` // only used for files } @@ -160,11 +160,11 @@ func (t *Torrent) ComputeBiggestFileSize() int64 { } func (t *Torrent) OlderThanDuration(duration time.Duration) bool { - latestAdded, err := time.Parse(time.RFC3339, t.LatestAdded) + added, err := time.Parse(time.RFC3339, t.Added) if err != nil { return false } - return time.Since(latestAdded) > duration + return time.Since(added) > duration } type File struct {