This commit is contained in:
Ben Sarmiento
2024-01-16 20:10:46 +01:00
parent 2cb29284f6
commit 727c694c02
5 changed files with 41 additions and 22 deletions

View File

@@ -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)
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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) {