diff --git a/internal/torrent/bins.go b/internal/torrent/bins.go index 756cd0b..7c356e1 100644 --- a/internal/torrent/bins.go +++ b/internal/torrent/bins.go @@ -124,7 +124,7 @@ func (t *TorrentManager) binOnceDone(torrentId string) bool { } hasError := false - t.OnceDoneBin.Each(func(entry string) bool { + t.OnceDoneBin.Clone().Each(func(entry string) bool { if strings.Contains(entry, specialCase) { idToDelete := strings.Split(entry, "-")[1] if err := t.api.DeleteTorrent(idToDelete); err != nil { diff --git a/internal/torrent/delete.go b/internal/torrent/delete.go index 7bc3ab4..aa83f9c 100644 --- a/internal/torrent/delete.go +++ b/internal/torrent/delete.go @@ -24,12 +24,11 @@ func (t *TorrentManager) Delete(accessKey string, deleteInRD bool) { allTorrents, _ := t.DirectoryMap.Get(INT_ALL) if torrent, ok := allTorrents.Get(accessKey); ok { if deleteInRD { - torrent.DownloadedIDs.Each(func(torrentID string) bool { + torrent.DownloadedIDs.Clone().Each(func(torrentID string) bool { t.log.Debugf("Deleting torrent %s (id=%s) in RD", accessKey, torrentID) t.api.DeleteTorrent(torrentID) t.deleteInfoFile(torrentID) return false - }) } } diff --git a/internal/torrent/manager.go b/internal/torrent/manager.go index a80b476..b755c43 100644 --- a/internal/torrent/manager.go +++ b/internal/torrent/manager.go @@ -46,7 +46,8 @@ type TorrentManager struct { DumpTrigger chan struct{} AnalyzeTrigger chan struct{} - latestState *LibraryState + latestState *LibraryState + inProgressHashes mapset.Set[string] repairTrigger chan *Torrent repairQueue mapset.Set[*Torrent] @@ -221,7 +222,7 @@ func (t *TorrentManager) writeTorrentToFile(torrent *Torrent) { return } - t.log.Debugf("Saved torrent %s to file", t.GetKey(torrent)) + // t.log.Debugf("Saved torrent %s to file", t.GetKey(torrent)) } func (t *TorrentManager) applyMediaInfoDetails(torrent *Torrent) { @@ -269,11 +270,6 @@ func (t *TorrentManager) readTorrentFromFile(filePath string) *Torrent { return torrent } -func (t *TorrentManager) deleteTorrentFile(filename string) { - filePath := "data/" + filename + ".zurgtorrent" - _ = os.Remove(filePath) -} - /// end torrent functions /// info functions diff --git a/internal/torrent/refresh.go b/internal/torrent/refresh.go index 0cfe546..ec8ea27 100644 --- a/internal/torrent/refresh.go +++ b/internal/torrent/refresh.go @@ -15,7 +15,12 @@ import ( cmap "github.com/orcaman/concurrent-map/v2" ) +func inProgressStatus(status string) bool { + return status == "downloading" || status == "uploading" || status == "queued" || status == "compressing" +} + func (t *TorrentManager) refreshTorrents() []string { + t.inProgressHashes = mapset.NewSet[string]() instances, _, err := t.api.GetTorrents(false) if err != nil { t.log.Warnf("Cannot get torrents: %v", err) @@ -40,6 +45,9 @@ func (t *TorrentManager) refreshTorrents() []string { if t.binImmediately(instances[idx].ID) || t.binOnceDoneErrorCheck(instances[idx].ID, instances[idx].Status) || instances[idx].Progress != 100 { + if inProgressStatus(instances[idx].Status) { + t.inProgressHashes.Add(instances[idx].Hash) + } mergeChan <- nil return } diff --git a/internal/torrent/repair.go b/internal/torrent/repair.go index 4a523bd..fe445cd 100644 --- a/internal/torrent/repair.go +++ b/internal/torrent/repair.go @@ -154,7 +154,7 @@ func (t *TorrentManager) Repair(torrent *Torrent, wg *sync.WaitGroup) { return } - if err := torrent.State.Event(context.Background(), "repair_torrent"); err != nil { + if err := torrent.State.Event(context.Background(), "repair_torrent"); err != nil && t.inProgressHashes.Contains(torrent.Hash) { t.repairLog.Errorf("Failed to mark torrent %s as under repair: %v", t.GetKey(torrent), err) return } @@ -191,7 +191,7 @@ func (t *TorrentManager) repair(torrent *Torrent) { torrent.State.Event(context.Background(), "mark_as_repaired") t.repairLog.Infof("Successfully repaired torrent %s by redownloading whole torrent", t.GetKey(torrent)) // delete the torrents it replaced - torrent.DownloadedIDs.Each(func(torrentID string) bool { + torrent.DownloadedIDs.Clone().Each(func(torrentID string) bool { if torrentID != info.ID { t.setXToBinOnceYDone(torrentID, info.ID) } @@ -201,7 +201,7 @@ func (t *TorrentManager) repair(torrent *Torrent) { } else if info != nil && info.Progress != 100 { t.repairLog.Infof("Torrent %s is still in progress after redownloading whole torrent but it should be repaired once done", t.GetKey(torrent)) // once info.ID is done, we can delete the old torrent - torrent.DownloadedIDs.Each(func(torrentID string) bool { + torrent.DownloadedIDs.Clone().Each(func(torrentID string) bool { if torrentID != info.ID { t.setXToBinOnceYDone(torrentID, info.ID) } @@ -272,8 +272,9 @@ func (t *TorrentManager) assignLinks(torrent *Torrent) bool { rarCount := 0 unassignedCount := 0 newUnassignedLinks := cmap.New[*realdebrid.Download]() + var assignedLinks []string - torrent.UnassignedLinks.Each(func(link string) bool { + torrent.UnassignedLinks.Clone().Each(func(link string) bool { // unrestrict each unassigned link that was filled out during torrent init unrestrict := t.UnrestrictLinkUntilOk(link, true) if unrestrict == nil { @@ -287,6 +288,7 @@ func (t *TorrentManager) assignLinks(torrent *Torrent) bool { // base it on size because why not? if !assigned && file.State.Is("broken_file") && file.Bytes == unrestrict.Filesize && strings.HasSuffix(strings.ToLower(file.Path), strings.ToLower(unrestrict.Filename)) { file.Link = link + assignedLinks = append(assignedLinks, link) if strings.HasPrefix(file.Link, "https://real-debrid.com/d/") { file.Link = file.Link[0:39] } @@ -314,6 +316,12 @@ func (t *TorrentManager) assignLinks(torrent *Torrent) bool { processedCount := assignedCount + unassignedCount + expiredCount if processedCount%10 == 0 || processedCount == unassignedTotal { + // save each progress + for _, assignedLink := range assignedLinks { + torrent.UnassignedLinks.Remove(assignedLink) + } + t.writeTorrentToFile(torrent) + t.repairLog.Infof("Processed %d out of %d links (%d expired) to broken torrent %s", processedCount, unassignedTotal, expiredCount, t.GetKey(torrent)) }