Ensure only 1 instance is being fixed

This commit is contained in:
Ben Sarmiento
2024-01-19 01:06:18 +01:00
parent 4b08a8efdf
commit bacee5178a
2 changed files with 23 additions and 23 deletions

View File

@@ -27,8 +27,8 @@ type TorrentManager struct {
DirectoryMap cmap.ConcurrentMap[string, cmap.ConcurrentMap[string, *Torrent]] // directory -> accessKey -> Torrent DirectoryMap cmap.ConcurrentMap[string, cmap.ConcurrentMap[string, *Torrent]] // directory -> accessKey -> Torrent
DownloadCache cmap.ConcurrentMap[string, *realdebrid.Download] DownloadCache cmap.ConcurrentMap[string, *realdebrid.Download]
DownloadMap cmap.ConcurrentMap[string, *realdebrid.Download] DownloadMap cmap.ConcurrentMap[string, *realdebrid.Download]
Repairs cmap.ConcurrentMap[string, bool]
onlyForRepair cmap.ConcurrentMap[string, *Torrent] onlyForRepair cmap.ConcurrentMap[string, *Torrent]
Repairs mapset.Set[string]
allAccessKeys mapset.Set[string] allAccessKeys mapset.Set[string]
latestState *LibraryState latestState *LibraryState
requiredVersion string requiredVersion string
@@ -48,7 +48,7 @@ func NewTorrentManager(cfg config.ConfigInterface, api *realdebrid.RealDebrid, w
DownloadCache: cmap.New[*realdebrid.Download](), DownloadCache: cmap.New[*realdebrid.Download](),
DownloadMap: cmap.New[*realdebrid.Download](), DownloadMap: cmap.New[*realdebrid.Download](),
onlyForRepair: cmap.New[*Torrent](), onlyForRepair: cmap.New[*Torrent](),
Repairs: cmap.New[bool](), Repairs: mapset.NewSet[string](),
allAccessKeys: mapset.NewSet[string](), allAccessKeys: mapset.NewSet[string](),
latestState: &LibraryState{}, latestState: &LibraryState{},
requiredVersion: "11.01.2024", requiredVersion: "11.01.2024",

View File

@@ -67,7 +67,7 @@ func (t *TorrentManager) repairAll() {
} }
t.log.Debugf("Found %d torrents that are no longer cached", uncachedCount) t.log.Debugf("Found %d torrents that are no longer cached", uncachedCount)
var toRepair []*Torrent toRepair := mapset.NewSet[*Torrent]()
allTorrents.IterCb(func(_ string, torrent *Torrent) { allTorrents.IterCb(func(_ string, torrent *Torrent) {
if torrent.AnyInProgress() || torrent.Unrepairable { if torrent.AnyInProgress() || torrent.Unrepairable {
return return
@@ -83,20 +83,20 @@ func (t *TorrentManager) repairAll() {
// check 2: for broken files // check 2: for broken files
hasBrokenFiles := false hasBrokenFiles := false
torrent.SelectedFiles.IterCb(func(_ string, file *File) { torrent.SelectedFiles.IterCb(func(_ string, file *File) {
if file.Link == "repair" || file.Link == "" { if !strings.HasPrefix(file.Link, "http") && file.Link != "unselect" {
hasBrokenFiles = true hasBrokenFiles = true
} }
}) })
if !isCached || hasBrokenFiles || torrent.UnassignedLinks.Cardinality() > 0 { if !isCached || hasBrokenFiles || torrent.UnassignedLinks.Cardinality() > 0 {
toRepair = append(toRepair, torrent) toRepair.Add(torrent)
} }
}) })
t.log.Debugf("Found %d broken torrents to repair in total", len(toRepair)) t.log.Debugf("Found %d broken torrents to repair in total", toRepair.Cardinality())
for i := range toRepair { toRepair.Each(func(torrent *Torrent) bool {
torrent := toRepair[i]
t.Repair(torrent) t.Repair(torrent)
} return false
})
} }
func (t *TorrentManager) Repair(torrent *Torrent) { func (t *TorrentManager) Repair(torrent *Torrent) {
@@ -104,11 +104,11 @@ func (t *TorrentManager) Repair(torrent *Torrent) {
t.log.Warnf("Torrent %s is unfixable, skipping repair", t.GetKey(torrent)) t.log.Warnf("Torrent %s is unfixable, skipping repair", t.GetKey(torrent))
return return
} }
if repairing, ok := t.Repairs.Get(t.GetKey(torrent)); ok && repairing { if t.Repairs.Contains(t.GetKey(torrent)) {
t.log.Warnf("Torrent %s is already being repaired, skipping repair", t.GetKey(torrent)) t.log.Warnf("Torrent %s is already being repaired, skipping repair", t.GetKey(torrent))
return return
} }
t.Repairs.Set(t.GetKey(torrent), true) t.Repairs.Add(t.GetKey(torrent))
// save the broken files to the file cache // save the broken files to the file cache
infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE) infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE)
torrent.DownloadedIDs.Each(func(id string) bool { torrent.DownloadedIDs.Each(func(id string) bool {
@@ -116,7 +116,7 @@ func (t *TorrentManager) Repair(torrent *Torrent) {
info.SelectedFiles.IterCb(func(_ string, file *File) { info.SelectedFiles.IterCb(func(_ string, file *File) {
torrent.BrokenLinks.Each(func(link string) bool { torrent.BrokenLinks.Each(func(link string) bool {
if file.Link == link { if file.Link == link {
file.Link = "repair" file.Link = ""
} }
return file.Link == link return file.Link == link
}) })
@@ -125,14 +125,13 @@ func (t *TorrentManager) Repair(torrent *Torrent) {
return false return false
}) })
_ = t.workerPool.Submit(func() { _ = t.workerPool.Submit(func() {
t.log.Infof("Repairing torrent %s", t.GetKey(torrent))
t.repair(torrent) t.repair(torrent)
t.Repairs.Remove(t.GetKey(torrent)) t.Repairs.Remove(t.GetKey(torrent))
t.log.Infof("Finished repairing torrent %s", t.GetKey(torrent))
}) })
} }
func (t *TorrentManager) repair(torrent *Torrent) { func (t *TorrentManager) repair(torrent *Torrent) {
t.log.Infof("Attempting repair for torrent %s", t.GetKey(torrent))
if torrent.AnyInProgress() { if torrent.AnyInProgress() {
t.log.Infof("Torrent %s is in progress, skipping repair until download is done", t.GetKey(torrent)) t.log.Infof("Torrent %s is in progress, skipping repair until download is done", t.GetKey(torrent))
return return
@@ -192,6 +191,7 @@ func (t *TorrentManager) repair(torrent *Torrent) {
t.log.Warnf("Torrent %s is rar'ed and we cannot repair it, deleting it as configured", t.GetKey(torrent)) 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) t.Delete(t.GetKey(torrent), true)
} else { } else {
t.log.Warnf("Torrent %s is rar'ed and we cannot repair it, skipping repair", t.GetKey(torrent))
newUnassignedLinks.IterCb(func(_ string, unassigned *realdebrid.Download) { newUnassignedLinks.IterCb(func(_ string, unassigned *realdebrid.Download) {
if unassigned == nil { if unassigned == nil {
return return
@@ -220,24 +220,24 @@ func (t *TorrentManager) repair(torrent *Torrent) {
t.log.Debugf("During repair, zurg found %d broken files for torrent %s", len(brokenFiles), t.GetKey(torrent)) t.log.Debugf("During repair, zurg found %d broken files for torrent %s", len(brokenFiles), t.GetKey(torrent))
// first solution: reinsert and see if the broken file is now working // first solution: reinsert and see if the broken file is now working
t.log.Debugf("Repair_try#1: Trying to redownload torrent %s to repair it", t.GetKey(torrent)) t.log.Debugf("repair_method#1: Trying to redownload torrent %s to repair it", t.GetKey(torrent))
info, err := t.redownloadTorrent(torrent, "") info, err := t.redownloadTorrent(torrent, "")
if err != nil { if err != nil {
t.log.Warnf("Cannot repair torrent %s", t.GetKey(torrent)) t.log.Warnf("Cannot repair torrent %s", t.GetKey(torrent))
} else if info.Progress != 100 || (info.Progress == 100 && !t.isStillBroken(info, brokenFiles)) { } else if info.Progress != 100 || (info.Progress == 100 && !t.isStillBroken(info, brokenFiles)) {
t.log.Infof("Successfully repaired torrent %s", t.GetKey(torrent)) t.log.Infof("Successfully repaired torrent %s using repair_method#1", t.GetKey(torrent))
return return
} }
// second solution: add only the broken files // second solution: add only the broken files
if len(brokenFiles) > 0 { if len(brokenFiles) > 0 {
t.log.Infof("Repair_try#2: Redownloading %dof%d broken files for torrent %s", len(brokenFiles), torrent.SelectedFiles.Count(), t.GetKey(torrent)) t.log.Infof("repair_method#2: Redownloading %dof%d broken files for torrent %s", len(brokenFiles), torrent.SelectedFiles.Count(), t.GetKey(torrent))
brokenFileIDs := strings.Join(getFileIDs(brokenFiles), ",") brokenFileIDs := strings.Join(getFileIDs(brokenFiles), ",")
_, err := t.redownloadTorrent(torrent, brokenFileIDs) _, err := t.redownloadTorrent(torrent, brokenFileIDs)
if err != nil { if err != nil {
t.log.Warnf("Cannot repair torrent %s", t.GetKey(torrent)) t.log.Warnf("Cannot repair torrent %s", t.GetKey(torrent))
} else { } else {
t.log.Infof("Successfully repaired torrent %s", t.GetKey(torrent)) t.log.Infof("Successfully repaired torrent %s using repair_method#2", t.GetKey(torrent))
} }
} else { } else {
t.log.Warnf("Torrent %s has no broken files to repair", t.GetKey(torrent)) t.log.Warnf("Torrent %s has no broken files to repair", t.GetKey(torrent))
@@ -286,7 +286,7 @@ func (t *TorrentManager) redownloadTorrent(torrent *Torrent, brokenFiles string)
info, err := t.Api.GetTorrentInfo(newTorrentID) info, err := t.Api.GetTorrentInfo(newTorrentID)
if err != nil { if err != nil {
t.Api.DeleteTorrent(newTorrentID) t.Api.DeleteTorrent(newTorrentID)
return nil, fmt.Errorf("cannot get info on redownloaded torrent id=%s : %v", newTorrentID, err) return nil, fmt.Errorf("cannot get info on redownloaded torrent %s (id=%s) : %v", t.GetKey(torrent), newTorrentID, err)
} }
// documented status: magnet_error, magnet_conversion, waiting_files_selection, queued, downloading, downloaded, error, virus, compressing, uploading, dead // documented status: magnet_error, magnet_conversion, waiting_files_selection, queued, downloading, downloaded, error, virus, compressing, uploading, dead
@@ -301,11 +301,11 @@ func (t *TorrentManager) redownloadTorrent(torrent *Torrent, brokenFiles string)
} }
if !isOkStatus { if !isOkStatus {
t.Api.DeleteTorrent(newTorrentID) t.Api.DeleteTorrent(newTorrentID)
return nil, fmt.Errorf("the redownloaded torrent id=%s is in error state: %s", newTorrentID, info.Status) return nil, fmt.Errorf("the redownloaded torrent %s (id=%s) is in error state: %s", t.GetKey(torrent), newTorrentID, info.Status)
} }
if info.Progress != 100 { if info.Progress != 100 {
t.log.Infof("Torrent id=%s is not cached anymore so we have to wait until completion (this should fix the issue already)", info.ID) t.log.Infof("Torrent %s (id=%s) is not cached anymore so we have to wait until completion (this should fix the issue already)", t.GetKey(torrent), info.ID)
if len(oldTorrentIDs) > 0 { if len(oldTorrentIDs) > 0 {
// only triggered when brokenFiles == "" // only triggered when brokenFiles == ""
for _, id := range oldTorrentIDs { for _, id := range oldTorrentIDs {
@@ -320,10 +320,10 @@ func (t *TorrentManager) redownloadTorrent(torrent *Torrent, brokenFiles string)
brokenCount := len(strings.Split(brokenFiles, ",")) brokenCount := len(strings.Split(brokenFiles, ","))
if len(info.Links) != brokenCount { if len(info.Links) != brokenCount {
t.Api.DeleteTorrent(newTorrentID) t.Api.DeleteTorrent(newTorrentID)
return nil, fmt.Errorf("it did not fix the issue for id=%s, only got %d files but we need %d, undoing", info.ID, len(info.Links), brokenCount) return nil, fmt.Errorf("it did not fix the issue for %s (id=%s), only got %d files but we need %d, undoing", t.GetKey(torrent), info.ID, len(info.Links), brokenCount)
} }
t.log.Infof("Redownload successful id=%s", newTorrentID) t.log.Infof("Redownload successful %s (id=%s)", t.GetKey(torrent), newTorrentID)
if len(oldTorrentIDs) > 0 { if len(oldTorrentIDs) > 0 {
// only triggered when brokenFiles == "" // only triggered when brokenFiles == ""
for _, id := range oldTorrentIDs { for _, id := range oldTorrentIDs {