SlimeReadTheme: Fix pagination and add scan id (#7152)

Fix pagination and add scan id
This commit is contained in:
Chopper 2025-01-13 10:01:58 -03:00 committed by Draff
parent d3d31ec815
commit 49efe333db
No known key found for this signature in database
GPG Key ID: E8A89F3211677653
3 changed files with 48 additions and 28 deletions

View File

@ -2,4 +2,4 @@ plugins {
id("lib-multisrc") id("lib-multisrc")
} }
baseVersionCode = 2 baseVersionCode = 3

View File

@ -33,6 +33,7 @@ abstract class SlimeReadTheme(
override val name: String, override val name: String,
override val baseUrl: String, override val baseUrl: String,
override val lang: String, override val lang: String,
private val scanId: String = "",
) : HttpSource() { ) : HttpSource() {
protected open val apiUrl: String by lazy { getApiUrlFromPage() } protected open val apiUrl: String by lazy { getApiUrlFromPage() }
@ -72,35 +73,19 @@ abstract class SlimeReadTheme(
} }
// ============================== Popular =============================== // ============================== Popular ===============================
private var currentSlice = 0
private var popularMangeCache: MangasPage? = null private var popularMangeCache: MangasPage? = null
override fun popularMangaRequest(page: Int) = override fun popularMangaRequest(page: Int): Request {
GET("$apiUrl/book_search?order=1&status=0", headers) val url = "$apiUrl/book_search?order=1&status=0".toHttpUrl().newBuilder()
.addIfNotBlank("scan_id", scanId)
.build()
return GET(url, headers)
}
// Returns a large JSON, so the app can't handle the list without pagination
override fun fetchPopularManga(page: Int): Observable<MangasPage> { override fun fetchPopularManga(page: Int): Observable<MangasPage> {
if (page == 1 || popularMangeCache == null) { popularMangeCache = popularMangeCache?.takeIf { page != 1 }
popularMangeCache = super.fetchPopularManga(page) ?: super.fetchPopularManga(page).toBlocking().last()
.toBlocking() return pageableOf(page, popularMangeCache!!)
.last()
}
// Handling a large manga list
return Observable.just(popularMangeCache!!)
.map { mangaPage ->
val mangas = mangaPage.mangas
val pageSize = 15
currentSlice = (page - 1) * pageSize
val startIndex = min(mangas.size - 1, currentSlice)
val endIndex = min(mangas.size, currentSlice + pageSize)
val slice = mangas.subList(startIndex, endIndex)
MangasPage(slice, slice.isNotEmpty())
}
} }
override fun popularMangaParse(response: Response): MangasPage { override fun popularMangaParse(response: Response): MangasPage {
@ -110,7 +95,13 @@ abstract class SlimeReadTheme(
} }
// =============================== Latest =============================== // =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) = GET("$apiUrl/books?page=$page", headers)
override fun latestUpdatesRequest(page: Int): Request {
val url = "$apiUrl/books?page=$page".toHttpUrl().newBuilder()
.addIfNotBlank("scan_id", scanId)
.build()
return GET(url, headers)
}
override fun latestUpdatesParse(response: Response): MangasPage { override fun latestUpdatesParse(response: Response): MangasPage {
val dto = response.parseAs<LatestResponseDto>() val dto = response.parseAs<LatestResponseDto>()
@ -120,6 +111,9 @@ abstract class SlimeReadTheme(
} }
// =============================== Search =============================== // =============================== Search ===============================
private var searchMangaCache: MangasPage? = null
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
val id = query.removePrefix(PREFIX_SEARCH) val id = query.removePrefix(PREFIX_SEARCH)
@ -127,7 +121,9 @@ abstract class SlimeReadTheme(
.asObservableSuccess() .asObservableSuccess()
.map(::searchMangaByIdParse) .map(::searchMangaByIdParse)
} else { } else {
super.fetchSearchManga(page, query, filters) searchMangaCache = searchMangaCache?.takeIf { page != 1 }
?: super.fetchSearchManga(page, query, filters).toBlocking().last()
pageableOf(page, searchMangaCache!!)
} }
} }
@ -146,6 +142,7 @@ abstract class SlimeReadTheme(
.addIfNotBlank("genre[]", params.genre) .addIfNotBlank("genre[]", params.genre)
.addIfNotBlank("status", params.status) .addIfNotBlank("status", params.status)
.addIfNotBlank("searchMethod", params.searchMethod) .addIfNotBlank("searchMethod", params.searchMethod)
.addIfNotBlank("scan_id", scanId)
.apply { .apply {
params.categories.forEach { params.categories.forEach {
addQueryParameter("categories[]", it) addQueryParameter("categories[]", it)
@ -237,6 +234,28 @@ abstract class SlimeReadTheme(
} }
// ============================= Utilities ============================== // ============================= Utilities ==============================
/**
* Handles a large manga list and returns a paginated response.
* The app can't handle the large JSON list without pagination.
*
* @param page The page number to retrieve.
* @param cache The cached manga page containing the full list of mangas.
*/
private fun pageableOf(page: Int, cache: MangasPage) = Observable.just(cache).map { mangaPage ->
val mangas = mangaPage.mangas
val pageSize = 15
val currentSlice = (page - 1) * pageSize
val startIndex = min(mangas.size, currentSlice)
val endIndex = min(mangas.size, currentSlice + pageSize)
val slice = mangas.subList(startIndex, endIndex)
MangasPage(slice, hasNextPage = endIndex < mangas.size)
}
private inline fun <reified T> Response.parseAs(): T = use { private inline fun <reified T> Response.parseAs(): T = use {
json.decodeFromStream(it.body.byteStream()) json.decodeFromStream(it.body.byteStream())
} }

View File

@ -7,6 +7,7 @@ class MahouScan : SlimeReadTheme(
"MahouScan", "MahouScan",
"https://mahouscan.com", "https://mahouscan.com",
"pt-BR", "pt-BR",
scanId = "1292193100",
) { ) {
override val client = super.client.newBuilder() override val client = super.client.newBuilder()
.rateLimit(2) .rateLimit(2)