Fix missing half of the page at FS. (#7989)
This commit is contained in:
parent
2262ce212d
commit
1ff4c578c3
|
@ -1,21 +1,127 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.flamescans
|
package eu.kanade.tachiyomi.extension.en.flamescans
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.util.Log
|
||||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
||||||
import eu.kanade.tachiyomi.multisrc.wpmangareader.WPMangaReader
|
import eu.kanade.tachiyomi.multisrc.wpmangareader.WPMangaReader
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Protocol
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class FlameScans : WPMangaReader("Flame Scans", "https://flamescans.org", "en", "/series") {
|
class FlameScans : WPMangaReader(
|
||||||
private val rateLimitInterceptor = RateLimitInterceptor(1)
|
"Flame Scans",
|
||||||
private val userAgent = "Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
|
"https://flamescans.org",
|
||||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
"en",
|
||||||
.add("User-Agent", userAgent)
|
"/series"
|
||||||
|
) {
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||||
.connectTimeout(10, TimeUnit.SECONDS)
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
.addNetworkInterceptor(rateLimitInterceptor)
|
.addInterceptor(::composedImageIntercept)
|
||||||
|
.addInterceptor(RateLimitInterceptor(1, 1, TimeUnit.SECONDS))
|
||||||
.build()
|
.build()
|
||||||
}
|
|
||||||
|
|
||||||
|
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||||
|
.add("User-Agent", USER_AGENT)
|
||||||
|
|
||||||
|
private val composedSelector: String = "#readerarea div.figure_container div.composed_figure"
|
||||||
|
|
||||||
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
|
val hasSplitImages = document
|
||||||
|
.select(composedSelector)
|
||||||
|
.firstOrNull() != null
|
||||||
|
|
||||||
|
if (!hasSplitImages) {
|
||||||
|
return super.pageListParse(document)
|
||||||
|
}
|
||||||
|
|
||||||
|
return document.select("#readerarea p:has(img), $composedSelector")
|
||||||
|
.filter {
|
||||||
|
it.select("img").all { imgEl ->
|
||||||
|
imgEl.attr("abs:src").isNullOrEmpty().not()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mapIndexed { i, el ->
|
||||||
|
if (el.tagName() == "p") {
|
||||||
|
Page(i, "", el.select("img").attr("abs:src"))
|
||||||
|
} else {
|
||||||
|
val imageUrls = el.select("img")
|
||||||
|
.joinToString("|") { it.attr("abs:src") }
|
||||||
|
|
||||||
|
Page(i, "", imageUrls + COMPOSED_SUFFIX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun composedImageIntercept(chain: Interceptor.Chain): Response {
|
||||||
|
if (!chain.request().url.toString().endsWith(COMPOSED_SUFFIX)) {
|
||||||
|
return chain.proceed(chain.request())
|
||||||
|
}
|
||||||
|
|
||||||
|
val imageUrls = chain.request().url.toString()
|
||||||
|
.removeSuffix(COMPOSED_SUFFIX)
|
||||||
|
.split("%7C")
|
||||||
|
|
||||||
|
var width = 0
|
||||||
|
var height = 0
|
||||||
|
|
||||||
|
val imageBitmaps = imageUrls.map { imageUrl ->
|
||||||
|
val request = chain.request().newBuilder().url(imageUrl).build()
|
||||||
|
val response = chain.proceed(request)
|
||||||
|
|
||||||
|
val bitmap = BitmapFactory.decodeStream(response.body!!.byteStream())
|
||||||
|
|
||||||
|
width += bitmap.width
|
||||||
|
height = bitmap.height
|
||||||
|
|
||||||
|
bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||||
|
val canvas = Canvas(result)
|
||||||
|
|
||||||
|
var left = 0
|
||||||
|
|
||||||
|
imageBitmaps.forEach { bitmap ->
|
||||||
|
val srcRect = Rect(0, 0, bitmap.width, bitmap.height)
|
||||||
|
val dstRect = Rect(left, 0, left + bitmap.width, bitmap.height)
|
||||||
|
|
||||||
|
canvas.drawBitmap(bitmap, srcRect, dstRect, null)
|
||||||
|
|
||||||
|
left += bitmap.width
|
||||||
|
}
|
||||||
|
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
result.compress(Bitmap.CompressFormat.PNG, 100, output)
|
||||||
|
|
||||||
|
val responseBody = output.toByteArray().toResponseBody(MEDIA_TYPE)
|
||||||
|
|
||||||
|
return Response.Builder()
|
||||||
|
.code(200)
|
||||||
|
.protocol(Protocol.HTTP_1_1)
|
||||||
|
.request(chain.request())
|
||||||
|
.message("OK")
|
||||||
|
.body(responseBody)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val USER_AGENT = "Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||||
|
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
|
||||||
|
|
||||||
|
private const val COMPOSED_SUFFIX = "?comp"
|
||||||
|
private val MEDIA_TYPE = "image/png".toMediaType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ class WPMangaReaderGenerator : ThemeSourceGenerator {
|
||||||
SingleLang("Mangasusu", "https://mangasusu.co.in", "id", isNsfw = true),
|
SingleLang("Mangasusu", "https://mangasusu.co.in", "id", isNsfw = true),
|
||||||
SingleLang("TurkToon", "https://turktoon.com", "tr"),
|
SingleLang("TurkToon", "https://turktoon.com", "tr"),
|
||||||
SingleLang("Gecenin Lordu", "https://geceninlordu.com/", "tr", overrideVersionCode = 1),
|
SingleLang("Gecenin Lordu", "https://geceninlordu.com/", "tr", overrideVersionCode = 1),
|
||||||
SingleLang("Flame Scans", "https://flamescans.org", "en", overrideVersionCode = 6),
|
SingleLang("Flame Scans", "https://flamescans.org", "en", overrideVersionCode = 7),
|
||||||
SingleLang("A Pair of 2+", "https://pairof2.com", "en", className = "APairOf2"),
|
SingleLang("A Pair of 2+", "https://pairof2.com", "en", className = "APairOf2"),
|
||||||
SingleLang("PMScans", "https://reader.pmscans.com", "en"),
|
SingleLang("PMScans", "https://reader.pmscans.com", "en"),
|
||||||
SingleLang("Skull Scans", "https://www.skullscans.com", "en"),
|
SingleLang("Skull Scans", "https://www.skullscans.com", "en"),
|
||||||
|
|
Loading…
Reference in New Issue