From 431f22913c2825eaf7e8df1df11115abf6b12f19 Mon Sep 17 00:00:00 2001 From: Troy121 Date: Tue, 28 Dec 2021 13:52:46 +0100 Subject: [PATCH] Imperfect Comics: Added handling of mirrored and color inverted chapters (#10254) --- .../imperfectcomics/src/ImperfectComics.kt | 100 ++++++++++++++++++ .../multisrc/madara/MadaraGenerator.kt | 2 +- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/multisrc/overrides/madara/imperfectcomics/src/ImperfectComics.kt b/multisrc/overrides/madara/imperfectcomics/src/ImperfectComics.kt index 4a11acc5c..fff2aaa0a 100644 --- a/multisrc/overrides/madara/imperfectcomics/src/ImperfectComics.kt +++ b/multisrc/overrides/madara/imperfectcomics/src/ImperfectComics.kt @@ -1,9 +1,109 @@ package eu.kanade.tachiyomi.extension.en.imperfectcomics +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.ColorMatrix +import android.graphics.ColorMatrixColorFilter +import android.graphics.Matrix +import android.graphics.Paint import eu.kanade.tachiyomi.multisrc.madara.Madara +import eu.kanade.tachiyomi.source.model.Page +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.Interceptor +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.OkHttpClient +import okhttp3.Response +import okhttp3.ResponseBody.Companion.toResponseBody +import org.jsoup.nodes.Document +import java.io.ByteArrayOutputStream +import java.io.InputStream import java.text.SimpleDateFormat class ImperfectComics : Madara("Imperfect Comics", "https://imperfectcomic.com", "en", SimpleDateFormat("yyyy-MM-dd")) { override val useNewChapterEndpoint: Boolean = true + + override val client: OkHttpClient = super.client.newBuilder() + .addInterceptor(::imageIntercept) + .build() + + override fun pageListParse(document: Document): List { + val mangaId = document.select("#manga-reading-nav-head").attr("data-id") + val chapterId = document.select("#wp-manga-current-chap").attr("data-id") + val mangaRegex = """data-id=\"$mangaId\"(?:.|\n)*?(?=\})""".toRegex() + val chapterRegex = """data-id=\"$chapterId\"(?:.|\n)*?(?=\})""".toRegex() + val css = document.selectFirst("#wp-custom-css").html() + val props = mangaRegex.find(css).let { mId -> + mId?.value ?: chapterRegex.find(css).let { cId -> + cId?.value ?: "" + } + } + + countViews(document) + + return document.select(pageListParseSelector).mapIndexed { index, element -> + val imageUrl = element.selectFirst("img")?.absUrl("src")!! + .toHttpUrlOrNull()!!.newBuilder() + + if (props.contains("transform")) + imageUrl.addQueryParameter("mirror", "1") + if (props.contains("invert")) + imageUrl.addQueryParameter("invert", "1") + + Page(index, document.location(), imageUrl.toString()) + } + } + + private fun imageIntercept(chain: Interceptor.Chain): Response { + var request = chain.request() + val mirror = request.url.queryParameter("mirror") != null + val invert = request.url.queryParameter("invert") != null + + if (!(mirror || invert)) { + return chain.proceed(request) + } + + val newUrl = request.url.newBuilder() + .removeAllQueryParameters("mirror") + .removeAllQueryParameters("invert") + .build() + request = request.newBuilder().url(newUrl).build() + + val response = chain.proceed(request) + val image = processImage(response.body!!.byteStream(), mirror, invert) + val body = image.toResponseBody("image/png".toMediaTypeOrNull()) + + response.close() + + return response.newBuilder().body(body).build() + } + + private fun processImage(image: InputStream, mirror: Boolean, invert: Boolean): ByteArray { + var input = BitmapFactory.decodeStream(image) + val matrix = Matrix().apply { postScale(-1F, 1F, input.width / 2F, input.height / 2F) } + val paint = Paint().apply { + colorFilter = ColorMatrixColorFilter( + ColorMatrix().apply { + set( + floatArrayOf( + -1f, 0f, 0f, 0f, 255f, + 0f, -1f, 0f, 0f, 255f, + 0f, 0f, -1f, 0f, 255f, + 0f, 0f, 0f, 1f, 0f + ) + ) + } + ) + } + + if (mirror) + input = Bitmap.createBitmap(input, 0, 0, input.width, input.height, matrix, true) + if (invert) + Canvas(input).drawBitmap(input, 0f, 0f, paint) + + val output = ByteArrayOutputStream() + input.compress(Bitmap.CompressFormat.PNG, 100, output) + return output.toByteArray() + } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt index 78aee0340..5f755afa7 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt @@ -117,7 +117,7 @@ class MadaraGenerator : ThemeSourceGenerator { SingleLang("Ichirin No Hana Yuri", "https://ichirinnohanayuri.com.br", "pt-BR", overrideVersionCode = 3), SingleLang("Ikifeng", "https://ikifeng.com", "es", isNsfw = true), SingleLang("Immortal Updates", "https://immortalupdates.com", "en", overrideVersionCode = 2), - SingleLang("Imperfect Comics", "https://imperfectcomic.com", "en", overrideVersionCode = 2), + SingleLang("Imperfect Comics", "https://imperfectcomic.com", "en", overrideVersionCode = 3), SingleLang("Império Scans", "https://imperioscans.com.br", "pt-BR", className = "ImperioScans", overrideVersionCode = 1), SingleLang("InfraFandub", "https://infrafandub.xyz", "es"), SingleLang("Inmortal Scan", "https://manga.mundodrama.site", "es"),