Fix repairs for rared torrents
This commit is contained in:
@@ -13,7 +13,7 @@ const BINS_FILE = "data/bins.json"
|
|||||||
// initializeBins reads from bins.json and assigns values to t.trashBin and t.repairBin
|
// initializeBins reads from bins.json and assigns values to t.trashBin and t.repairBin
|
||||||
func (t *TorrentManager) initializeBins() {
|
func (t *TorrentManager) initializeBins() {
|
||||||
if _, err := os.Stat(BINS_FILE); os.IsNotExist(err) {
|
if _, err := os.Stat(BINS_FILE); os.IsNotExist(err) {
|
||||||
t.repairLog.Warn("data/bins.json does not exist. Initializing empty bins.")
|
t.repairLog.Info("data/bins.json does not exist. Initializing empty bins.")
|
||||||
t.ImmediateBin = mapset.NewSet[string]()
|
t.ImmediateBin = mapset.NewSet[string]()
|
||||||
t.OnceDoneBin = mapset.NewSet[string]()
|
t.OnceDoneBin = mapset.NewSet[string]()
|
||||||
return
|
return
|
||||||
@@ -120,6 +120,7 @@ func (t *TorrentManager) binImmediately(torrentId string) bool {
|
|||||||
t.repairLog.Warnf("Failed to delete torrent %s: %v", torrentId, err)
|
t.repairLog.Warnf("Failed to delete torrent %s: %v", torrentId, err)
|
||||||
}
|
}
|
||||||
t.ImmediateBin.Remove(torrentId)
|
t.ImmediateBin.Remove(torrentId)
|
||||||
|
t.repairLog.Debugf("Bin: immediate deletion of torrent %s", torrentId)
|
||||||
t.persistBins()
|
t.persistBins()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -128,21 +129,27 @@ func (t *TorrentManager) binImmediately(torrentId string) bool {
|
|||||||
|
|
||||||
// binOnceDoneErrorCheck checks if the torrent is in error states and then checks if it should be deleted
|
// binOnceDoneErrorCheck checks if the torrent is in error states and then checks if it should be deleted
|
||||||
func (t *TorrentManager) binOnceDoneErrorCheck(torrentId, status string) bool {
|
func (t *TorrentManager) binOnceDoneErrorCheck(torrentId, status string) bool {
|
||||||
if status == "downloading" || status == "downloaded" || status == "uploading" || status == "queued" || status == "compressing" {
|
if status == "downloading" || status == "downloaded" || status == "uploading" || status == "queued" || status == "compressing" || status == "waiting_files_selection" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return t.binOnceDone(torrentId)
|
t.repairLog.Errorf("Bin: error status=%s, checking if %s should be deleted", status, torrentId)
|
||||||
|
return t.binOnceDone(torrentId, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// binOnceDone checks if the torrent is in the OnceDoneBin and deletes it if it is.
|
// binOnceDone checks if the torrent is in the OnceDoneBin and deletes it if it is.
|
||||||
// returns true if the torrent was in the bin and was deleted, false otherwise
|
// returns true if the torrent was in the bin and was deleted, false otherwise
|
||||||
func (t *TorrentManager) binOnceDone(completedTorrentId string) bool {
|
func (t *TorrentManager) binOnceDone(completedTorrentId string, errorCheck bool) bool {
|
||||||
if t.OnceDoneBin.Contains(completedTorrentId) {
|
if t.OnceDoneBin.Contains(completedTorrentId) {
|
||||||
if err := t.api.DeleteTorrent(completedTorrentId); err != nil {
|
if err := t.api.DeleteTorrent(completedTorrentId); err != nil {
|
||||||
t.repairLog.Warnf("Failed to delete torrent %s: %v", completedTorrentId, err)
|
t.repairLog.Warnf("Failed to delete torrent %s: %v", completedTorrentId, err)
|
||||||
}
|
}
|
||||||
t.deleteInfoFile(completedTorrentId)
|
t.deleteInfoFile(completedTorrentId)
|
||||||
t.OnceDoneBin.Remove(completedTorrentId)
|
t.OnceDoneBin.Remove(completedTorrentId)
|
||||||
|
if errorCheck {
|
||||||
|
t.repairLog.Errorf("Bin: error deletion of torrent %s", completedTorrentId)
|
||||||
|
} else {
|
||||||
|
t.repairLog.Debugf("Bin: done deletion of torrent %s", completedTorrentId)
|
||||||
|
}
|
||||||
t.persistBins()
|
t.persistBins()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -152,14 +159,22 @@ func (t *TorrentManager) binOnceDone(completedTorrentId string) bool {
|
|||||||
if !t.OnceDoneBin.Contains(specialCase) {
|
if !t.OnceDoneBin.Contains(specialCase) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
t.OnceDoneBin.Remove(specialCase)
|
|
||||||
t.OnceDoneBin.Clone().Each(func(entry string) bool {
|
t.OnceDoneBin.Clone().Each(func(entry string) bool {
|
||||||
if strings.Contains(entry, specialCase) {
|
if strings.Contains(entry, specialCase) {
|
||||||
|
if errorCheck {
|
||||||
|
if err := t.api.DeleteTorrent(completedTorrentId); err != nil {
|
||||||
|
t.repairLog.Warnf("Failed to delete torrent %s: %v", completedTorrentId, err)
|
||||||
|
}
|
||||||
|
t.OnceDoneBin.Remove(entry)
|
||||||
|
t.repairLog.Errorf("Bin: error deletion of torrent %s", completedTorrentId)
|
||||||
|
} else {
|
||||||
idToDelete := strings.Split(entry, "-")[1]
|
idToDelete := strings.Split(entry, "-")[1]
|
||||||
if err := t.api.DeleteTorrent(idToDelete); err != nil {
|
if err := t.api.DeleteTorrent(idToDelete); err != nil {
|
||||||
t.repairLog.Warnf("Failed to delete torrent %s: %v", idToDelete, err)
|
t.repairLog.Warnf("Failed to delete torrent %s: %v", idToDelete, err)
|
||||||
}
|
}
|
||||||
t.OnceDoneBin.Remove(entry)
|
t.OnceDoneBin.Remove(entry)
|
||||||
|
t.repairLog.Debugf("Bin: %s completed, done deletion of torrent %s", completedTorrentId, idToDelete)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -45,13 +45,6 @@ func (se *ScriptExecutor) Execute() (string, error) {
|
|||||||
return out.String(), nil
|
return out.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TorrentManager) TriggerHookOnLibraryUpdate(updatedPaths []string) {
|
|
||||||
_ = t.workerPool.Submit(func() {
|
|
||||||
OnLibraryUpdateHook(updatedPaths, t.Config, t.log)
|
|
||||||
t.log.Debugf("Triggered hook on_library_update for %d path(s)", len(updatedPaths))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func OnLibraryUpdateHook(paths []string, config config.ConfigInterface, log *logutil.Logger) {
|
func OnLibraryUpdateHook(paths []string, config config.ConfigInterface, log *logutil.Logger) {
|
||||||
executor := &ScriptExecutor{
|
executor := &ScriptExecutor{
|
||||||
Script: config.GetOnLibraryUpdate(),
|
Script: config.GetOnLibraryUpdate(),
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ func NewTorrentManager(cfg config.ConfigInterface, api *realdebrid.RealDebrid, r
|
|||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
t.refreshTorrents()
|
t.refreshTorrents(true)
|
||||||
})
|
})
|
||||||
t.workerPool.Submit(func() {
|
t.workerPool.Submit(func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func inProgressStatus(status string) bool {
|
|||||||
return status == "downloading" || status == "uploading" || status == "queued" || status == "compressing"
|
return status == "downloading" || status == "uploading" || status == "queued" || status == "compressing"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TorrentManager) refreshTorrents() {
|
func (t *TorrentManager) refreshTorrents(initialRun bool) {
|
||||||
t.inProgressHashes = mapset.NewSet[string]()
|
t.inProgressHashes = mapset.NewSet[string]()
|
||||||
instances, _, err := t.api.GetTorrents(false)
|
instances, _, err := t.api.GetTorrents(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -62,7 +62,7 @@ func (t *TorrentManager) refreshTorrents() {
|
|||||||
if !exists {
|
if !exists {
|
||||||
allTorrents.Set(accessKey, torrent)
|
allTorrents.Set(accessKey, torrent)
|
||||||
t.writeTorrentToFile(torrent)
|
t.writeTorrentToFile(torrent)
|
||||||
t.assignDirectory(torrent, true)
|
t.assignDirectory(torrent, !initialRun)
|
||||||
} else if !mainTorrent.DownloadedIDs.Contains(tInfo.ID) {
|
} else if !mainTorrent.DownloadedIDs.Contains(tInfo.ID) {
|
||||||
forMerging = torrent
|
forMerging = torrent
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ func (t *TorrentManager) refreshTorrents() {
|
|||||||
mainTorrent := t.mergeTorrents(existing, torrent)
|
mainTorrent := t.mergeTorrents(existing, torrent)
|
||||||
allTorrents.Set(accessKey, mainTorrent)
|
allTorrents.Set(accessKey, mainTorrent)
|
||||||
t.writeTorrentToFile(mainTorrent)
|
t.writeTorrentToFile(mainTorrent)
|
||||||
t.assignDirectory(mainTorrent, true)
|
t.assignDirectory(mainTorrent, !initialRun)
|
||||||
}
|
}
|
||||||
|
|
||||||
// removed torrents
|
// removed torrents
|
||||||
@@ -106,20 +106,18 @@ func (t *TorrentManager) refreshTorrents() {
|
|||||||
|
|
||||||
t.log.Infof("Compiled into %d unique torrents", allTorrents.Count())
|
t.log.Infof("Compiled into %d unique torrents", allTorrents.Count())
|
||||||
|
|
||||||
t.workerPool.Submit(func() {
|
|
||||||
// delete info files that are no longer present
|
// delete info files that are no longer present
|
||||||
t.getInfoFiles().Each(func(path string) bool {
|
t.getInfoFiles().Each(func(path string) bool {
|
||||||
path = filepath.Base(path)
|
path = filepath.Base(path)
|
||||||
torrentID := strings.TrimSuffix(path, ".zurginfo")
|
torrentID := strings.TrimSuffix(path, ".zurginfo")
|
||||||
// if binOnceDone returns true, it means the info file is deleted
|
// if binOnceDone returns true, it means the info file is deleted
|
||||||
// if false, then we check if it's one of the torrents we just fetched
|
// if false, then we check if it's one of the torrents we just fetched
|
||||||
// if not, then we delete the info file
|
// if not (both are false), then we delete the info file
|
||||||
if !t.binOnceDone(torrentID) && !freshIDs.Contains(torrentID) {
|
if !t.binOnceDone(torrentID, false) && !freshIDs.Contains(torrentID) {
|
||||||
t.deleteInfoFile(torrentID)
|
t.deleteInfoFile(torrentID)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
t.workerPool.Submit(func() {
|
t.workerPool.Submit(func() {
|
||||||
// update DownloadedIDs field of torrents
|
// update DownloadedIDs field of torrents
|
||||||
@@ -152,7 +150,7 @@ func (t *TorrentManager) StartRefreshJob() {
|
|||||||
}
|
}
|
||||||
t.setNewLatestState(checksum)
|
t.setNewLatestState(checksum)
|
||||||
|
|
||||||
t.refreshTorrents()
|
t.refreshTorrents(false)
|
||||||
t.log.Info("Finished refreshing torrents")
|
t.log.Info("Finished refreshing torrents")
|
||||||
case <-t.RefreshKillSwitch:
|
case <-t.RefreshKillSwitch:
|
||||||
t.log.Info("Stopping periodic refresh job")
|
t.log.Info("Stopping periodic refresh job")
|
||||||
@@ -293,6 +291,8 @@ func (t *TorrentManager) mergeTorrents(existing, toMerge *Torrent) *Torrent {
|
|||||||
if !ok || !f.State.Is("ok_file") {
|
if !ok || !f.State.Is("ok_file") {
|
||||||
mergedTorrent.SelectedFiles.Set(key, file)
|
mergedTorrent.SelectedFiles.Set(key, file)
|
||||||
}
|
}
|
||||||
|
// get the file again, set the media info
|
||||||
|
f, ok = mergedTorrent.SelectedFiles.Get(key)
|
||||||
if ok && f.MediaInfo == nil && mediaInfo != nil {
|
if ok && f.MediaInfo == nil && mediaInfo != nil {
|
||||||
f.MediaInfo = mediaInfo
|
f.MediaInfo = mediaInfo
|
||||||
}
|
}
|
||||||
@@ -328,6 +328,8 @@ func (t *TorrentManager) mergeTorrents(existing, toMerge *Torrent) *Torrent {
|
|||||||
mergedTorrent.State.Event(context.Background(), "mark_as_repaired")
|
mergedTorrent.State.Event(context.Background(), "mark_as_repaired")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.log.Debugf("Merged torrent %s has %d broken files", t.GetKey(mergedTorrent), brokenCount)
|
||||||
|
|
||||||
return mergedTorrent
|
return mergedTorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,6 +368,7 @@ func (t *TorrentManager) assignDirectory(tor *Torrent, triggerHook bool) {
|
|||||||
// Map torrents to directories
|
// Map torrents to directories
|
||||||
switch t.Config.GetVersion() {
|
switch t.Config.GetVersion() {
|
||||||
case "v1":
|
case "v1":
|
||||||
|
updatedPaths := make([]string, 0)
|
||||||
configV1 := t.Config.(*config.ZurgConfigV1)
|
configV1 := t.Config.(*config.ZurgConfigV1)
|
||||||
for _, directories := range configV1.GetGroupMap() {
|
for _, directories := range configV1.GetGroupMap() {
|
||||||
for _, directory := range directories {
|
for _, directory := range directories {
|
||||||
@@ -374,12 +377,15 @@ func (t *TorrentManager) assignDirectory(tor *Torrent, triggerHook bool) {
|
|||||||
listing.Set(accessKey, tor)
|
listing.Set(accessKey, tor)
|
||||||
|
|
||||||
if triggerHook {
|
if triggerHook {
|
||||||
t.TriggerHookOnLibraryUpdate([]string{fmt.Sprintf("%s/%s", directory, accessKey)})
|
updatedPaths = append(updatedPaths, fmt.Sprintf("%s/%s", directory, accessKey))
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if triggerHook {
|
||||||
|
OnLibraryUpdateHook(updatedPaths, t.Config, t.log)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ func (t *TorrentManager) repair(torrent *Torrent) {
|
|||||||
|
|
||||||
allPlayable = false
|
allPlayable = false
|
||||||
if t.Config.GetRarAction() == "extract" && file.ID != 0 {
|
if t.Config.GetRarAction() == "extract" && file.ID != 0 {
|
||||||
|
t.repairLog.Debugf("Extracting file %s from rar'ed torrent %s", file.Path, t.GetKey(torrent))
|
||||||
info, _ := t.redownloadTorrent(torrent, []string{fmt.Sprintf("%d", file.ID)})
|
info, _ := t.redownloadTorrent(torrent, []string{fmt.Sprintf("%d", file.ID)})
|
||||||
if info != nil {
|
if info != nil {
|
||||||
t.setToBinOnceDone(info.ID)
|
t.setToBinOnceDone(info.ID)
|
||||||
@@ -381,7 +382,8 @@ func (t *TorrentManager) assignLinks(torrent *Torrent) bool {
|
|||||||
torrent.SelectedFiles.IterCb(func(_ string, file *File) {
|
torrent.SelectedFiles.IterCb(func(_ string, file *File) {
|
||||||
if utils.IsPlayable(file.Path) {
|
if utils.IsPlayable(file.Path) {
|
||||||
videoFiles = append(videoFiles, fmt.Sprintf("%d", file.ID))
|
videoFiles = append(videoFiles, fmt.Sprintf("%d", file.ID))
|
||||||
} else {
|
} else if file.ID != 0 {
|
||||||
|
t.repairLog.Debugf("Extracting file %s from rar'ed torrent %s", file.Path, t.GetKey(torrent))
|
||||||
info, _ := t.redownloadTorrent(torrent, []string{fmt.Sprintf("%d", file.ID)})
|
info, _ := t.redownloadTorrent(torrent, []string{fmt.Sprintf("%d", file.ID)})
|
||||||
if info != nil {
|
if info != nil {
|
||||||
t.setToBinOnceDone(info.ID)
|
t.setToBinOnceDone(info.ID)
|
||||||
|
|||||||
Reference in New Issue
Block a user