package exh.md.handlers import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.toMangaInfo import eu.kanade.tachiyomi.source.model.toSChapter import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.util.lang.runAsObservable import eu.kanade.tachiyomi.util.lang.withIOContext import exh.md.handlers.serializers.ChapterResponse import exh.md.handlers.serializers.GroupListResponse import exh.md.utils.MdUtil import exh.md.utils.mdListCall import exh.metadata.metadata.MangaDexSearchMetadata import kotlinx.coroutines.async import okhttp3.CacheControl import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request import rx.Observable import tachiyomi.source.model.ChapterInfo import tachiyomi.source.model.MangaInfo import uy.kohesive.injekt.api.get class MangaHandler( val client: OkHttpClient, val headers: Headers, private val lang: String, private val apiMangaParser: ApiMangaParser, private val followsHandler: FollowsHandler ) { suspend fun fetchMangaAndChapterDetails(manga: MangaInfo, sourceId: Long, forceLatestCovers: Boolean): Pair> { return withIOContext { val response = client.newCall(mangaRequest(manga)).await() apiMangaParser.parseToManga(manga, response, sourceId) to getChapterList(manga) } } /*suspend fun getCovers(manga: MangaInfo, forceLatestCovers: Boolean): List { *//* if (forceLatestCovers) { val covers = client.newCall(coverRequest(manga)).await().parseAs(MdUtil.jsonParser) return covers.data.map { it.url } } else {*//* return emptyList() // } }*/ suspend fun getMangaIdFromChapterId(urlChapterId: String): String { return withIOContext { val request = GET(MdUtil.chapterUrl + urlChapterId) val response = client.newCall(request).await() apiMangaParser.chapterParseForMangaId(response) } } suspend fun getMangaDetails(manga: MangaInfo, sourceId: Long, forceLatestCovers: Boolean): MangaInfo { val response = withIOContext { client.newCall(mangaRequest(manga)).await() } return apiMangaParser.parseToManga(manga, response, sourceId) } fun fetchMangaDetailsObservable(manga: SManga, sourceId: Long, forceLatestCovers: Boolean): Observable { return runAsObservable({ getMangaDetails(manga.toMangaInfo(), sourceId, forceLatestCovers).toSManga() }) } fun fetchChapterListObservable(manga: SManga): Observable> = runAsObservable({ getChapterList(manga.toMangaInfo()).map { it.toSChapter() } }) suspend fun getChapterList(manga: MangaInfo): List { return withIOContext { val results = client.mdListCall { mangaFeedRequest(manga, it, lang) } val groupMap = getGroupMap(results) apiMangaParser.chapterListParse(results, groupMap) } } private suspend fun getGroupMap(results: List): Map { val groupIds = results.asSequence() .flatMap { chapter -> chapter.relationships } .filter { it.type == "scanlation_group" } .map { it.id } .toSet() return runCatching { groupIds.chunked(100).flatMapIndexed { index, ids -> val response = client.newCall(groupIdRequest(ids, 100 * index)).await() if (response.code != 204) { response .parseAs(MdUtil.jsonParser) .results.map { group -> group.data.id to group.data.attributes.name } } else { emptyList() } }.toMap() }.getOrNull().orEmpty() } suspend fun fetchRandomMangaId(): String { return withIOContext { val response = client.newCall(randomMangaRequest()).await() apiMangaParser.randomMangaIdParse(response) } } suspend fun getTrackingInfo(track: Track): Pair { return withIOContext { /*val metadata = async { val mangaUrl = MdUtil.buildMangaUrl(MdUtil.getMangaId(track.tracking_url)) val manga = MangaInfo(mangaUrl, track.title) val response = client.newCall(mangaRequest(manga)).await() val metadata = MangaDexSearchMetadata() apiMangaParser.parseIntoMetadata(metadata, response, emptyList()) metadata }*/ val remoteTrack = async { followsHandler.fetchTrackingInfo(track.tracking_url) } remoteTrack.await() to null } } private fun randomMangaRequest(): Request { return GET(MdUtil.randomMangaUrl, cache = CacheControl.FORCE_NETWORK) } private fun mangaRequest(manga: MangaInfo): Request { return GET(MdUtil.mangaUrl + "/" + MdUtil.getMangaId(manga.key), headers, CacheControl.FORCE_NETWORK) } private fun mangaFeedRequest(manga: MangaInfo, offset: Int, lang: String): Request { return GET(MdUtil.mangaFeedUrl(MdUtil.getMangaId(manga.key), offset, lang), headers, CacheControl.FORCE_NETWORK) } private fun groupIdRequest(id: List, offset: Int): Request { val urlSuffix = id.joinToString("&ids[]=", "?limit=100&offset=$offset&ids[]=") return GET(MdUtil.groupUrl + urlSuffix, headers) } /* private fun coverRequest(manga: SManga): Request { return GET(MdUtil.apiUrl + MdUtil.apiManga + MdUtil.getMangaId(manga.url) + MdUtil.apiCovers, headers, CacheControl.FORCE_NETWORK) }*/ companion object { } }