Mangadex Api 5.0.4

This commit is contained in:
Jobobby04 2021-05-09 17:37:19 -04:00
parent c26adbb81d
commit fc354f5792
7 changed files with 75 additions and 49 deletions

View File

@ -8,7 +8,7 @@ import exh.md.utils.FollowStatus
import exh.metadata.metadata.base.RaisedSearchMetadata
interface FollowsSource : CatalogueSource {
suspend fun fetchFollows(): MangasPage
suspend fun fetchFollows(page: Int): MangasPage
/**
* Returns a list of all Follows retrieved by Coroutines

View File

@ -161,8 +161,8 @@ class MangaDex(delegate: HttpSource, val context: Context) :
ApiMangaParser(baseHttpClient, mdLang.lang).parseIntoMetadata(metadata, input, emptyList())
}
override suspend fun fetchFollows(): MangasPage {
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).fetchFollows()
override suspend fun fetchFollows(page: Int): MangasPage {
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).fetchFollows(page)
}
override val requiresLogin: Boolean = false

View File

@ -14,7 +14,7 @@ import rx.schedulers.Schedulers
class MangaDexFollowsPager(val source: MangaDex) : Pager() {
override fun requestNext(): Observable<MangasPage> {
return runAsObservable({ source.fetchFollows() })
return runAsObservable({ source.fetchFollows(currentPage) })
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { onPageReceived(it) }

View File

@ -219,7 +219,7 @@ class ApiMangaParser(val client: OkHttpClient, private val lang: String) {
private fun parseStatus(status: String) = when (status) {
"ongoing" -> SManga.ONGOING
"complete" -> SManga.PUBLICATION_COMPLETE
"abandoned" -> SManga.CANCELLED
"cancelled" -> SManga.CANCELLED
"hiatus" -> SManga.HIATUS
else -> SManga.UNKNOWN
}

View File

@ -14,15 +14,14 @@ import eu.kanade.tachiyomi.source.model.toSManga
import eu.kanade.tachiyomi.util.lang.withIOContext
import exh.md.handlers.serializers.MangaListResponse
import exh.md.handlers.serializers.MangaResponse
import exh.md.handlers.serializers.MangaStatusListResponse
import exh.md.handlers.serializers.MangaStatusResponse
import exh.md.handlers.serializers.UpdateReadingStatus
import exh.md.utils.FollowStatus
import exh.md.utils.MdUtil
import exh.metadata.metadata.MangaDexSearchMetadata
import exh.util.under
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.CacheControl
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
@ -31,7 +30,6 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import tachiyomi.source.model.MangaInfo
import java.util.Locale
class FollowsHandler(
@ -44,28 +42,22 @@ class FollowsHandler(
) {
/**
* fetch all follows
* fetch follows page
*/
suspend fun fetchFollows(): MetadataMangasPage {
suspend fun fetchFollows(page: Int): MetadataMangasPage {
return withIOContext {
val response = client.newCall(followsListRequest(0)).await()
val response = client.newCall(followsListRequest(MdUtil.mangaLimit * page - 1)).await()
val mangaListResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
val results = mangaListResponse.results.toMutableList()
var hasMoreResults = mangaListResponse.limit + mangaListResponse.offset under mangaListResponse.total
var lastOffset = mangaListResponse.offset
while (hasMoreResults) {
val offset = lastOffset + mangaListResponse.limit
val newMangaListResponse = client.newCall(followsListRequest(offset)).await()
.parseAs<MangaListResponse>(MdUtil.jsonParser)
results.addAll(newMangaListResponse.results)
hasMoreResults = newMangaListResponse.limit + newMangaListResponse.offset under newMangaListResponse.total
lastOffset = newMangaListResponse.offset
if (mangaListResponse.results.isEmpty()) {
return@withIOContext MetadataMangasPage(emptyList(), false, emptyList())
}
val statusListResponse = client.newCall(statusListRequest()).await().parseAs<JsonObject>()
followsParseMangaPage(results, statusListResponse)
val hasMoreResults = mangaListResponse.limit + mangaListResponse.offset under mangaListResponse.total
val statusListResponse = client.newCall(mangaStatusListRequest(mangaListResponse.results)).await().parseAs<MangaStatusListResponse>()
val results = followsParseMangaPage(mangaListResponse.results, statusListResponse)
MetadataMangasPage(results.map { it.first }, hasMoreResults, results.map { it.second })
}
}
@ -73,25 +65,29 @@ class FollowsHandler(
* Parse follows api to manga page
* used when multiple follows
*/
private fun followsParseMangaPage(response: List<MangaResponse>, statusListResponse: JsonObject): MetadataMangasPage {
val comparator = compareBy<Pair<MangaInfo, MangaDexSearchMetadata>> { it.second.followStatus }
private fun followsParseMangaPage(response: List<MangaResponse>, statusListResponse: MangaStatusListResponse): List<Pair<SManga, MangaDexSearchMetadata>> {
val comparator = compareBy<Pair<SManga, MangaDexSearchMetadata>> { it.second.followStatus }
.thenBy { it.first.title }
val result = response.map {
MdUtil.createMangaEntry(it, lang, useLowQualityCovers) to MangaDexSearchMetadata().apply {
followStatus = getFollowStatus(statusListResponse, it.data.id).int
return response.map {
MdUtil.createMangaEntry(
it,
lang,
useLowQualityCovers
).toSManga() to MangaDexSearchMetadata().apply {
followStatus = FollowStatus.fromDex(statusListResponse.statuses[it.data.id]).int
}
}.sortedWith(comparator)
return MetadataMangasPage(result.map { it.first.toSManga() }, false, result.map { it.second })
}
/**
* fetch follow status used when fetching status for 1 manga
*/
private fun followStatusParse(response: Response, statusListResponse: JsonObject): Track {
private fun followStatusParse(response: Response, sResponse: Response): Track {
val mangaResponse = response.parseAs<MangaResponse>(MdUtil.jsonParser)
val statusResponse = sResponse.parseAs<MangaStatusResponse>()
val track = Track.create(TrackManager.MDLIST)
track.status = getFollowStatus(statusListResponse, mangaResponse.data.id).int
track.status = FollowStatus.fromDex(statusResponse.status).int
track.tracking_url = MdUtil.baseUrl + "/manga/" + mangaResponse.data.id
track.title = mangaResponse.data.attributes.title[lang] ?: mangaResponse.data.attributes.title["en"]!!
@ -197,30 +193,51 @@ class FollowsHandler(
*/
suspend fun fetchAllFollows(): List<Pair<SManga, MangaDexSearchMetadata>> {
return withIOContext {
val metadata: List<MangaDexSearchMetadata>
fetchFollows().also { metadata = it.mangasMetadata.filterIsInstance<MangaDexSearchMetadata>() }.mangas.mapIndexed { index, manga ->
manga to metadata[index]
val response = client.newCall(followsListRequest(0)).await()
val mangaListResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
val results = mangaListResponse.results.toMutableList()
if (results.isEmpty()) {
return@withIOContext emptyList()
}
var hasMoreResults = mangaListResponse.limit + mangaListResponse.offset under mangaListResponse.total
var lastOffset = mangaListResponse.offset
while (hasMoreResults) {
val offset = lastOffset + mangaListResponse.limit
val newMangaListResponse = client.newCall(followsListRequest(offset)).await()
.parseAs<MangaListResponse>(MdUtil.jsonParser)
results.addAll(newMangaListResponse.results)
hasMoreResults = newMangaListResponse.limit + newMangaListResponse.offset under newMangaListResponse.total
lastOffset = newMangaListResponse.offset
}
val statusListResponse = client.newCall(mangaStatusListRequest(results)).await().parseAs<MangaStatusListResponse>()
followsParseMangaPage(results, statusListResponse)
}
}
suspend fun fetchTrackingInfo(url: String): Track {
return withIOContext {
val statusListResponse = client.newCall(statusListRequest()).await().parseAs<JsonObject>(MdUtil.jsonParser)
val mangaId = MdUtil.getMangaId(url)
val request = GET(
MdUtil.mangaUrl + "/" + MdUtil.getMangaId(url),
MdUtil.mangaUrl + "/" + mangaId,
MdUtil.getAuthHeaders(headers, preferences, mdList),
CacheControl.FORCE_NETWORK
)
val statusRequest = GET(
MdUtil.mangaUrl + "/" + mangaId + "/status",
MdUtil.getAuthHeaders(headers, preferences, mdList),
CacheControl.FORCE_NETWORK
)
val response = client.newCall(request).await()
followStatusParse(response, statusListResponse)
val statusResponse = client.newCall(statusRequest).await()
followStatusParse(response, statusResponse)
}
}
private fun getFollowStatus(jsonObject: JsonObject, id: String) =
FollowStatus.fromDex(jsonObject["statuses"]?.jsonObject?.get(id)?.jsonPrimitive?.content)
private fun statusListRequest(): Request {
return GET(MdUtil.mangaStatus, MdUtil.getAuthHeaders(headers, preferences, mdList), CacheControl.FORCE_NETWORK)
private fun mangaStatusListRequest(mangaListResponse: List<MangaResponse>): Request {
return GET(MdUtil.mangaStatus + "/" + mangaListResponse.joinToString("&ids[]=", "?ids[]=") { it.data.id }, MdUtil.getAuthHeaders(headers, preferences, mdList), CacheControl.FORCE_NETWORK)
}
}

View File

@ -27,7 +27,7 @@ data class NetworkChapter(
@Serializable
data class ChapterAttributes(
val title: String?,
val volume: Int?,
val volume: String?,
val chapter: String?,
val translatedLanguage: String,
val publishAt: String,

View File

@ -27,14 +27,13 @@ data class NetworkMangaAttributes(
val description: Map<String, String>,
val links: Map<String, String>?,
val originalLanguage: String,
val lastVolume: Int?,
val lastVolume: String?,
val lastChapter: String,
val contentRating: String?,
val publicationDemographic: String?,
val status: String?,
val year: Int?,
val tags: List<TagsSerializer>
// val readingStatus: String? = null,
)
@Serializable
@ -80,3 +79,13 @@ data class AuthorAttributes(
data class UpdateReadingStatus(
val status: String?
)
@Serializable
data class MangaStatusResponse(
val status: String?
)
@Serializable
data class MangaStatusListResponse(
val statuses: Map<String, String?>
)