package torrent import ( "io" "os" "github.com/debridmediamanager/zurg/pkg/realdebrid" cmap "github.com/orcaman/concurrent-map/v2" ) // fixers are commands that will be run on the next refresh // they are stored in a file so that they can be run on startup // they follow the format of: // key: value: // id_trigger: this means a specific torrent id's completion // commands: delete | repair func (t *TorrentManager) fixerAddCommand(trigger, command string) { t.log.Debugf("Adding fixer command: %s %s", trigger, command) t.fixers.Set(trigger, command) t.writeFixersToFile() } func (t *TorrentManager) handleFixers(instances []realdebrid.Torrent) { t.log.Debugf("Handling fixers - %d left", t.fixers.Count()) var toDelete []string var toRedownload []*Torrent allTorrents, _ := t.DirectoryMap.Get(INT_ALL) for _, instance := range instances { id := instance.ID if !t.fixers.Has(id) { continue } command, _ := t.fixers.Pop(id) // delete the fixer if it's done switch command { case "replaced": // id is old torrent id t.log.Debugf("Deleting old id=%s because it's redundant to fixed %s ", id, instance.Name) toDelete = append(toDelete, id) case "download_failed": // id is failed fixer id t.log.Debugf("Deleting failed fixer id=%s of torrent %s", id, instance.Name) toDelete = append(toDelete, id) case "repaired": // this torrent contains broken files if instance.Progress != 100 { continue } torrent := t.getMoreInfo(instance) t.log.Debugf("Repairing torrent %s again now that fixer id=%s is done", t.GetKey(torrent), id) repairMe, _ := allTorrents.Get(t.GetKey(torrent)) toRedownload = append(toRedownload, repairMe) } } infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE) for _, id := range toDelete { t.Api.DeleteTorrent(id) infoCache.Remove(id) t.deleteTorrentFile(id) } for _, torrent := range toRedownload { t.redownloadTorrent(torrent, "") } // remove expired fixers var expired []string t.fixers.IterCb(func(trigger string, command string) { if infoCache.Has(trigger) { return } expired = append(expired, trigger) }) for _, trigger := range expired { t.log.Debugf("Removing expired fixer id=%s", trigger) t.fixers.Remove(trigger) } t.writeFixersToFile() t.log.Debugf("Finished handling fixers") } func (t *TorrentManager) writeFixersToFile() { filePath := "data/fixers.json" file, err := os.Create(filePath) if err != nil { t.log.Warnf("Cannot create fixer file %s: %v", filePath, err) return } defer file.Close() fileData, err := t.fixers.MarshalJSON() if err != nil { t.log.Warnf("Cannot marshal fixers: %v", err) return } _, err = file.Write(fileData) if err != nil { t.log.Warnf("Cannot write to fixer file %s: %v", filePath, err) return } } func (t *TorrentManager) readFixersFromFile() (ret cmap.ConcurrentMap[string, string]) { ret = cmap.New[string]() filePath := "data/fixers.json" file, err := os.Open(filePath) if err != nil { if os.IsNotExist(err) { return } t.log.Warnf("Cannot open fixer file %s: %v", filePath, err) return } defer file.Close() fileData, err := io.ReadAll(file) if err != nil { t.log.Warnf("Cannot read fixer file %s: %v", filePath, err) return } err = ret.UnmarshalJSON(fileData) if err != nil { t.log.Warnf("Cannot unmarshal fixer file %s: %v", filePath, err) return } return }