Important hotfixes:

- Re-inserting botched torrents
- Fixing issues with failed download link
This commit is contained in:
Mukhtar Akere
2025-04-29 11:36:16 +01:00
parent 75a5bb90a3
commit 6c2bfa811a
2 changed files with 49 additions and 28 deletions

View File

@@ -151,14 +151,17 @@ func (c *Cache) reInsertTorrent(ct *CachedTorrent) (*CachedTorrent, error) {
c.repairRequest.Delete(oldID) c.repairRequest.Delete(oldID)
}() }()
if torrent.Magnet == nil {
torrent.Magnet = utils.ConstructMagnet(torrent.InfoHash, torrent.Name)
}
// Submit the magnet to the debrid service // Submit the magnet to the debrid service
torrent.Id = "" newTorrent := &types.Torrent{
Name: torrent.Name,
Magnet: utils.ConstructMagnet(torrent.InfoHash, torrent.Name),
InfoHash: torrent.InfoHash,
Size: torrent.Size,
Files: make(map[string]types.File),
Arr: torrent.Arr,
}
var err error var err error
torrent, err = c.client.SubmitMagnet(torrent) newTorrent, err = c.client.SubmitMagnet(newTorrent)
if err != nil { if err != nil {
c.failedToReinsert.Store(oldID, struct{}{}) c.failedToReinsert.Store(oldID, struct{}{})
// Remove the old torrent from the cache and debrid service // Remove the old torrent from the cache and debrid service
@@ -166,19 +169,19 @@ func (c *Cache) reInsertTorrent(ct *CachedTorrent) (*CachedTorrent, error) {
} }
// Check if the torrent was submitted // Check if the torrent was submitted
if torrent == nil || torrent.Id == "" { if newTorrent == nil || newTorrent.Id == "" {
c.failedToReinsert.Store(oldID, struct{}{}) c.failedToReinsert.Store(oldID, struct{}{})
return ct, 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 newTorrent.DownloadUncached = false // Set to false, avoid re-downloading
torrent, err = c.client.CheckStatus(torrent, true) newTorrent, err = c.client.CheckStatus(newTorrent, true)
if err != nil { if err != nil {
if torrent != nil && torrent.Id != "" { if newTorrent != nil && newTorrent.Id != "" {
// Delete the torrent if it was not downloaded // Delete the torrent if it was not downloaded
_ = c.client.DeleteTorrent(torrent.Id) _ = c.client.DeleteTorrent(newTorrent.Id)
} }
c.failedToReinsert.Store(oldID, struct{}{}) c.failedToReinsert.Store(oldID, struct{}{})
return ct, fmt.Errorf("failed to check status: %w", err) return ct, err
} }
// Update the torrent in the cache // Update the torrent in the cache
@@ -186,21 +189,21 @@ func (c *Cache) reInsertTorrent(ct *CachedTorrent) (*CachedTorrent, error) {
if err != nil { if err != nil {
addedOn = time.Now() addedOn = time.Now()
} }
for _, f := range torrent.Files { for _, f := range newTorrent.Files {
if f.Link == "" { if f.Link == "" {
c.failedToReinsert.Store(oldID, struct{}{}) c.failedToReinsert.Store(oldID, struct{}{})
return ct, fmt.Errorf("failed to reinsert torrent: empty link") return ct, fmt.Errorf("failed to reinsert torrent: empty link")
} }
} }
// Set torrent to newTorrent
ct = &CachedTorrent{ ct = &CachedTorrent{
Torrent: torrent, Torrent: newTorrent,
AddedOn: addedOn, AddedOn: addedOn,
IsComplete: len(torrent.Files) > 0, IsComplete: len(newTorrent.Files) > 0,
} }
c.setTorrent(ct)
c.RefreshListings(true)
// We can safely delete the old torrent here // We can safely delete the old torrent here
c.setTorrent(ct)
if oldID != "" { if oldID != "" {
if err := c.DeleteTorrent(oldID); err != nil { if err := c.DeleteTorrent(oldID); err != nil {
return ct, fmt.Errorf("failed to delete old torrent: %w", err) return ct, fmt.Errorf("failed to delete old torrent: %w", err)

View File

@@ -319,15 +319,17 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Handle GET requests for file/directory content // Handle GET requests for file/directory content
if r.Method == "GET" { if r.Method == "GET" {
f, err := h.OpenFile(r.Context(), r.URL.Path, os.O_RDONLY, 0) fRaw, err := h.OpenFile(r.Context(), r.URL.Path, os.O_RDONLY, 0)
if err != nil { if err != nil {
h.logger.Error().Err(err).Str("path", r.URL.Path).Msg("Failed to open file") h.logger.Error().Err(err).
Str("path", r.URL.Path).
Msg("Failed to open file")
http.NotFound(w, r) http.NotFound(w, r)
return return
} }
defer f.Close() defer fRaw.Close()
fi, err := f.Stat() fi, err := fRaw.Stat()
if err != nil { if err != nil {
h.logger.Error().Err(err).Msg("Failed to stat file") h.logger.Error().Err(err).Msg("Failed to stat file")
http.Error(w, "Server Error", http.StatusInternalServerError) http.Error(w, "Server Error", http.StatusInternalServerError)
@@ -336,14 +338,31 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// If the target is a directory, use your directory listing logic. // If the target is a directory, use your directory listing logic.
if fi.IsDir() { if fi.IsDir() {
h.serveDirectory(w, r, f) h.serveDirectory(w, r, fRaw)
return return
} }
rs, ok := f.(io.ReadSeeker) if file, ok := fRaw.(*File); ok {
link, err := file.getDownloadLink()
if err != nil {
h.logger.Error().
Err(err).
Str("path", r.URL.Path).
Msg("Could not fetch download link")
http.Error(w, "Could not fetch download link", http.StatusServiceUnavailable)
return
}
if link == "" {
http.NotFound(w, r)
return
}
file.downloadLink = link
}
rs, ok := fRaw.(io.ReadSeeker)
if !ok { if !ok {
// If not, read the entire file into memory as a fallback. // If not, read the entire file into memory as a fallback.
buf, err := io.ReadAll(f) buf, err := io.ReadAll(fRaw)
if err != nil { if err != nil {
h.logger.Error().Err(err).Msg("Failed to read file content") h.logger.Error().Err(err).Msg("Failed to read file content")
http.Error(w, "Server Error", http.StatusInternalServerError) http.Error(w, "Server Error", http.StatusInternalServerError)
@@ -354,8 +373,6 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fileName := fi.Name() fileName := fi.Name()
contentType := getContentType(fileName) contentType := getContentType(fileName)
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
// Serve the file with the correct modification time.
// http.ServeContent automatically handles Range requests. // http.ServeContent automatically handles Range requests.
http.ServeContent(w, r, fileName, fi.ModTime(), rs) http.ServeContent(w, r, fileName, fi.ModTime(), rs)
return return
@@ -378,11 +395,12 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
w.Header().Set("Content-Type", getContentType(fi.Name())) w.Header().Set("Content-Type", getContentType(fi.Name()))
w.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size())) w.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size()))
w.Header().Set("Last-Modified", fi.ModTime().UTC().Format(http.TimeFormat))
w.Header().Set("Accept-Ranges", "bytes")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
return return
} }
// Fallback: for other methods, use the standard WebDAV handler.
handler := &webdav.Handler{ handler := &webdav.Handler{
FileSystem: h, FileSystem: h,
LockSystem: webdav.NewMemLS(), LockSystem: webdav.NewMemLS(),