Tighter extraction

This commit is contained in:
Sadwhy 2025-05-06 20:39:49 +06:00 committed by GitHub
parent a4d3a117cf
commit afb5e0c56f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,22 +1,27 @@
package eu.kanade.tachiyomi.lib.buzzheavierextractor package eu.kanade.tachiyomi.lib.buzzheavierextractor
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parseAs import eu.kanade.tachiyomi.util.parseAs
import java.io.IOException
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.internal.EMPTY_HEADERS import okhttp3.Request
import okhttp3.Response
class BuzzheavierExtractor( class BuzzheavierExtractor(
private val client: OkHttpClient, private val client: OkHttpClient,
private val headers: Headers, private val headers: Headers,
) { ) {
companion object {
private val SIZE_REGEX = Regex("""Size\s*-\s*([0-9.]+\s*[GMK]B)""")
}
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
fun videosFromUrl(url: String, prefix: String = "Buzzheavier - ", proxyUrl: String? = null): List<Video> { fun videosFromUrl(url: String, prefix: String = "Buzzheavier - ", proxyUrl: String? = null): List<Video> {
val httpUrl = url.toHttpUrl() val httpUrl = url.toHttpUrl()
@ -24,29 +29,52 @@ class BuzzheavierExtractor(
val dlHeaders = headers.newBuilder().apply { val dlHeaders = headers.newBuilder().apply {
add("Accept", "*/*") add("Accept", "*/*")
add("Host", httpUrl.host)
add("HX-Current-URL", url) add("HX-Current-URL", url)
add("HX-Request", "true") add("HX-Request", "true")
add("Priority", "u=1, i")
add("Referer", url) add("Referer", url)
}.build() }.build()
val videoHeaders = headers.newBuilder().apply { val videoHeaders = headers.newBuilder().apply {
add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
add("Priority", "u=0, i")
add("Referer", url) add("Referer", url)
}.build() }.build()
val path = client.newCall( val siteRequest = client.newCall(GET(url)).execute()
GET("https://${httpUrl.host}/$id/download", dlHeaders) val parsedHtml = siteRequest.asJsoup()
).execute().headers["hx-redirect"].orEmpty() val detailsText = parsedHtml.selectFirst("li:contains(Details:)")?.text() ?: ""
val size = SIZE_REGEX.find(detailsText)?.groupValues?.getOrNull(1)?.trim() ?: "Unknown"
return if (path.isNotEmpty()) { val downloadRequest = GET("https://${httpUrl.host}/$id/download", dlHeaders)
val videoUrl = if (path.startsWith("http")) path else "https://${httpUrl.host}$path" val path = client.executeWithRetry(downloadRequest, 5, 204).use { response ->
listOf(Video(videoUrl, "${prefix}Video", videoUrl, videoHeaders)) response.header("hx-redirect").orEmpty()
} else if (proxyUrl?.isNotEmpty() == true) {
val videoUrl = client.newCall(GET(proxyUrl + id)).execute().parseAs<UrlDto>().url
listOf(Video(videoUrl, "${prefix}Video", videoUrl, videoHeaders))
} else {
emptyList()
} }
val videoUrl = if (path.isNotEmpty()) {
if (path.startsWith("http")) path else "https://${httpUrl.host}$path"
} else if (proxyUrl?.isNotEmpty() == true) {
client.executeWithRetry(GET(proxyUrl + id), 5, 200).parseAs<UrlDto>().url
} else {
return emptyList()
}
return listOf(Video(videoUrl, "${prefix}${size}", videoUrl, videoHeaders))
}
private fun OkHttpClient.executeWithRetry(request: Request, maxRetries: Int, validCode: Int): Response {
var response: Response? = null
for (attempt in 0 until maxRetries) {
response?.close()
response = this.newCall(request).execute()
if (response.code == validCode) {
return response
}
if (attempt < maxRetries - 1) {
Thread.sleep(1000)
}
}
return response ?: throw IOException("Failed to execute request after $maxRetries attempts")
} }
@Serializable @Serializable