Skip to content

Commit

Permalink
Handle finished downloads that weren't removed from the queue (#683)
Browse files Browse the repository at this point in the history
In case a download was finished, but the downloader got stopped before it was able to remove the finished download from the queue, the downloader got stuck in an endless loop of starting and pausing downloads.

This was caused by selecting the next chapter to download and then recognizing in "Downloader::step", that there is another chapter to download before the current one in the queue.
However, since this recognized chapter is already downloaded, the downloader selected the next queued chapter again.
It was then stuck in this loop until the finished chapter was manually removed from the queue.
  • Loading branch information
schroda authored Sep 16, 2023
1 parent 553b35d commit 7086055
Showing 1 changed file with 18 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import mu.KLogger
import mu.KotlinLogging
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.transactions.transaction
Expand Down Expand Up @@ -83,17 +84,32 @@ class Downloader(
logger.debug { "stopped" }
}

private suspend fun finishDownload(logger: KLogger, download: DownloadChapter) {
downloadQueue.removeIf { it.mangaId == download.mangaId && it.chapterIndex == download.chapterIndex }
step(null, false)
logger.debug { "finished" }
onDownloadFinished()
}

private suspend fun run() {
while (downloadQueue.isNotEmpty() && currentCoroutineContext().isActive) {
val download = availableSourceDownloads.firstOrNull {
(it.state == Queued || (it.state == Error && it.tries < 3)) // 3 re-tries per download
(it.state == Queued || it.state == Finished || (it.state == Error && it.tries < 3)) // 3 re-tries per download
} ?: break

val logContext = "${logger.name} - downloadChapter($download))"
val downloadLogger = KotlinLogging.logger(logContext)

downloadLogger.debug { "start" }

// handle cases were the downloader was stopped before the finished download could be removed from the queue
// otherwise, it will create an endless loop, due to never removing the finished chapter and thinking that the
// current download chapter was moved down in the queue
if (download.state == Finished) {
finishDownload(downloadLogger, download)
break
}

try {
download.state = Downloading
step(download, true)
Expand All @@ -109,11 +125,7 @@ class Downloader(
}
}
step(download, true)

downloadQueue.removeIf { it.mangaId == download.mangaId && it.chapterIndex == download.chapterIndex }
step(null, false)
downloadLogger.debug { "finished" }
onDownloadFinished()
finishDownload(downloadLogger, download)
} catch (e: CancellationException) {
logger.debug("Downloader was stopped")
availableSourceDownloads.filter { it.state == Downloading }.forEach { it.state = Queued }
Expand Down

0 comments on commit 7086055

Please sign in to comment.