fix: prevent duplicate downloads from concurrent stream requests

This commit is contained in:
V1ck3s
2026-01-12 18:40:45 +01:00
committed by Vickes
parent 1d4c46b4f3
commit 7a08f15523

View File

@@ -139,6 +139,11 @@ public abstract class BaseDownloadService : IDownloadService
var songId = $"ext-{externalProvider}-{externalId}";
var isCache = SubsonicSettings.StorageMode == StorageMode.Cache;
// Acquire lock BEFORE checking existence to prevent race conditions with concurrent requests
await DownloadLock.WaitAsync(cancellationToken);
try
{
// Check if already downloaded (skip for cache mode as we want to check cache folder)
if (!isCache)
{
@@ -165,7 +170,10 @@ public abstract class BaseDownloadService : IDownloadService
// Check if download in progress
if (ActiveDownloads.TryGetValue(songId, out var activeDownload) && activeDownload.Status == DownloadStatus.InProgress)
{
Logger.LogInformation("Download already in progress for {SongId}", songId);
Logger.LogInformation("Download already in progress for {SongId}, waiting...", songId);
// Release lock while waiting
DownloadLock.Release();
while (ActiveDownloads.TryGetValue(songId, out activeDownload) && activeDownload.Status == DownloadStatus.InProgress)
{
await Task.Delay(500, cancellationToken);
@@ -179,9 +187,6 @@ public abstract class BaseDownloadService : IDownloadService
throw new Exception(activeDownload?.ErrorMessage ?? "Download failed");
}
await DownloadLock.WaitAsync(cancellationToken);
try
{
// Get metadata
// In Album mode, fetch the full album first to ensure AlbumArtist is correctly set
Song? song = null;
@@ -227,8 +232,6 @@ public abstract class BaseDownloadService : IDownloadService
};
ActiveDownloads[songId] = downloadInfo;
try
{
var localPath = await DownloadTrackAsync(externalId, song, cancellationToken);
downloadInfo.Status = DownloadStatus.Completed;
@@ -275,13 +278,15 @@ public abstract class BaseDownloadService : IDownloadService
return localPath;
}
catch (Exception ex)
{
if (ActiveDownloads.TryGetValue(songId, out var downloadInfo))
{
downloadInfo.Status = DownloadStatus.Failed;
downloadInfo.ErrorMessage = ex.Message;
}
Logger.LogError(ex, "Download failed for {SongId}", songId);
throw;
}
}
finally
{
DownloadLock.Release();