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 import exh.metadata.metadata.base.RaisedSearchMetadata
interface FollowsSource : CatalogueSource { interface FollowsSource : CatalogueSource {
suspend fun fetchFollows(): MangasPage suspend fun fetchFollows(page: Int): MangasPage
/** /**
* Returns a list of all Follows retrieved by Coroutines * 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()) ApiMangaParser(baseHttpClient, mdLang.lang).parseIntoMetadata(metadata, input, emptyList())
} }
override suspend fun fetchFollows(): MangasPage { override suspend fun fetchFollows(page: Int): MangasPage {
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).fetchFollows() return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).fetchFollows(page)
} }
override val requiresLogin: Boolean = false override val requiresLogin: Boolean = false

View File

@ -14,7 +14,7 @@ import rx.schedulers.Schedulers
class MangaDexFollowsPager(val source: MangaDex) : Pager() { class MangaDexFollowsPager(val source: MangaDex) : Pager() {
override fun requestNext(): Observable<MangasPage> { override fun requestNext(): Observable<MangasPage> {
return runAsObservable({ source.fetchFollows() }) return runAsObservable({ source.fetchFollows(currentPage) })
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.doOnNext { onPageReceived(it) } .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) { private fun parseStatus(status: String) = when (status) {
"ongoing" -> SManga.ONGOING "ongoing" -> SManga.ONGOING
"complete" -> SManga.PUBLICATION_COMPLETE "complete" -> SManga.PUBLICATION_COMPLETE
"abandoned" -> SManga.CANCELLED "cancelled" -> SManga.CANCELLED
"hiatus" -> SManga.HIATUS "hiatus" -> SManga.HIATUS
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }

View File

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

View File

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

View File

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