Repairs
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/debridmediamanager/zurg/internal/config"
|
"github.com/debridmediamanager/zurg/internal/config"
|
||||||
"github.com/debridmediamanager/zurg/internal/dav"
|
"github.com/debridmediamanager/zurg/internal/dav"
|
||||||
@@ -100,12 +101,20 @@ func AttachHandlers(router *chi.Mux, downloader *universal.Downloader, torMgr *t
|
|||||||
|
|
||||||
func (hs *Handlers) innerRootHandler(resp http.ResponseWriter, req *http.Request, handleFunc func(*torrent.TorrentManager) ([]byte, error), contentType string) {
|
func (hs *Handlers) innerRootHandler(resp http.ResponseWriter, req *http.Request, handleFunc func(*torrent.TorrentManager) ([]byte, error), contentType string) {
|
||||||
out, err := handleFunc(hs.torMgr)
|
out, err := handleFunc(hs.torMgr)
|
||||||
if err != nil {
|
if err != nil && strings.Contains(contentType, "xml") {
|
||||||
|
resp.WriteHeader(http.StatusNotImplemented)
|
||||||
|
resp.Write([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?><d:error xmlns:d=\"DAV:\" xmlns:s=\"DAV\"><s:exception>NotImplemented</s:exception><s:message>Not Implemented Method</s:message></d:error>"))
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
http.NotFound(resp, req)
|
http.NotFound(resp, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp.Header().Set("Content-Type", contentType)
|
resp.Header().Set("Content-Type", contentType)
|
||||||
resp.WriteHeader(http.StatusOK)
|
if strings.Contains(contentType, "xml") {
|
||||||
|
resp.WriteHeader(http.StatusMultiStatus)
|
||||||
|
} else {
|
||||||
|
resp.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
resp.Write(out)
|
resp.Write(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,12 +135,20 @@ func (hs *Handlers) handleInfuseRoot(resp http.ResponseWriter, req *http.Request
|
|||||||
func (hs *Handlers) innerTorrentsListHandler(resp http.ResponseWriter, req *http.Request, handleFunc func(string, *torrent.TorrentManager) ([]byte, error), contentType string) {
|
func (hs *Handlers) innerTorrentsListHandler(resp http.ResponseWriter, req *http.Request, handleFunc func(string, *torrent.TorrentManager) ([]byte, error), contentType string) {
|
||||||
directory := chi.URLParam(req, "directory")
|
directory := chi.URLParam(req, "directory")
|
||||||
out, err := handleFunc(directory, hs.torMgr)
|
out, err := handleFunc(directory, hs.torMgr)
|
||||||
if err != nil {
|
if err != nil && strings.Contains(contentType, "xml") {
|
||||||
|
resp.WriteHeader(http.StatusNotImplemented)
|
||||||
|
resp.Write([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?><d:error xmlns:d=\"DAV:\" xmlns:s=\"DAV\"><s:exception>NotImplemented</s:exception><s:message>Not Implemented Method</s:message></d:error>"))
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
http.NotFound(resp, req)
|
http.NotFound(resp, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp.Header().Set("Content-Type", contentType)
|
resp.Header().Set("Content-Type", contentType)
|
||||||
resp.WriteHeader(http.StatusOK)
|
if strings.Contains(contentType, "xml") {
|
||||||
|
resp.WriteHeader(http.StatusMultiStatus)
|
||||||
|
} else {
|
||||||
|
resp.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
resp.Write(out)
|
resp.Write(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,12 +191,20 @@ func (hs *Handlers) innerFilesListHandler(resp http.ResponseWriter, req *http.Re
|
|||||||
directory := chi.URLParam(req, "directory")
|
directory := chi.URLParam(req, "directory")
|
||||||
torrentName := chi.URLParam(req, "torrent")
|
torrentName := chi.URLParam(req, "torrent")
|
||||||
out, err := handleFunc(directory, torrentName, hs.torMgr)
|
out, err := handleFunc(directory, torrentName, hs.torMgr)
|
||||||
if err != nil {
|
if err != nil && strings.Contains(contentType, "xml") {
|
||||||
|
resp.WriteHeader(http.StatusNotImplemented)
|
||||||
|
resp.Write([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?><d:error xmlns:d=\"DAV:\" xmlns:s=\"DAV\"><s:exception>NotImplemented</s:exception><s:message>Not Implemented Method</s:message></d:error>"))
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
http.NotFound(resp, req)
|
http.NotFound(resp, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp.Header().Set("Content-Type", contentType)
|
resp.Header().Set("Content-Type", contentType)
|
||||||
resp.WriteHeader(http.StatusOK)
|
if strings.Contains(contentType, "xml") {
|
||||||
|
resp.WriteHeader(http.StatusMultiStatus)
|
||||||
|
} else {
|
||||||
|
resp.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
resp.Write(out)
|
resp.Write(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ type TorrentManager struct {
|
|||||||
DirectoryMap cmap.ConcurrentMap[string, cmap.ConcurrentMap[string, *Torrent]] // directory -> accessKey -> Torrent
|
DirectoryMap cmap.ConcurrentMap[string, cmap.ConcurrentMap[string, *Torrent]] // directory -> accessKey -> Torrent
|
||||||
DownloadCache cmap.ConcurrentMap[string, *realdebrid.Download]
|
DownloadCache cmap.ConcurrentMap[string, *realdebrid.Download]
|
||||||
DownloadMap cmap.ConcurrentMap[string, *realdebrid.Download]
|
DownloadMap cmap.ConcurrentMap[string, *realdebrid.Download]
|
||||||
|
Repairs cmap.ConcurrentMap[string, bool]
|
||||||
allAccessKeys mapset.Set[string]
|
allAccessKeys mapset.Set[string]
|
||||||
forRepairs mapset.Set[string]
|
forRepairs mapset.Set[string]
|
||||||
latestState *LibraryState
|
latestState *LibraryState
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ func (t *TorrentManager) RefreshTorrents() []string {
|
|||||||
|
|
||||||
for i := range instances {
|
for i := range instances {
|
||||||
idx := i
|
idx := i
|
||||||
|
wg.Add(1)
|
||||||
_ = t.workerPool.Submit(func() {
|
_ = t.workerPool.Submit(func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
infoChan <- t.getMoreInfo(instances[idx])
|
infoChan <- t.getMoreInfo(instances[idx])
|
||||||
})
|
})
|
||||||
wg.Add(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
@@ -168,7 +168,6 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent {
|
|||||||
OriginalName: info.OriginalName,
|
OriginalName: info.OriginalName,
|
||||||
Added: info.Added,
|
Added: info.Added,
|
||||||
Hash: info.Hash,
|
Hash: info.Hash,
|
||||||
Lock: &sync.Mutex{},
|
|
||||||
}
|
}
|
||||||
// SelectedFiles is a subset of Files with only the selected ones
|
// SelectedFiles is a subset of Files with only the selected ones
|
||||||
// it also has a Link field, which can be empty
|
// it also has a Link field, which can be empty
|
||||||
@@ -234,7 +233,6 @@ func (t *TorrentManager) mergeToMain(existing, toMerge *Torrent) Torrent {
|
|||||||
Unfixable: existing.Unfixable || toMerge.Unfixable,
|
Unfixable: existing.Unfixable || toMerge.Unfixable,
|
||||||
UnassignedLinks: existing.UnassignedLinks.Union(toMerge.UnassignedLinks),
|
UnassignedLinks: existing.UnassignedLinks.Union(toMerge.UnassignedLinks),
|
||||||
BrokenLinks: existing.BrokenLinks.Union(toMerge.BrokenLinks),
|
BrokenLinks: existing.BrokenLinks.Union(toMerge.BrokenLinks),
|
||||||
Lock: &sync.Mutex{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function triggers only when we have a new DownloadedID
|
// this function triggers only when we have a new DownloadedID
|
||||||
|
|||||||
@@ -100,6 +100,12 @@ func (t *TorrentManager) repairAll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TorrentManager) Repair(torrent *Torrent) {
|
func (t *TorrentManager) Repair(torrent *Torrent) {
|
||||||
|
if repairing, ok := t.Repairs.Get(t.GetKey(torrent)); ok && repairing {
|
||||||
|
t.log.Warnf("Torrent %s is already being repaired, skipping repair", t.GetKey(torrent))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Repairs.Set(t.GetKey(torrent), true)
|
||||||
|
|
||||||
if torrent.Unfixable {
|
if torrent.Unfixable {
|
||||||
t.log.Warnf("Torrent %s is unfixable, skipping repair", t.GetKey(torrent))
|
t.log.Warnf("Torrent %s is unfixable, skipping repair", t.GetKey(torrent))
|
||||||
return
|
return
|
||||||
@@ -121,17 +127,13 @@ func (t *TorrentManager) Repair(torrent *Torrent) {
|
|||||||
})
|
})
|
||||||
_ = t.workerPool.Submit(func() {
|
_ = t.workerPool.Submit(func() {
|
||||||
t.log.Infof("Repairing torrent %s", t.GetKey(torrent))
|
t.log.Infof("Repairing torrent %s", t.GetKey(torrent))
|
||||||
torrent.Lock.Lock()
|
|
||||||
defer torrent.Lock.Unlock()
|
|
||||||
torrent.Repairing = true
|
|
||||||
t.repair(torrent)
|
t.repair(torrent)
|
||||||
torrent.Repairing = false
|
|
||||||
t.log.Infof("Finished repairing torrent %s", t.GetKey(torrent))
|
t.log.Infof("Finished repairing torrent %s", t.GetKey(torrent))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TorrentManager) repair(torrent *Torrent) {
|
func (t *TorrentManager) repair(torrent *Torrent) {
|
||||||
if torrent.AnyInProgress() || torrent.Repairing {
|
if torrent.AnyInProgress() {
|
||||||
t.log.Infof("Torrent %s is in progress, skipping repair until download is done", t.GetKey(torrent))
|
t.log.Infof("Torrent %s is in progress, skipping repair until download is done", t.GetKey(torrent))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -387,14 +389,10 @@ func (t *TorrentManager) markAsUnplayable(torrent *Torrent) {
|
|||||||
|
|
||||||
func (t *TorrentManager) markAsUnfixable(torrent *Torrent) {
|
func (t *TorrentManager) markAsUnfixable(torrent *Torrent) {
|
||||||
t.log.Warnf("Marking torrent %s as unfixable", t.GetKey(torrent))
|
t.log.Warnf("Marking torrent %s as unfixable", t.GetKey(torrent))
|
||||||
torrent.Lock.Lock()
|
|
||||||
defer torrent.Lock.Unlock()
|
|
||||||
torrent.Unfixable = true
|
torrent.Unfixable = true
|
||||||
infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE)
|
infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE)
|
||||||
torrent.DownloadedIDs.Each(func(id string) bool {
|
torrent.DownloadedIDs.Each(func(id string) bool {
|
||||||
info, _ := infoCache.Get(id)
|
info, _ := infoCache.Get(id)
|
||||||
info.Lock.Lock()
|
|
||||||
defer info.Lock.Unlock()
|
|
||||||
info.Unfixable = true
|
info.Unfixable = true
|
||||||
t.writeTorrentToFile(id, info)
|
t.writeTorrentToFile(id, info)
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package torrent
|
|||||||
import (
|
import (
|
||||||
stdjson "encoding/json"
|
stdjson "encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/debridmediamanager/zurg/pkg/realdebrid"
|
"github.com/debridmediamanager/zurg/pkg/realdebrid"
|
||||||
@@ -27,9 +26,7 @@ type Torrent struct {
|
|||||||
Unfixable bool `json:"Unfixable"` // modified over time
|
Unfixable bool `json:"Unfixable"` // modified over time
|
||||||
BrokenLinks mapset.Set[string] `json:"BrokenLinks"` // only relevant on repair
|
BrokenLinks mapset.Set[string] `json:"BrokenLinks"` // only relevant on repair
|
||||||
|
|
||||||
Version string `json:"Version"` // only used for files
|
Version string `json:"Version"` // only used for files
|
||||||
Repairing bool `json:"-"`
|
|
||||||
Lock *sync.Mutex `json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) MarshalJSON() ([]byte, error) {
|
func (t *Torrent) MarshalJSON() ([]byte, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user