From 6a5bc79852b77ee247cd43ee241175f481d6e8aa Mon Sep 17 00:00:00 2001 From: Ben Sarmiento Date: Sun, 14 Jan 2024 12:37:37 +0100 Subject: [PATCH] Repair logic --- internal/torrent/manager.go | 2 ++ internal/torrent/refresh.go | 17 +++++++++++++++++ internal/torrent/repair.go | 37 ++++++++++++++++++++++++++++--------- pkg/realdebrid/types.go | 1 + 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/internal/torrent/manager.go b/internal/torrent/manager.go index 8f535c2..e496bfb 100644 --- a/internal/torrent/manager.go +++ b/internal/torrent/manager.go @@ -28,6 +28,7 @@ type TorrentManager struct { DownloadCache cmap.ConcurrentMap[string, *realdebrid.Download] DownloadMap cmap.ConcurrentMap[string, *realdebrid.Download] allAccessKeys mapset.Set[string] + forRepairs mapset.Set[string] latestState *LibraryState requiredVersion string workerPool *ants.Pool @@ -42,6 +43,7 @@ func NewTorrentManager(cfg config.ConfigInterface, api *realdebrid.RealDebrid, p Config: cfg, Api: api, allAccessKeys: mapset.NewSet[string](), + forRepairs: mapset.NewSet[string](), latestState: &LibraryState{}, requiredVersion: "11.01.2024", workerPool: p, diff --git a/internal/torrent/refresh.go b/internal/torrent/refresh.go index 113ed17..151ee35 100644 --- a/internal/torrent/refresh.go +++ b/internal/torrent/refresh.go @@ -37,12 +37,22 @@ func (t *TorrentManager) RefreshTorrents() []string { freshKeys := mapset.NewSet[string]() allTorrents, _ := t.DirectoryMap.Get(INT_ALL) + toReinsert := mapset.NewSet[string]() noInfoCount := 0 for info := range infoChan { if info == nil { noInfoCount++ continue } + torrentID := info.DownloadedIDs.ToSlice()[0] + if !info.AnyInProgress() && t.forRepairs.Contains(torrentID) { + // if it's 100% and it's a temp repair, remove it + t.Api.DeleteTorrent(torrentID) + toReinsert.Add(t.GetKey(info)) + infoChan <- nil + t.forRepairs.Remove(torrentID) + continue + } if !info.AnyInProgress() { freshKeys.Add(t.GetKey(info)) } @@ -54,6 +64,7 @@ func (t *TorrentManager) RefreshTorrents() []string { } } t.log.Infof("Compiled into %d torrents, %d were missing info", allTorrents.Count(), noInfoCount) + var updatedPaths []string // torrents yet to be assigned in a directory freshKeys.Difference(t.allAccessKeys).Each(func(accessKey string) bool { @@ -82,6 +93,12 @@ func (t *TorrentManager) RefreshTorrents() []string { return false }) + toReinsert.Each(func(accessKey string) bool { + torrent, _ := allTorrents.Get(accessKey) + t.reinsertTorrent(torrent, "") + return false + }) + return updatedPaths } diff --git a/internal/torrent/repair.go b/internal/torrent/repair.go index b7fcf5e..3eff8c6 100644 --- a/internal/torrent/repair.go +++ b/internal/torrent/repair.go @@ -14,7 +14,6 @@ import ( const ( EXPIRED_LINK_TOLERANCE_HOURS = 24 - REPAIR_SEMAPHORE = "semaphore" ) func (t *TorrentManager) RepairAll() { @@ -119,7 +118,6 @@ func (t *TorrentManager) Repair(torrent *Torrent) { _ = t.workerPool.Submit(func() { t.log.Infof("Repairing torrent %s", t.GetKey(torrent)) t.repair(torrent) - torrent.InProgressIDs.Remove(REPAIR_SEMAPHORE) t.log.Infof("Finished repairing torrent %s", t.GetKey(torrent)) }) } @@ -129,7 +127,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 if !proceed { @@ -249,8 +246,10 @@ func (t *TorrentManager) repair(torrent *Torrent) { } func (t *TorrentManager) reinsertTorrent(torrent *Torrent, brokenFiles string) bool { - oldTorrentIDs := make([]string, 0) // broken files means broken links + + oldTorrentIDs := make([]string, 0) + // if brokenFiles is not provided if brokenFiles == "" { // only replace the torrent if we are reinserting all files @@ -294,7 +293,17 @@ func (t *TorrentManager) reinsertTorrent(torrent *Torrent, brokenFiles string) b return false } - if info.Status == "magnet_error" || info.Status == "error" || info.Status == "virus" || info.Status == "dead" { + // documented status: magnet_error, magnet_conversion, waiting_files_selection, queued, downloading, downloaded, error, virus, compressing, uploading, dead + okStatuses := []string{"magnet_conversion", "waiting_files_selection", "queued", "downloading", "downloaded", "uploading"} + // not compressing because we need playable files + isOkStatus := false + for _, status := range okStatuses { + if info.Status == status { + isOkStatus = true + break + } + } + if !isOkStatus { t.log.Warnf("The redownloaded torrent id=%s is in error state: %s", newTorrentID, info.Status) t.Api.DeleteTorrent(newTorrentID) return false @@ -302,8 +311,13 @@ func (t *TorrentManager) reinsertTorrent(torrent *Torrent, brokenFiles string) b 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) - for _, id := range oldTorrentIDs { - t.Api.DeleteTorrent(id) + t.forRepairs.Add(newTorrentID) + if len(oldTorrentIDs) > 0 { + for _, id := range oldTorrentIDs { + t.Api.DeleteTorrent(id) + } + } else { + t.forRepairs.Add(newTorrentID) } return true } @@ -316,8 +330,13 @@ func (t *TorrentManager) reinsertTorrent(torrent *Torrent, brokenFiles string) b } t.log.Infof("Repair successful id=%s", newTorrentID) - for _, id := range oldTorrentIDs { - t.Api.DeleteTorrent(id) + t.forRepairs.Add(newTorrentID) + if len(oldTorrentIDs) > 0 { + for _, id := range oldTorrentIDs { + t.Api.DeleteTorrent(id) + } + } else { + t.forRepairs.Add(newTorrentID) } return true } diff --git a/pkg/realdebrid/types.go b/pkg/realdebrid/types.go index be13262..2631ef3 100644 --- a/pkg/realdebrid/types.go +++ b/pkg/realdebrid/types.go @@ -43,6 +43,7 @@ func (d *Download) UnmarshalJSON(data []byte) error { type Torrent struct { ID string `json:"id"` Name string `json:"filename"` + Hash string `json:"hash"` Progress int `json:"-"` Status string `json:"status"` Links []string `json:"links"`