diff --git a/internal/handlers/home.go b/internal/handlers/home.go index 121c766..f3efbe6 100644 --- a/internal/handlers/home.go +++ b/internal/handlers/home.go @@ -206,21 +206,13 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { Can Repair %t - - Repair Every... - %d mins - Action to take on RAR'ed torrents %s - API Timeout - %d secs - - - Download Timeout - %d secs + Repair Every... + %d mins Refresh Download Mount Every... @@ -230,6 +222,14 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { Dump Torrents Every... %d mins + + API Timeout + %d secs + + + Download Timeout + %d secs + Rate Limit Sleep for... %d secs @@ -286,6 +286,9 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) {
+
+ +
@@ -331,12 +334,12 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { response.Config.EnableRetainRDTorrentName(), response.Config.EnableRetainFolderNameExtension(), response.Config.EnableRepair(), - response.Config.GetRepairEveryMins(), response.Config.GetRarAction(), - response.Config.GetApiTimeoutSecs(), - response.Config.GetDownloadTimeoutSecs(), + response.Config.GetRepairEveryMins(), response.Config.GetDownloadsEveryMins(), response.Config.GetDumpTorrentsEveryMins(), + response.Config.GetApiTimeoutSecs(), + response.Config.GetDownloadTimeoutSecs(), response.Config.GetRateLimitSleepSecs(), response.Config.GetRetriesUntilFailed(), response.Config.GetNetworkBufferSize(), @@ -360,7 +363,7 @@ func (zr *Handlers) handleRebootWorkerPool(resp http.ResponseWriter, req *http.R func (zr *Handlers) handleRebootRefreshWorker(resp http.ResponseWriter, req *http.Request) { resp.Header().Set("Refresh", "2; url=/") - zr.torMgr.RefreshKillSwitch <- struct{}{} + zr.torMgr.RefreshWorkerKillSwitch <- struct{}{} zr.torMgr.StartRefreshJob() zr.log.Infof("Rebooted refresh worker") fmt.Fprint(resp, "Rebooting refresh worker...") @@ -368,7 +371,7 @@ func (zr *Handlers) handleRebootRefreshWorker(resp http.ResponseWriter, req *htt func (zr *Handlers) handleRebootRepairWorker(resp http.ResponseWriter, req *http.Request) { resp.Header().Set("Refresh", "2; url=/") - zr.torMgr.RepairKillSwitch <- struct{}{} + zr.torMgr.RepairWorkerKillSwitch <- struct{}{} zr.torMgr.StartRepairJob() zr.log.Infof("Rebooted repair worker") fmt.Fprint(resp, "Rebooting repair worker...") @@ -395,6 +398,13 @@ func (zr *Handlers) handleAnalyzeTorrents(resp http.ResponseWriter, req *http.Re fmt.Fprint(resp, "Analyzing all torrents...") } +func (zr *Handlers) handleTriggerRepairAll(resp http.ResponseWriter, req *http.Request) { + resp.Header().Set("Refresh", "2; url=/") + zr.torMgr.RepairAllTrigger <- struct{}{} + zr.log.Infof("Triggered repair of all torrents") + fmt.Fprint(resp, "Repairing all torrents...") +} + func bToMb(b uint64) uint64 { return b / 1024 / 1024 } diff --git a/internal/handlers/router.go b/internal/handlers/router.go index 35de821..0cc70be 100644 --- a/internal/handlers/router.go +++ b/internal/handlers/router.go @@ -56,6 +56,7 @@ func AttachHandlers(router *chi.Mux, downloader *universal.Downloader, torMgr *t router.Post("/downloads/remount", hs.handleRemountDownloads) router.Post("/torrents/dump", hs.handleDumpTorrents) router.Post("/torrents/analyze", hs.handleAnalyzeTorrents) + router.Post("/torrents/repair", hs.handleTriggerRepairAll) // version router.Get(fmt.Sprintf("/{mountType}/%s", version.FILE), hs.handleVersionFile) router.Head(fmt.Sprintf("/{mountType}/%s", version.FILE), hs.handleCheckVersionFile) diff --git a/internal/torrent/bins.go b/internal/torrent/bins.go index bcf6381..da5774f 100644 --- a/internal/torrent/bins.go +++ b/internal/torrent/bins.go @@ -134,7 +134,7 @@ func (t *TorrentManager) binOnceDoneErrorCheck(torrentId, status string) bool { if status == "downloading" || status == "downloaded" || status == "uploading" || status == "queued" || status == "compressing" || status == "waiting_files_selection" { return false } - t.repairLog.Errorf("Bin: error status=%s, checking if %s should be deleted", status, torrentId) + t.repairLog.Infof("Bin: error status=%s, checking if %s should be deleted", status, torrentId) return t.binOnceDone(torrentId, true) } diff --git a/internal/torrent/manager.go b/internal/torrent/manager.go index 50d7876..1b3dcf5 100644 --- a/internal/torrent/manager.go +++ b/internal/torrent/manager.go @@ -39,11 +39,12 @@ type TorrentManager struct { RootNode *fs.FileNode - RefreshKillSwitch chan struct{} - RepairKillSwitch chan struct{} - RemountTrigger chan struct{} - DumpTrigger chan struct{} - AnalyzeTrigger chan struct{} + RefreshWorkerKillSwitch chan struct{} + RepairWorkerKillSwitch chan struct{} + RemountTrigger chan struct{} + RepairAllTrigger chan struct{} + DumpTrigger chan struct{} + AnalyzeTrigger chan struct{} latestState *LibraryState inProgressHashes mapset.Set[string] @@ -76,11 +77,12 @@ func NewTorrentManager(cfg config.ConfigInterface, api *realdebrid.RealDebrid, w RootNode: fs.NewFileNode("root", true), - RefreshKillSwitch: make(chan struct{}, 1), - RepairKillSwitch: make(chan struct{}, 1), - RemountTrigger: make(chan struct{}, 1), - DumpTrigger: make(chan struct{}, 1), - AnalyzeTrigger: make(chan struct{}, 1), + RefreshWorkerKillSwitch: make(chan struct{}, 1), + RepairWorkerKillSwitch: make(chan struct{}, 1), + RemountTrigger: make(chan struct{}, 1), + // RepairAllTrigger: make(chan struct{}, 1), // initialized in repair.go + DumpTrigger: make(chan struct{}, 1), + AnalyzeTrigger: make(chan struct{}, 1), latestState: &LibraryState{log: log}, } diff --git a/internal/torrent/refresh.go b/internal/torrent/refresh.go index bb73169..ba15973 100644 --- a/internal/torrent/refresh.go +++ b/internal/torrent/refresh.go @@ -152,7 +152,7 @@ func (t *TorrentManager) StartRefreshJob() { t.refreshTorrents(false) t.log.Info("Finished refreshing torrents") - case <-t.RefreshKillSwitch: + case <-t.RefreshWorkerKillSwitch: t.log.Info("Stopping periodic refresh job") return } diff --git a/internal/torrent/repair.go b/internal/torrent/repair.go index 46491b9..393cbd8 100644 --- a/internal/torrent/repair.go +++ b/internal/torrent/repair.go @@ -26,6 +26,7 @@ func (t *TorrentManager) StartRepairJob() { } t.repairTrigger = make(chan *Torrent) t.repairQueue = mapset.NewSet[*Torrent]() + t.RepairAllTrigger = make(chan struct{}) // there is 1 repair worker, with max 1 blocking task t.workerPool.Submit(func() { t.repairLog.Debug("Starting periodic repair job") @@ -36,10 +37,12 @@ func (t *TorrentManager) StartRepairJob() { select { case <-repairTicker.C: t.invokeRepair(nil) + case <-t.RepairAllTrigger: + t.invokeRepair(nil) case torrent := <-t.repairTrigger: // On-demand trigger with a specific torrent t.invokeRepair(torrent) - case <-t.RepairKillSwitch: + case <-t.RepairWorkerKillSwitch: t.repairLog.Info("Stopping periodic repair job") return } @@ -76,15 +79,19 @@ func (t *TorrentManager) invokeRepair(torrent *Torrent) { // TriggerRepair allows an on-demand repair to be initiated. func (t *TorrentManager) TriggerRepair(torrent *Torrent) { + if !t.Config.EnableRepair() { + if torrent != nil { + t.repairLog.Warnf("Repair is disabled, skipping repair for torrent %s", t.GetKey(torrent)) + } else { + t.repairLog.Warn("Repair is disabled, skipping repair") + } + return + } if torrent != nil { if err := torrent.State.Event(context.Background(), "break_torrent"); err != nil { // t.repairLog.Errorf("Failed to mark torrent %s as broken: %v", t.GetKey(torrent), err) return } - if !t.Config.EnableRepair() { - t.repairLog.Warnf("Repair is disabled, skipping repair for torrent %s", t.GetKey(torrent)) - return - } } t.repairTrigger <- torrent }