fix(buondua): enhance Cloudflare challenge bypass ()

* fix(buondua): enhance Cloudflare challenge bypass

- Add rate limiting (max 10 requests/second)
- Implement random User-Agent rotation
- Inject Referer header
- Version bump 2 → 3

refs: 

* chore(buondua): replace interceptor with headersBuilder for request headers

- Replace the interceptor with  headersBuilder()
- Move the SimpleDateFormat to the companion object or class variable

Refs: 
This commit is contained in:
marioplus 2025-03-28 09:01:20 +08:00 committed by Draff
parent f4a08ea908
commit 2723d5d0ca
No known key found for this signature in database
GPG Key ID: E8A89F3211677653
2 changed files with 25 additions and 2 deletions
src/all/buondua
build.gradle
src/eu/kanade/tachiyomi/extension/all/buondua

@ -1,8 +1,12 @@
ext { ext {
extName = 'Buon Dua' extName = 'Buon Dua'
extClass = '.BuonDua' extClass = '.BuonDua'
extVersionCode = 2 extVersionCode = 3
isNsfw = true isNsfw = true
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(":lib:randomua"))
}

@ -1,6 +1,9 @@
package eu.kanade.tachiyomi.extension.all.buondua package eu.kanade.tachiyomi.extension.all.buondua
import eu.kanade.tachiyomi.lib.randomua.UserAgentType
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -8,11 +11,14 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import keiyoushi.utils.tryParse
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request import okhttp3.Request
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit
class BuonDua() : ParsedHttpSource() { class BuonDua() : ParsedHttpSource() {
override val baseUrl = "https://buondua.com" override val baseUrl = "https://buondua.com"
@ -20,6 +26,13 @@ class BuonDua() : ParsedHttpSource() {
override val name = "Buon Dua" override val name = "Buon Dua"
override val supportsLatest = true override val supportsLatest = true
override val client = network.cloudflareClient.newBuilder()
.rateLimitHost(baseUrl.toHttpUrl(), 10, 1, TimeUnit.SECONDS)
.setRandomUserAgent(UserAgentType.MOBILE)
.build()
override fun headersBuilder() = super.headersBuilder().add("Referer", "$baseUrl/")
// Latest // Latest
override fun latestUpdatesFromElement(element: Element): SManga { override fun latestUpdatesFromElement(element: Element): SManga {
val manga = SManga.create() val manga = SManga.create()
@ -43,6 +56,7 @@ class BuonDua() : ParsedHttpSource() {
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/hot?start=${20 * (page - 1)}") return GET("$baseUrl/hot?start=${20 * (page - 1)}")
} }
override fun popularMangaSelector() = latestUpdatesSelector() override fun popularMangaSelector() = latestUpdatesSelector()
// Search // Search
@ -57,6 +71,7 @@ class BuonDua() : ParsedHttpSource() {
else -> popularMangaRequest(page) else -> popularMangaRequest(page)
} }
} }
override fun searchMangaSelector() = latestUpdatesSelector() override fun searchMangaSelector() = latestUpdatesSelector()
// Details // Details
@ -77,7 +92,7 @@ class BuonDua() : ParsedHttpSource() {
chapter.setUrlWithoutDomain(element.select(".is-current").first()!!.attr("abs:href")) chapter.setUrlWithoutDomain(element.select(".is-current").first()!!.attr("abs:href"))
chapter.chapter_number = 0F chapter.chapter_number = 0F
chapter.name = element.select(".article-header").text() chapter.name = element.select(".article-header").text()
chapter.date_upload = SimpleDateFormat("H:m DD-MM-yyyy", Locale.US).parse(element.select(".article-info > small").text())?.time ?: 0L chapter.date_upload = DATE_FORMAT.tryParse(element.selectFirst(".article-info > small")?.text())
return chapter return chapter
} }
@ -114,4 +129,8 @@ class BuonDua() : ParsedHttpSource() {
class TagFilter : Filter.Text("Tag ID") class TagFilter : Filter.Text("Tag ID")
private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T
companion object {
private val DATE_FORMAT = SimpleDateFormat("H:m DD-MM-yyyy", Locale.US)
}
} }