Fix blocking calls in coroutines
This commit is contained in:
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.local.data
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import kotlinx.coroutines.*
|
||||
import org.koitharu.kotatsu.utils.ext.deleteAwait
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
@@ -13,7 +14,6 @@ class WritableCbzFile(private val file: File) {
|
||||
|
||||
private val dir = File(file.parentFile, file.nameWithoutExtension)
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun prepare() = withContext(Dispatchers.IO) {
|
||||
check(dir.list().isNullOrEmpty()) {
|
||||
"Dir ${dir.name} is not empty"
|
||||
@@ -45,11 +45,10 @@ class WritableCbzFile(private val file: File) {
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun flush() = withContext(Dispatchers.IO) {
|
||||
val tempFile = File(file.path + ".tmp")
|
||||
if (tempFile.exists()) {
|
||||
tempFile.delete()
|
||||
tempFile.deleteAwait()
|
||||
}
|
||||
try {
|
||||
runInterruptible {
|
||||
@@ -63,7 +62,7 @@ class WritableCbzFile(private val file: File) {
|
||||
tempFile.renameTo(file)
|
||||
} finally {
|
||||
if (tempFile.exists()) {
|
||||
tempFile.delete()
|
||||
tempFile.deleteAwait()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.collection.ArraySet
|
||||
import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
@@ -43,38 +44,39 @@ class LocalMangaRepository(private val context: Context) : MangaRepository {
|
||||
getFromFile(Uri.parse(manga.url).toFile())
|
||||
} else manga
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val uri = Uri.parse(chapter.url)
|
||||
val file = uri.toFile()
|
||||
val zip = ZipFile(file)
|
||||
val index = zip.getEntry(MangaZip.INDEX_ENTRY)?.let(zip::readText)?.let(::MangaIndex)
|
||||
var entries = zip.entries().asSequence()
|
||||
entries = if (index != null) {
|
||||
val pattern = index.getChapterNamesPattern(chapter)
|
||||
entries.filter { x -> !x.isDirectory && x.name.substringBefore('.').matches(pattern) }
|
||||
} else {
|
||||
val parent = uri.fragment.orEmpty()
|
||||
entries.filter { x ->
|
||||
!x.isDirectory && x.name.substringBeforeLast(
|
||||
File.separatorChar,
|
||||
""
|
||||
) == parent
|
||||
return runInterruptible(Dispatchers.IO){
|
||||
val uri = Uri.parse(chapter.url)
|
||||
val file = uri.toFile()
|
||||
val zip = ZipFile(file)
|
||||
val index = zip.getEntry(MangaZip.INDEX_ENTRY)?.let(zip::readText)?.let(::MangaIndex)
|
||||
var entries = zip.entries().asSequence()
|
||||
entries = if (index != null) {
|
||||
val pattern = index.getChapterNamesPattern(chapter)
|
||||
entries.filter { x -> !x.isDirectory && x.name.substringBefore('.').matches(pattern) }
|
||||
} else {
|
||||
val parent = uri.fragment.orEmpty()
|
||||
entries.filter { x ->
|
||||
!x.isDirectory && x.name.substringBeforeLast(
|
||||
File.separatorChar,
|
||||
""
|
||||
) == parent
|
||||
}
|
||||
}
|
||||
entries
|
||||
.toList()
|
||||
.sortedWith(compareBy(AlphanumComparator()) { x -> x.name })
|
||||
.map { x ->
|
||||
val entryUri = zipUri(file, x.name)
|
||||
MangaPage(
|
||||
id = entryUri.longHashCode(),
|
||||
url = entryUri,
|
||||
preview = null,
|
||||
referer = chapter.url,
|
||||
source = MangaSource.LOCAL,
|
||||
)
|
||||
}
|
||||
}
|
||||
return entries
|
||||
.toList()
|
||||
.sortedWith(compareBy(AlphanumComparator()) { x -> x.name })
|
||||
.map { x ->
|
||||
val entryUri = zipUri(file, x.name)
|
||||
MangaPage(
|
||||
id = entryUri.longHashCode(),
|
||||
url = entryUri,
|
||||
preview = null,
|
||||
referer = chapter.url,
|
||||
source = MangaSource.LOCAL,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun delete(manga: Manga): Boolean {
|
||||
@@ -138,20 +140,18 @@ class LocalMangaRepository(private val context: Context) : MangaRepository {
|
||||
val file = runCatching {
|
||||
Uri.parse(localManga.url).toFile()
|
||||
}.getOrNull() ?: return null
|
||||
return withContext(Dispatchers.IO) {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
return runInterruptible(Dispatchers.IO) {
|
||||
ZipFile(file).use { zip ->
|
||||
val entry = zip.getEntry(MangaZip.INDEX_ENTRY)
|
||||
val index = entry?.let(zip::readText)?.let(::MangaIndex) ?: return@withContext null
|
||||
index.getMangaInfo()
|
||||
val index = entry?.let(zip::readText)?.let(::MangaIndex)
|
||||
index?.getMangaInfo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun findSavedManga(remoteManga: Manga): Manga? = withContext(Dispatchers.IO) {
|
||||
suspend fun findSavedManga(remoteManga: Manga): Manga? = runInterruptible(Dispatchers.IO) {
|
||||
val files = getAllFiles()
|
||||
for (file in files) {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
val index = ZipFile(file).use { zip ->
|
||||
val entry = zip.getEntry(MangaZip.INDEX_ENTRY)
|
||||
entry?.let(zip::readText)?.let(::MangaIndex)
|
||||
@@ -159,7 +159,7 @@ class LocalMangaRepository(private val context: Context) : MangaRepository {
|
||||
val info = index.getMangaInfo() ?: continue
|
||||
if (info.id == remoteManga.id) {
|
||||
val fileUri = file.toUri().toString()
|
||||
return@withContext info.copy(
|
||||
return@runInterruptible info.copy(
|
||||
source = MangaSource.LOCAL,
|
||||
url = fileUri,
|
||||
chapters = info.chapters?.map { c -> c.copy(url = fileUri) }
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException
|
||||
@@ -81,10 +82,11 @@ class LocalListViewModel(
|
||||
}
|
||||
val dest = settings.getStorageDir(context)?.let { File(it, name) }
|
||||
?: throw IOException("External files dir unavailable")
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
contentResolver.openInputStream(uri)?.use { source ->
|
||||
dest.outputStream().use { output ->
|
||||
source.copyTo(output)
|
||||
runInterruptible {
|
||||
contentResolver.openInputStream(uri)?.use { source ->
|
||||
dest.outputStream().use { output ->
|
||||
source.copyTo(output)
|
||||
}
|
||||
}
|
||||
} ?: throw IOException("Cannot open input stream: $uri")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user