diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadService.kt index 273b9b41..a24f941f 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadService.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadService.kt @@ -423,7 +423,7 @@ class DownloadService : private suspend fun deleteAsync(track: Track) { withContext(Dispatchers.IO) { downloadQueue.get(track.id)?.let { downloadQueue.remove(it) } - failedList[track.id]?.let { downloadQueue.remove(it) } + failedList.remove(track.id) cancelDownload(track) Storage.delete(track.getPartialFile()) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadTask.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadTask.kt index 89b00619..275e36f8 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadTask.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadTask.kt @@ -206,8 +206,14 @@ class DownloadTask( exception -> Timber.w(exception, "Exception in DownloadTask ${downloadTrack.pinnedFile}") - Storage.delete(downloadTrack.completeFile) - Storage.delete(downloadTrack.pinnedFile) + // Only ever touch the partial file here: the complete/pinned files may hold a + // download that has already been finalized (the exception may have happened + // during a post-rename step such as the catalog write), so deleting them would + // destroy finished data. The partial file is removed so that a retry does not + // append to a possibly untrustworthy stream; pure cancellation keeps the partial + // file, because the exception handler is not invoked for CancellationException + // and cancelled downloads should remain resumable. + Storage.delete(downloadTrack.partialFile) } fun start() {