Fix downloading edited manga (close #1493)
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
package org.koitharu.kotatsu.core.util.ext
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.net.Uri
|
||||
import androidx.annotation.CheckResult
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
@@ -12,6 +15,7 @@ import okio.FileSystem
|
||||
import okio.IOException
|
||||
import okio.Path
|
||||
import okio.Source
|
||||
import okio.source
|
||||
import org.koitharu.kotatsu.core.util.CancellableSource
|
||||
import org.koitharu.kotatsu.core.util.progress.ProgressResponseBody
|
||||
import java.io.ByteArrayOutputStream
|
||||
@@ -57,3 +61,8 @@ fun FileSystem.isRegularFile(path: Path) = try {
|
||||
} catch (_: IOException) {
|
||||
false
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
fun ContentResolver.openSource(uri: Uri): Source = checkNotNull(openInputStream(uri)) {
|
||||
"Cannot open input stream from $uri"
|
||||
}.source()
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.Context
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.os.Build
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.hilt.work.HiltWorker
|
||||
import androidx.work.BackoffPolicy
|
||||
import androidx.work.Constraints
|
||||
@@ -64,8 +65,11 @@ import org.koitharu.kotatsu.core.util.ext.ensureSuccess
|
||||
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.core.util.ext.getWorkInputData
|
||||
import org.koitharu.kotatsu.core.util.ext.getWorkSpec
|
||||
import org.koitharu.kotatsu.core.util.ext.openSource
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.core.util.ext.toFileOrNull
|
||||
import org.koitharu.kotatsu.core.util.ext.toMimeType
|
||||
import org.koitharu.kotatsu.core.util.ext.toMimeTypeOrNull
|
||||
import org.koitharu.kotatsu.core.util.ext.withTicker
|
||||
import org.koitharu.kotatsu.core.util.ext.writeAllCancellable
|
||||
import org.koitharu.kotatsu.core.util.progress.RealtimeEtaEstimator
|
||||
@@ -371,6 +375,25 @@ class DownloadWorker @AssistedInject constructor(
|
||||
destination: File,
|
||||
source: MangaSource,
|
||||
): File {
|
||||
if (url.startsWith("content:", ignoreCase = true) || url.startsWith("file:", ignoreCase = true)) {
|
||||
val uri = url.toUri()
|
||||
val cr = applicationContext.contentResolver
|
||||
val ext = uri.toFileOrNull()?.let {
|
||||
MimeTypes.getNormalizedExtension(it.name)
|
||||
} ?: cr.getType(uri)?.toMimeTypeOrNull()?.let { MimeTypes.getExtension(it) }
|
||||
val file = destination.createTempFile(ext)
|
||||
try {
|
||||
cr.openSource(uri).use { input ->
|
||||
file.sink(append = false).buffer().use {
|
||||
it.writeAllCancellable(input)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
file.delete()
|
||||
throw e
|
||||
}
|
||||
return file
|
||||
}
|
||||
val request = PageLoader.createPageRequest(url, source)
|
||||
slowdownDispatcher.delay(source)
|
||||
return imageProxyInterceptor.interceptPageRequest(request, okHttp)
|
||||
@@ -379,22 +402,14 @@ class DownloadWorker @AssistedInject constructor(
|
||||
var file: File? = null
|
||||
try {
|
||||
response.requireBody().use { body ->
|
||||
file = File(
|
||||
destination,
|
||||
buildString {
|
||||
append(UUID.randomUUID().toString())
|
||||
MimeTypes.getExtension(body.contentType()?.toMimeType())?.let { ext ->
|
||||
append('.')
|
||||
append(ext)
|
||||
}
|
||||
append(".tmp")
|
||||
},
|
||||
file = destination.createTempFile(
|
||||
ext = MimeTypes.getExtension(body.contentType()?.toMimeType())
|
||||
)
|
||||
file.sink(append = false).buffer().use {
|
||||
it.writeAllCancellable(body.source())
|
||||
}
|
||||
}
|
||||
} catch (e: CancellationException) {
|
||||
} catch (e: Exception) {
|
||||
file?.delete()
|
||||
throw e
|
||||
}
|
||||
@@ -402,6 +417,18 @@ class DownloadWorker @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun File.createTempFile(ext: String?) = File(
|
||||
this,
|
||||
buildString {
|
||||
append(UUID.randomUUID().toString())
|
||||
if (!ext.isNullOrEmpty()) {
|
||||
append('.')
|
||||
append(ext)
|
||||
}
|
||||
append(".tmp")
|
||||
},
|
||||
)
|
||||
|
||||
private suspend fun publishState(state: DownloadState) {
|
||||
val previousState = currentState
|
||||
lastPublishedState = state
|
||||
|
||||
@@ -11,8 +11,8 @@ import kotlinx.coroutines.runInterruptible
|
||||
import kotlinx.coroutines.withContext
|
||||
import okio.buffer
|
||||
import okio.sink
|
||||
import okio.source
|
||||
import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException
|
||||
import org.koitharu.kotatsu.core.util.ext.openSource
|
||||
import org.koitharu.kotatsu.core.util.ext.resolveName
|
||||
import org.koitharu.kotatsu.core.util.ext.writeAllCancellable
|
||||
import org.koitharu.kotatsu.local.data.LocalStorageChanges
|
||||
@@ -51,12 +51,12 @@ class SingleMangaImporter @Inject constructor(
|
||||
}
|
||||
val dest = File(getOutputDir(), name)
|
||||
runInterruptible {
|
||||
contentResolver.openInputStream(uri)
|
||||
}?.use { source ->
|
||||
contentResolver.openSource(uri)
|
||||
}.use { source ->
|
||||
dest.sink().buffer().use { output ->
|
||||
output.writeAllCancellable(source.source())
|
||||
output.writeAllCancellable(source)
|
||||
}
|
||||
} ?: throw IOException("Cannot open input stream: $uri")
|
||||
}
|
||||
LocalMangaParser(dest).getManga(withDetails = false)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class SingleMangaImporter @Inject constructor(
|
||||
docFile.copyTo(subDir)
|
||||
}
|
||||
} else {
|
||||
inputStream().source().use { input ->
|
||||
source().use { input ->
|
||||
File(destDir, requireName()).sink().buffer().use { output ->
|
||||
output.writeAllCancellable(input)
|
||||
}
|
||||
@@ -92,8 +92,8 @@ class SingleMangaImporter @Inject constructor(
|
||||
return storageManager.getDefaultWriteableDir() ?: throw IOException("External files dir unavailable")
|
||||
}
|
||||
|
||||
private suspend fun DocumentFile.inputStream() = runInterruptible(Dispatchers.IO) {
|
||||
contentResolver.openInputStream(uri) ?: throw IOException("Cannot open input stream: $uri")
|
||||
private suspend fun DocumentFile.source() = runInterruptible(Dispatchers.IO) {
|
||||
contentResolver.openSource(uri)
|
||||
}
|
||||
|
||||
private fun DocumentFile.requireName(): String {
|
||||
|
||||
Reference in New Issue
Block a user