Mangadex code cleanup

This commit is contained in:
Jobobby04 2021-01-15 22:29:57 -05:00
parent ae15a178e5
commit 37787f040c
6 changed files with 63 additions and 58 deletions

View File

@ -114,9 +114,9 @@ fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListene
return progressClient.newCall(request) return progressClient.newCall(request)
} }
inline fun <reified T> Response.parseAs(): T { inline fun <reified T> Response.parseAs(/* SY --> */ json: Json = Injekt.getInstance(fullType<Json>().type) /* SY <-- */): T {
// Avoiding Injekt.get<Json>() due to compiler issues // Avoiding Injekt.get<Json>() due to compiler issues
val json = Injekt.getInstance<Json>(fullType<Json>().type) // val json = Injekt.getInstance<Json>(fullType<Json>().type)
this.use { this.use {
val responseBody = it.body?.string().orEmpty() val responseBody = it.body?.string().orEmpty()
return json.decodeFromString(responseBody) return json.decodeFromString(responseBody)

View File

@ -56,12 +56,14 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import rx.Observable import rx.Observable
import tachiyomi.source.model.ChapterInfo
import tachiyomi.source.model.MangaInfo import tachiyomi.source.model.MangaInfo
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import kotlin.reflect.KClass import kotlin.reflect.KClass
@Suppress("OverridingDeprecatedMember")
class MangaDex(delegate: HttpSource, val context: Context) : class MangaDex(delegate: HttpSource, val context: Context) :
DelegatedHttpSource(delegate), DelegatedHttpSource(delegate),
MetadataSource<MangaDexSearchMetadata, Response>, MetadataSource<MangaDexSearchMetadata, Response>,
@ -112,7 +114,7 @@ class MangaDex(delegate: HttpSource, val context: Context) :
override fun mapUrlToChapterUrl(uri: Uri): String? { override fun mapUrlToChapterUrl(uri: Uri): String? {
if (!uri.pathSegments.firstOrNull().equals("chapter", true)) return null if (!uri.pathSegments.firstOrNull().equals("chapter", true)) return null
val id = uri.pathSegments.getOrNull(1) ?: return null val id = uri.pathSegments.getOrNull(1)?.toIntOrNull() ?: return null
return MdUtil.oldApiChapter + id return MdUtil.oldApiChapter + id
} }
@ -134,6 +136,10 @@ class MangaDex(delegate: HttpSource, val context: Context) :
return MangaHandler(client, headers, mdLang, preferences.mangaDexForceLatestCovers().get()).fetchChapterListObservable(manga) return MangaHandler(client, headers, mdLang, preferences.mangaDexForceLatestCovers().get()).fetchChapterListObservable(manga)
} }
override suspend fun getChapterList(manga: MangaInfo): List<ChapterInfo> {
return MangaHandler(client, headers, mdLang, preferences.mangaDexForceLatestCovers().get()).getChapterList(manga)
}
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> { override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
return if (chapter.scanlator == "MangaPlus") { return if (chapter.scanlator == "MangaPlus") {
client.newCall(mangaPlusPageListRequest(chapter)) client.newCall(mangaPlusPageListRequest(chapter))

View File

@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.source.online.RandomMangaSource
import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.util.lang.withIOContext
import exh.md.follows.MangaDexFollowsController import exh.md.follows.MangaDexFollowsController
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -38,9 +39,10 @@ class MangaDexFabHeaderAdapter(val controller: BaseController<*>, val source: Ca
} }
binding.mangadexRandom.clicks() binding.mangadexRandom.clicks()
.onEach { .onEach {
(source as? RandomMangaSource)?.fetchRandomMangaUrl()?.let { randomMangaId -> val randomMangaUrl = withIOContext {
controller.router.replaceTopController(BrowseSourceController(source, randomMangaId).withFadeTransaction()) (source as? RandomMangaSource)?.fetchRandomMangaUrl()
} }
controller.router.replaceTopController(BrowseSourceController(source, randomMangaUrl).withFadeTransaction())
}.launchIn(controller.viewScope) }.launchIn(controller.viewScope)
} }
} }

View File

@ -1,5 +1,6 @@
package exh.md.handlers package exh.md.handlers
import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import exh.md.handlers.serializers.ApiChapterSerializer import exh.md.handlers.serializers.ApiChapterSerializer
import exh.md.utils.MdUtil import exh.md.utils.MdUtil
@ -11,22 +12,18 @@ import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Response import okhttp3.Response
class ApiChapterParser { class ApiChapterParser {
// Only used in [PageHandler], which means its currently unused, kept for reference
fun pageListParse(response: Response): List<Page> { fun pageListParse(response: Response): List<Page> {
val jsonData = response.body!!.string() val networkApiChapter = response.parseAs<ApiChapterSerializer>(MdUtil.jsonParser)
val networkApiChapter = MdUtil.jsonParser.decodeFromString<ApiChapterSerializer>(jsonData)
val pages = mutableListOf<Page>()
val hash = networkApiChapter.data.hash val hash = networkApiChapter.data.hash
val pageArray = networkApiChapter.data.pages val pageArray = networkApiChapter.data.pages
val server = networkApiChapter.data.server val server = networkApiChapter.data.server
pageArray.forEach { return pageArray.mapIndexed { index, page ->
val url = "$hash/$it" val url = "$hash/$page"
pages.add(Page(pages.size, "$server,${response.request.url},${System.currentTimeMillis()}", url)) Page(index, "$server,${response.request.url},${System.currentTimeMillis()}", url)
} }
return pages
} }
fun externalParse(response: Response): String { fun externalParse(response: Response): String {

View File

@ -3,7 +3,7 @@ package exh.md.handlers
import com.elvishew.xlog.XLog import com.elvishew.xlog.XLog
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import exh.md.handlers.serializers.ApiMangaSerializer import exh.md.handlers.serializers.ApiMangaSerializer
@ -26,6 +26,7 @@ import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Response import okhttp3.Response
import rx.Completable import rx.Completable
import rx.Single import rx.Single
import tachiyomi.source.model.ChapterInfo
import tachiyomi.source.model.MangaInfo import tachiyomi.source.model.MangaInfo
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -94,7 +95,7 @@ class ApiMangaParser(private val lang: String) {
fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Response, coverUrls: List<String>) { fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Response, coverUrls: List<String>) {
with(metadata) { with(metadata) {
try { try {
val networkApiManga = MdUtil.jsonParser.decodeFromString<ApiMangaSerializer>(input.body!!.string()) val networkApiManga = input.parseAs<ApiMangaSerializer>(MdUtil.jsonParser)
val networkManga = networkApiManga.data.manga val networkManga = networkApiManga.data.manga
mdId = MdUtil.getMangaId(input.request.url.toString()) mdId = MdUtil.getMangaId(input.request.url.toString())
mdUrl = input.request.url.toString() mdUrl = input.request.url.toString()
@ -222,13 +223,12 @@ class ApiMangaParser(private val lang: String) {
return MdUtil.getMangaId(randMangaUrl) return MdUtil.getMangaId(randMangaUrl)
} }
fun chapterListParse(response: Response): List<SChapter> { fun chapterListParse(response: Response): List<ChapterInfo> {
return chapterListParse(response.body!!.string()) return chapterListParse(response.parseAs<ApiMangaSerializer>(MdUtil.jsonParser))
} }
fun chapterListParse(jsonData: String): List<SChapter> { fun chapterListParse(networkApiManga: ApiMangaSerializer): List<ChapterInfo> {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val networkApiManga = MdUtil.jsonParser.decodeFromString<ApiMangaSerializer>(jsonData)
val networkManga = networkApiManga.data.manga val networkManga = networkApiManga.data.manga
val networkChapters = networkApiManga.data.chapters val networkChapters = networkApiManga.data.chapters
val groups = networkApiManga.data.groups.mapNotNull { val groups = networkApiManga.data.groups.mapNotNull {
@ -245,10 +245,10 @@ class ApiMangaParser(private val lang: String) {
// Skip chapters that don't match the desired language, or are future releases // Skip chapters that don't match the desired language, or are future releases
val chapLangs = MdLang.values().filter { lang == it.dexLang } val chapLang = MdLang.values().firstOrNull { lang == it.dexLang }
return networkChapters.asSequence() return networkChapters.asSequence()
.filter { lang == it.language && (it.timestamp * 1000) <= now } .filter { lang == it.language && (it.timestamp * 1000) <= now }
.map { mapChapter(it, finalChapterNumber, status, chapLangs, networkChapters.size, groups) }.toList() .map { mapChapter(it, finalChapterNumber, status, chapLang, networkChapters.size, groups) }.toList()
} }
fun chapterParseForMangaId(response: Response): Int { fun chapterParseForMangaId(response: Response): Int {
@ -271,14 +271,14 @@ class ApiMangaParser(private val lang: String) {
networkChapter: ChapterSerializer, networkChapter: ChapterSerializer,
finalChapterNumber: String?, finalChapterNumber: String?,
status: Int, status: Int,
chapLangs: List<MdLang>, chapLang: MdLang?,
totalChapterCount: Int, totalChapterCount: Int,
groups: Map<Long, String> groups: Map<Long, String>
): SChapter { ): ChapterInfo {
val chapter = SChapter.create() val key = MdUtil.oldApiChapter + networkChapter.id
chapter.url = MdUtil.oldApiChapter + networkChapter.id
val chapterName = mutableListOf<String>()
// Build chapter name // Build chapter name
val chapterName = mutableListOf<String>()
if (!networkChapter.volume.isNullOrBlank()) { if (!networkChapter.volume.isNullOrBlank()) {
val vol = "Vol." + networkChapter.volume val vol = "Vol." + networkChapter.volume
@ -315,19 +315,24 @@ class ApiMangaParser(private val lang: String) {
} }
} }
chapter.name = MdUtil.cleanString(chapterName.joinToString(" ")) val name = MdUtil.cleanString(chapterName.joinToString(" "))
// Convert from unix time // Convert from unix time
chapter.date_upload = networkChapter.timestamp * 1000 val dateUpload = networkChapter.timestamp * 1000
val scanlatorName = mutableSetOf<String>() val scanlatorName = mutableSetOf<String>()
networkChapter.groups.mapNotNull { groups[it] }.forEach { scanlatorName.add(it) } networkChapter.groups.mapNotNull { groups[it] }.forEach { scanlatorName.add(it) }
chapter.scanlator = MdUtil.cleanString(MdUtil.getScanlatorString(scanlatorName)) val scanlator = MdUtil.cleanString(MdUtil.getScanlatorString(scanlatorName))
// chapter.mangadex_chapter_id = MdUtil.getChapterId(chapter.url) // val mangadexChapterId = MdUtil.getChapterId(chapter.url)
// chapter.language = chapLangs.firstOrNull { it.dexLang == networkChapter.language }?.name // val language = chapLang?.name
return chapter return ChapterInfo(
key = key,
name = name,
dateUpload = dateUpload,
scanlator = scanlator
)
} }
} }

View File

@ -1,6 +1,5 @@
package exh.md.handlers package exh.md.handlers
import com.elvishew.xlog.XLog
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.await
@ -8,45 +7,41 @@ import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.toMangaInfo import eu.kanade.tachiyomi.source.model.toMangaInfo
import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.model.toSChapter
import eu.kanade.tachiyomi.util.lang.runAsObservable import eu.kanade.tachiyomi.util.lang.runAsObservable
import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withIOContext
import exh.md.handlers.serializers.ApiCovers import exh.md.handlers.serializers.ApiCovers
import exh.md.handlers.serializers.ApiMangaSerializer
import exh.md.utils.MdUtil import exh.md.utils.MdUtil
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import rx.Observable import rx.Observable
import tachiyomi.source.model.ChapterInfo
import tachiyomi.source.model.MangaInfo import tachiyomi.source.model.MangaInfo
class MangaHandler(val client: OkHttpClient, val headers: Headers, val lang: String, val forceLatestCovers: Boolean = false) { class MangaHandler(val client: OkHttpClient, val headers: Headers, val lang: String, val forceLatestCovers: Boolean = false) {
// TODO make use of this // TODO make use of this
suspend fun fetchMangaAndChapterDetails(manga: MangaInfo, sourceId: Long): Pair<MangaInfo, List<SChapter>> { suspend fun fetchMangaAndChapterDetails(manga: MangaInfo, sourceId: Long): Pair<MangaInfo, List<ChapterInfo>> {
return withIOContext { return withIOContext {
val response = client.newCall(apiRequest(manga.toSManga())).await() val apiNetworkManga = client.newCall(apiRequest(manga)).await().parseAs<ApiMangaSerializer>()
val covers = getCovers(manga, forceLatestCovers) val covers = getCovers(manga, forceLatestCovers)
val parser = ApiMangaParser(lang) val parser = ApiMangaParser(lang)
val jsonData = withIOContext { response.body!!.string() } // TODO fix this
if (response.code != 200) { /*val mangaInfo = parser.parseToManga(manga, response, covers, sourceId)
XLog.tag("MangaHandler").enableStackTrace(2).e("error from MangaDex with response code ${response.code} \n body: \n$jsonData") val chapterList = parser.chapterListParse(apiNetworkManga)
throw Exception("Error from MangaDex Response code ${response.code} ")
}
parser.parseToManga(manga, response, covers, sourceId) mangaInfo to chapterList*/
val chapterList = parser.chapterListParse(jsonData) manga to emptyList()
Pair(
manga,
chapterList
)
} }
} }
suspend fun getCovers(manga: MangaInfo, forceLatestCovers: Boolean): List<String> { suspend fun getCovers(manga: MangaInfo, forceLatestCovers: Boolean): List<String> {
return if (forceLatestCovers) { return if (forceLatestCovers) {
val covers = client.newCall(coverRequest(manga.toSManga())).await().parseAs<ApiCovers>() val covers = client.newCall(coverRequest(manga)).await().parseAs<ApiCovers>(MdUtil.jsonParser)
covers.data.map { it.url } covers.data.map { it.url }
} else { } else {
emptyList() emptyList()
@ -63,14 +58,14 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val lang: Str
suspend fun getMangaDetails(manga: MangaInfo, sourceId: Long): MangaInfo { suspend fun getMangaDetails(manga: MangaInfo, sourceId: Long): MangaInfo {
return withIOContext { return withIOContext {
val response = client.newCall(apiRequest(manga.toSManga())).await() val response = client.newCall(apiRequest(manga)).await()
val covers = getCovers(manga, forceLatestCovers) val covers = getCovers(manga, forceLatestCovers)
ApiMangaParser(lang).parseToManga(manga, response, covers, sourceId) ApiMangaParser(lang).parseToManga(manga, response, covers, sourceId)
} }
} }
fun fetchMangaDetailsObservable(manga: SManga): Observable<SManga> { fun fetchMangaDetailsObservable(manga: SManga): Observable<SManga> {
return client.newCall(apiRequest(manga)) return client.newCall(apiRequest(manga.toMangaInfo()))
.asObservableSuccess() .asObservableSuccess()
.flatMap { response -> .flatMap { response ->
runAsObservable({ runAsObservable({
@ -91,14 +86,14 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val lang: Str
} }
fun fetchChapterListObservable(manga: SManga): Observable<List<SChapter>> { fun fetchChapterListObservable(manga: SManga): Observable<List<SChapter>> {
return client.newCall(apiRequest(manga)) return client.newCall(apiRequest(manga.toMangaInfo()))
.asObservableSuccess() .asObservableSuccess()
.map { response -> .map { response ->
ApiMangaParser(lang).chapterListParse(response) ApiMangaParser(lang).chapterListParse(response).map { it.toSChapter() }
} }
} }
suspend fun fetchChapterList(manga: SManga): List<SChapter> { suspend fun getChapterList(manga: MangaInfo): List<ChapterInfo> {
return withIOContext { return withIOContext {
val response = client.newCall(apiRequest(manga)).await() val response = client.newCall(apiRequest(manga)).await()
ApiMangaParser(lang).chapterListParse(response) ApiMangaParser(lang).chapterListParse(response)
@ -124,11 +119,11 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val lang: Str
return GET(MdUtil.baseUrl + MdUtil.randMangaPage, cache = CacheControl.Builder().noCache().build()) return GET(MdUtil.baseUrl + MdUtil.randMangaPage, cache = CacheControl.Builder().noCache().build())
} }
private fun apiRequest(manga: SManga): Request { private fun apiRequest(manga: MangaInfo): Request {
return GET(MdUtil.apiUrl + MdUtil.apiManga + MdUtil.getMangaId(manga.url) + MdUtil.includeChapters, headers, CacheControl.FORCE_NETWORK) return GET(MdUtil.apiUrl + MdUtil.apiManga + MdUtil.getMangaId(manga.key) + MdUtil.includeChapters, headers, CacheControl.FORCE_NETWORK)
} }
private fun coverRequest(manga: SManga): Request { private fun coverRequest(manga: MangaInfo): Request {
return GET(MdUtil.apiUrl + MdUtil.apiManga + MdUtil.getMangaId(manga.url) + MdUtil.apiCovers, headers, CacheControl.FORCE_NETWORK) return GET(MdUtil.apiUrl + MdUtil.apiManga + MdUtil.getMangaId(manga.key) + MdUtil.apiCovers, headers, CacheControl.FORCE_NETWORK)
} }
} }