Hotfixes:

- Fix % error in url encode
- FIx alldebrid downloading bug
- Fix dupicate checks for newly added torrents
This commit is contained in:
Mukhtar Akere
2025-04-20 00:44:58 +01:00
parent dc8ee3d150
commit a27c5dd491
11 changed files with 137 additions and 92 deletions

View File

@@ -10,3 +10,12 @@ func EscapePath(path string) string {
return escapedPath return escapedPath
} }
func UnescapePath(path string) string {
// unescape %
unescapedPath := strings.ReplaceAll(path, "%25", "%")
// add others
return unescapedPath
}

View File

@@ -247,6 +247,12 @@ func (a *Arr) DeleteFiles(files []ContentFile) error {
for _, f := range files { for _, f := range files {
ids = append(ids, f.FileId) ids = append(ids, f.FileId)
} }
defer func() {
// Delete files, or at least try
for _, f := range files {
f.Delete()
}
}()
var payload interface{} var payload interface{}
switch a.Type { switch a.Type {
case Sonarr: case Sonarr:

View File

@@ -1,5 +1,7 @@
package arr package arr
import "os"
type Movie struct { type Movie struct {
Title string `json:"title"` Title string `json:"title"`
OriginalTitle string `json:"originalTitle"` OriginalTitle string `json:"originalTitle"`
@@ -25,6 +27,12 @@ type ContentFile struct {
SeasonNumber int `json:"seasonNumber"` SeasonNumber int `json:"seasonNumber"`
} }
func (file *ContentFile) Delete() {
// This is useful for when sonarr bulk delete fails(this usually happens)
// and we need to delete the file manually
_ = os.Remove(file.Path) // nolint:errcheck
}
type Content struct { type Content struct {
Title string `json:"title"` Title string `json:"title"`
Id int `json:"id"` Id int `json:"id"`

View File

@@ -198,15 +198,16 @@ func (ad *AllDebrid) UpdateTorrent(t *types.Torrent) error {
t.Folder = name t.Folder = name
t.MountPath = ad.MountPath t.MountPath = ad.MountPath
t.Debrid = ad.Name t.Debrid = ad.Name
t.Bytes = data.Size
t.Seeders = data.Seeders
if status == "downloaded" { if status == "downloaded" {
t.Bytes = data.Size t.Progress = 100
t.Progress = float64((data.Downloaded / data.Size) * 100)
t.Speed = data.DownloadSpeed
t.Seeders = data.Seeders
index := -1 index := -1
files := flattenFiles(data.Files, "", &index) files := flattenFiles(data.Files, "", &index)
t.Files = files t.Files = files
} else {
t.Progress = float64(data.Downloaded) / float64(data.Size) * 100
t.Speed = data.DownloadSpeed
} }
return nil return nil
} }
@@ -269,7 +270,7 @@ func (ad *AllDebrid) GenerateDownloadLinks(t *types.Torrent) error {
} }
file.DownloadLink = link file.DownloadLink = link
if link != nil { if link != nil {
errCh <- fmt.Errorf("error getting download links %w", err) errCh <- fmt.Errorf("download link is empty")
return return
} }
filesCh <- file filesCh <- file
@@ -310,9 +311,13 @@ func (ad *AllDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types
if err = json.Unmarshal(resp, &data); err != nil { if err = json.Unmarshal(resp, &data); err != nil {
return nil, err return nil, err
} }
if data.Error != nil {
return nil, fmt.Errorf("error getting download link: %s", data.Error.Message)
}
link := data.Data.Link link := data.Data.Link
if link == "" { if link == "" {
return nil, fmt.Errorf("error getting download links %s", data.Error.Message) return nil, fmt.Errorf("download link is empty")
} }
return &types.DownloadLink{ return &types.DownloadLink{
Link: file.Link, Link: file.Link,

View File

@@ -194,7 +194,6 @@ func (c *Cache) load() (map[string]*CachedTorrent, error) {
wg.Add(1) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
now := time.Now()
for { for {
file, ok := <-workChan file, ok := <-workChan
@@ -227,11 +226,10 @@ func (c *Cache) load() (map[string]*CachedTorrent, error) {
} }
if isComplete { if isComplete {
addedOn, err := time.Parse(time.RFC3339, ct.Added)
if err != nil { if addedOn, err := time.Parse(time.RFC3339, ct.Added); err == nil {
addedOn = now ct.AddedOn = addedOn
} }
ct.AddedOn = addedOn
ct.IsComplete = true ct.IsComplete = true
ct.Name = path.Clean(ct.Name) ct.Name = path.Clean(ct.Name)
results.Store(ct.Id, &ct) results.Store(ct.Id, &ct)
@@ -278,9 +276,9 @@ func (c *Cache) Sync() error {
c.logger.Info().Msgf("Got %d torrents from %s", len(torrents), c.client.GetName()) c.logger.Info().Msgf("Got %d torrents from %s", len(torrents), c.client.GetName())
newTorrents := make([]*types.Torrent, 0) newTorrents := make([]*types.Torrent, 0)
idStore := make(map[string]struct{}, len(torrents)) idStore := make(map[string]string, len(torrents))
for _, t := range torrents { for _, t := range torrents {
idStore[t.Id] = struct{}{} idStore[t.Id] = t.Added
if _, ok := cachedTorrents[t.Id]; !ok { if _, ok := cachedTorrents[t.Id]; !ok {
newTorrents = append(newTorrents, t) newTorrents = append(newTorrents, t)
} }
@@ -289,6 +287,10 @@ func (c *Cache) Sync() error {
// Check for deleted torrents // Check for deleted torrents
deletedTorrents := make([]string, 0) deletedTorrents := make([]string, 0)
for _, t := range cachedTorrents { for _, t := range cachedTorrents {
t.Added = idStore[t.Id]
if addedOn, err := time.Parse(time.RFC3339, t.Added); err == nil {
t.AddedOn = addedOn
}
if _, ok := idStore[t.Id]; !ok { if _, ok := idStore[t.Id]; !ok {
deletedTorrents = append(deletedTorrents, t.Id) deletedTorrents = append(deletedTorrents, t.Id)
} }
@@ -399,20 +401,35 @@ func (c *Cache) GetTorrentFolder(torrent *types.Torrent) string {
func (c *Cache) setTorrent(t *CachedTorrent) { func (c *Cache) setTorrent(t *CachedTorrent) {
c.torrents.Store(t.Id, t) c.torrents.Store(t.Id, t)
torrentKey := c.GetTorrentFolder(t.Torrent)
c.torrentsNames.Store(c.GetTorrentFolder(t.Torrent), t) if o, ok := c.torrentsNames.Load(torrentKey); ok && o.Id != t.Id {
// Save the most recent torrent
if t.AddedOn.After(o.AddedOn) {
c.torrentsNames.Delete(torrentKey)
} else {
t = o
}
}
c.torrentsNames.Store(torrentKey, t)
c.SaveTorrent(t) c.SaveTorrent(t)
} }
func (c *Cache) setTorrents(torrents map[string]*CachedTorrent) { func (c *Cache) setTorrents(torrents map[string]*CachedTorrent) {
for _, t := range torrents { for _, t := range torrents {
c.torrents.Store(t.Id, t) c.torrents.Store(t.Id, t)
c.torrentsNames.Store(c.GetTorrentFolder(t.Torrent), t) torrentKey := c.GetTorrentFolder(t.Torrent)
if o, ok := c.torrentsNames.Load(torrentKey); ok && o.Id != t.Id {
// Save the most recent torrent
if t.AddedOn.After(o.AddedOn) {
c.torrentsNames.Delete(torrentKey)
} else {
t = o
}
}
c.torrentsNames.Store(torrentKey, t)
} }
c.RefreshListings(true) c.RefreshListings(false)
c.SaveTorrents() c.SaveTorrents()
} }
@@ -552,13 +569,6 @@ func (c *Cache) ProcessTorrent(t *types.Torrent) error {
if !isComplete(t.Files) { if !isComplete(t.Files) {
c.logger.Debug().Msgf("Torrent %s is still not complete. Triggering a reinsert(disabled)", t.Id) c.logger.Debug().Msgf("Torrent %s is still not complete. Triggering a reinsert(disabled)", t.Id)
//err := c.reInsertTorrent(t)
//if err != nil {
// c.logger.Error().Err(err).Msgf("Failed to reinsert torrent %s", t.Id)
// return err
//}
//c.logger.Debug().Msgf("Reinserted torrent %s", ct.Id)
} else { } else {
addedOn, err := time.Parse(time.RFC3339, t.Added) addedOn, err := time.Parse(time.RFC3339, t.Added)
if err != nil { if err != nil {
@@ -601,10 +611,12 @@ func (c *Cache) GetDownloadLink(torrentId, filename, fileLink string) string {
if file.Link == "" { if file.Link == "" {
c.logger.Debug().Msgf("File link is empty for %s. Release is probably nerfed", filename) c.logger.Debug().Msgf("File link is empty for %s. Release is probably nerfed", filename)
// Try to reinsert the torrent? // Try to reinsert the torrent?
if err := c.reInsertTorrent(ct); err != nil { newCt, err := c.reInsertTorrent(ct)
if err != nil {
c.logger.Error().Err(err).Msgf("Failed to reinsert torrent %s", ct.Name) c.logger.Error().Err(err).Msgf("Failed to reinsert torrent %s", ct.Name)
return "" return ""
} }
ct = newCt
file = ct.Files[filename] file = ct.Files[filename]
c.logger.Debug().Msgf("Reinserted torrent %s", ct.Name) c.logger.Debug().Msgf("Reinserted torrent %s", ct.Name)
} }
@@ -614,11 +626,12 @@ func (c *Cache) GetDownloadLink(torrentId, filename, fileLink string) string {
if err != nil { if err != nil {
if errors.Is(err, request.HosterUnavailableError) { if errors.Is(err, request.HosterUnavailableError) {
c.logger.Error().Err(err).Msgf("Hoster is unavailable. Triggering repair for %s", ct.Name) c.logger.Error().Err(err).Msgf("Hoster is unavailable. Triggering repair for %s", ct.Name)
err := c.reInsertTorrent(ct) newCt, err := c.reInsertTorrent(ct)
if err != nil { if err != nil {
c.logger.Error().Err(err).Msgf("Failed to reinsert torrent %s", ct.Name) c.logger.Error().Err(err).Msgf("Failed to reinsert torrent %s", ct.Name)
return "" return ""
} }
ct = newCt
c.logger.Debug().Msgf("Reinserted torrent %s", ct.Name) c.logger.Debug().Msgf("Reinserted torrent %s", ct.Name)
file = ct.Files[filename] file = ct.Files[filename]
// Retry getting the download link // Retry getting the download link

View File

@@ -109,11 +109,11 @@ func (c *Cache) refreshTorrents() {
if len(newTorrents) == 0 { if len(newTorrents) == 0 {
return return
} }
c.logger.Debug().Msgf("Found %d new torrents", len(newTorrents))
workChan := make(chan *types.Torrent, min(100, len(newTorrents))) workChan := make(chan *types.Torrent, min(100, len(newTorrents)))
errChan := make(chan error, len(newTorrents)) errChan := make(chan error, len(newTorrents))
var wg sync.WaitGroup var wg sync.WaitGroup
counter := 0
for i := 0; i < c.workers; i++ { for i := 0; i < c.workers; i++ {
wg.Add(1) wg.Add(1)
@@ -121,13 +121,12 @@ func (c *Cache) refreshTorrents() {
defer wg.Done() defer wg.Done()
for t := range workChan { for t := range workChan {
select { select {
case <-c.ctx.Done():
return
default: default:
} if err := c.ProcessTorrent(t); err != nil {
if err := c.ProcessTorrent(t); err != nil { c.logger.Error().Err(err).Msgf("Failed to process new torrent %s", t.Id)
c.logger.Error().Err(err).Msgf("Failed to process new torrent %s", t.Id) errChan <- err
errChan <- err }
counter++
} }
} }
}() }()
@@ -135,8 +134,6 @@ func (c *Cache) refreshTorrents() {
for _, t := range newTorrents { for _, t := range newTorrents {
select { select {
case <-c.ctx.Done():
break
default: default:
workChan <- t workChan <- t
} }
@@ -146,7 +143,7 @@ func (c *Cache) refreshTorrents() {
c.RefreshListings(true) c.RefreshListings(true)
c.logger.Debug().Msgf("Processed %d new torrents", len(newTorrents)) c.logger.Debug().Msgf("Processed %d new torrents", counter)
} }
func (c *Cache) RefreshRclone() error { func (c *Cache) RefreshRclone() error {

View File

@@ -37,6 +37,11 @@ func (c *Cache) IsTorrentBroken(t *CachedTorrent, filenames []string) bool {
} }
} }
if t == nil || t.Torrent == nil {
c.logger.Error().Str("torrentId", t.Torrent.Id).Msg("Failed to refresh torrent")
return true
}
files = t.Files files = t.Files
for _, f := range files { for _, f := range files {
@@ -58,13 +63,11 @@ func (c *Cache) IsTorrentBroken(t *CachedTorrent, filenames []string) bool {
// Try to reinsert the torrent if it's broken // Try to reinsert the torrent if it's broken
if cfg.Repair.ReInsert && isBroken && t.Torrent != nil { if cfg.Repair.ReInsert && isBroken && t.Torrent != nil {
// Check if the torrent is already in progress // Check if the torrent is already in progress
if err := c.reInsertTorrent(t); err != nil { if _, err := c.reInsertTorrent(t); err != nil {
c.logger.Error().Err(err).Str("torrentId", t.Torrent.Id).Msg("Failed to reinsert torrent") c.logger.Error().Err(err).Str("torrentId", t.Torrent.Id).Msg("Failed to reinsert torrent")
return true return true
} else {
c.logger.Debug().Str("torrentId", t.Torrent.Id).Msg("Reinserted torrent")
return false
} }
return false
} }
return isBroken return isBroken
@@ -86,7 +89,7 @@ func (c *Cache) repairWorker() {
switch req.Type { switch req.Type {
case RepairTypeReinsert: case RepairTypeReinsert:
c.logger.Debug().Str("torrentId", torrentId).Msg("Reinserting torrent") c.logger.Debug().Str("torrentId", torrentId).Msg("Reinserting torrent")
if err := c.reInsertTorrent(cachedTorrent); err != nil { if _, err := c.reInsertTorrent(cachedTorrent); err != nil {
c.logger.Error().Err(err).Str("torrentId", cachedTorrent.Id).Msg("Failed to reinsert torrent") c.logger.Error().Err(err).Str("torrentId", cachedTorrent.Id).Msg("Failed to reinsert torrent")
continue continue
} }
@@ -100,12 +103,12 @@ func (c *Cache) repairWorker() {
} }
} }
func (c *Cache) reInsertTorrent(ct *CachedTorrent) error { func (c *Cache) reInsertTorrent(ct *CachedTorrent) (*CachedTorrent, error) {
// Check if Magnet is not empty, if empty, reconstruct the magnet // Check if Magnet is not empty, if empty, reconstruct the magnet
torrent := ct.Torrent torrent := ct.Torrent
oldID := torrent.Id // Store the old ID oldID := torrent.Id // Store the old ID
if _, ok := c.repairsInProgress.Load(oldID); ok { if _, ok := c.repairsInProgress.Load(oldID); ok {
return fmt.Errorf("repair already in progress for torrent %s", torrent.Id) return ct, fmt.Errorf("repair already in progress for torrent %s", torrent.Id)
} }
c.repairsInProgress.Store(oldID, struct{}{}) c.repairsInProgress.Store(oldID, struct{}{})
defer c.repairsInProgress.Delete(oldID) defer c.repairsInProgress.Delete(oldID)
@@ -120,53 +123,53 @@ func (c *Cache) reInsertTorrent(ct *CachedTorrent) error {
torrent, err = c.client.SubmitMagnet(torrent) torrent, err = c.client.SubmitMagnet(torrent)
if err != nil { if err != nil {
// Remove the old torrent from the cache and debrid service // Remove the old torrent from the cache and debrid service
return fmt.Errorf("failed to submit magnet: %w", err) return ct, fmt.Errorf("failed to submit magnet: %w", err)
} }
// Check if the torrent was submitted // Check if the torrent was submitted
if torrent == nil || torrent.Id == "" { if torrent == nil || torrent.Id == "" {
return fmt.Errorf("failed to submit magnet: empty torrent") return ct, fmt.Errorf("failed to submit magnet: empty torrent")
} }
torrent.DownloadUncached = false // Set to false, avoid re-downloading torrent.DownloadUncached = false // Set to false, avoid re-downloading
torrent, err = c.client.CheckStatus(torrent, true) torrent, err = c.client.CheckStatus(torrent, true)
if err != nil && torrent != nil { if err != nil && torrent != nil {
// Torrent is likely in progress // Torrent is likely in progress
_ = c.DeleteTorrent(torrent.Id) _ = c.DeleteTorrent(torrent.Id)
return ct, fmt.Errorf("failed to check status: %w", err)
return fmt.Errorf("failed to check status: %w", err)
} }
if torrent == nil { if torrent == nil {
return fmt.Errorf("failed to check status: empty torrent") return ct, fmt.Errorf("failed to check status: empty torrent")
} }
// Update the torrent in the cache // Update the torrent in the cache
addedOn, err := time.Parse(time.RFC3339, torrent.Added) addedOn, err := time.Parse(time.RFC3339, torrent.Added)
if err != nil {
addedOn = time.Now()
}
for _, f := range torrent.Files { for _, f := range torrent.Files {
if f.Link == "" { if f.Link == "" {
// Delete the new torrent // Delete the new torrent
_ = c.DeleteTorrent(torrent.Id) _ = c.DeleteTorrent(torrent.Id)
return fmt.Errorf("failed to reinsert torrent: empty link") return ct, fmt.Errorf("failed to reinsert torrent: empty link")
} }
} }
if err != nil {
addedOn = time.Now()
}
// We can safely delete the old torrent here // We can safely delete the old torrent here
if oldID != "" { if oldID != "" {
if err := c.DeleteTorrent(oldID); err != nil { if err := c.DeleteTorrent(oldID); err != nil {
return fmt.Errorf("failed to delete old torrent: %w", err) return ct, fmt.Errorf("failed to delete old torrent: %w", err)
} }
} }
ct.Torrent = torrent ct = &CachedTorrent{
ct.IsComplete = len(torrent.Files) > 0 Torrent: torrent,
ct.AddedOn = addedOn AddedOn: addedOn,
IsComplete: len(torrent.Files) > 0,
}
c.setTorrent(ct) c.setTorrent(ct)
c.RefreshListings(true) c.RefreshListings(true)
c.logger.Debug().Str("torrentId", torrent.Id).Msg("Reinserted torrent") c.logger.Debug().Str("torrentId", torrent.Id).Msg("Reinserted torrent")
return nil return ct, nil
} }
func (c *Cache) resetInvalidLinks() { func (c *Cache) resetInvalidLinks() {

View File

@@ -181,8 +181,7 @@ func (q *QBit) UpdateTorrentMin(t *Torrent, debridTorrent *debrid.Torrent) *Torr
addedOn = time.Now() addedOn = time.Now()
} }
totalSize := debridTorrent.Bytes totalSize := debridTorrent.Bytes
progress := cmp.Or(debridTorrent.Progress, 0.0) progress := (cmp.Or(debridTorrent.Progress, 0.0)) / 100.0
progress = progress / 100.0
sizeCompleted := int64(float64(totalSize) * progress) sizeCompleted := int64(float64(totalSize) * progress)
var speed int64 var speed int64
@@ -218,9 +217,11 @@ func (q *QBit) UpdateTorrent(t *Torrent, debridTorrent *debrid.Torrent) *Torrent
if debridTorrent == nil { if debridTorrent == nil {
return t return t
} }
_db := service.GetDebrid().GetClient(debridTorrent.Debrid)
if debridTorrent.Status != "downloaded" { if debridClient := service.GetDebrid().GetClient(debridTorrent.Debrid); debridClient != nil {
_ = _db.UpdateTorrent(debridTorrent) if debridTorrent.Status != "downloaded" {
_ = debridClient.UpdateTorrent(debridTorrent)
}
} }
t = q.UpdateTorrentMin(t, debridTorrent) t = q.UpdateTorrentMin(t, debridTorrent)
t.ContentPath = t.TorrentPath + string(os.PathSeparator) t.ContentPath = t.TorrentPath + string(os.PathSeparator)

View File

@@ -228,7 +228,7 @@ type Torrent struct {
} }
func (t *Torrent) IsReady() bool { func (t *Torrent) IsReady() bool {
return t.AmountLeft <= 0 && t.TorrentPath != "" return (t.AmountLeft <= 0 || t.Progress == 1) && t.TorrentPath != ""
} }
func (t *Torrent) discordContext() string { func (t *Torrent) discordContext() string {

View File

@@ -81,14 +81,14 @@ func (f *File) stream() (*http.Response, error) {
downloadLink = f.getDownloadLink() // Uses the first API key downloadLink = f.getDownloadLink() // Uses the first API key
if downloadLink == "" { if downloadLink == "" {
_log.Error().Msgf("Failed to get download link for %s. Empty download link", f.name) _log.Trace().Msgf("Failed to get download link for %s. Empty download link", f.name)
return nil, fmt.Errorf("failed to get download link") return nil, io.EOF
} }
req, err := http.NewRequest("GET", downloadLink, nil) req, err := http.NewRequest("GET", downloadLink, nil)
if err != nil { if err != nil {
_log.Error().Msgf("Failed to create HTTP request: %s", err) _log.Trace().Msgf("Failed to create HTTP request: %s", err)
return nil, fmt.Errorf("failed to create HTTP request: %w", err) return nil, io.EOF
} }
if f.offset > 0 { if f.offset > 0 {
@@ -97,7 +97,7 @@ func (f *File) stream() (*http.Response, error) {
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return resp, fmt.Errorf("HTTP request error: %w", err) return resp, io.EOF
} }
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent { if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
@@ -113,15 +113,17 @@ func (f *File) stream() (*http.Response, error) {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
err := resp.Body.Close() err := resp.Body.Close()
if err != nil { if err != nil {
return nil, err _log.Trace().Msgf("Failed to close response body: %s", err)
return nil, io.EOF
} }
if strings.Contains(string(b), "You can not download this file because you have exceeded your traffic on this hoster") { if strings.Contains(string(b), "You can not download this file because you have exceeded your traffic on this hoster") {
_log.Error().Msgf("Failed to get download link for %s. Download link expired", f.name) _log.Trace().Msgf("Failed to get download link for %s. Download link expired", f.name)
f.cache.MarkDownloadLinkAsInvalid(f.link, downloadLink, "bandwidth_exceeded") f.cache.MarkDownloadLinkAsInvalid(f.link, downloadLink, "bandwidth_exceeded")
// Retry with a different API key if it's available // Retry with a different API key if it's available
return f.stream() return f.stream()
} else { } else {
return resp, fmt.Errorf("link not found") _log.Trace().Msgf("Failed to get download link for %s. %s", f.name, string(b))
return resp, io.EOF
} }
} else if resp.StatusCode == http.StatusNotFound { } else if resp.StatusCode == http.StatusNotFound {
@@ -132,12 +134,12 @@ func (f *File) stream() (*http.Response, error) {
// Generate a new download link // Generate a new download link
downloadLink = f.getDownloadLink() downloadLink = f.getDownloadLink()
if downloadLink == "" { if downloadLink == "" {
_log.Error().Msgf("Failed to get download link for %s", f.name) _log.Trace().Msgf("Failed to get download link for %s", f.name)
return nil, fmt.Errorf("failed to get download link") return nil, io.EOF
} }
req, err = http.NewRequest("GET", downloadLink, nil) req, err = http.NewRequest("GET", downloadLink, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create HTTP request: %w", err) return nil, io.EOF
} }
if f.offset > 0 { if f.offset > 0 {
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", f.offset)) req.Header.Set("Range", fmt.Sprintf("bytes=%d-", f.offset))
@@ -151,13 +153,13 @@ func (f *File) stream() (*http.Response, error) {
closeResp() closeResp()
// Read the body to consume the response // Read the body to consume the response
f.cache.MarkDownloadLinkAsInvalid(f.link, downloadLink, "link_not_found") f.cache.MarkDownloadLinkAsInvalid(f.link, downloadLink, "link_not_found")
return resp, fmt.Errorf("link not found") return resp, io.EOF
} }
return resp, nil return resp, nil
} else { } else {
closeResp() closeResp()
return resp, fmt.Errorf("unexpected HTTP status: %d", resp.StatusCode) return resp, io.EOF
} }
} }
@@ -194,7 +196,7 @@ func (f *File) Read(p []byte) (n int, err error) {
return 0, err return 0, err
} }
if resp == nil { if resp == nil {
return 0, fmt.Errorf("failed to get response") return 0, io.EOF
} }
f.reader = resp.Body f.reader = resp.Body

View File

@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/sirrobot01/decypharr/internal/request" "github.com/sirrobot01/decypharr/internal/request"
"github.com/sirrobot01/decypharr/internal/utils"
"github.com/sirrobot01/decypharr/pkg/debrid/debrid" "github.com/sirrobot01/decypharr/pkg/debrid/debrid"
"github.com/sirrobot01/decypharr/pkg/debrid/types" "github.com/sirrobot01/decypharr/pkg/debrid/types"
"github.com/sirrobot01/decypharr/pkg/version" "github.com/sirrobot01/decypharr/pkg/version"
@@ -103,7 +104,7 @@ func (h *Handler) getParentFiles() []os.FileInfo {
} }
func (h *Handler) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) { func (h *Handler) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
name = path.Clean("/" + name) name = utils.UnescapePath(path.Clean("/" + name))
rootDir := h.getRootPath() rootDir := h.getRootPath()
metadataOnly := ctx.Value("metadataOnly") != nil metadataOnly := ctx.Value("metadataOnly") != nil
@@ -261,16 +262,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// __all__ or torrents folder // __all__ or torrents folder
// Manually build the xml // Manually build the xml
ttl = 30 * time.Second ttl = 30 * time.Second
if served := h.serveFromCacheIfValid(w, r, cacheKey, ttl); served { //if served := h.serveFromCacheIfValid(w, r, cacheKey, ttl); served {
return // return
} //}
// Refresh the parent XML //// Refresh the parent XML
h.cache.RefreshListings(false) //h.cache.RefreshListings(false)
// Check again if the cache is valid //// Check again if the cache is valid
// If not, we will use the default WebDAV handler //// If not, we will use the default WebDAV handler
if served := h.serveFromCacheIfValid(w, r, cacheKey, ttl); served { //if served := h.serveFromCacheIfValid(w, r, cacheKey, ttl); served {
return // return
} //}
} }
if served := h.serveFromCacheIfValid(w, r, cacheKey, ttl); served { if served := h.serveFromCacheIfValid(w, r, cacheKey, ttl); served {