Important hotfixes:
- Re-inserting botched torrents - Fixing issues with failed download link
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
Reference in New Issue
Block a user