Baozimanhua: fix page list parse (#12064)

* Baozimanhua: fix page list parse

* Baozimanhua: make interceptor singleton

* Baozimanhua: remove some overhead in interceptor
This commit is contained in:
kasperskier 2022-06-05 08:38:34 +08:00 committed by GitHub
parent 05b75dd216
commit 42e6a5064f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 55 deletions

View File

@ -1,3 +1,8 @@
## 1.2.7 (2022-06-04)
- 修复章节图片解析
- 整理筛选器代码
## 1.2.6 (2022-05-27) ## 1.2.6 (2022-05-27)
- 整理代码 - 整理代码

View File

@ -5,7 +5,7 @@ ext {
extName = 'Baozimanhua' extName = 'Baozimanhua'
pkgNameSuffix = 'zh.baozimanhua' pkgNameSuffix = 'zh.baozimanhua'
extClass = '.Baozimanhua' extClass = '.Baozimanhua'
extVersionCode = 6 extVersionCode = 7
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -9,7 +9,11 @@ package eu.kanade.tachiyomi.extension.zh.baozimanhua
const val BANNER_BASE64 = "\ const val BANNER_BASE64 = "\
''' '''
tail = b'"\n' tail = b'''\
"
const val BANNER_WIDTH = 800
const val BANNER_HEIGHT = 282
'''
with open('src/eu/kanade/tachiyomi/extension/zh/baozimanhua/BannerData.kt', 'wb') as f: with open('src/eu/kanade/tachiyomi/extension/zh/baozimanhua/BannerData.kt', 'wb') as f:
f.write(head) f.write(head)

File diff suppressed because one or more lines are too long

View File

@ -8,24 +8,20 @@ import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Response import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody import okhttp3.ResponseBody.Companion.toResponseBody
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.util.EnumSet
import kotlin.math.abs import kotlin.math.abs
class BannerInterceptor : Interceptor { object BannerInterceptor : Interceptor {
private val banner: Bitmap by lazy { private const val w = BANNER_WIDTH
val buffer = Base64.decode(BANNER_BASE64, Base64.DEFAULT) private const val h = BANNER_HEIGHT
BitmapFactory.decodeByteArray(buffer, 0, buffer.size) private const val size = w * h
} private const val threshold = w * h * 3 // 1 per pixel per channel
private val w by lazy { banner.width }
private val h by lazy { banner.height }
private val size by lazy { w * h }
private val bannerBuffer by lazy { private val bannerBuffer by lazy {
val buffer = IntArray(size) val buffer = Base64.decode(BANNER_BASE64, Base64.DEFAULT)
banner.getPixels(buffer, 0, w, 0, 0, w, h) val banner = BitmapFactory.decodeByteArray(buffer, 0, buffer.size)
banner.recycle() val pixels = IntArray(size)
buffer banner.getPixels(pixels, 0, w, 0, 0, w, h)
pixels
} }
private val threshold by lazy { w * h * 3 } // 1 per pixel per channel
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
val url = chain.request().url.toString() val url = chain.request().url.toString()
@ -36,12 +32,12 @@ class BannerInterceptor : Interceptor {
val content = body.bytes() val content = body.bytes()
val bitmap = BitmapFactory.decodeByteArray(content, 0, content.size) val bitmap = BitmapFactory.decodeByteArray(content, 0, content.size)
val positions = checkBanner(bitmap) val positions = checkBanner(bitmap)
return if (positions.isEmpty()) { return if (positions == 0) {
response.newBuilder().body(content.toResponseBody(contentType)).build() response.newBuilder().body(content.toResponseBody(contentType)).build()
} else { } else {
val result = Bitmap.createBitmap( val result = Bitmap.createBitmap(
bitmap, 0, if (positions.contains(BannerPosition.TOP)) h else 0, bitmap, 0, if (positions and TOP == TOP) h else 0,
bitmap.width, bitmap.height - h * positions.size bitmap.width, bitmap.height - if (positions == BOTH) h * 2 else h
) )
val output = ByteArrayOutputStream() val output = ByteArrayOutputStream()
result.compress(Bitmap.CompressFormat.JPEG, 90, output) result.compress(Bitmap.CompressFormat.JPEG, 90, output)
@ -50,16 +46,16 @@ class BannerInterceptor : Interceptor {
} }
} }
private fun checkBanner(image: Bitmap): EnumSet<BannerPosition> { private fun checkBanner(image: Bitmap): Int {
val result = EnumSet.noneOf(BannerPosition::class.java) if (image.width < w || image.height < h) return 0
if (image.width < w || image.height < h) return result if ((image.width - w) % 2 != 0) return 0
if ((image.width - w) % 2 != 0) return result
val pad = (image.width - w) / 2 val pad = (image.width - w) / 2
val buf = IntArray(size) val buf = IntArray(size)
var result = 0
image.getPixels(buf, 0, w, pad, 0, w, h) // top image.getPixels(buf, 0, w, pad, 0, w, h) // top
if (isIdentical(bannerBuffer, buf)) result.add(BannerPosition.TOP) if (isIdentical(bannerBuffer, buf)) result = result or TOP
image.getPixels(buf, 0, w, pad, image.height - h, w, h) // bottom image.getPixels(buf, 0, w, pad, image.height - h, w, h) // bottom
if (isIdentical(bannerBuffer, buf)) result.add(BannerPosition.BOTTOM) if (isIdentical(bannerBuffer, buf)) result = result or BOTTOM
return result return result
} }
@ -76,7 +72,9 @@ class BannerInterceptor : Interceptor {
return true return true
} }
private enum class BannerPosition { TOP, BOTTOM } private const val TOP = 0b01
} private const val BOTTOM = 0b10
private const val BOTH = 0b11
const val COMIC_IMAGE_SUFFIX = "#baozi" const val COMIC_IMAGE_SUFFIX = "#baozi"
}

View File

@ -40,7 +40,7 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(BannerInterceptor()).build() .addInterceptor(BannerInterceptor).build()
override fun chapterListSelector() = throw UnsupportedOperationException("Not used.") override fun chapterListSelector() = throw UnsupportedOperationException("Not used.")
@ -108,8 +108,8 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
} }
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
return document.select(".comic-contain > .chapter-img > img").mapIndexed { index, element -> return document.select(".comic-contain > amp-img").mapIndexed { index, element ->
Page(index, imageUrl = element.attr("data-src").trim() + COMIC_IMAGE_SUFFIX) Page(index, imageUrl = element.attr("src").trim() + BannerInterceptor.COMIC_IMAGE_SUFFIX)
} }
} }
@ -145,27 +145,8 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
return if (query.isNotEmpty()) { return if (query.isNotEmpty()) {
GET("$baseUrl/search?q=$query", headers) GET("$baseUrl/search?q=$query", headers)
} else { } else {
lateinit var tag: String val parts = filters.filterIsInstance<UriPartFilter>().joinToString("&") { it.toUriPart() }
lateinit var region: String GET("$baseUrl/classify?page=$page&$parts", headers)
lateinit var status: String
lateinit var start: String
filters.forEach { filter ->
when (filter) {
is TagFilter -> {
tag = filter.toUriPart()
}
is RegionFilter -> {
region = filter.toUriPart()
}
is StatusFilter -> {
status = filter.toUriPart()
}
is StartFilter -> {
start = filter.toUriPart()
}
}
}
GET("$baseUrl/classify?type=$tag&region=$region&state=$status&filter=$start&page=$page")
} }
} }
@ -194,13 +175,14 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
StartFilter() StartFilter()
) )
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : private open class UriPartFilter(name: String, val query: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { Filter.Select<String>(name, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second fun toUriPart() = "$query=${vals[state].second}"
} }
private class TagFilter : UriPartFilter( private class TagFilter : UriPartFilter(
"标签", "标签",
"type",
arrayOf( arrayOf(
Pair("全部", "all"), Pair("全部", "all"),
Pair("都市", "dushi"), Pair("都市", "dushi"),
@ -271,6 +253,7 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
private class RegionFilter : UriPartFilter( private class RegionFilter : UriPartFilter(
"地区", "地区",
"region",
arrayOf( arrayOf(
Pair("全部", "all"), Pair("全部", "all"),
Pair("国漫", "cn"), Pair("国漫", "cn"),
@ -282,6 +265,7 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
private class StatusFilter : UriPartFilter( private class StatusFilter : UriPartFilter(
"进度", "进度",
"state",
arrayOf( arrayOf(
Pair("全部", "all"), Pair("全部", "all"),
Pair("连载中", "serial"), Pair("连载中", "serial"),
@ -291,6 +275,7 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
private class StartFilter : UriPartFilter( private class StartFilter : UriPartFilter(
"标题开头", "标题开头",
"filter",
arrayOf( arrayOf(
Pair("全部", "*"), Pair("全部", "*"),
Pair("ABCD", "ABCD"), Pair("ABCD", "ABCD"),