From e69964d1f5c3849f0b527513dac89171a01a8856 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 12 May 2023 14:22:08 +0300 Subject: [PATCH] Fix obtaining manga output --- app/build.gradle | 4 +- .../download/ui/worker/PausingReceiver.kt | 6 +- .../local/data/output/LocalMangaOutput.kt | 77 +++++++++++++++---- .../kotatsu/reader/domain/PageLoader.kt | 2 +- 4 files changed, 67 insertions(+), 22 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5f3632d76..d275cece8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 targetSdkVersion 33 - versionCode 542 - versionName '5.1-b1' + versionCode 543 + versionName '5.1-b2' generatedDensities = [] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt b/app/src/main/java/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt index bad07e7df..353911801 100644 --- a/app/src/main/java/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt +++ b/app/src/main/java/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt @@ -17,8 +17,10 @@ class PausingReceiver( override fun onReceive(context: Context, intent: Intent?) { val uuid = intent?.getStringExtra(EXTRA_UUID)?.toUUIDOrNull() - assert(uuid == id) - when (intent?.action) { + if (uuid != id) { + return + } + when (intent.action) { ACTION_RESUME -> pausingHandle.resume() ACTION_PAUSE -> pausingHandle.pause() } diff --git a/app/src/main/java/org/koitharu/kotatsu/local/data/output/LocalMangaOutput.kt b/app/src/main/java/org/koitharu/kotatsu/local/data/output/LocalMangaOutput.kt index e3445f387..30c161037 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/data/output/LocalMangaOutput.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/data/output/LocalMangaOutput.kt @@ -1,6 +1,11 @@ package org.koitharu.kotatsu.local.data.output +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext import okio.Closeable +import org.koitharu.kotatsu.local.data.input.LocalMangaInput import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.util.toFileNameSafe @@ -26,25 +31,63 @@ sealed class LocalMangaOutput( const val ENTRY_NAME_INDEX = "index.json" const val SUFFIX_TMP = ".tmp" + private val mutex = Mutex() - fun getOrCreate(root: File, manga: Manga): LocalMangaOutput { - return checkNotNull(getImpl(root, manga, onlyIfExists = false)) - } - - fun get(root: File, manga: Manga): LocalMangaOutput? { - return getImpl(root, manga, onlyIfExists = true) - } - - private fun getImpl(root: File, manga: Manga, onlyIfExists: Boolean): LocalMangaOutput? { - val fileName = manga.title.toFileNameSafe() - val dir = File(root, fileName) - val zip = File(root, "$fileName.cbz") - return when { - dir.isDirectory -> LocalMangaDirOutput(dir, manga) - zip.isFile -> LocalMangaZipOutput(zip, manga) - !onlyIfExists -> LocalMangaDirOutput(dir, manga) - else -> null + suspend fun getOrCreate(root: File, manga: Manga): LocalMangaOutput = withContext(Dispatchers.IO) { + val preferSingleCbz = manga.chapters.let { + it != null && it.size <= 3 } + checkNotNull(getImpl(root, manga, onlyIfExists = false, preferSingleCbz)) + } + + suspend fun get(root: File, manga: Manga): LocalMangaOutput? = withContext(Dispatchers.IO) { + getImpl(root, manga, onlyIfExists = true, preferSingleCbz = false) + } + + private suspend fun getImpl( + root: File, + manga: Manga, + onlyIfExists: Boolean, + preferSingleCbz: Boolean, + ): LocalMangaOutput? { + mutex.withLock { + var i = 0 + val baseName = manga.title.toFileNameSafe() + while (true) { + val fileName = if (i == 0) baseName else baseName + "_$i" + val dir = File(root, fileName) + val zip = File(root, "$fileName.cbz") + i++ + return when { + dir.isDirectory -> { + if (canWriteTo(dir, manga)) { + LocalMangaDirOutput(dir, manga) + } else { + continue + } + } + + zip.isFile -> if (canWriteTo(zip, manga)) { + LocalMangaZipOutput(zip, manga) + } else { + continue + } + + !onlyIfExists -> if (preferSingleCbz) { + LocalMangaZipOutput(zip, manga) + } else { + LocalMangaDirOutput(dir, manga) + } + + else -> null + } + } + } + } + + private suspend fun canWriteTo(file: File, manga: Manga): Boolean { + val info = LocalMangaInput.of(file).getMangaInfo() ?: return false + return info.id == manga.id } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt b/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt index 35546a83a..a4ba27794 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/domain/PageLoader.kt @@ -200,7 +200,7 @@ class PageLoader @Inject constructor( .build() okHttp.newCall(request).await().use { response -> check(response.isSuccessful) { - "Invalid response: ${response.code} ${response.message}" + "Invalid response: ${response.code} ${response.message} at $pageUrl" } val body = checkNotNull(response.body) { "Null response"