MangaHub: Fix chapter pages not loading (#16229)
* MangaHub: Fix chapter pages not loading * Make mangaSource nullable
This commit is contained in:
parent
406e2ddfb5
commit
950a2ac1b4
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.multisrc.mangahub
|
package eu.kanade.tachiyomi.multisrc.mangahub
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||||
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
|
||||||
|
@ -12,16 +13,18 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.IOException
|
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
@ -53,6 +56,9 @@ abstract class MangaHub(
|
||||||
|
|
||||||
open val json: Json by injectLazy()
|
open val json: Json by injectLazy()
|
||||||
|
|
||||||
|
private var baseApiUrl = "https://api.mghubcdn.com"
|
||||||
|
private var baseCdnUrl = "https://imgx.mghubcdn.com"
|
||||||
|
|
||||||
private var userAgent: String? = null
|
private var userAgent: String? = null
|
||||||
private var checkedUa = false
|
private var checkedUa = false
|
||||||
|
|
||||||
|
@ -271,62 +277,45 @@ abstract class MangaHub(
|
||||||
}
|
}
|
||||||
|
|
||||||
// pages
|
// pages
|
||||||
private fun findPageCount(urlTemplate: String, extension: String): Int {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
var lowerBound = 1
|
val body = buildJsonObject {
|
||||||
var upperBound = 500
|
put("query", PAGES_QUERY)
|
||||||
|
put(
|
||||||
|
"variables",
|
||||||
|
buildJsonObject {
|
||||||
|
val mangaSource = when (name) {
|
||||||
|
"MangaHub" -> "m01"
|
||||||
|
"MangaReader.site" -> "mr01"
|
||||||
|
"MangaPanda.onl" -> "mr02"
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
val chapterUrl = chapter.url.split("/")
|
||||||
|
|
||||||
while (lowerBound <= upperBound) {
|
put("mangaSource", mangaSource)
|
||||||
val midpoint = lowerBound + (upperBound - lowerBound) / 2
|
put("slug", chapterUrl[2])
|
||||||
val url = urlTemplate.replaceAfterLast("/", "$midpoint.$extension")
|
put("number", chapterUrl[3].substringAfter("-").toFloat())
|
||||||
val request = Request.Builder()
|
},
|
||||||
.url(url)
|
)
|
||||||
.headers(headers)
|
|
||||||
.head()
|
|
||||||
.build()
|
|
||||||
val response = try {
|
|
||||||
client.newCall(request).execute()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw Exception("Failed to fetch $url")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.code == 404) {
|
|
||||||
upperBound = midpoint - 1
|
|
||||||
} else {
|
|
||||||
lowerBound = midpoint + 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.toString()
|
||||||
|
.toRequestBody()
|
||||||
|
|
||||||
return lowerBound - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
val urlTemplate = document.select("#mangareader img").attr("abs:src")
|
|
||||||
val extension = urlTemplate.substringAfterLast(".")
|
|
||||||
|
|
||||||
// make some calls to check if the pages exist using findPageCount()
|
|
||||||
// increase or decreasing by using binary search algorithm
|
|
||||||
val maxPage = findPageCount(urlTemplate, extension)
|
|
||||||
|
|
||||||
for (page in 1..maxPage) {
|
|
||||||
val url = urlTemplate.replaceAfterLast("/", "$page.$extension")
|
|
||||||
val pageObject = Page(page - 1, "", url)
|
|
||||||
pages.add(pageObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlRequest(page: Page): Request {
|
|
||||||
val newHeaders = headersBuilder()
|
val newHeaders = headersBuilder()
|
||||||
.set("Accept", "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8")
|
.set("Content-Type", "application/json")
|
||||||
.set("Sec-Fetch-Dest", "image")
|
.set("Origin", baseUrl)
|
||||||
.set("Sec-Fetch-Mode", "no-cors")
|
|
||||||
.set("Sec-Fetch-Site", "cross-site")
|
|
||||||
.removeAll("Upgrade-Insecure-Requests")
|
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return GET(page.url, newHeaders)
|
return POST("$baseApiUrl/graphql", newHeaders, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(document: Document): List<Page> = throw UnsupportedOperationException("Not used")
|
||||||
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
|
val pagesString = json.decodeFromString<ApiChapterPagesResponse>(response.body.string()).data.chapter.pages
|
||||||
|
val pages = json.decodeFromString<ApiChapterPages>(pagesString)
|
||||||
|
|
||||||
|
return pages.i.mapIndexed { i, page ->
|
||||||
|
Page(i, "", "$baseCdnUrl/${pages.p}$page")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
|
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
|
||||||
|
|
|
@ -9,7 +9,7 @@ class MangaHubGenerator : ThemeSourceGenerator {
|
||||||
|
|
||||||
override val themeClass = "MangaHub"
|
override val themeClass = "MangaHub"
|
||||||
|
|
||||||
override val baseVersionCode: Int = 17
|
override val baseVersionCode: Int = 18
|
||||||
|
|
||||||
override val sources = listOf(
|
override val sources = listOf(
|
||||||
// SingleLang("1Manga.co", "https://1manga.co", "en", isNsfw = true, className = "OneMangaCo"),
|
// SingleLang("1Manga.co", "https://1manga.co", "en", isNsfw = true, className = "OneMangaCo"),
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package eu.kanade.tachiyomi.multisrc.mangahub
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
private fun buildQuery(queryAction: () -> String) = queryAction().replace("%", "$")
|
||||||
|
|
||||||
|
val PAGES_QUERY = buildQuery {
|
||||||
|
"""
|
||||||
|
query(%mangaSource: MangaSource, %slug: String!, %number: Float!) {
|
||||||
|
chapter(x: %mangaSource, slug: %slug, number: %number) {
|
||||||
|
pages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ApiChapterPagesResponse(
|
||||||
|
val data: ApiChapterData,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ApiChapterData(
|
||||||
|
val chapter: ApiChapter,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ApiChapter(
|
||||||
|
val pages: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ApiChapterPages(
|
||||||
|
val p: String,
|
||||||
|
val i: List<String>,
|
||||||
|
)
|
Loading…
Reference in New Issue