@@ -1,14 +1,11 @@
|
||||
package org.koitharu.kotatsu.core.backup
|
||||
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import okhttp3.internal.closeQuietly
|
||||
import okio.Closeable
|
||||
import org.json.JSONArray
|
||||
import org.koitharu.kotatsu.core.exceptions.BadBackupFormatException
|
||||
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
|
||||
import java.io.File
|
||||
import java.util.EnumSet
|
||||
import java.util.zip.ZipException
|
||||
@@ -36,13 +33,9 @@ class BackupZipInput private constructor(val file: File) : Closeable {
|
||||
zipFile.close()
|
||||
}
|
||||
|
||||
fun cleanupAsync() {
|
||||
processLifecycleScope.launch(Dispatchers.IO, CoroutineStart.ATOMIC) {
|
||||
runCatching {
|
||||
closeQuietly()
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
fun closeAndDelete() {
|
||||
closeQuietly()
|
||||
file.delete()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -55,7 +48,7 @@ class BackupZipInput private constructor(val file: File) : Closeable {
|
||||
throw BadBackupFormatException(null)
|
||||
}
|
||||
res
|
||||
} catch (exception: Exception) {
|
||||
} catch (exception: Throwable) {
|
||||
res?.closeQuietly()
|
||||
throw if (exception is ZipException) {
|
||||
BadBackupFormatException(exception)
|
||||
|
||||
@@ -39,14 +39,6 @@ fun ZipFile.readText(entry: ZipEntry) = getInputStream(entry).bufferedReader().u
|
||||
it.readText()
|
||||
}
|
||||
|
||||
@Blocking
|
||||
fun ZipFile.getInputStreamOrClose(entry: ZipEntry): InputStream = try {
|
||||
getInputStream(entry)
|
||||
} catch (e: Throwable) {
|
||||
closeQuietly()
|
||||
throw e
|
||||
}
|
||||
|
||||
fun File.getStorageName(context: Context): String = runCatching {
|
||||
val manager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.util.ext
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toFile
|
||||
import okhttp3.internal.closeQuietly
|
||||
import okio.Source
|
||||
import okio.source
|
||||
import okio.use
|
||||
@@ -40,8 +41,13 @@ fun Uri.source(): Source = when (scheme) {
|
||||
URI_SCHEME_FILE -> toFile().source()
|
||||
URI_SCHEME_ZIP -> {
|
||||
val zip = ZipFile(schemeSpecificPart)
|
||||
val entry = zip.getEntry(fragment)
|
||||
zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip)
|
||||
try {
|
||||
val entry = zip.getEntry(fragment)
|
||||
zip.getInputStream(entry).source().withExtraCloseable(zip)
|
||||
} catch (e: Throwable) {
|
||||
zip.closeQuietly()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
else -> unsupportedUri(this)
|
||||
|
||||
@@ -16,13 +16,13 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.internal.closeQuietly
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import okio.buffer
|
||||
import okio.source
|
||||
import org.koitharu.kotatsu.core.network.MangaHttpClient
|
||||
import org.koitharu.kotatsu.core.network.imageproxy.ImageProxyInterceptor
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.util.ext.getInputStreamOrClose
|
||||
import org.koitharu.kotatsu.local.data.PagesCache
|
||||
import org.koitharu.kotatsu.local.data.isFileUri
|
||||
import org.koitharu.kotatsu.local.data.isZipUri
|
||||
@@ -67,17 +67,22 @@ class MangaPageFetcher(
|
||||
return when {
|
||||
uri.isZipUri() -> runInterruptible(Dispatchers.IO) {
|
||||
val zip = ZipFile(uri.schemeSpecificPart)
|
||||
val entry = zip.getEntry(uri.fragment)
|
||||
SourceResult(
|
||||
source = ImageSource(
|
||||
source = zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip).buffer(),
|
||||
context = context,
|
||||
metadata = MangaPageMetadata(page),
|
||||
),
|
||||
mimeType = MimeTypeMap.getSingleton()
|
||||
.getMimeTypeFromExtension(entry.name.substringAfterLast('.', "")),
|
||||
dataSource = DataSource.DISK,
|
||||
)
|
||||
try {
|
||||
val entry = zip.getEntry(uri.fragment)
|
||||
SourceResult(
|
||||
source = ImageSource(
|
||||
source = zip.getInputStream(entry).source().withExtraCloseable(zip).buffer(),
|
||||
context = context,
|
||||
metadata = MangaPageMetadata(page),
|
||||
),
|
||||
mimeType = MimeTypeMap.getSingleton()
|
||||
.getMimeTypeFromExtension(entry.name.substringAfterLast('.', "")),
|
||||
dataSource = DataSource.DISK,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
zip.closeQuietly()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
uri.isFileUri() -> runInterruptible(Dispatchers.IO) {
|
||||
|
||||
@@ -10,9 +10,9 @@ import coil.fetch.SourceResult
|
||||
import coil.request.Options
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import okhttp3.internal.closeQuietly
|
||||
import okio.buffer
|
||||
import okio.source
|
||||
import org.koitharu.kotatsu.core.util.ext.getInputStreamOrClose
|
||||
import org.koitharu.kotatsu.local.data.util.withExtraCloseable
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
@@ -23,18 +23,23 @@ class CbzFetcher(
|
||||
|
||||
override suspend fun fetch() = runInterruptible(Dispatchers.IO) {
|
||||
val zip = ZipFile(uri.schemeSpecificPart)
|
||||
val entry = zip.getEntry(uri.fragment)
|
||||
val ext = MimeTypeMap.getFileExtensionFromUrl(entry.name)
|
||||
val bufferedSource = zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip).buffer()
|
||||
SourceResult(
|
||||
source = ImageSource(
|
||||
source = bufferedSource,
|
||||
context = options.context,
|
||||
metadata = CbzMetadata(uri),
|
||||
),
|
||||
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext),
|
||||
dataSource = DataSource.DISK,
|
||||
)
|
||||
try {
|
||||
val entry = zip.getEntry(uri.fragment)
|
||||
val ext = MimeTypeMap.getFileExtensionFromUrl(entry.name)
|
||||
val bufferedSource = zip.getInputStream(entry).source().withExtraCloseable(zip).buffer()
|
||||
SourceResult(
|
||||
source = ImageSource(
|
||||
source = bufferedSource,
|
||||
context = options.context,
|
||||
metadata = CbzMetadata(uri),
|
||||
),
|
||||
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext),
|
||||
dataSource = DataSource.DISK,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
zip.closeQuietly()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
class Factory : Fetcher.Factory<Uri> {
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.koitharu.kotatsu.core.backup.CompositeResult
|
||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||
import org.koitharu.kotatsu.core.util.ext.call
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.core.util.ext.toUriOrNull
|
||||
import org.koitharu.kotatsu.parsers.util.SuspendLazy
|
||||
import java.io.File
|
||||
@@ -71,7 +72,11 @@ class RestoreViewModel @Inject constructor(
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
backupInput.peek()?.cleanupAsync()
|
||||
runCatching {
|
||||
backupInput.peek()?.closeAndDelete()
|
||||
}.onFailure {
|
||||
it.printStackTraceDebug()
|
||||
}
|
||||
}
|
||||
|
||||
fun onItemClick(item: BackupEntryModel) {
|
||||
|
||||
Reference in New Issue
Block a user