- Fix nil checks

- Enable add arr to config page
- Other minor fixes
This commit is contained in:
Mukhtar Akere
2025-04-27 23:43:19 +01:00
parent a3e64cc269
commit f977c52571
6 changed files with 41 additions and 35 deletions

View File

@@ -621,13 +621,12 @@ func (c *Cache) GetClient() types.Client {
} }
func (c *Cache) DeleteTorrent(id string) error { func (c *Cache) DeleteTorrent(id string) error {
c.logger.Info().Msgf("Deleting torrent %s from cache", id)
c.torrentsRefreshMu.Lock() c.torrentsRefreshMu.Lock()
defer c.torrentsRefreshMu.Unlock() defer c.torrentsRefreshMu.Unlock()
if c.deleteTorrent(id, true) { if c.deleteTorrent(id, true) {
c.RefreshListings(true) c.RefreshListings(true)
c.logger.Info().Msgf("Torrent %s deleted successfully", id) c.logger.Trace().Msgf("Torrent %s deleted successfully", id)
return nil return nil
} }
return nil return nil

View File

@@ -55,12 +55,16 @@ func (c *Cache) IsTorrentBroken(t *CachedTorrent, filenames []string) bool {
// Check if file is missing // Check if file is missing
if f.Link == "" { if f.Link == "" {
// refresh torrent and then break // refresh torrent and then break
t = c.refreshTorrent(t) if newT := c.refreshTorrent(t); newT != nil {
break t = newT
} else {
c.logger.Error().Str("torrentId", t.Torrent.Id).Msg("Failed to refresh torrent")
return true
}
} }
} }
if t == nil || t.Torrent == nil { if t.Torrent == nil {
c.logger.Error().Str("torrentId", t.Torrent.Id).Msg("Failed to refresh torrent") c.logger.Error().Str("torrentId", t.Torrent.Id).Msg("Failed to refresh torrent")
return true return true
} }

View File

@@ -222,39 +222,44 @@ func (q *QBit) createSymlinks(debridTorrent *debrid.Torrent, rclonePath, torrent
return "", fmt.Errorf("failed to create directory: %s: %v", symlinkPath, err) return "", fmt.Errorf("failed to create directory: %s: %v", symlinkPath, err)
} }
pending := make(map[string]debrid.File) remainingFiles := make(map[string]debrid.File)
for _, file := range files { for _, file := range files {
pending[file.Path] = file remainingFiles[file.Path] = file
} }
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
filePaths := make([]string, 0, len(pending))
for len(pending) > 0 { ticker := time.NewTicker(100 * time.Millisecond)
<-ticker.C defer ticker.Stop()
for path, file := range pending { timeout := time.After(30 * time.Minute)
fullFilePath := filepath.Join(rclonePath, file.Name) filePaths := make([]string, 0, len(files))
if _, err := os.Stat(fullFilePath); !os.IsNotExist(err) {
q.logger.Info().Msgf("File is ready: %s", file.Name) for len(remainingFiles) > 0 {
fileSymlinkPath := filepath.Join(symlinkPath, file.Name) select {
if err := os.Symlink(fullFilePath, fileSymlinkPath); err != nil && !os.IsExist(err) { case <-ticker.C:
q.logger.Debug().Msgf("Failed to create symlink: %s: %v", fileSymlinkPath, err) entries, err := os.ReadDir(rclonePath)
} if err != nil {
filePaths = append(filePaths, fileSymlinkPath) continue
delete(pending, path) }
} else if file.Name != file.Path {
// This is likely alldebrid nested files(not using webdav) // Check which files exist in this batch
fullFilePath = filepath.Join(rclonePath, file.Path) for _, entry := range entries {
if _, err := os.Stat(fullFilePath); !os.IsNotExist(err) { filename := entry.Name()
q.logger.Info().Msgf("File is ready: %s", file.Path) if file, exists := remainingFiles[filename]; exists {
fileSymlinkPath := filepath.Join(symlinkPath, file.Path) fullFilePath := filepath.Join(rclonePath, filename)
fileSymlinkPath := filepath.Join(symlinkPath, file.Name)
if err := os.Symlink(fullFilePath, fileSymlinkPath); err != nil && !os.IsExist(err) { if err := os.Symlink(fullFilePath, fileSymlinkPath); err != nil && !os.IsExist(err) {
q.logger.Debug().Msgf("Failed to create symlink: %s: %v", fileSymlinkPath, err) q.logger.Debug().Msgf("Failed to create symlink: %s: %v", fileSymlinkPath, err)
} else {
filePaths = append(filePaths, fileSymlinkPath)
delete(remainingFiles, filename)
q.logger.Info().Msgf("File is ready: %s", file.Name)
} }
filePaths = append(filePaths, fileSymlinkPath)
delete(pending, path)
} }
} }
case <-timeout:
q.logger.Warn().Msgf("Timeout waiting for files, %d files still pending", len(remainingFiles))
return symlinkPath, fmt.Errorf("timeout waiting for files")
} }
} }
@@ -267,10 +272,9 @@ func (q *QBit) createSymlinks(debridTorrent *debrid.Torrent, rclonePath, torrent
if err := q.preCacheFile(debridTorrent.Name, filePaths); err != nil { if err := q.preCacheFile(debridTorrent.Name, filePaths); err != nil {
q.logger.Error().Msgf("Failed to pre-cache file: %s", err) q.logger.Error().Msgf("Failed to pre-cache file: %s", err)
} else { } else {
q.logger.Debug().Msgf("Pre-cached %d files", len(filePaths)) q.logger.Trace().Msgf("Pre-cached %d files", len(filePaths))
} }
}() // Pre-cache the files in the background }() // Pre-cache the files in the background
// Pre-cache the first 256KB and 1MB of the file
return symlinkPath, nil return symlinkPath, nil
} }

View File

@@ -103,8 +103,6 @@ func (q *QBit) ProcessFiles(torrent *Torrent, debridTorrent *debrid.Torrent, arr
) )
debridTorrent.Arr = arr debridTorrent.Arr = arr
// File is done downloading at this stage
// Check if debrid supports webdav by checking cache // Check if debrid supports webdav by checking cache
if isSymlink { if isSymlink {
cache, ok := svc.Debrid.Caches[debridTorrent.Debrid] cache, ok := svc.Debrid.Caches[debridTorrent.Debrid]

View File

@@ -241,6 +241,7 @@ func (ui *Handler) handleUpdateConfig(w http.ResponseWriter, r *http.Request) {
DownloadUncached: a.DownloadUncached, DownloadUncached: a.DownloadUncached,
}) })
} }
currentConfig.Arrs = updatedConfig.Arrs
if err := currentConfig.Save(); err != nil { if err := currentConfig.Save(); err != nil {
http.Error(w, "Error saving config: "+err.Error(), http.StatusInternalServerError) http.Error(w, "Error saving config: "+err.Error(), http.StatusInternalServerError)
return return

View File

@@ -228,7 +228,7 @@
<div class="setup-step d-none" id="step4"> <div class="setup-step d-none" id="step4">
<div class="section mb-5"> <div class="section mb-5">
<div id="arrConfigs"></div> <div id="arrConfigs"></div>
<div class="mb-3 d-none"> <div class="mb-3">
<button type="button" id="addArrBtn" class="btn btn-secondary"> <button type="button" id="addArrBtn" class="btn btn-secondary">
<i class="bi bi-plus"></i> Add New Arr <i class="bi bi-plus"></i> Add New Arr
</button> </button>