From 4c9b54c01ce6d5b795bf1cbed689d8db4818ba72 Mon Sep 17 00:00:00 2001 From: Ben Sarmiento Date: Wed, 31 Jan 2024 18:08:48 +0100 Subject: [PATCH] Fix possible issues --- Dockerfile | 4 +-- internal/torrent/latestState.go | 48 ++++++++------------------------ internal/torrent/manager.go | 2 +- internal/torrent/refresh.go | 18 +++++++----- internal/torrent/repair.go | 34 +++++++++++++--------- internal/universal/downloader.go | 6 +++- 6 files changed, 52 insertions(+), 60 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2f31ed5..f253d1b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,8 +11,8 @@ RUN go build -ldflags "-s -w -X 'github.com/debridmediamanager/zurg/internal/ver FROM alpine:3 AS obfuscator WORKDIR /app COPY --from=builder /app/zurg . -# RUN apk add --no-cache upx -# RUN upx --brute zurg +RUN apk add --no-cache upx +RUN upx --brute zurg # Create a health check script that extracts the port from the config file COPY ./healthcheck.sh /app/healthcheck.sh RUN chmod +x /app/healthcheck.sh diff --git a/internal/torrent/latestState.go b/internal/torrent/latestState.go index 684bea9..b425a4f 100644 --- a/internal/torrent/latestState.go +++ b/internal/torrent/latestState.go @@ -1,68 +1,44 @@ package torrent -import ( - "github.com/debridmediamanager/zurg/pkg/realdebrid" -) - type LibraryState struct { - TotalCount int - ActiveCount int - FirstTorrent *realdebrid.Torrent - FirstActiveTorrent *realdebrid.Torrent + TotalCount int + ActiveCount int + FirstActiveTorrentId string } -func (ls LibraryState) equal(a LibraryState) bool { - if a.TotalCount != ls.TotalCount || a.ActiveCount != ls.ActiveCount { +func (ls *LibraryState) Eq(a LibraryState) bool { + if ls.TotalCount == 0 || ls.FirstActiveTorrentId == "" { return false } - if (ls.FirstTorrent == nil) != (a.FirstTorrent == nil) { - return false - } - if ls.FirstTorrent != nil && (ls.FirstTorrent.ID != a.FirstTorrent.ID || ls.FirstTorrent.Status != a.FirstTorrent.Status) { - return false - } - if (ls.FirstActiveTorrent == nil) != (a.FirstActiveTorrent == nil) { - return false - } - if ls.FirstActiveTorrent != nil && (ls.FirstActiveTorrent.ID != a.FirstActiveTorrent.ID || ls.FirstActiveTorrent.Status != a.FirstActiveTorrent.Status) { + if a.TotalCount != ls.TotalCount || a.ActiveCount != ls.ActiveCount || a.FirstActiveTorrentId != ls.FirstActiveTorrentId { return false } return true } -func (t *TorrentManager) SetNewLatestState(checksum LibraryState) { +func (t *TorrentManager) setNewLatestState(checksum LibraryState) { t.latestState.ActiveCount = checksum.ActiveCount t.latestState.TotalCount = checksum.TotalCount - t.latestState.FirstTorrent = checksum.FirstTorrent - t.latestState.FirstActiveTorrent = checksum.FirstActiveTorrent + t.latestState.FirstActiveTorrentId = checksum.FirstActiveTorrentId } // generates a checksum based on the number of torrents, the first torrent id and the number of active torrents func (t *TorrentManager) getCurrentState() LibraryState { var state LibraryState - torrents, totalCount, err := t.Api.GetTorrents(1, false) + activeTorrents, totalCount, err := t.Api.GetTorrents(1, true) if err != nil { - t.log.Warnf("Checksum API Error (GetTorrents): %v", err) + t.log.Errorf("Checksum API Error (GetTorrents): %v", err) return LibraryState{} } - if len(torrents) > 0 { - state.FirstTorrent = &torrents[0] - } state.TotalCount = totalCount - - activeTorrents, _, err := t.Api.GetTorrents(1, true) - if err != nil { - t.log.Warnf("Checksum API Error (GetTorrents): %v", err) - return LibraryState{} - } if len(activeTorrents) > 0 { - state.FirstActiveTorrent = &activeTorrents[0] + state.FirstActiveTorrentId = activeTorrents[0].ID } count, err := t.Api.GetActiveTorrentCount() if err != nil { - t.log.Warnf("Checksum API Error (GetActiveTorrentCount): %v", err) + t.log.Errorf("Checksum API Error (GetActiveTorrentCount): %v", err) return LibraryState{} } state.ActiveCount = count.DownloadingCount diff --git a/internal/torrent/manager.go b/internal/torrent/manager.go index c8f0b75..30cd5f6 100644 --- a/internal/torrent/manager.go +++ b/internal/torrent/manager.go @@ -62,7 +62,7 @@ func NewTorrentManager(cfg config.ConfigInterface, api *realdebrid.RealDebrid, w t.initializeDirectories() t.mountDownloads() t.refreshTorrents() - t.SetNewLatestState(t.getCurrentState()) + t.setNewLatestState(t.getCurrentState()) t.StartRefreshJob() t.StartRepairJob() diff --git a/internal/torrent/refresh.go b/internal/torrent/refresh.go index 0fb4d42..2c7738d 100644 --- a/internal/torrent/refresh.go +++ b/internal/torrent/refresh.go @@ -87,7 +87,9 @@ func (t *TorrentManager) refreshTorrents() []string { }) if t.Config.EnableRepair() { - t.handleFixers() + t.workerPool.Submit(func() { + t.handleFixers() + }) } return updatedPaths @@ -104,11 +106,11 @@ func (t *TorrentManager) StartRefreshJob() { select { case <-refreshTicker.C: checksum := t.getCurrentState() - if t.latestState.equal(checksum) { + if t.latestState.Eq(checksum) { continue } - t.SetNewLatestState(checksum) t.log.Infof("Detected changes! Refreshing %d torrents", checksum.TotalCount) + t.setNewLatestState(checksum) updatedPaths := t.refreshTorrents() t.log.Info("Finished refreshing torrents") @@ -175,15 +177,17 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent { continue } selectedFiles = append(selectedFiles, &File{ - File: file, - Ended: info.Ended, - Link: "", // no link yet + File: file, + Ended: info.Ended, + Link: "", // no link yet + IsBroken: true, }) } if len(selectedFiles) == len(info.Links) { // all links are still intact! good! for i, file := range selectedFiles { file.Link = info.Links[i] + file.IsBroken = false } torrent.UnassignedLinks = mapset.NewSet[string]() } else { @@ -278,7 +282,7 @@ func (t *TorrentManager) mergeToMain(existing, toMerge *Torrent) Torrent { // 1. https://*** - the file is available // 3. empty - the file is not available mainTorrent.SelectedFiles.IterCb(func(key string, file *File) { - if file.Link == "" { + if file.IsBroken { file, ok := older.SelectedFiles.Get(key) if ok { mainTorrent.SelectedFiles.Set(key, file) diff --git a/internal/torrent/repair.go b/internal/torrent/repair.go index 766c440..7de6556 100644 --- a/internal/torrent/repair.go +++ b/internal/torrent/repair.go @@ -106,11 +106,11 @@ func (t *TorrentManager) repairAll(torrent *Torrent) { } }) if brokenFileIDs.Cardinality() > 0 { - t.log.Debugf("Torrent %s has broken files (ids=%v), adding to repair list", t.GetKey(torrent), brokenFileIDs.ToSlice()) + t.log.Debugf("Torrent %s has %d broken files (ids=%v), adding to repair list", t.GetKey(torrent), brokenFileIDs.Cardinality(), brokenFileIDs.ToSlice()) toRepair.Add(torrent) return } - // check 2: for expired links + // check 2: for unassigned links (this means the torrent has started to deteriorate) if torrent.UnassignedLinks.Cardinality() > 0 { t.log.Debugf("Torrent %s has unassigned links, adding to repair list", t.GetKey(torrent)) toRepair.Add(torrent) @@ -170,7 +170,7 @@ func (t *TorrentManager) repair(torrent *Torrent) { // get all broken files brokenFiles := getBrokenFiles(torrent) - t.log.Debugf("Torrent %s has %d broken out of %d files", t.GetKey(torrent), len(brokenFiles), torrent.SelectedFiles.Count()) + t.log.Debugf("Torrent %s has %d broken files (total is %d)", t.GetKey(torrent), len(brokenFiles), torrent.SelectedFiles.Count()) brokenFileIDs := getFileIDs(brokenFiles) // first step: redownload the whole torrent @@ -187,6 +187,7 @@ func (t *TorrentManager) repair(torrent *Torrent) { for _, newFile := range selectedFiles { if oldFile.Bytes == newFile.Bytes { oldFile.Link = newFile.Link + oldFile.IsBroken = false break } } @@ -220,9 +221,10 @@ func (t *TorrentManager) repair(torrent *Torrent) { t.fixerAddCommand(redownloadedTorrent.ID, "repair") return } + } else { + t.log.Infof("Torrent %s has no broken files to repair", t.GetKey(torrent)) } - t.log.Infof("Torrent %s has no broken files to repair", t.GetKey(torrent)) } func (t *TorrentManager) assignUnassignedLinks(torrent *Torrent) bool { @@ -245,6 +247,7 @@ func (t *TorrentManager) assignUnassignedLinks(torrent *Torrent) bool { // base it on size because why not? if file.Bytes == unrestrict.Filesize { file.Link = link + file.IsBroken = false assigned = true assignedCount++ } @@ -275,10 +278,11 @@ func (t *TorrentManager) assignUnassignedLinks(torrent *Torrent) bool { ID: 0, Path: unassigned.Filename, Bytes: unassigned.Filesize, - Selected: 1, + Selected: 0, }, - Ended: torrent.Added, - Link: unassigned.Link, + Ended: torrent.Added, + Link: unassigned.Link, + IsBroken: false, } torrent.SelectedFiles.Set(unassigned.Filename, newFile) }) @@ -470,15 +474,17 @@ func (t *TorrentManager) isStillBroken(info *realdebrid.TorrentInfo, brokenFiles continue } selectedFiles = append(selectedFiles, &File{ - File: file, - Ended: info.Ended, - Link: "", // no link yet + File: file, + Ended: info.Ended, + Link: "", // no link yet + IsBroken: true, }) } if len(selectedFiles) == len(info.Links) { // all links are still intact! good! for i, file := range selectedFiles { file.Link = info.Links[i] + file.IsBroken = false } } else { // if we can't assign links, it's still broken @@ -512,15 +518,17 @@ func getSelectedFiles(info *realdebrid.TorrentInfo) []*File { continue } selectedFiles = append(selectedFiles, &File{ - File: file, - Ended: info.Ended, - Link: "", // no link yet + File: file, + Ended: info.Ended, + Link: "", // no link yet + IsBroken: true, }) } if len(selectedFiles) == len(info.Links) { // all links are still intact! good! for i, file := range selectedFiles { file.Link = info.Links[i] + file.IsBroken = false } } return selectedFiles diff --git a/internal/universal/downloader.go b/internal/universal/downloader.go index c1cfa46..2e0dc9a 100644 --- a/internal/universal/downloader.go +++ b/internal/universal/downloader.go @@ -48,7 +48,11 @@ func (dl *Downloader) DownloadFile(directory, torrentName, fileName string, resp // log.Debugf("Opening file %s from torrent %s (%s)", fileName, torMgr.GetKey(torrent), file.Link) if file.IsBroken { - http.Error(resp, "File is not available", http.StatusInternalServerError) + if cfg.EnableRepair() { + http.Error(resp, "File is temporarily unavailable", http.StatusInternalServerError) + } else { + http.Error(resp, "File is not available", http.StatusNotFound) + } return }