Refactor the MangaDex code a bit (#17267)
* Refactor the MangaDex code a bit. * Bump the extension version.
This commit is contained in:
parent
873f752d61
commit
a59ef3a817
|
@ -6,7 +6,7 @@ ext {
|
|||
extName = 'MangaDex'
|
||||
pkgNameSuffix = 'all.mangadex'
|
||||
extClass = '.MangaDexFactory'
|
||||
extVersionCode = 183
|
||||
extVersionCode = 184
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<MangaListDto>()
|
||||
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<ChapterListDto>()
|
||||
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<MangaListDto>()
|
||||
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<CoverArtListDto>().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<SChapter> {
|
||||
|
@ -508,7 +512,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
|||
return emptyList()
|
||||
}
|
||||
|
||||
val chapterListResponse = response.parseAs<ChapterListDto>()
|
||||
var chapterListResponse = response.parseAs<ChapterListDto>()
|
||||
|
||||
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<ChapterListDto>()
|
||||
chapterListResults.addAll(newChapterList.data)
|
||||
hasMoreResults = (limit + offset) < newChapterList.total
|
||||
|
||||
hasNextPage = newChapterList.hasNextPage
|
||||
}
|
||||
|
||||
return chapterListResults
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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<UrlQueryFilter>()
|
||||
.forEach { filter -> filter.addQueryParameter(url, dexLang) }
|
||||
|
||||
return url.toString()
|
||||
return url.build()
|
||||
}
|
||||
|
||||
private fun List<Tag>.sortIfTranslated(intl: MangaDexIntl): List<Tag> = apply {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,11 @@ data class PaginatedResponseDto<T : EntityDto>(
|
|||
val limit: Int = 0,
|
||||
val offset: Int = 0,
|
||||
val total: Int = 0,
|
||||
)
|
||||
) {
|
||||
|
||||
val hasNextPage: Boolean
|
||||
get() = limit + offset < total
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ResponseDto<T : EntityDto>(
|
||||
|
|
Loading…
Reference in New Issue