Update mangadex to api 5.0.10
This commit is contained in:
parent
e37d4afce6
commit
20cbadb23d
@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||||||
import eu.kanade.tachiyomi.data.track.mdlist.MdList
|
import eu.kanade.tachiyomi.data.track.mdlist.MdList
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
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.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
@ -267,29 +266,6 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
|||||||
return similarHandler.getSimilar(manga)
|
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> =
|
/*private fun importIdToMdId(query: String, fail: () -> Observable<MangasPage>): Observable<MangasPage> =
|
||||||
when {
|
when {
|
||||||
query.toIntOrNull() != null -> {
|
query.toIntOrNull() != null -> {
|
||||||
|
@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||||||
import exh.log.xLogE
|
import exh.log.xLogE
|
||||||
import exh.md.handlers.serializers.AuthorResponseList
|
import exh.md.handlers.serializers.AuthorResponseList
|
||||||
import exh.md.handlers.serializers.ChapterResponse
|
import exh.md.handlers.serializers.ChapterResponse
|
||||||
|
import exh.md.handlers.serializers.CoverListResponse
|
||||||
import exh.md.handlers.serializers.MangaResponse
|
import exh.md.handlers.serializers.MangaResponse
|
||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||||
@ -72,13 +73,19 @@ class ApiMangaParser(val client: OkHttpClient, private val lang: String) {
|
|||||||
mdUuid = networkApiManga.data.id
|
mdUuid = networkApiManga.data.id
|
||||||
title = MdUtil.cleanString(networkManga.title[lang] ?: networkManga.title["en"]!!)
|
title = MdUtil.cleanString(networkManga.title[lang] ?: networkManga.title["en"]!!)
|
||||||
altTitles = networkManga.altTitles.mapNotNull { it[lang] }
|
altTitles = networkManga.altTitles.mapNotNull { it[lang] }
|
||||||
cover =
|
|
||||||
if (coverUrls.isNotEmpty()) {
|
var coverUrl = MdUtil.formThumbUrl(networkApiManga.data.id)
|
||||||
coverUrls.last()
|
val coverUrlId = networkApiManga.relationships.firstOrNull { it.type == "cover_art" }?.id
|
||||||
} else {
|
if (coverUrlId != null) {
|
||||||
null
|
runCatching {
|
||||||
// networkManga.mainCover
|
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"]!!)
|
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 }
|
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 filteredChapters = filterChapterForChecking(networkApiManga)
|
||||||
|
|
||||||
val tempStatus = parseStatus(networkManga.status ?: "")
|
val tempStatus = parseStatus(networkManga.status ?: "")
|
||||||
|
@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.model.toSManga
|
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.CoverListResponse
|
||||||
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.MangaStatusListResponse
|
||||||
@ -71,14 +72,27 @@ 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>, 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 }
|
val comparator = compareBy<Pair<SManga, MangaDexSearchMetadata>> { it.second.followStatus }
|
||||||
.thenBy { it.first.title }
|
.thenBy { it.first.title }
|
||||||
|
|
||||||
return response.map {
|
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(
|
MdUtil.createMangaEntry(
|
||||||
it,
|
it,
|
||||||
lang
|
lang,
|
||||||
|
coverUrl
|
||||||
).toSManga() to MangaDexSearchMetadata().apply {
|
).toSManga() to MangaDexSearchMetadata().apply {
|
||||||
followStatus = FollowStatus.fromDex(statuses[it.data.id]).int
|
followStatus = FollowStatus.fromDex(statuses[it.data.id]).int
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@ package exh.md.handlers
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.toSManga
|
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.MangaListResponse
|
||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
import okhttp3.CacheControl
|
import okhttp3.CacheControl
|
||||||
@ -23,8 +26,10 @@ class PopularHandler(val client: OkHttpClient, private val headers: Headers, pri
|
|||||||
fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||||
return client.newCall(popularMangaRequest(page))
|
return client.newCall(popularMangaRequest(page))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { response ->
|
.flatMap { response ->
|
||||||
|
runAsObservable({
|
||||||
popularMangaParse(response)
|
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)
|
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 mlResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
|
||||||
val hasMoreResults = mlResponse.limit + mlResponse.offset < mlResponse.total
|
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)
|
return MangasPage(mangaList, hasMoreResults)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,13 @@ package exh.md.handlers
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.toSManga
|
import eu.kanade.tachiyomi.source.model.toSManga
|
||||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||||
|
import exh.md.handlers.serializers.CoverListResponse
|
||||||
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.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
@ -28,24 +30,52 @@ class SearchHandler(val client: OkHttpClient, private val headers: Headers, val
|
|||||||
.flatMap { response ->
|
.flatMap { response ->
|
||||||
runAsObservable({
|
runAsObservable({
|
||||||
val mangaResponse = response.parseAs<MangaResponse>(MdUtil.jsonParser)
|
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
|
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)
|
MangasPage(listOf(details), false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.newCall(searchMangaRequest(page, query, filters))
|
client.newCall(searchMangaRequest(page, query, filters))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { response ->
|
.flatMap { response ->
|
||||||
|
runAsObservable({
|
||||||
searchMangaParse(response)
|
searchMangaParse(response)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun searchMangaParse(response: Response): MangasPage {
|
private suspend fun searchMangaParse(response: Response): MangasPage {
|
||||||
val mlResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
|
val mlResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
|
||||||
val hasMoreResults = mlResponse.limit + mlResponse.offset < mlResponse.total
|
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)
|
return MangasPage(mangaList, hasMoreResults)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,3 +89,23 @@ data class MangaStatusResponse(
|
|||||||
data class MangaStatusListResponse(
|
data class MangaStatusListResponse(
|
||||||
val statuses: Map<String, String?>
|
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,
|
||||||
|
)
|
||||||
|
@ -62,18 +62,19 @@ class MdUtil {
|
|||||||
return "$mangaUrl/$id/feed".toHttpUrl().newBuilder().apply {
|
return "$mangaUrl/$id/feed".toHttpUrl().newBuilder().apply {
|
||||||
addQueryParameter("limit", "500")
|
addQueryParameter("limit", "500")
|
||||||
addQueryParameter("offset", offset.toString())
|
addQueryParameter("offset", offset.toString())
|
||||||
addQueryParameter("locales[]", language)
|
addQueryParameter("translatedLanguage[]", language)
|
||||||
addQueryParameter("order[volume]", "desc")
|
addQueryParameter("order[volume]", "desc")
|
||||||
addQueryParameter("order[chapter]", "desc")
|
addQueryParameter("order[chapter]", "desc")
|
||||||
}.build().toString()
|
}.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 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 similarCacheCdn = "https://cdn.statically.io/gh/goldbattle/MangadexRecomendations/master/output/api/"
|
||||||
const val similarBaseApi = "https://api.similarmanga.com/similar/"
|
const val similarBaseApi = "https://api.similarmanga.com/similar/"
|
||||||
|
|
||||||
const val groupSearchUrl = "$baseUrl/groups/0/1/"
|
const val groupSearchUrl = "$baseUrl/groups/0/1/"
|
||||||
const val apiCovers = "/covers"
|
|
||||||
const val reportUrl = "https://api.mangadex.network/report"
|
const val reportUrl = "https://api.mangadex.network/report"
|
||||||
|
|
||||||
const val mdAtHomeTokenLifespan = 10 * 60 * 1000
|
const val mdAtHomeTokenLifespan = 10 * 60 * 1000
|
||||||
@ -300,12 +301,12 @@ class MdUtil {
|
|||||||
fun parseDate(dateAsString: String): Long =
|
fun parseDate(dateAsString: String): Long =
|
||||||
dateFormatter.parse(dateAsString)?.time ?: 0
|
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)
|
val key = buildMangaUrl(json.data.id)
|
||||||
return MangaInfo(
|
return MangaInfo(
|
||||||
key = key,
|
key = key,
|
||||||
title = cleanString(json.data.attributes.title[lang] ?: json.data.attributes.title["en"]!!),
|
title = cleanString(json.data.attributes.title[lang] ?: json.data.attributes.title["en"]!!),
|
||||||
cover = formThumbUrl(key)
|
cover = coverUrl
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user