From a59ef3a81716faa7f32d731a968af65e2bd7b526 Mon Sep 17 00:00:00 2001 From: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:18:12 -0300 Subject: [PATCH] Refactor the MangaDex code a bit (#17267) * Refactor the MangaDex code a bit. * Bump the extension version. --- src/all/mangadex/build.gradle | 2 +- .../extension/all/mangadex/MDConstants.kt | 9 +- .../extension/all/mangadex/MangaDex.kt | 129 +++++++++--------- .../extension/all/mangadex/MangaDexFactory.kt | 80 +++++------ .../extension/all/mangadex/MangaDexFilters.kt | 4 +- .../extension/all/mangadex/MangaDexHelper.kt | 60 ++++---- .../extension/all/mangadex/MangaDexIntl.kt | 5 + .../all/mangadex/MdAtHomeReportInterceptor.kt | 40 +++--- .../extension/all/mangadex/dto/ResponseDto.kt | 6 +- 9 files changed, 175 insertions(+), 160 deletions(-) diff --git a/src/all/mangadex/build.gradle b/src/all/mangadex/build.gradle index af4c1d2e2..2c736d44a 100644 --- a/src/all/mangadex/build.gradle +++ b/src/all/mangadex/build.gradle @@ -6,7 +6,7 @@ ext { extName = 'MangaDex' pkgNameSuffix = 'all.mangadex' extClass = '.MangaDexFactory' - extVersionCode = 183 + extVersionCode = 184 isNsfw = true } diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MDConstants.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MDConstants.kt index b7f8eaa11..566db25ad 100644 --- a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MDConstants.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MDConstants.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.all.mangadex import java.text.SimpleDateFormat import java.util.Locale import java.util.TimeZone +import kotlin.time.Duration.Companion.minutes object MDConstants { @@ -31,7 +32,7 @@ object MDConstants { const val atHomePostUrl = "https://api.mangadex.network/report" val whitespaceRegex = "\\s".toRegex() - const val mdAtHomeTokenLifespan = 5 * 60 * 1000 + val mdAtHomeTokenLifespan = 5.minutes.inWholeMilliseconds val dateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+SSS", Locale.US) .apply { timeZone = TimeZone.getTimeZone("UTC") } @@ -74,6 +75,12 @@ object MDConstants { const val contentRatingPrefValErotica = "erotica" const val contentRatingPrefValPornographic = "pornographic" val contentRatingPrefDefaults = setOf(contentRatingPrefValSafe, contentRatingPrefValSuggestive) + val allContentRatings = setOf( + contentRatingPrefValSafe, + contentRatingPrefValSuggestive, + contentRatingPrefValErotica, + contentRatingPrefValPornographic, + ) fun getContentRatingPrefKey(dexLang: String): String { return "${contentRatingPref}_$dexLang" diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDex.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDex.kt index 2bb9a1495..b5b9b0050 100644 --- a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDex.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDex.kt @@ -34,7 +34,6 @@ import okhttp3.CacheControl import okhttp3.Headers import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.Request import okhttp3.Response import rx.Observable @@ -42,9 +41,8 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.util.Date -abstract class MangaDex(final override val lang: String, private val dexLang: String) : - ConfigurableSource, - HttpSource() { +abstract class MangaDex(final override val lang: String, private val dexLang: String = lang) : + ConfigurableSource, HttpSource() { override val name = MangaDexIntl.MANGADEX_NAME @@ -82,12 +80,9 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St .addQueryParameter("includes[]", MDConstants.coverArt) .addQueryParameter("contentRating[]", preferences.contentRating) .addQueryParameter("originalLanguage[]", preferences.originalLanguages) + .build() - return GET( - url = url.build().toString(), - headers = headers, - cache = CacheControl.FORCE_NETWORK, - ) + return GET(url, headers, CacheControl.FORCE_NETWORK) } override fun popularMangaParse(response: Response): MangasPage { @@ -96,7 +91,6 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St } val mangaListDto = response.parseAs() - val hasMoreResults = mangaListDto.limit + mangaListDto.offset < mangaListDto.total val coverSuffix = preferences.coverQuality val firstVolumeCovers = fetchFirstVolumeCovers(mangaListDto.data).orEmpty() @@ -109,17 +103,37 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St helper.createBasicManga(mangaDataDto, fileName, coverSuffix, dexLang) } - return MangasPage(mangaList, hasMoreResults) + return MangasPage(mangaList, mangaListDto.hasNextPage) } // Latest manga section + override fun latestUpdatesRequest(page: Int): Request { + val url = MDConstants.apiChapterUrl.toHttpUrl().newBuilder() + .addQueryParameter("offset", helper.getLatestChapterOffset(page)) + .addQueryParameter("limit", MDConstants.latestChapterLimit.toString()) + .addQueryParameter("translatedLanguage[]", dexLang) + .addQueryParameter("order[publishAt]", "desc") + .addQueryParameter("includeFutureUpdates", "0") + .addQueryParameter("originalLanguage[]", preferences.originalLanguages) + .addQueryParameter("contentRating[]", preferences.contentRating) + .addQueryParameter( + "excludedGroups[]", + MDConstants.defaultBlockedGroups + preferences.blockedGroups, + ) + .addQueryParameter("excludedUploaders[]", preferences.blockedUploaders) + .addQueryParameter("includeFuturePublishAt", "0") + .addQueryParameter("includeEmptyPages", "0") + .build() + + return GET(url, headers, CacheControl.FORCE_NETWORK) + } + /** * The API endpoint can't sort by date yet, so not implemented. */ override fun latestUpdatesParse(response: Response): MangasPage { val chapterListDto = response.parseAs() - val hasMoreResults = chapterListDto.limit + chapterListDto.offset < chapterListDto.total val mangaIds = chapterListDto.data .flatMap { it.relationships } @@ -128,13 +142,14 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St .distinct() .toSet() - val mangaUrl = MDConstants.apiMangaUrl.toHttpUrlOrNull()!!.newBuilder() + val mangaApiUrl = MDConstants.apiMangaUrl.toHttpUrl().newBuilder() .addQueryParameter("includes[]", MDConstants.coverArt) .addQueryParameter("limit", mangaIds.size.toString()) .addQueryParameter("contentRating[]", preferences.contentRating) .addQueryParameter("ids[]", mangaIds) + .build() - val mangaRequest = GET(mangaUrl.build().toString(), headers, CacheControl.FORCE_NETWORK) + val mangaRequest = GET(mangaApiUrl, headers, CacheControl.FORCE_NETWORK) val mangaResponse = client.newCall(mangaRequest).execute() val mangaListDto = mangaResponse.parseAs() val firstVolumeCovers = fetchFirstVolumeCovers(mangaListDto.data).orEmpty() @@ -151,27 +166,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St helper.createBasicManga(mangaDataDto, fileName, coverSuffix, dexLang) } - return MangasPage(mangaList, hasMoreResults) - } - - override fun latestUpdatesRequest(page: Int): Request { - val url = MDConstants.apiChapterUrl.toHttpUrlOrNull()!!.newBuilder() - .addQueryParameter("offset", helper.getLatestChapterOffset(page)) - .addQueryParameter("limit", MDConstants.latestChapterLimit.toString()) - .addQueryParameter("translatedLanguage[]", dexLang) - .addQueryParameter("order[publishAt]", "desc") - .addQueryParameter("includeFutureUpdates", "0") - .addQueryParameter("originalLanguage[]", preferences.originalLanguages) - .addQueryParameter("contentRating[]", preferences.contentRating) - .addQueryParameter( - "excludedGroups[]", - MDConstants.defaultBlockedGroups + preferences.blockedGroups, - ) - .addQueryParameter("excludedUploaders[]", preferences.blockedUploaders) - .addQueryParameter("includeFuturePublishAt", "0") - .addQueryParameter("includeEmptyPages", "0") - - return GET(url.build().toString(), headers, CacheControl.FORCE_NETWORK) + return MangasPage(mangaList, chapterListDto.hasNextPage) } // Search manga section @@ -228,26 +223,31 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St } override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + if (query.startsWith(MDConstants.prefixIdSearch)) { + val mangaId = query.removePrefix(MDConstants.prefixIdSearch) + + if (!helper.containsUuid(mangaId)) { + throw Exception(helper.intl.invalidMangaId) + } + + val url = MDConstants.apiMangaUrl.toHttpUrl().newBuilder() + .addQueryParameter("ids[]", query.removePrefix(MDConstants.prefixIdSearch)) + .addQueryParameter("includes[]", MDConstants.coverArt) + .addQueryParameter("contentRating[]", MDConstants.allContentRatings) + .build() + + return GET(url, headers, CacheControl.FORCE_NETWORK) + } + val tempUrl = MDConstants.apiMangaUrl.toHttpUrl().newBuilder() .addQueryParameter("limit", MDConstants.mangaLimit.toString()) .addQueryParameter("offset", helper.getMangaListOffset(page)) .addQueryParameter("includes[]", MDConstants.coverArt) when { - query.startsWith(MDConstants.prefixIdSearch) -> { - val url = MDConstants.apiMangaUrl.toHttpUrlOrNull()!!.newBuilder() - .addQueryParameter("ids[]", query.removePrefix(MDConstants.prefixIdSearch)) - .addQueryParameter("includes[]", MDConstants.coverArt) - .addQueryParameter("contentRating[]", "safe") - .addQueryParameter("contentRating[]", "suggestive") - .addQueryParameter("contentRating[]", "erotica") - .addQueryParameter("contentRating[]", "pornographic") - - return GET(url.build().toString(), headers, CacheControl.FORCE_NETWORK) - } - query.startsWith(MDConstants.prefixGrpSearch) -> { val groupId = query.removePrefix(MDConstants.prefixGrpSearch) + if (!helper.containsUuid(groupId)) { throw Exception(helper.intl.invalidGroupId) } @@ -257,6 +257,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St query.startsWith(MDConstants.prefixAuthSearch) -> { val authorId = query.removePrefix(MDConstants.prefixAuthSearch) + if (!helper.containsUuid(authorId)) { throw Exception(helper.intl.invalidAuthorId) } @@ -311,7 +312,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St url.addQueryParameter("ids[]", ids) - val mangaRequest = GET(url.build().toString(), headers, CacheControl.FORCE_NETWORK) + val mangaRequest = GET(url.build(), headers, CacheControl.FORCE_NETWORK) val mangaResponse = client.newCall(mangaRequest).execute() val mangaList = searchMangaListParse(mangaResponse) @@ -345,7 +346,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St } private fun searchMangaUploaderRequest(page: Int, uploader: String): Request { - val url = MDConstants.apiChapterUrl.toHttpUrlOrNull()!!.newBuilder() + val url = MDConstants.apiChapterUrl.toHttpUrl().newBuilder() .addQueryParameter("offset", helper.getLatestChapterOffset(page)) .addQueryParameter("limit", MDConstants.latestChapterLimit.toString()) .addQueryParameter("translatedLanguage[]", dexLang) @@ -361,8 +362,9 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St MDConstants.defaultBlockedGroups + preferences.blockedGroups, ) .addQueryParameter("excludedUploaders[]", preferences.blockedUploaders) + .build() - return GET(url.build().toString(), headers, CacheControl.FORCE_NETWORK) + return GET(url, headers, CacheControl.FORCE_NETWORK) } // Manga Details section @@ -370,7 +372,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St override fun getMangaUrl(manga: SManga): String { // TODO: Remove once redirect for /manga is fixed. val title = manga.title - val url = "${baseUrl}${manga.url.replace("manga", "title")}" + val url = baseUrl + manga.url.replaceFirst("manga", "title") return "$url/" + helper.titleToSlug(title) } @@ -389,8 +391,9 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St .addQueryParameter("includes[]", MDConstants.coverArt) .addQueryParameter("includes[]", MDConstants.author) .addQueryParameter("includes[]", MDConstants.artist) + .build() - return GET(url.build().toString(), headers, CacheControl.FORCE_NETWORK) + return GET(url, headers, CacheControl.FORCE_NETWORK) } override fun mangaDetailsParse(response: Response): SManga { @@ -453,7 +456,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St .addQueryParameter("locales[]", locales.toSet()) .addQueryParameter("limit", limit.toString()) .addQueryParameter("offset", "0") - .toString() + .build() val result = runCatching { client.newCall(GET(apiUrl, headers)).execute().parseAs().data @@ -499,8 +502,9 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St .addQueryParameter("contentRating[]", "pornographic") .addQueryParameter("excludedGroups[]", preferences.blockedGroups) .addQueryParameter("excludedUploaders[]", preferences.blockedUploaders) + .build() - return GET(url.build().toString(), headers, CacheControl.FORCE_NETWORK) + return GET(url, headers, CacheControl.FORCE_NETWORK) } override fun chapterListParse(response: Response): List { @@ -508,7 +512,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St return emptyList() } - val chapterListResponse = response.parseAs() + var chapterListResponse = response.parseAs() val chapterListResults = chapterListResponse.data.toMutableList() @@ -516,21 +520,20 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St .substringBefore("/feed") .substringAfter("${MDConstants.apiMangaUrl}/") - val limit = chapterListResponse.limit - var offset = chapterListResponse.offset - - var hasMoreResults = (limit + offset) < chapterListResponse.total + var hasNextPage = chapterListResponse.hasNextPage // Max results that can be returned is 500 so need to make more API - // calls if limit + offset > total chapters - while (hasMoreResults) { - offset += limit + // calls if the chapter list response has a next page. + while (hasNextPage) { + offset += chapterListResponse.limit + val newRequest = paginatedChapterListRequest(mangaId, offset) val newResponse = client.newCall(newRequest).execute() val newChapterList = newResponse.parseAs() chapterListResults.addAll(newChapterList.data) - hasMoreResults = (limit + offset) < newChapterList.total + + hasNextPage = newChapterList.hasNextPage } return chapterListResults diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexFactory.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexFactory.kt index cd5ab1a45..f41813667 100644 --- a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexFactory.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexFactory.kt @@ -53,48 +53,48 @@ class MangaDexFactory : SourceFactory { ) } -class MangaDexArabic : MangaDex("ar", "ar") -class MangaDexBengali : MangaDex("bn", "bn") -class MangaDexBulgarian : MangaDex("bg", "bg") -class MangaDexBurmese : MangaDex("my", "my") -class MangaDexCatalan : MangaDex("ca", "ca") +class MangaDexArabic : MangaDex("ar") +class MangaDexBengali : MangaDex("bn") +class MangaDexBulgarian : MangaDex("bg") +class MangaDexBurmese : MangaDex("my") +class MangaDexCatalan : MangaDex("ca") class MangaDexChineseSimplified : MangaDex("zh-Hans", "zh") class MangaDexChineseTraditional : MangaDex("zh-Hant", "zh-hk") -class MangaDexCzech : MangaDex("cs", "cs") -class MangaDexDanish : MangaDex("da", "da") -class MangaDexDutch : MangaDex("nl", "nl") -class MangaDexEnglish : MangaDex("en", "en") +class MangaDexCzech : MangaDex("cs") +class MangaDexDanish : MangaDex("da") +class MangaDexDutch : MangaDex("nl") +class MangaDexEnglish : MangaDex("en") class MangaDexFilipino : MangaDex("fil", "tl") -class MangaDexFinnish : MangaDex("fi", "fi") -class MangaDexFrench : MangaDex("fr", "fr") -class MangaDexGerman : MangaDex("de", "de") -class MangaDexGreek : MangaDex("el", "el") -class MangaDexHebrew : MangaDex("he", "he") -class MangaDexHindi : MangaDex("hi", "hi") -class MangaDexHungarian : MangaDex("hu", "hu") -class MangaDexIndonesian : MangaDex("id", "id") -class MangaDexItalian : MangaDex("it", "it") -class MangaDexJapanese : MangaDex("ja", "ja") -class MangaDexKazakh : MangaDex("kk", "kk") -class MangaDexKorean : MangaDex("ko", "ko") -class MangaDexLatin : MangaDex("la", "la") -class MangaDexLithuanian : MangaDex("lt", "lt") -class MangaDexMalay : MangaDex("ms", "ms") -class MangaDexMongolian : MangaDex("mn", "mn") -class MangaDexNepali : MangaDex("ne", "ne") -class MangaDexNorwegian : MangaDex("no", "no") -class MangaDexPersian : MangaDex("fa", "fa") -class MangaDexPolish : MangaDex("pl", "pl") +class MangaDexFinnish : MangaDex("fi") +class MangaDexFrench : MangaDex("fr") +class MangaDexGerman : MangaDex("de") +class MangaDexGreek : MangaDex("el") +class MangaDexHebrew : MangaDex("he") +class MangaDexHindi : MangaDex("hi") +class MangaDexHungarian : MangaDex("hu") +class MangaDexIndonesian : MangaDex("id") +class MangaDexItalian : MangaDex("it") +class MangaDexJapanese : MangaDex("ja") +class MangaDexKazakh : MangaDex("kk") +class MangaDexKorean : MangaDex("ko") +class MangaDexLatin : MangaDex("la") +class MangaDexLithuanian : MangaDex("lt") +class MangaDexMalay : MangaDex("ms") +class MangaDexMongolian : MangaDex("mn") +class MangaDexNepali : MangaDex("ne") +class MangaDexNorwegian : MangaDex("no") +class MangaDexPersian : MangaDex("fa") +class MangaDexPolish : MangaDex("pl") class MangaDexPortugueseBrazil : MangaDex("pt-BR", "pt-br") -class MangaDexPortuguesePortugal : MangaDex("pt", "pt") -class MangaDexRomanian : MangaDex("ro", "ro") -class MangaDexRussian : MangaDex("ru", "ru") -class MangaDexSerboCroatian : MangaDex("sh", "sh") +class MangaDexPortuguesePortugal : MangaDex("pt") +class MangaDexRomanian : MangaDex("ro") +class MangaDexRussian : MangaDex("ru") +class MangaDexSerboCroatian : MangaDex("sh") class MangaDexSpanishLatinAmerica : MangaDex("es-419", "es-la") -class MangaDexSpanishSpain : MangaDex("es", "es") -class MangaDexSwedish : MangaDex("sv", "sv") -class MangaDexTamil : MangaDex("ta", "ta") -class MangaDexThai : MangaDex("th", "th") -class MangaDexTurkish : MangaDex("tr", "tr") -class MangaDexUkrainian : MangaDex("uk", "uk") -class MangaDexVietnamese : MangaDex("vi", "vi") +class MangaDexSpanishSpain : MangaDex("es") +class MangaDexSwedish : MangaDex("sv") +class MangaDexTamil : MangaDex("ta") +class MangaDexThai : MangaDex("th") +class MangaDexTurkish : MangaDex("tr") +class MangaDexUkrainian : MangaDex("uk") +class MangaDexVietnamese : MangaDex("vi") diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexFilters.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexFilters.kt index d6e8f4959..5a67f7e9a 100644 --- a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexFilters.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexFilters.kt @@ -373,11 +373,11 @@ class MangaDexFilters { TagExclusionMode(intl, getTagModes(intl)), ) - internal fun addFiltersToUrl(url: HttpUrl.Builder, filters: FilterList, dexLang: String): String { + internal fun addFiltersToUrl(url: HttpUrl.Builder, filters: FilterList, dexLang: String): HttpUrl { filters.filterIsInstance() .forEach { filter -> filter.addQueryParameter(url, dexLang) } - return url.toString() + return url.build() } private fun List.sortIfTranslated(intl: MangaDexIntl): List = apply { diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexHelper.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexHelper.kt index 60234e8ae..ed4b3b53f 100644 --- a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexHelper.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexHelper.kt @@ -199,20 +199,18 @@ class MangaDexHelper(lang: String) { * Check the token map to see if the MD@Home host is still valid. */ fun getValidImageUrlForPage(page: Page, headers: Headers, client: OkHttpClient): Request { - val data = page.url.split(",") + val (host, tokenRequestUrl, time) = page.url.split(",") val mdAtHomeServerUrl = - when (Date().time - data[2].toLong() > MDConstants.mdAtHomeTokenLifespan) { - false -> data[0] + when (Date().time - time.toLong() > MDConstants.mdAtHomeTokenLifespan) { + false -> host true -> { - val tokenRequestUrl = data[1] val tokenLifespan = Date().time - (tokenTracker[tokenRequestUrl] ?: 0) - val cacheControl = - if (tokenLifespan > MDConstants.mdAtHomeTokenLifespan) { - CacheControl.FORCE_NETWORK - } else { - USE_CACHE - } + val cacheControl = if (tokenLifespan > MDConstants.mdAtHomeTokenLifespan) { + CacheControl.FORCE_NETWORK + } else { + USE_CACHE + } getMdAtHomeUrl(tokenRequestUrl, client, headers, cacheControl) } } @@ -265,22 +263,20 @@ class MangaDexHelper(lang: String) { coverFileName: String?, coverSuffix: String?, lang: String, - ): SManga { - return SManga.create().apply { - url = "/manga/${mangaDataDto.id}" - val titleMap = mangaDataDto.attributes!!.title - val dirtyTitle = - titleMap.values.firstOrNull() // use literally anything from title as first resort - ?: mangaDataDto.attributes.altTitles - .find { (it[lang] ?: it["en"]) !== null } - ?.values?.singleOrNull() // find something else from alt titles - title = (dirtyTitle ?: "").removeEntitiesAndMarkdown() + ): SManga = SManga.create().apply { + url = "/manga/${mangaDataDto.id}" + val titleMap = mangaDataDto.attributes!!.title + val dirtyTitle = + titleMap.values.firstOrNull() // use literally anything from title as first resort + ?: mangaDataDto.attributes.altTitles + .find { (it[lang] ?: it["en"]) !== null } + ?.values?.singleOrNull() // find something else from alt titles + title = dirtyTitle?.removeEntitiesAndMarkdown().orEmpty() - coverFileName?.let { - thumbnail_url = when (!coverSuffix.isNullOrEmpty()) { - true -> "${MDConstants.cdnUrl}/covers/${mangaDataDto.id}/$coverFileName$coverSuffix" - else -> "${MDConstants.cdnUrl}/covers/${mangaDataDto.id}/$coverFileName" - } + coverFileName?.let { + thumbnail_url = when (!coverSuffix.isNullOrEmpty()) { + true -> "${MDConstants.cdnUrl}/covers/${mangaDataDto.id}/$coverFileName$coverSuffix" + else -> "${MDConstants.cdnUrl}/covers/${mangaDataDto.id}/$coverFileName" } } } @@ -335,10 +331,12 @@ class MangaDexHelper(lang: String) { val genreList = MDConstants.tagGroupsOrder.flatMap { genresMap[it].orEmpty() } + nonGenres - var desc = (attr.description[lang] ?: attr.description["en"])?.removeEntitiesAndMarkdown() ?: "" + var desc = (attr.description[lang] ?: attr.description["en"]) + ?.removeEntitiesAndMarkdown() + .orEmpty() if (altTitlesInDesc) { - val romanizedOriginalLang = MDConstants.romanizedLangCodes[attr.originalLanguage] ?: "" + val romanizedOriginalLang = MDConstants.romanizedLangCodes[attr.originalLanguage].orEmpty() val altTitles = attr.altTitles .filter { it.containsKey(lang) || it.containsKey(romanizedOriginalLang) } .mapNotNull { it.values.singleOrNull() } @@ -447,13 +445,9 @@ class MangaDexHelper(lang: String) { editText.addTextChangedListener( object : TextWatcher { - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { - // Do nothing. - } + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - // Do nothing. - } + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit override fun afterTextChanged(editable: Editable?) { requireNotNull(editable) diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexIntl.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexIntl.kt index 4a91a3b68..875708e1c 100644 --- a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexIntl.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangaDexIntl.kt @@ -18,6 +18,11 @@ class MangaDexIntl(lang: String) { else -> "The text contains invalid UUIDs" } + val invalidMangaId: String = when (availableLang) { + BRAZILIAN_PORTUGUESE, PORTUGUESE -> "ID do mangá inválido" + else -> "Not a valid manga ID" + } + val invalidGroupId: String = when (availableLang) { BRAZILIAN_PORTUGUESE, PORTUGUESE -> "ID do grupo inválido" SPANISH_LATAM, SPANISH -> "ID de grupo inválida" diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MdAtHomeReportInterceptor.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MdAtHomeReportInterceptor.kt index c71787420..0864f3121 100644 --- a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MdAtHomeReportInterceptor.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MdAtHomeReportInterceptor.kt @@ -14,10 +14,9 @@ import okhttp3.OkHttpClient import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import uy.kohesive.injekt.injectLazy -import java.io.IOException /** - * Interceptor to post to md@home for MangaDex Stats + * Interceptor to post to MD@Home for MangaDex Stats */ class MdAtHomeReportInterceptor( private val client: OkHttpClient, @@ -26,23 +25,20 @@ class MdAtHomeReportInterceptor( private val json: Json by injectLazy() - private val mdAtHomeUrlRegex = - Regex("""^https://[\w\d]+\.[\w\d]+\.mangadex(\b-test\b)?\.network.*${'$'}""") - override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() val response = chain.proceed(chain.request()) val url = originalRequest.url.toString() - if (!url.contains(mdAtHomeUrlRegex)) { + if (!url.contains(MD_AT_HOME_URL_REGEX)) { return response } val result = ImageReportDto( - url, + url = url, success = response.isSuccessful, bytes = response.peekBody(Long.MAX_VALUE).bytes().size, - cached = response.header("X-Cache", "") == "HIT", + cached = response.headers["X-Cache"] == "HIT", duration = response.receivedResponseAtMillis - response.sentRequestAtMillis, ) @@ -57,22 +53,28 @@ class MdAtHomeReportInterceptor( // Execute the report endpoint network call asynchronously to avoid blocking // the reader from showing the image once it's fully loaded if the report call // gets stuck, as it tend to happens sometimes. - client.newCall(reportRequest).enqueue( - object : Callback { - override fun onFailure(call: Call, e: IOException) { - Log.e("MangaDex", "Error trying to POST report to MD@Home: ${e.message}") - } - - override fun onResponse(call: Call, response: Response) { - response.close() - } - }, - ) + client.newCall(reportRequest).enqueue(REPORT_CALLBACK) return response } companion object { private val JSON_MEDIA_TYPE = "application/json".toMediaType() + private val MD_AT_HOME_URL_REGEX = + """^https://[\w\d]+\.[\w\d]+\.mangadex(\b-test\b)?\.network.*${'$'}""".toRegex() + + private val REPORT_CALLBACK = object : Callback { + override fun onFailure(call: Call, e: okio.IOException) { + Log.e("MangaDex", "Error trying to POST report to MD@Home: ${e.message}") + } + + override fun onResponse(call: Call, response: Response) { + if (!response.isSuccessful) { + Log.e("MangaDex", "Error trying to POST report to MD@Home: HTTP error ${response.code}") + } + + response.close() + } + } } } diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/dto/ResponseDto.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/dto/ResponseDto.kt index 47dd7ef5b..68c7db935 100644 --- a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/dto/ResponseDto.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/dto/ResponseDto.kt @@ -10,7 +10,11 @@ data class PaginatedResponseDto( val limit: Int = 0, val offset: Int = 0, val total: Int = 0, -) +) { + + val hasNextPage: Boolean + get() = limit + offset < total +} @Serializable data class ResponseDto(