diff --git a/pkg/arr/content.go b/pkg/arr/content.go index 3bcc22e..03937e3 100644 --- a/pkg/arr/content.go +++ b/pkg/arr/content.go @@ -234,6 +234,35 @@ func (a *Arr) searchRadarr(files []ContentFile) error { } func (a *Arr) SearchMissing(files []ContentFile) error { + if len(files) == 0 { + return nil + } + return a.batchSearchMissing(files) +} + +func (a *Arr) batchSearchMissing(files []ContentFile) error { + if len(files) == 0 { + return nil + } + BatchSize := 50 + // Batch search for missing files + if len(files) > BatchSize { + for i := 0; i < len(files); i += BatchSize { + end := i + BatchSize + if end > len(files) { + end = len(files) + } + if err := a.searchMissing(files[i:end]); err != nil { + // continue searching the rest of the files + continue + } + } + return nil + } + return a.searchMissing(files) +} + +func (a *Arr) searchMissing(files []ContentFile) error { switch a.Type { case Sonarr: return a.searchSonarr(files) @@ -245,6 +274,28 @@ func (a *Arr) SearchMissing(files []ContentFile) error { } func (a *Arr) DeleteFiles(files []ContentFile) error { + if len(files) == 0 { + return nil + } + BatchSize := 50 + // Batch delete files + if len(files) > BatchSize { + for i := 0; i < len(files); i += BatchSize { + end := i + BatchSize + if end > len(files) { + end = len(files) + } + if err := a.batchDeleteFiles(files[i:end]); err != nil { + // continue deleting the rest of the files + continue + } + } + return nil + } + return a.batchDeleteFiles(files) +} + +func (a *Arr) batchDeleteFiles(files []ContentFile) error { ids := make([]int, 0) for _, f := range files { ids = append(ids, f.FileId) diff --git a/pkg/debrid/store/cache.go b/pkg/debrid/store/cache.go index 4634863..8f61f12 100644 --- a/pkg/debrid/store/cache.go +++ b/pkg/debrid/store/cache.go @@ -534,7 +534,7 @@ func (c *Cache) setTorrent(t CachedTorrent, callback func(torrent CachedTorrent) mergedFiles := mergeFiles(o, updatedTorrent) // Useful for merging files across multiple torrents, while keeping the most recent updatedTorrent.Files = mergedFiles } - c.torrents.set(torrentName, t, updatedTorrent) + c.torrents.set(torrentName, t) go c.SaveTorrent(t) if callback != nil { go callback(updatedTorrent) @@ -550,7 +550,7 @@ func (c *Cache) setTorrents(torrents map[string]CachedTorrent, callback func()) mergedFiles := mergeFiles(o, updatedTorrent) updatedTorrent.Files = mergedFiles } - c.torrents.set(torrentName, t, updatedTorrent) + c.torrents.set(torrentName, t) } c.SaveTorrents() if callback != nil { diff --git a/pkg/debrid/store/torrent.go b/pkg/debrid/store/torrent.go index 2188dc8..565f785 100644 --- a/pkg/debrid/store/torrent.go +++ b/pkg/debrid/store/torrent.go @@ -42,8 +42,8 @@ type directoryFilter struct { type torrents struct { sync.RWMutex - byID map[string]CachedTorrent - byName map[string]CachedTorrent + storage map[string]CachedTorrent // id to CachedTorrent + byName map[string]string // name to id } type folders struct { @@ -72,8 +72,8 @@ func newTorrentCache(dirFilters map[string][]directoryFilter) *torrentCache { tc := &torrentCache{ torrents: torrents{ - byID: make(map[string]CachedTorrent), - byName: make(map[string]CachedTorrent), + storage: make(map[string]CachedTorrent), // id to CachedTorrent + byName: make(map[string]string), }, folders: folders{ listing: make(map[string][]os.FileInfo), @@ -88,8 +88,8 @@ func newTorrentCache(dirFilters map[string][]directoryFilter) *torrentCache { func (tc *torrentCache) reset() { tc.torrents.Lock() - tc.torrents.byID = make(map[string]CachedTorrent) - tc.torrents.byName = make(map[string]CachedTorrent) + tc.torrents.byName = make(map[string]string) + tc.torrents.storage = make(map[string]CachedTorrent) // Reset the storage map tc.torrents.Unlock() // reset the sorted listing @@ -105,23 +105,27 @@ func (tc *torrentCache) reset() { func (tc *torrentCache) getByID(id string) (CachedTorrent, bool) { tc.torrents.RLock() defer tc.torrents.RUnlock() - torrent, exists := tc.torrents.byID[id] + torrent, exists := tc.torrents.storage[id] return torrent, exists } func (tc *torrentCache) getByName(name string) (CachedTorrent, bool) { tc.torrents.RLock() defer tc.torrents.RUnlock() - torrent, exists := tc.torrents.byName[name] + torrentID, exists := tc.torrents.byName[name] + if !exists { + return CachedTorrent{}, false + } + torrent, exists := tc.torrents.storage[torrentID] return torrent, exists } -func (tc *torrentCache) set(name string, torrent, newTorrent CachedTorrent) { +func (tc *torrentCache) set(name string, torrent CachedTorrent) { tc.torrents.Lock() // Set the id first - tc.torrents.byName[name] = torrent - tc.torrents.byID[torrent.Id] = torrent // This is the unadulterated torrent + tc.torrents.byName[name] = torrent.Id + tc.torrents.storage[torrent.Id] = torrent tc.torrents.Unlock() tc.sortNeeded.Store(true) } @@ -154,7 +158,11 @@ func (tc *torrentCache) refreshListing() { tc.torrents.RLock() all := make([]sortableFile, 0, len(tc.torrents.byName)) - for name, t := range tc.torrents.byName { + for name, torrentID := range tc.torrents.byName { + t, exists := tc.torrents.storage[torrentID] + if !exists { + continue // Skip if torrent not found + } all = append(all, sortableFile{t.Id, name, t.AddedOn, t.Bytes, t.Bad}) } tc.sortNeeded.Store(false) @@ -280,9 +288,9 @@ func (tc *torrentCache) torrentMatchDirectory(filters []directoryFilter, file so func (tc *torrentCache) getAll() map[string]CachedTorrent { tc.torrents.RLock() defer tc.torrents.RUnlock() - result := make(map[string]CachedTorrent, len(tc.torrents.byID)) - for name, torrent := range tc.torrents.byID { - result[name] = torrent + result := make(map[string]CachedTorrent, len(tc.torrents.storage)) + for torrentID, torrent := range tc.torrents.storage { + result[torrentID] = torrent } return result } @@ -290,14 +298,18 @@ func (tc *torrentCache) getAll() map[string]CachedTorrent { func (tc *torrentCache) getAllCount() int { tc.torrents.RLock() defer tc.torrents.RUnlock() - return len(tc.torrents.byID) + return len(tc.torrents.storage) } func (tc *torrentCache) getAllByName() map[string]CachedTorrent { tc.torrents.RLock() defer tc.torrents.RUnlock() results := make(map[string]CachedTorrent, len(tc.torrents.byName)) - for name, torrent := range tc.torrents.byName { + for name, torrentID := range tc.torrents.byName { + torrent, exists := tc.torrents.storage[torrentID] + if !exists { + continue // Skip if torrent not found + } results[name] = torrent } return results @@ -306,8 +318,8 @@ func (tc *torrentCache) getAllByName() map[string]CachedTorrent { func (tc *torrentCache) getIdMaps() map[string]struct{} { tc.torrents.RLock() defer tc.torrents.RUnlock() - res := make(map[string]struct{}, len(tc.torrents.byID)) - for id := range tc.torrents.byID { + res := make(map[string]struct{}, len(tc.torrents.storage)) + for id := range tc.torrents.storage { res[id] = struct{}{} } return res @@ -316,7 +328,7 @@ func (tc *torrentCache) getIdMaps() map[string]struct{} { func (tc *torrentCache) removeId(id string) { tc.torrents.Lock() defer tc.torrents.Unlock() - delete(tc.torrents.byID, id) + delete(tc.torrents.storage, id) tc.sortNeeded.Store(true) }