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)
- 整理代码

View File

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

View File

@ -9,7 +9,11 @@ package eu.kanade.tachiyomi.extension.zh.baozimanhua
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:
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.ResponseBody.Companion.toResponseBody
import java.io.ByteArrayOutputStream
import java.util.EnumSet
import kotlin.math.abs
class BannerInterceptor : Interceptor {
private val banner: Bitmap by lazy {
val buffer = Base64.decode(BANNER_BASE64, Base64.DEFAULT)
BitmapFactory.decodeByteArray(buffer, 0, buffer.size)
}
private val w by lazy { banner.width }
private val h by lazy { banner.height }
private val size by lazy { w * h }
object BannerInterceptor : Interceptor {
private const val w = BANNER_WIDTH
private const val h = BANNER_HEIGHT
private const val size = w * h
private const val threshold = w * h * 3 // 1 per pixel per channel
private val bannerBuffer by lazy {
val buffer = IntArray(size)
banner.getPixels(buffer, 0, w, 0, 0, w, h)
banner.recycle()
buffer
val buffer = Base64.decode(BANNER_BASE64, Base64.DEFAULT)
val banner = BitmapFactory.decodeByteArray(buffer, 0, buffer.size)
val pixels = IntArray(size)
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 {
val url = chain.request().url.toString()
@ -36,12 +32,12 @@ class BannerInterceptor : Interceptor {
val content = body.bytes()
val bitmap = BitmapFactory.decodeByteArray(content, 0, content.size)
val positions = checkBanner(bitmap)
return if (positions.isEmpty()) {
return if (positions == 0) {
response.newBuilder().body(content.toResponseBody(contentType)).build()
} else {
val result = Bitmap.createBitmap(
bitmap, 0, if (positions.contains(BannerPosition.TOP)) h else 0,
bitmap.width, bitmap.height - h * positions.size
bitmap, 0, if (positions and TOP == TOP) h else 0,
bitmap.width, bitmap.height - if (positions == BOTH) h * 2 else h
)
val output = ByteArrayOutputStream()
result.compress(Bitmap.CompressFormat.JPEG, 90, output)
@ -50,16 +46,16 @@ class BannerInterceptor : Interceptor {
}
}
private fun checkBanner(image: Bitmap): EnumSet<BannerPosition> {
val result = EnumSet.noneOf(BannerPosition::class.java)
if (image.width < w || image.height < h) return result
if ((image.width - w) % 2 != 0) return result
private fun checkBanner(image: Bitmap): Int {
if (image.width < w || image.height < h) return 0
if ((image.width - w) % 2 != 0) return 0
val pad = (image.width - w) / 2
val buf = IntArray(size)
var result = 0
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
if (isIdentical(bannerBuffer, buf)) result.add(BannerPosition.BOTTOM)
if (isIdentical(bannerBuffer, buf)) result = result or BOTTOM
return result
}
@ -76,7 +72,9 @@ class BannerInterceptor : Interceptor {
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 client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(BannerInterceptor()).build()
.addInterceptor(BannerInterceptor).build()
override fun chapterListSelector() = throw UnsupportedOperationException("Not used.")
@ -108,8 +108,8 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
}
override fun pageListParse(document: Document): List<Page> {
return document.select(".comic-contain > .chapter-img > img").mapIndexed { index, element ->
Page(index, imageUrl = element.attr("data-src").trim() + COMIC_IMAGE_SUFFIX)
return document.select(".comic-contain > amp-img").mapIndexed { index, element ->
Page(index, imageUrl = element.attr("src").trim() + BannerInterceptor.COMIC_IMAGE_SUFFIX)
}
}
@ -145,27 +145,8 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
return if (query.isNotEmpty()) {
GET("$baseUrl/search?q=$query", headers)
} else {
lateinit var tag: String
lateinit var region: String
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")
val parts = filters.filterIsInstance<UriPartFilter>().joinToString("&") { it.toUriPart() }
GET("$baseUrl/classify?page=$page&$parts", headers)
}
}
@ -194,13 +175,14 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
StartFilter()
)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
private open class UriPartFilter(name: String, val query: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(name, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = "$query=${vals[state].second}"
}
private class TagFilter : UriPartFilter(
"标签",
"type",
arrayOf(
Pair("全部", "all"),
Pair("都市", "dushi"),
@ -271,6 +253,7 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
private class RegionFilter : UriPartFilter(
"地区",
"region",
arrayOf(
Pair("全部", "all"),
Pair("国漫", "cn"),
@ -282,6 +265,7 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
private class StatusFilter : UriPartFilter(
"进度",
"state",
arrayOf(
Pair("全部", "all"),
Pair("连载中", "serial"),
@ -291,6 +275,7 @@ class Baozimanhua : ParsedHttpSource(), ConfigurableSource {
private class StartFilter : UriPartFilter(
"标题开头",
"filter",
arrayOf(
Pair("全部", "*"),
Pair("ABCD", "ABCD"),