Files
zurg/internal/torrent/fixer.go
2024-02-16 05:52:17 +01:00

139 lines
3.5 KiB
Go

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: <id_trigger> value: <command>
// 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) processFixers(instances []realdebrid.Torrent) {
t.log.Debugf("Processing fixers (%d left: %v)", t.fixers.Count(), t.fixers)
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 {
t.fixers.Set(id, "repaired") // requeue the fixer
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)
toDelete = append(toDelete, id)
}
}
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, "")
}
t.writeFixersToFile()
t.log.Debugf("Finished processing fixers")
}
func (t *TorrentManager) removeExpiredFixers(instances []realdebrid.Torrent) {
fixers := t.fixers.Keys()
if len(fixers) == 0 {
return
}
for _, fixerID := range fixers {
found := false
for _, instance := range instances {
if instance.ID == fixerID {
found = true
break
}
}
if !found {
t.log.Debugf("Removing expired fixer id=%s", fixerID)
t.fixers.Remove(fixerID)
}
}
}
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
}