diff --git a/app/build.gradle b/app/build.gradle index c64ac0512..760c4440c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdk = 21 targetSdk = 35 - versionCode = 672 - versionName = '7.6-b1' + versionCode = 673 + versionName = '7.6' generatedDensities = [] testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner' ksp { @@ -83,7 +83,7 @@ afterEvaluate { } dependencies { //noinspection GradleDependency - implementation('com.github.KotatsuApp:kotatsu-parsers:cc62981f12') { + implementation('com.github.KotatsuApp:kotatsu-parsers:3cdd391410') { exclude group: 'org.json', module: 'json' } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/MangaSource.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/MangaSource.kt index 9c8ff510d..ce77eed36 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/model/MangaSource.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/model/MangaSource.kt @@ -62,6 +62,10 @@ val ContentType.titleResId ContentType.MANHUA -> R.string.content_type_manhua ContentType.NOVEL -> R.string.content_type_novel ContentType.ONE_SHOT -> R.string.content_type_one_shot + ContentType.DOUJINSHI -> R.string.content_type_doujinshi + ContentType.IMAGE_SET -> R.string.content_type_image_set + ContentType.ARTIST_CG -> R.string.content_type_artist_cg + ContentType.GAME_CG -> R.string.content_type_game_cg } tailrec fun MangaSource.unwrap(): MangaSource = if (this is MangaSourceInfo) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/BitmapWrapper.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/BitmapWrapper.kt index 13d429091..09d2d6ec8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/BitmapWrapper.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/BitmapWrapper.kt @@ -9,7 +9,7 @@ import android.graphics.Rect as AndroidRect class BitmapWrapper private constructor( private val androidBitmap: AndroidBitmap, -) : Bitmap { +) : Bitmap, AutoCloseable { private val canvas by lazy { Canvas(androidBitmap) } // is not always used, so initialized lazily @@ -24,17 +24,21 @@ class BitmapWrapper private constructor( canvas.drawBitmap(androidSourceBitmap, src.toAndroidRect(), dst.toAndroidRect(), null) } + override fun close() { + androidBitmap.recycle() + } + fun compressTo(output: OutputStream) { androidBitmap.compress(AndroidBitmap.CompressFormat.PNG, 100, output) } companion object { - fun create(width: Int, height: Int): Bitmap = BitmapWrapper( + fun create(width: Int, height: Int) = BitmapWrapper( AndroidBitmap.createBitmap(width, height, AndroidBitmap.Config.ARGB_8888), ) - fun create(bitmap: AndroidBitmap): Bitmap = BitmapWrapper( + fun create(bitmap: AndroidBitmap) = BitmapWrapper( if (bitmap.isMutable) bitmap else bitmap.copy(AndroidBitmap.Config.ARGB_8888, true), ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt index a4fe4fa25..b6fb9f9f3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt @@ -21,14 +21,15 @@ import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.core.util.ext.configureForParser import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug -import org.koitharu.kotatsu.core.util.ext.requireBody import org.koitharu.kotatsu.core.util.ext.sanitizeHeaderValue import org.koitharu.kotatsu.core.util.ext.toList +import org.koitharu.kotatsu.core.util.ext.use import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.bitmap.Bitmap import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.network.UserAgents +import org.koitharu.kotatsu.parsers.util.map import java.lang.ref.WeakReference import java.util.Locale import javax.inject.Inject @@ -76,32 +77,25 @@ class MangaLoaderContextImpl @Inject constructor( } override fun redrawImageResponse(response: Response, redraw: (image: Bitmap) -> Bitmap): Response { - val image = response.requireBody().byteStream() - - val opts = BitmapFactory.Options() - opts.inMutable = true - val bitmap = BitmapFactory.decodeStream(image, null, opts) ?: error("Cannot decode bitmap") - val result = redraw(BitmapWrapper.create(bitmap)) as BitmapWrapper - - val body = Buffer().also { - result.compressTo(it.outputStream()) - }.asResponseBody("image/jpeg".toMediaType()) - - return response.newBuilder() - .body(body) - .build() + return response.map { body -> + val opts = BitmapFactory.Options() + opts.inMutable = true + BitmapFactory.decodeStream(body.byteStream(), null, opts)?.use { bitmap -> + (redraw(BitmapWrapper.create(bitmap)) as BitmapWrapper).use { result -> + Buffer().also { + result.compressTo(it.outputStream()) + }.asResponseBody("image/jpeg".toMediaType()) + } + } ?: error("Cannot decode bitmap") + } } - override fun createBitmap(width: Int, height: Int): Bitmap { - return BitmapWrapper.create(width, height) - } + override fun createBitmap(width: Int, height: Int): Bitmap = BitmapWrapper.create(width, height) @MainThread - private fun obtainWebView(): WebView { - return webViewCached?.get() ?: WebView(androidContext).also { - it.configureForParser(null) - webViewCached = WeakReference(it) - } + private fun obtainWebView(): WebView = webViewCached?.get() ?: WebView(androidContext).also { + it.configureForParser(null) + webViewCached = WeakReference(it) } private fun obtainWebViewUserAgent(): String { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/favicon/FaviconFetcher.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/favicon/FaviconFetcher.kt index 035e14c9e..1d28509c7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/favicon/FaviconFetcher.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/favicon/FaviconFetcher.kt @@ -37,12 +37,12 @@ import org.koitharu.kotatsu.core.parser.EmptyMangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository import org.koitharu.kotatsu.core.parser.external.ExternalMangaRepository -import org.koitharu.kotatsu.core.util.ext.requireBody import org.koitharu.kotatsu.core.util.ext.writeAllCancellable import org.koitharu.kotatsu.local.data.CacheDir import org.koitharu.kotatsu.local.data.util.withExtraCloseable import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.util.await +import org.koitharu.kotatsu.parsers.util.requireBody import java.net.HttpURLConnection import kotlin.coroutines.coroutineContext diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Http.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Http.kt index 018d594e1..5d384ba88 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Http.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Http.kt @@ -5,7 +5,6 @@ import okhttp3.HttpUrl import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response -import okhttp3.ResponseBody import okhttp3.internal.closeQuietly import okio.IOException import org.json.JSONObject @@ -41,8 +40,6 @@ fun Response.ensureSuccess() = apply { } } -fun Response.requireBody(): ResponseBody = checkNotNull(body) { "Response body is null" } - fun Cookie.newBuilder(): Cookie.Builder = Cookie.Builder().also { c -> c.name(name) c.value(value) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2076ad1f7..2648670ac 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -729,4 +729,8 @@ This source does not support search with filters. Your filters have been cleared Kodomo One shot + Doujinshi + Image set + Artist CG + Game CG