Update mangadex to api 5.0.10

This commit is contained in:
Jobobby04 2021-05-22 14:38:47 -04:00
parent e37d4afce6
commit 20cbadb23d
7 changed files with 112 additions and 55 deletions

View File

@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.mdlist.MdList
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
@ -267,29 +266,6 @@ class MangaDex(delegate: HttpSource, val context: Context) :
return similarHandler.getSimilar(manga)
}
// todo remove when mangadex gets it cover api
override fun fetchSearchManga(
page: Int,
query: String,
filters: FilterList
): Observable<MangasPage> {
return super.fetchSearchManga(page, query, filters).doOnNext { mangaPage ->
mangaPage.mangas.forEach {
it.thumbnail_url = "https://coverapi.orell.dev/api/v1/mdaltimage/manga/${MdUtil.getMangaId(it.url)}/cover"
}
}
}
override fun fetchPopularManga(
page: Int
): Observable<MangasPage> {
return super.fetchPopularManga(page).doOnNext { mangaPage ->
mangaPage.mangas.forEach {
it.thumbnail_url = "https://coverapi.orell.dev/api/v1/mdaltimage/manga/${MdUtil.getMangaId(it.url)}/cover"
}
}
}
/*private fun importIdToMdId(query: String, fail: () -> Observable<MangasPage>): Observable<MangasPage> =
when {
query.toIntOrNull() != null -> {

View File

@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.source.model.SManga
import exh.log.xLogE
import exh.md.handlers.serializers.AuthorResponseList
import exh.md.handlers.serializers.ChapterResponse
import exh.md.handlers.serializers.CoverListResponse
import exh.md.handlers.serializers.MangaResponse
import exh.md.utils.MdUtil
import exh.metadata.metadata.MangaDexSearchMetadata
@ -72,13 +73,19 @@ class ApiMangaParser(val client: OkHttpClient, private val lang: String) {
mdUuid = networkApiManga.data.id
title = MdUtil.cleanString(networkManga.title[lang] ?: networkManga.title["en"]!!)
altTitles = networkManga.altTitles.mapNotNull { it[lang] }
cover =
if (coverUrls.isNotEmpty()) {
coverUrls.last()
} else {
null
// networkManga.mainCover
var coverUrl = MdUtil.formThumbUrl(networkApiManga.data.id)
val coverUrlId = networkApiManga.relationships.firstOrNull { it.type == "cover_art" }?.id
if (coverUrlId != null) {
runCatching {
val json = client.newCall(GET(MdUtil.coverUrl(networkApiManga.data.id, coverUrlId))).await()
.parseAs<CoverListResponse>(MdUtil.jsonParser)
json.results.firstOrNull()?.data?.attributes?.fileName?.let { fileName ->
coverUrl = "${MdUtil.cdnUrl}/covers/${networkApiManga.data.id}/$fileName"
}
}
}
cover = coverUrl
description = MdUtil.cleanDescription(networkManga.description[lang] ?: networkManga.description["en"]!!)
@ -130,16 +137,6 @@ class ApiMangaParser(val client: OkHttpClient, private val lang: String) {
links["ap"]?.let { animePlanetId = it }
}
if (kitsuId?.toIntOrNull() != null) {
cover = "https://media.kitsu.io/manga/poster_images/$kitsuId/large.jpg"
}
if (cover == null && !myAnimeListId.isNullOrEmpty()) {
cover = "https://coverapi.orell.dev/api/v1/mal/manga/$myAnimeListId/cover"
}
if (cover == null) {
cover = MdUtil.formThumbUrl(mdUuid.toString())
}
// val filteredChapters = filterChapterForChecking(networkApiManga)
val tempStatus = parseStatus(networkManga.status ?: "")

View File

@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.source.model.MetadataMangasPage
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.toSManga
import eu.kanade.tachiyomi.util.lang.withIOContext
import exh.md.handlers.serializers.CoverListResponse
import exh.md.handlers.serializers.MangaListResponse
import exh.md.handlers.serializers.MangaResponse
import exh.md.handlers.serializers.MangaStatusListResponse
@ -71,14 +72,27 @@ class FollowsHandler(
* Parse follows api to manga page
* used when multiple follows
*/
private fun followsParseMangaPage(response: List<MangaResponse>, statuses: Map<String, String?>): List<Pair<SManga, MangaDexSearchMetadata>> {
private suspend fun followsParseMangaPage(response: List<MangaResponse>, statuses: Map<String, String?>): List<Pair<SManga, MangaDexSearchMetadata>> {
val comparator = compareBy<Pair<SManga, MangaDexSearchMetadata>> { it.second.followStatus }
.thenBy { it.first.title }
return response.map {
var coverUrl = MdUtil.formThumbUrl(it.data.id)
val coverUrlId = it.relationships.firstOrNull { it.type == "cover_art" }?.id
if (coverUrlId != null) {
runCatching {
val covers = client.newCall(GET(MdUtil.coverUrl(it.data.id, coverUrlId))).await()
.parseAs<CoverListResponse>()
covers.results.firstOrNull()?.data?.attributes?.fileName?.let { fileName ->
coverUrl = "${MdUtil.cdnUrl}/covers/${it.data.id}/$fileName"
}
}
}
MdUtil.createMangaEntry(
it,
lang
lang,
coverUrl
).toSManga() to MangaDexSearchMetadata().apply {
followStatus = FollowStatus.fromDex(statuses[it.data.id]).int
}

View File

@ -2,9 +2,12 @@ package exh.md.handlers
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.toSManga
import eu.kanade.tachiyomi.util.lang.runAsObservable
import exh.md.handlers.serializers.CoverListResponse
import exh.md.handlers.serializers.MangaListResponse
import exh.md.utils.MdUtil
import okhttp3.CacheControl
@ -23,8 +26,10 @@ class PopularHandler(val client: OkHttpClient, private val headers: Headers, pri
fun fetchPopularManga(page: Int): Observable<MangasPage> {
return client.newCall(popularMangaRequest(page))
.asObservableSuccess()
.map { response ->
popularMangaParse(response)
.flatMap { response ->
runAsObservable({
popularMangaParse(response)
})
}
}
@ -39,10 +44,24 @@ class PopularHandler(val client: OkHttpClient, private val headers: Headers, pri
return GET(tempUrl.build().toString(), headers, CacheControl.FORCE_NETWORK)
}
private fun popularMangaParse(response: Response): MangasPage {
private suspend fun popularMangaParse(response: Response): MangasPage {
val mlResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
val hasMoreResults = mlResponse.limit + mlResponse.offset < mlResponse.total
val mangaList = mlResponse.results.map { MdUtil.createMangaEntry(it, lang).toSManga() }
val mangaList = mlResponse.results.map {
var coverUrl = MdUtil.formThumbUrl(it.data.id)
val coverUrlId = it.relationships.firstOrNull { it.type == "cover_art" }?.id
if (coverUrlId != null) {
runCatching {
val covers = client.newCall(GET(MdUtil.coverUrl(it.data.id, coverUrlId))).await()
.parseAs<CoverListResponse>()
covers.results.firstOrNull()?.data?.attributes?.fileName?.let { fileName ->
coverUrl = "${MdUtil.cdnUrl}/covers/${it.data.id}/$fileName"
}
}
}
MdUtil.createMangaEntry(it, lang, coverUrl).toSManga()
}
return MangasPage(mangaList, hasMoreResults)
}
}

View File

@ -2,11 +2,13 @@ package exh.md.handlers
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.toSManga
import eu.kanade.tachiyomi.util.lang.runAsObservable
import exh.md.handlers.serializers.CoverListResponse
import exh.md.handlers.serializers.MangaListResponse
import exh.md.handlers.serializers.MangaResponse
import exh.md.utils.MdUtil
@ -28,24 +30,52 @@ class SearchHandler(val client: OkHttpClient, private val headers: Headers, val
.flatMap { response ->
runAsObservable({
val mangaResponse = response.parseAs<MangaResponse>(MdUtil.jsonParser)
var coverUrl = MdUtil.formThumbUrl(mangaResponse.data.id)
val coverUrlId = mangaResponse.relationships.firstOrNull { it.type == "cover_art" }?.id
if (coverUrlId != null) {
runCatching {
val covers = client.newCall(GET(MdUtil.coverUrl(mangaResponse.data.id, coverUrlId))).await()
.parseAs<CoverListResponse>()
covers.results.firstOrNull()?.data?.attributes?.fileName?.let { fileName ->
coverUrl = "${MdUtil.cdnUrl}/covers/${mangaResponse.data.id}/$fileName"
}
}
}
val details = apiMangaParser
.parseToManga(MdUtil.createMangaEntry(mangaResponse, lang), response, emptyList(), sourceId).toSManga()
.parseToManga(MdUtil.createMangaEntry(mangaResponse, lang, coverUrl), response, emptyList(), sourceId).toSManga()
MangasPage(listOf(details), false)
})
}
} else {
client.newCall(searchMangaRequest(page, query, filters))
.asObservableSuccess()
.map { response ->
searchMangaParse(response)
.flatMap { response ->
runAsObservable({
searchMangaParse(response)
})
}
}
}
private fun searchMangaParse(response: Response): MangasPage {
private suspend fun searchMangaParse(response: Response): MangasPage {
val mlResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
val hasMoreResults = mlResponse.limit + mlResponse.offset < mlResponse.total
val mangaList = mlResponse.results.map { MdUtil.createMangaEntry(it, lang).toSManga() }
val mangaList = mlResponse.results.map {
var coverUrl = MdUtil.formThumbUrl(it.data.id)
val coverUrlId = it.relationships.firstOrNull { it.type == "cover_art" }?.id
if (coverUrlId != null) {
runCatching {
val covers = client.newCall(GET(MdUtil.coverUrl(it.data.id, coverUrlId))).await()
.parseAs<CoverListResponse>()
covers.results.firstOrNull()?.data?.attributes?.fileName?.let { fileName ->
coverUrl = "${MdUtil.cdnUrl}/covers/${it.data.id}/$fileName"
}
}
}
MdUtil.createMangaEntry(it, lang, coverUrl).toSManga()
}
return MangasPage(mangaList, hasMoreResults)
}

View File

@ -89,3 +89,23 @@ data class MangaStatusResponse(
data class MangaStatusListResponse(
val statuses: Map<String, String?>
)
@Serializable
data class CoverListResponse(
val results: List<CoverResponse>,
)
@Serializable
data class CoverResponse(
val data: Cover,
)
@Serializable
data class Cover(
val attributes: CoverAttributes,
)
@Serializable
data class CoverAttributes(
val fileName: String,
)

View File

@ -62,18 +62,19 @@ class MdUtil {
return "$mangaUrl/$id/feed".toHttpUrl().newBuilder().apply {
addQueryParameter("limit", "500")
addQueryParameter("offset", offset.toString())
addQueryParameter("locales[]", language)
addQueryParameter("translatedLanguage[]", language)
addQueryParameter("order[volume]", "desc")
addQueryParameter("order[chapter]", "desc")
}.build().toString()
}
fun coverUrl(mangaId: String, coverId: String) = "$apiUrl/cover/?manga[]=$mangaId&ids[]=$coverId"
const val similarCache = "https://raw.githubusercontent.com/goldbattle/MangadexRecomendations/master/output/api/"
const val similarCacheCdn = "https://cdn.statically.io/gh/goldbattle/MangadexRecomendations/master/output/api/"
const val similarBaseApi = "https://api.similarmanga.com/similar/"
const val groupSearchUrl = "$baseUrl/groups/0/1/"
const val apiCovers = "/covers"
const val reportUrl = "https://api.mangadex.network/report"
const val mdAtHomeTokenLifespan = 10 * 60 * 1000
@ -300,12 +301,12 @@ class MdUtil {
fun parseDate(dateAsString: String): Long =
dateFormatter.parse(dateAsString)?.time ?: 0
fun createMangaEntry(json: MangaResponse, lang: String): MangaInfo {
fun createMangaEntry(json: MangaResponse, lang: String, coverUrl: String): MangaInfo {
val key = buildMangaUrl(json.data.id)
return MangaInfo(
key = key,
title = cleanString(json.data.attributes.title[lang] ?: json.data.attributes.title["en"]!!),
cover = formThumbUrl(key)
cover = coverUrl
)
}