diff --git a/internal/torrent/repair.go b/internal/torrent/repair.go index ae5a2ef..3bada63 100644 --- a/internal/torrent/repair.go +++ b/internal/torrent/repair.go @@ -162,9 +162,8 @@ func (t *TorrentManager) repair(torrent *Torrent) { t.log.Infof("Started repair process for torrent %s (ids=%v)", t.GetKey(torrent), torrentIDs) // handle torrents with incomplete links for selected files - // torrent can be rare'ed by RD, so we need to check for that + // torrent can be rar'ed by RD, so we need to check for that if !t.assignUnassignedLinks(torrent) { - t.log.Debugf("Ending repair process early for torrent %s", t.GetKey(torrent)) return } @@ -174,7 +173,8 @@ func (t *TorrentManager) repair(torrent *Torrent) { t.log.Debugf("Torrent %s has %d broken files (ids=%s; total is %d), repairing by redownloading", t.GetKey(torrent), len(brokenFiles), brokenFileIDs, torrent.SelectedFiles.Count()) // first step: redownload the whole torrent - info, err := t.redownloadTorrent(torrent, "") // reinsert the torrent, passing "" + + info, err := t.redownloadTorrent(torrent, "") // reinsert the whole torrent, passing "" if info != nil && info.Progress != 100 { t.log.Infof("Torrent %s (files=%s) is still in progress after redownloading but it should be repaired once done", t.GetKey(torrent), brokenFileIDs) return @@ -247,17 +247,20 @@ func (t *TorrentManager) repair(torrent *Torrent) { func (t *TorrentManager) assignUnassignedLinks(torrent *Torrent) bool { unassignedTotal := torrent.UnassignedLinks.Cardinality() t.log.Infof("Trying to assign %d links to the %d selected of incomplete torrent %s", unassignedTotal, torrent.SelectedFiles.Count(), t.GetKey(torrent)) + // handle torrents with incomplete links for selected files assignedCount := 0 expiredCount := 0 rarCount := 0 + unassignedCount := 0 newUnassignedLinks := cmap.New[*realdebrid.Download]() + torrent.UnassignedLinks.Each(func(link string) bool { // unrestrict each unassigned link that was filled out during torrent init unrestrict := t.UnrestrictLinkUntilOk(link) if unrestrict == nil { expiredCount++ - return false // next + return false // next unassigned link } // try to assign to a selected file @@ -266,7 +269,7 @@ func (t *TorrentManager) assignUnassignedLinks(torrent *Torrent) bool { // base it on size because why not? if !assigned && file.State.Is("broken_file") && ((unrestrict.Filesize > 1_000_000 && file.Bytes == unrestrict.Filesize) || strings.HasSuffix(strings.ToLower(file.Path), strings.ToLower(unrestrict.Filename))) { file.Link = link - err := file.State.Event(context.Background(), "repair_done_file") + err := file.State.Event(context.Background(), "repair_file") if err != nil { t.log.Errorf("Failed to mark file %s as repaired: %v", file.Path, err) return @@ -286,20 +289,23 @@ func (t *TorrentManager) assignUnassignedLinks(torrent *Torrent) bool { newUnassignedLinks.Set(link, unrestrict) } - processedCount := assignedCount + newUnassignedLinks.Count() + expiredCount - if processedCount%10 == 0 { + processedCount := assignedCount + unassignedCount + expiredCount + if processedCount%10 == 0 || processedCount == unassignedTotal { t.log.Infof("Processed %d out of %d links (%d expired) to broken torrent %s", processedCount, unassignedTotal, expiredCount, t.GetKey(torrent)) } - return false + return false // next unassigned link }) - t.log.Debugf("Assigned %d links to the %d selected files of torrent %s", assignedCount, torrent.SelectedFiles.Count(), t.GetKey(torrent)) - t.log.Debugf("Expired %d links to the %d selected files of torrent %s", expiredCount, torrent.SelectedFiles.Count(), t.GetKey(torrent)) - t.log.Debugf("Rar'ed %d links to the %d selected files of torrent %s", rarCount, torrent.SelectedFiles.Count(), t.GetKey(torrent)) - t.log.Debugf("Unassigned %d links to the %d selected files of torrent %s", newUnassignedLinks.Count(), torrent.SelectedFiles.Count(), t.GetKey(torrent)) + // magnet:?xt=urn:btih:ba8720dde2472e650a87efbb78efb4fbcea3f7ee + // empty/reset the unassigned links as we have assigned them already + if unassignedTotal > 0 { + torrent.UnassignedLinks = mapset.NewSet[string]() + t.writeTorrentToFile(torrent) + } + + // this is a rar'ed torrent, nothing we can do if assignedCount == 0 && rarCount == 1 { - // this is a rar'ed torrent, nothing we can do if t.Config.ShouldDeleteRarFiles() { t.log.Warnf("Torrent %s is rar'ed and we cannot repair it, deleting it as configured", t.GetKey(torrent)) t.Delete(t.GetKey(torrent), true) @@ -326,13 +332,7 @@ func (t *TorrentManager) assignUnassignedLinks(torrent *Torrent) bool { t.markAsUnfixable(torrent, "rar'ed by RD") t.markAsUnplayable(torrent, "rar'ed by RD") } - return false - } - - // empty/reset the unassigned links as we have assigned them already - if torrent.UnassignedLinks.Cardinality() > 0 { - torrent.UnassignedLinks = mapset.NewSet[string]() - t.writeTorrentToFile(torrent) + return false // end repair } return true @@ -489,6 +489,8 @@ func (t *TorrentManager) markAsUnplayable(torrent *Torrent, reason string) { t.log.Errorf("Failed to mark torrent %s as unplayable: %v", t.GetKey(torrent), err) return } + t.writeTorrentToFile(torrent) + // reassign to unplayable torrents directory t.DirectoryMap.IterCb(func(directory string, torrents cmap.ConcurrentMap[string, *Torrent]) { torrents.Remove(t.GetKey(torrent)) })