diff --git a/lib-multisrc/madara/assets/i18n/messages_en.properties b/lib-multisrc/madara/assets/i18n/messages_en.properties new file mode 100644 index 000000000..4d11ccc50 --- /dev/null +++ b/lib-multisrc/madara/assets/i18n/messages_en.properties @@ -0,0 +1,27 @@ +author_filter_title=Author +artist_filter_title=Artist +year_filter_title=Year of Released +status_filter_title=Status +status_filter_completed=Completed +status_filter_ongoing=Ongoing +status_filter_canceled=Canceled +status_filter_on_hold=On Hold +order_by_filter_title=Order By +order_by_filter_relevance=Relevance +order_by_filter_latest=Latest +order_by_filter_az=A-Z +order_by_filter_rating=Rating +order_by_filter_trending=Trending +order_by_filter_views=Most Views +order_by_filter_new=New +genre_condition_filter_title=Genre condition +genre_condition_filter_or=OR +genre_condition_filter_and=AND +adult_content_filter_title=Adult Content +adult_content_filter_all=All +adult_content_filter_none=None +adult_content_filter_only=Only +genre_filter_header=Genres filter may not work for all sources +genre_filter_title=Genres +genre_missing_warning=Press 'Reset' to attempt to show the genres +alt_names_heading=Alternative Names: diff --git a/lib-multisrc/madara/assets/i18n/messages_pt_br.properties b/lib-multisrc/madara/assets/i18n/messages_pt_br.properties new file mode 100644 index 000000000..8a25ed24b --- /dev/null +++ b/lib-multisrc/madara/assets/i18n/messages_pt_br.properties @@ -0,0 +1,26 @@ +author_filter_title=Autor +artist_filter_title=Artista +year_filter_title=Ano de lançamento +status_filter_title=Estado +status_filter_completed=Completo +status_filter_ongoing=Em andamento +status_filter_canceled=Cancelado +status_filter_on_hold=Pausado +order_by_filter_title=Ordenar por +order_by_filter_relevance=Relevância +order_by_filter_latest=Recentes +order_by_filter_rating=Avaliação +order_by_filter_trending=Tendência +order_by_filter_views=Visualizações +order_by_filter_new=Novos +genre_condition_filter_title=Operador dos gêneros +genre_condition_filter_or=OU +genre_condition_filter_and=E +adult_content_filter_title=Conteúdo adulto +adult_content_filter_all=Indiferente +adult_content_filter_none=Nenhum +adult_content_filter_only=Somente +genre_filter_header=O filtro de gêneros pode não funcionar +genre_filter_title=Gêneros +genre_missing_warning=Aperte 'Redefinir' para tentar mostrar os gêneros +alt_names_heading=Nomes alternativos: diff --git a/lib-multisrc/madara/build.gradle.kts b/lib-multisrc/madara/build.gradle.kts index 723afc2b2..4abb04b09 100644 --- a/lib-multisrc/madara/build.gradle.kts +++ b/lib-multisrc/madara/build.gradle.kts @@ -2,9 +2,9 @@ plugins { id("lib-multisrc") } -baseVersionCode = 33 +baseVersionCode = 34 dependencies { api(project(":lib:cryptoaes")) - api(project(":lib:randomua")) + api(project(":lib:i18n")) } diff --git a/lib-multisrc/madara/src/eu/kanade/tachiyomi/multisrc/madara/Madara.kt b/lib-multisrc/madara/src/eu/kanade/tachiyomi/multisrc/madara/Madara.kt index d5c7f99ba..5f15ca304 100644 --- a/lib-multisrc/madara/src/eu/kanade/tachiyomi/multisrc/madara/Madara.kt +++ b/lib-multisrc/madara/src/eu/kanade/tachiyomi/multisrc/madara/Madara.kt @@ -1,18 +1,11 @@ package eu.kanade.tachiyomi.multisrc.madara -import android.app.Application -import android.content.SharedPreferences import android.util.Base64 -import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES -import eu.kanade.tachiyomi.lib.randomua.addRandomUAPreferenceToScreen -import eu.kanade.tachiyomi.lib.randomua.getPrefCustomUA -import eu.kanade.tachiyomi.lib.randomua.getPrefUAType -import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent +import eu.kanade.tachiyomi.lib.i18n.Intl import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.network.asObservable -import eu.kanade.tachiyomi.source.ConfigurableSource +import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage @@ -21,57 +14,55 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.util.asJsoup +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive -import okhttp3.CacheControl import okhttp3.FormBody import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element import rx.Observable -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import java.text.ParseException import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale -import java.util.concurrent.TimeUnit abstract class Madara( override val name: String, override val baseUrl: String, final override val lang: String, private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US), -) : ParsedHttpSource(), ConfigurableSource { - - private val preferences: SharedPreferences by lazy { - Injekt.get().getSharedPreferences("source_$id", 0x0000) - } +) : ParsedHttpSource() { override val supportsLatest = true - override val client: OkHttpClient by lazy { - network.cloudflareClient.newBuilder() - .setRandomUserAgent( - preferences.getPrefUAType(), - preferences.getPrefCustomUA(), - ) - .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - .build() - } + override val client = network.cloudflareClient override fun headersBuilder() = super.headersBuilder() .add("Referer", "$baseUrl/") + protected val xhrHeaders by lazy { + headersBuilder() + .set("X-Requested-With", "XMLHttpRequest") + .build() + } + protected open val json: Json by injectLazy() + protected val intl = Intl( + language = lang, + baseLanguage = "en", + availableLanguages = setOf("en", "pt-BR"), + classLoader = this::class.java.classLoader!!, + ) + /** * If enabled, will attempt to remove non-manga items in popular and latest. * The filter will not be used in search as the theme doesn't set the CSS class. @@ -93,11 +84,6 @@ abstract class Madara( */ private var genresList: List = emptyList() - /** - * Inner variable to control the genre fetching failed state. - */ - private var fetchGenresFailed: Boolean = false - /** * Inner variable to control how much tries the genres request was called. */ @@ -114,11 +100,58 @@ abstract class Madara( */ protected open val mangaSubString = "manga" + /** + * enable if the site use "madara_load_more" to load manga on the site + * Typically has "load More" instead of next/previous page + * + * with LoadMoreStrategy.AutoDetect it tries to detect if site uses `madara_load_more` + */ + protected open val useLoadMoreRequest = LoadMoreStrategy.AutoDetect + + enum class LoadMoreStrategy { + AutoDetect, Always, Never + } + + /** + * internal variable to save if site uses load_more or not + */ + private var loadMoreRequestDetected = LoadMoreDetection.Pending + + private enum class LoadMoreDetection { + Pending, True, False + } + + protected fun detectLoadMore(document: Document) { + if (useLoadMoreRequest == LoadMoreStrategy.AutoDetect && + loadMoreRequestDetected == LoadMoreDetection.Pending + ) { + loadMoreRequestDetected = when (document.selectFirst("nav.navigation-ajax") != null) { + true -> LoadMoreDetection.True + false -> LoadMoreDetection.False + } + } + } + + protected fun useLoadMoreRequest(): Boolean { + return when (useLoadMoreRequest) { + LoadMoreStrategy.Always -> true + LoadMoreStrategy.Never -> false + else -> loadMoreRequestDetected == LoadMoreDetection.True + } + } + // Popular Manga override fun popularMangaParse(response: Response): MangasPage { - runCatching { fetchGenres() } - return super.popularMangaParse(response) + val document = response.asJsoup() + + val entries = document.select(popularMangaSelector()) + .map(::popularMangaFromElement) + val hasNextPage = popularMangaNextPageSelector()?.let { document.selectFirst(it) } != null + + detectLoadMore(document) + + return MangasPage(entries, hasNextPage) } // exclude/filter bilibili manga from list @@ -130,12 +163,12 @@ abstract class Madara( val manga = SManga.create() with(element) { - select(popularMangaUrlSelector).first()?.let { + selectFirst(popularMangaUrlSelector)!!.let { manga.setUrlWithoutDomain(it.attr("abs:href")) manga.title = it.ownText() } - select("img").first()?.let { + selectFirst("img")?.let { manga.thumbnail_url = imageFromElement(it) } } @@ -143,15 +176,19 @@ abstract class Madara( return manga } - override fun popularMangaRequest(page: Int): Request { - return GET( - url = "$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=views", - headers = headers, - cache = CacheControl.FORCE_NETWORK, - ) - } + override fun popularMangaRequest(page: Int): Request = + if (useLoadMoreRequest()) { + loadMoreRequest(page, popular = true) + } else { + GET("$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=views", headers) + } - override fun popularMangaNextPageSelector(): String? = searchMangaNextPageSelector() + override fun popularMangaNextPageSelector(): String? = + if (useLoadMoreRequest()) { + "body:not(:has(.no-posts))" + } else { + "div.nav-previous, nav.navigation-ajax, a.nextpostslink" + } // Latest Updates @@ -162,53 +199,75 @@ abstract class Madara( return popularMangaFromElement(element) } - override fun latestUpdatesRequest(page: Int): Request { - return GET( - url = "$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=latest", - headers = headers, - cache = CacheControl.FORCE_NETWORK, - ) - } + override fun latestUpdatesRequest(page: Int): Request = + if (useLoadMoreRequest()) { + loadMoreRequest(page, popular = false) + } else { + GET("$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=latest", headers) + } override fun latestUpdatesNextPageSelector(): String? = popularMangaNextPageSelector() override fun latestUpdatesParse(response: Response): MangasPage { - val mp = super.latestUpdatesParse(response) + val mp = popularMangaParse(response) val mangas = mp.mangas.distinctBy { it.url } return MangasPage(mangas, mp.hasNextPage) } + // load more + protected fun loadMoreRequest(page: Int, popular: Boolean): Request { + val formBody = FormBody.Builder().apply { + add("action", "madara_load_more") + add("page", (page - 1).toString()) + add("template", "madara-core/content/content-archive") + add("vars[orderby]", "meta_value_num") + add("vars[paged]", "1") + add("vars[post_type]", "wp-manga") + add("vars[post_status]", "publish") + add("vars[meta_key]", if (popular) "_wp_manga_views" else "_latest_update") + add("vars[order]", "desc") + add("vars[sidebar]", "right") + add("vars[manga_archives_item_layout]", "big_thumbnail") + }.build() + + return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, formBody) + } + // Search Manga override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { if (query.startsWith(URL_SEARCH_PREFIX)) { - val mangaUrl = "$baseUrl/$mangaSubString/${query.substringAfter(URL_SEARCH_PREFIX)}" - return client.newCall(GET(mangaUrl, headers)) - .asObservable().map { response -> - MangasPage(listOf(mangaDetailsParse(response.asJsoup()).apply { url = "/$mangaSubString/${query.substringAfter(URL_SEARCH_PREFIX)}/" }), false) + val mangaUrl = "/$mangaSubString/${query.substringAfter(URL_SEARCH_PREFIX)}" + return client.newCall(GET("$baseUrl$mangaUrl", headers)) + .asObservableSuccess().map { response -> + val manga = mangaDetailsParse(response).apply { + url = mangaUrl + } + + MangasPage(listOf(manga), false) } } - return client.newCall(searchMangaRequest(page, query, filters)) - .asObservable().doOnNext { response -> - if (!response.isSuccessful) { - response.close() - // Error message for exceeding last page - if (response.code == 404) { - error("Already on the Last Page!") - } else { - throw Exception("HTTP error ${response.code}") - } - } - } - .map { response -> - searchMangaParse(response) - } + return super.fetchSearchManga(page, query, filters) } - protected open fun searchPage(page: Int): String = "page/$page/" + protected open fun searchPage(page: Int): String { + return if (page == 1) { + "" + } else { + "page/$page/" + } + } override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + return if (useLoadMoreRequest()) { + searchLoadMoreRequest(page, query, filters) + } else { + searchRequest(page, query, filters) + } + } + + protected open fun searchRequest(page: Int, query: String, filters: FilterList): Request { val url = "$baseUrl/${searchPage(page)}".toHttpUrl().newBuilder() url.addQueryParameter("s", query) url.addQueryParameter("post_type", "wp-manga") @@ -260,108 +319,182 @@ abstract class Madara( return GET(url.build(), headers) } - protected open val authorFilterTitle: String = when (lang) { - "pt-BR" -> "Autor" - else -> "Author" + protected open fun searchLoadMoreRequest(page: Int, query: String, filters: FilterList): Request { + val formBody = FormBody.Builder().apply { + add("action", "madara_load_more") + add("page", (page - 1).toString()) + add("template", "madara-core/content/content-search") + add("vars[paged]", "1") + add("vars[template]", "archive") + add("vars[sidebar]", "right") + add("vars[post_type]", "wp-manga") + add("vars[post_status]", "publish") + add("vars[manga_archives_item_layout]", "big_thumbnail") + + if (filterNonMangaItems) { + add("vars[meta_query][0][key]", "_wp_manga_chapter_type") + add("vars[meta_query][0][value]", "manga") + } + + add("vars[s]", query) + + var metaQueryIdx = if (filterNonMangaItems) 1 else 0 + var taxQueryIdx = 0 + val genres = filters.filterIsInstance().firstOrNull()?.state + ?.filter { it.state } + ?.map { it.id } + .orEmpty() + + filters.forEach { filter -> + when (filter) { + is AuthorFilter -> { + if (filter.state.isNotBlank()) { + add("vars[tax_query][$taxQueryIdx][taxonomy]", "wp-manga-author") + add("vars[tax_query][$taxQueryIdx][field]", "name") + add("vars[tax_query][$taxQueryIdx][terms]", filter.state) + + taxQueryIdx++ + } + } + is ArtistFilter -> { + if (filter.state.isNotBlank()) { + add("vars[tax_query][$taxQueryIdx][taxonomy]", "wp-manga-artist") + add("vars[tax_query][$taxQueryIdx][field]", "name") + add("vars[tax_query][$taxQueryIdx][terms]", filter.state) + + taxQueryIdx++ + } + } + is YearFilter -> { + if (filter.state.isNotBlank()) { + add("vars[tax_query][$taxQueryIdx][taxonomy]", "wp-manga-release") + add("vars[tax_query][$taxQueryIdx][field]", "name") + add("vars[tax_query][$taxQueryIdx][terms]", filter.state) + + taxQueryIdx++ + } + } + is StatusFilter -> { + val statuses = filter.state + .filter { it.state } + .map { it.id } + + if (statuses.isNotEmpty()) { + add("vars[meta_query][$metaQueryIdx][key]", "_wp_manga_status") + + statuses.forEachIndexed { i, slug -> + add("vars[meta_query][$metaQueryIdx][value][$i]", slug) + } + + metaQueryIdx++ + } + } + is OrderByFilter -> { + if (filter.state != 0) { + when (filter.toUriPart()) { + "latest" -> { + add("vars[orderby]", "meta_value_num") + add("vars[order]", "DESC") + add("vars[meta_key]", "_latest_update") + } + "alphabet" -> { + add("vars[orderby]", "post_title") + add("vars[order]", "ASC") + } + "rating" -> { + add("vars[orderby][query_average_reviews]", "DESC") + add("vars[orderby][query_total_reviews]", "DESC") + } + "trending" -> { + add("vars[orderby]", "meta_value_num") + add("vars[meta_key]", "_wp_manga_week_views_value") + add("vars[order]", "DESC") + } + "views" -> { + add("vars[orderby]", "meta_value_num") + add("vars[meta_key]", "_wp_manga_views") + add("vars[order]", "DESC") + } + else -> { + add("vars[orderby]", "date") + add("vars[order]", "DESC") + } + } + } + } + is AdultContentFilter -> { + if (filter.state != 0) { + add("vars[meta_query][$metaQueryIdx][key]", "manga_adult_content") + add( + "vars[meta_query][$metaQueryIdx][compare]", + if (filter.state == 1) "not exists" else "exists", + ) + + metaQueryIdx++ + } + } + is GenreConditionFilter -> { + if (filter.state == 1 && genres.isNotEmpty()) { + add("vars[tax_query][$taxQueryIdx][operation]", "AND") + } + } + is GenreList -> { + if (genres.isNotEmpty()) { + add("vars[tax_query][$taxQueryIdx][taxonomy]", "wp-manga-genre") + add("vars[tax_query][$taxQueryIdx][field]", "slug") + + genres.forEachIndexed { i, slug -> + add("vars[tax_query][$taxQueryIdx][terms][$i]", slug) + } + + taxQueryIdx++ + } + } + else -> {} + } + } + }.build() + + return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, formBody) } - protected open val artistFilterTitle: String = when (lang) { - "pt-BR" -> "Artista" - else -> "Artist" - } + protected open val statusFilterOptions: Map = + mapOf( + intl["status_filter_completed"] to "end", + intl["status_filter_ongoing"] to "on-going", + intl["status_filter_canceled"] to "canceled", + intl["status_filter_on_hold"] to "on-hold", + ) - protected open val yearFilterTitle: String = when (lang) { - "pt-BR" -> "Ano de lançamento" - else -> "Year of Released" - } - - protected open val statusFilterTitle: String = when (lang) { - "pt-BR" -> "Estado" - else -> "Status" - } - - protected open val statusFilterOptions: Array = when (lang) { - "pt-BR" -> arrayOf("Completo", "Em andamento", "Cancelado", "Pausado") - else -> arrayOf("Completed", "Ongoing", "Canceled", "On Hold") - } - - protected open val statusFilterOptionsValues: Array = arrayOf( - "end", - "on-going", - "canceled", - "on-hold", + protected open val orderByFilterOptions: Map = mapOf( + intl["order_by_filter_relevance"] to "", + intl["order_by_filter_latest"] to "latest", + intl["order_by_filter_az"] to "alphabet", + intl["order_by_filter_rating"] to "rating", + intl["order_by_filter_trending"] to "trending", + intl["order_by_filter_views"] to "views", + intl["order_by_filter_new"] to "new-manga", ) - protected open val orderByFilterTitle: String = when (lang) { - "pt-BR" -> "Ordenar por" - else -> "Order By" - } - - protected open val orderByFilterOptions: Array = when (lang) { - "pt-BR" -> arrayOf( - "Relevância", - "Recentes", - "A-Z", - "Avaliação", - "Tendência", - "Visualizações", - "Novos", + protected open val genreConditionFilterOptions: Array = + arrayOf( + intl["genre_condition_filter_or"], + intl["genre_condition_filter_and"], ) - else -> arrayOf( - "Relevance", - "Latest", - "A-Z", - "Rating", - "Trending", - "Most Views", - "New", + + protected open val adultContentFilterOptions: Array = + arrayOf( + intl["adult_content_filter_all"], + intl["adult_content_filter_none"], + intl["adult_content_filter_only"], ) + + open class UriPartFilter(displayName: String, private val vals: Array>, state: Int = 0) : + Filter.Select(displayName, vals.map { it.first }.toTypedArray(), state) { + fun toUriPart() = vals[state].second } - protected open val orderByFilterOptionsValues: Array = arrayOf( - "", - "latest", - "alphabet", - "rating", - "trending", - "views", - "new-manga", - ) - - protected open val genreConditionFilterTitle: String = when (lang) { - "pt-BR" -> "Operador dos gêneros" - else -> "Genre condition" - } - - protected open val genreConditionFilterOptions: Array = when (lang) { - "pt-BR" -> arrayOf("OU", "E") - else -> arrayOf("OR", "AND") - } - - protected open val adultContentFilterTitle: String = when (lang) { - "pt-BR" -> "Conteúdo adulto" - else -> "Adult Content" - } - - protected open val adultContentFilterOptions: Array = when (lang) { - "pt-BR" -> arrayOf("Indiferente", "Nenhum", "Somente") - else -> arrayOf("All", "None", "Only") - } - - protected open val genreFilterHeader: String = when (lang) { - "pt-BR" -> "O filtro de gêneros pode não funcionar" - else -> "Genres filter may not work for all sources" - } - - protected open val genreFilterTitle: String = when (lang) { - "pt-BR" -> "Gêneros" - else -> "Genres" - } - - protected open val genresMissingWarning: String = when (lang) { - "pt-BR" -> "Aperte 'Redefinir' para tentar mostrar os gêneros" - else -> "Press 'Reset' to attempt to show the genres" - } + open class Tag(val id: String, name: String) : Filter.CheckBox(name) protected class AuthorFilter(title: String) : Filter.Text(title) protected class ArtistFilter(title: String) : Filter.Text(title) @@ -386,50 +519,60 @@ abstract class Madara( class Genre(name: String, val id: String = name) : Filter.CheckBox(name) override fun getFilterList(): FilterList { + launchIO { fetchGenres() } + val filters = mutableListOf( - AuthorFilter(authorFilterTitle), - ArtistFilter(artistFilterTitle), - YearFilter(yearFilterTitle), - StatusFilter(statusFilterTitle, getStatusList()), + AuthorFilter(intl["author_filter_title"]), + ArtistFilter(intl["artist_filter_title"]), + YearFilter(intl["year_filter_title"]), + StatusFilter( + title = intl["status_filter_title"], + status = statusFilterOptions.map { Tag(it.key, it.value) }, + ), OrderByFilter( - title = orderByFilterTitle, - options = orderByFilterOptions.zip(orderByFilterOptionsValues), + title = intl["order_by_filter_title"], + options = orderByFilterOptions.map { Pair(it.key, it.value) }, state = 0, ), - AdultContentFilter(adultContentFilterTitle, adultContentFilterOptions), + AdultContentFilter( + title = intl["adult_content_filter_title"], + options = adultContentFilterOptions, + ), ) if (genresList.isNotEmpty()) { filters += listOf( Filter.Separator(), - Filter.Header(genreFilterHeader), - GenreConditionFilter(genreConditionFilterTitle, genreConditionFilterOptions), - GenreList(genreFilterTitle, genresList), + Filter.Header(intl["genre_filter_header"]), + GenreConditionFilter( + title = intl["genre_condition_filter_title"], + options = genreConditionFilterOptions, + ), + GenreList( + title = intl["genre_filter_title"], + genres = genresList, + ), ) } else if (fetchGenres) { filters += listOf( Filter.Separator(), - Filter.Header(genresMissingWarning), + Filter.Header(intl["genre_missing_warning"]), ) } return FilterList(filters) } - protected fun getStatusList() = statusFilterOptionsValues - .zip(statusFilterOptions) - .map { Tag(it.first, it.second) } - - open class UriPartFilter(displayName: String, private val vals: Array>, state: Int = 0) : - Filter.Select(displayName, vals.map { it.first }.toTypedArray(), state) { - fun toUriPart() = vals[state].second - } - - open class Tag(val id: String, name: String) : Filter.CheckBox(name) - override fun searchMangaParse(response: Response): MangasPage { - runCatching { fetchGenres() } - return super.searchMangaParse(response) + val document = response.asJsoup() + + val entries = document.select(searchMangaSelector()) + .map(::searchMangaFromElement) + val hasNextPage = searchMangaNextPageSelector()?.let { document.selectFirst(it) } != null + + detectLoadMore(document) + + return MangasPage(entries, hasNextPage) } override fun searchMangaSelector() = "div.c-tabs-item__content" @@ -438,11 +581,11 @@ abstract class Madara( val manga = SManga.create() with(element) { - select("div.post-title a").first()?.let { + selectFirst("div.post-title a")!!.let { manga.setUrlWithoutDomain(it.attr("abs:href")) manga.title = it.ownText() } - select("img").first()?.let { + selectFirst("img")?.let { manga.thumbnail_url = imageFromElement(it) } } @@ -450,7 +593,7 @@ abstract class Madara( return manga } - override fun searchMangaNextPageSelector(): String? = "div.nav-previous, nav.navigation-ajax, a.nextpostslink" + override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() // Manga Details Parse @@ -493,9 +636,7 @@ abstract class Madara( override fun mangaDetailsParse(document: Document): SManga { val manga = SManga.create() with(document) { - select(mangaDetailsSelectorTitle).first()?.let { - manga.title = it.ownText() - } + manga.title = selectFirst(mangaDetailsSelectorTitle)!!.ownText() select(mangaDetailsSelectorAuthor).eachText().filter { it.notUpdating() }.joinToString().takeIf { it.isNotBlank() }?.let { @@ -515,7 +656,7 @@ abstract class Madara( manga.description = it.text() } } - select(mangaDetailsSelectorThumbnail).first()?.let { + selectFirst(mangaDetailsSelectorThumbnail)?.let { manga.thumbnail_url = imageFromElement(it) } select(mangaDetailsSelectorStatus).last()?.let { @@ -533,13 +674,6 @@ abstract class Madara( .map { element -> element.text().lowercase(Locale.ROOT) } .toMutableSet() - // add tag(s) to genre - val mangaTitle = try { - manga.title - } catch (_: UninitializedPropertyAccessException) { - "not initialized" - } - if (mangaDetailsSelectorTag.isNotEmpty()) { select(mangaDetailsSelectorTag).forEach { element -> if (genres.contains(element.text()).not() && @@ -547,7 +681,7 @@ abstract class Madara( element.text().contains("read", true).not() && element.text().contains(name, true).not() && element.text().contains(name.replace(" ", ""), true).not() && - element.text().contains(mangaTitle, true).not() && + element.text().contains(manga.title, true).not() && element.text().contains(altName, true).not() ) { genres.add(element.text().lowercase(Locale.ROOT)) @@ -556,13 +690,13 @@ abstract class Madara( } // add manga/manhwa/manhua thinggy to genre - document.select(seriesTypeSelector).firstOrNull()?.ownText()?.let { + document.selectFirst(seriesTypeSelector)?.ownText()?.let { if (it.isEmpty().not() && it.notUpdating() && it != "-" && genres.contains(it).not()) { genres.add(it.lowercase(Locale.ROOT)) } } - manga.genre = genres.toList().joinToString(", ") { genre -> + manga.genre = genres.toList().joinToString { genre -> genre.replaceFirstChar { if (it.isLowerCase()) { it.titlecase( @@ -575,7 +709,7 @@ abstract class Madara( } // add alternative name to manga description - document.select(altNameSelector).firstOrNull()?.ownText()?.let { + document.selectFirst(altNameSelector)?.ownText()?.let { if (it.isBlank().not() && it.notUpdating()) { manga.description = when { manga.description.isNullOrBlank() -> altName + it @@ -600,17 +734,14 @@ abstract class Madara( open val seriesTypeSelector = ".post-content_item:contains(Type) .summary-content" open val altNameSelector = ".post-content_item:contains(Alt) .summary-content" - open val altName = when (lang) { - "pt-BR" -> "Nomes alternativos: " - else -> "Alternative Names: " - } + open val altName = intl["alt_names_heading"] open val updatingRegex = "Updating|Atualizando".toRegex(RegexOption.IGNORE_CASE) fun String.notUpdating(): Boolean { return this.contains(updatingRegex).not() } - fun String.containsIn(array: Array): Boolean { + private fun String.containsIn(array: Array): Boolean { return this.lowercase() in array.map { it.lowercase() } } @@ -644,25 +775,18 @@ abstract class Madara( .add("manga", mangaId) .build() - val xhrHeaders = headersBuilder() - .add("Content-Length", form.contentLength().toString()) - .add("Content-Type", form.contentType().toString()) - .add("X-Requested-With", "XMLHttpRequest") - .build() - return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, form) } protected open fun xhrChaptersRequest(mangaUrl: String): Request { - val xhrHeaders = headersBuilder() - .add("X-Requested-With", "XMLHttpRequest") - .build() - return POST("$mangaUrl/ajax/chapters", xhrHeaders) } override fun chapterListParse(response: Response): List { val document = response.asJsoup() + + launchIO { countViews(document) } + val chaptersWrapper = document.select("div[id^=manga-chapters-holder]") var chapterElements = document.select(chapterListSelector()) @@ -692,8 +816,6 @@ abstract class Madara( xhrResponse.close() } - countViews(document) - return chapterElements.map(::chapterFromElement) } @@ -710,7 +832,7 @@ abstract class Madara( val chapter = SChapter.create() with(element) { - select(chapterUrlSelector).first()?.let { urlElement -> + selectFirst(chapterUrlSelector)!!.let { urlElement -> chapter.url = urlElement.attr("abs:href").let { it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else "" } @@ -718,9 +840,9 @@ abstract class Madara( } // Dates can be part of a "new" graphic or plain text // Added "title" alternative - chapter.date_upload = select("img:not(.thumb)").firstOrNull()?.attr("alt")?.let { parseRelativeDate(it) } - ?: select("span a").firstOrNull()?.attr("title")?.let { parseRelativeDate(it) } - ?: parseChapterDate(select(chapterDateSelector()).firstOrNull()?.text()) + chapter.date_upload = selectFirst("img:not(.thumb)")?.attr("alt")?.let { parseRelativeDate(it) } + ?: selectFirst("span a")?.attr("title")?.let { parseRelativeDate(it) } + ?: parseChapterDate(selectFirst(chapterDateSelector())?.text()) } return chapter @@ -816,7 +938,7 @@ abstract class Madara( open val chapterProtectorSelector = "#chapter-protector-data" override fun pageListParse(document: Document): List { - countViews(document) + launchIO { countViews(document) } val chapterProtector = document.selectFirst(chapterProtectorSelector) ?: return document.select(pageListParseSelector).mapIndexed { index, element -> @@ -836,7 +958,7 @@ abstract class Madara( val unsaltedCiphertext = Base64.decode(chapterData["ct"]!!.jsonPrimitive.content, Base64.DEFAULT) val salt = chapterData["s"]!!.jsonPrimitive.content.decodeHex() - val ciphertext = SALTED + salt + unsaltedCiphertext + val ciphertext = salted + salt + unsaltedCiphertext val rawImgArray = CryptoAES.decrypt(Base64.encodeToString(ciphertext, Base64.DEFAULT), password) val imgArrayString = json.parseToJsonElement(rawImgArray).jsonPrimitive.content @@ -860,7 +982,7 @@ abstract class Madara( protected open val sendViewCount: Boolean = true protected open fun countViewsRequest(document: Document): Request? { - val wpMangaData = document.select("script#wp-manga-js-extra").firstOrNull() + val wpMangaData = document.selectFirst("script#wp-manga-js-extra") ?.data() ?: return null val wpMangaInfo = wpMangaData @@ -882,8 +1004,6 @@ abstract class Madara( val formBody = formBuilder.build() val newHeaders = headersBuilder() - .set("Content-Length", formBody.contentLength().toString()) - .set("Content-Type", formBody.contentType().toString()) .set("Referer", document.location()) .build() @@ -912,16 +1032,15 @@ abstract class Madara( /** * Fetch the genres from the source to be used in the filters. */ - protected open fun fetchGenres() { - if (fetchGenres && fetchGenresAttempts <= 3 && (genresList.isEmpty() || fetchGenresFailed)) { - val genres = runCatching { - client.newCall(genresRequest()).execute() + protected fun fetchGenres() { + if (fetchGenres && fetchGenresAttempts < 3 && genresList.isEmpty()) { + try { + genresList = client.newCall(genresRequest()).execute() .use { parseGenres(it.asJsoup()) } + } catch (_: Exception) { + } finally { + fetchGenresAttempts++ } - - fetchGenresFailed = genres.isFailure - genresList = genres.getOrNull().orEmpty() - fetchGenresAttempts++ } } @@ -950,7 +1069,7 @@ abstract class Madara( } // https://stackoverflow.com/a/66614516 - private fun String.decodeHex(): ByteArray { + protected fun String.decodeHex(): ByteArray { check(length % 2 == 0) { "Must have an even length" } return chunked(2) @@ -958,13 +1077,14 @@ abstract class Madara( .toByteArray() } - override fun setupPreferenceScreen(screen: PreferenceScreen) { - addRandomUAPreferenceToScreen(screen) - } + protected val salted = "Salted__".toByteArray(Charsets.UTF_8) + + private val scope = CoroutineScope(Dispatchers.IO) + + protected fun launchIO(block: () -> Unit) = scope.launch { block() } companion object { const val URL_SEARCH_PREFIX = "slug:" - val SALTED = "Salted__".toByteArray(Charsets.UTF_8) } } diff --git a/src/all/comicznetv2/src/eu/kanade/tachiyomi/extension/all/comicznetv2/ComiczNetV2.kt b/src/all/comicznetv2/src/eu/kanade/tachiyomi/extension/all/comicznetv2/ComiczNetV2.kt index c04d7bf89..de9f5e50e 100644 --- a/src/all/comicznetv2/src/eu/kanade/tachiyomi/extension/all/comicznetv2/ComiczNetV2.kt +++ b/src/all/comicznetv2/src/eu/kanade/tachiyomi/extension/all/comicznetv2/ComiczNetV2.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class ComiczNetV2 : Madara("Comicz.net v2", "https://v2.comiz.net", "all") { override val useNewChapterEndpoint = false - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/all/grabberzone/src/eu/kanade/tachiyomi/extension/all/grabberzone/GrabberZone.kt b/src/all/grabberzone/src/eu/kanade/tachiyomi/extension/all/grabberzone/GrabberZone.kt index 98a3b3502..04fdbaaf4 100644 --- a/src/all/grabberzone/src/eu/kanade/tachiyomi/extension/all/grabberzone/GrabberZone.kt +++ b/src/all/grabberzone/src/eu/kanade/tachiyomi/extension/all/grabberzone/GrabberZone.kt @@ -14,14 +14,6 @@ class GrabberZone : Madara( ) { override val mangaSubString = "comics" - override fun searchPage(page: Int): String { - return if (page > 1) { - "page/$page/" - } else { - "" - } - } - override fun chapterFromElement(element: Element): SChapter { return super.chapterFromElement(element).apply { name = element.selectFirst("a + a")!!.text() diff --git a/src/all/mangacrazy/src/eu/kanade/tachiyomi/extension/all/mangacrazy/MangaCrazy.kt b/src/all/mangacrazy/src/eu/kanade/tachiyomi/extension/all/mangacrazy/MangaCrazy.kt index c9fbab93f..09fecc3b4 100644 --- a/src/all/mangacrazy/src/eu/kanade/tachiyomi/extension/all/mangacrazy/MangaCrazy.kt +++ b/src/all/mangacrazy/src/eu/kanade/tachiyomi/extension/all/mangacrazy/MangaCrazy.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class MangaCrazy : Madara("MangaCrazy", "https://mangacrazy.net", "all") { override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/all/mangatopsite/src/eu/kanade/tachiyomi/extension/all/mangatopsite/MangaTopSite.kt b/src/all/mangatopsite/src/eu/kanade/tachiyomi/extension/all/mangatopsite/MangaTopSite.kt index 5a82c94af..ff1555c38 100644 --- a/src/all/mangatopsite/src/eu/kanade/tachiyomi/extension/all/mangatopsite/MangaTopSite.kt +++ b/src/all/mangatopsite/src/eu/kanade/tachiyomi/extension/all/mangatopsite/MangaTopSite.kt @@ -12,6 +12,4 @@ class MangaTopSite : Madara( ) { override val useNewChapterEndpoint = false override val chapterUrlSuffix = "" - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/ar/azora/src/eu/kanade/tachiyomi/extension/ar/azora/Azora.kt b/src/ar/azora/src/eu/kanade/tachiyomi/extension/ar/azora/Azora.kt index 040bf03fc..e55b7938c 100644 --- a/src/ar/azora/src/eu/kanade/tachiyomi/extension/ar/azora/Azora.kt +++ b/src/ar/azora/src/eu/kanade/tachiyomi/extension/ar/azora/Azora.kt @@ -1,16 +1,12 @@ package eu.kanade.tachiyomi.extension.ar.azora import eu.kanade.tachiyomi.multisrc.madara.Madara -import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.source.model.SChapter -import okhttp3.Request import org.jsoup.nodes.Element class Azora : Madara("Azora", "https://azoramoon.com", "ar") { override val mangaSubString = "series" override val useNewChapterEndpoint = false - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" - override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/page/$page/?m_orderby=views", headers) override fun chapterListSelector() = "li.wp-manga-chapter:not(.premium-block)" // Filter fake chapters override fun chapterFromElement(element: Element): SChapter { val chapter = SChapter.create() diff --git a/src/ar/comicarab/src/eu/kanade/tachiyomi/extension/ar/comicarab/ComicArab.kt b/src/ar/comicarab/src/eu/kanade/tachiyomi/extension/ar/comicarab/ComicArab.kt index 6dc77be66..ef6cab20e 100644 --- a/src/ar/comicarab/src/eu/kanade/tachiyomi/extension/ar/comicarab/ComicArab.kt +++ b/src/ar/comicarab/src/eu/kanade/tachiyomi/extension/ar/comicarab/ComicArab.kt @@ -9,12 +9,4 @@ class ComicArab : Madara( "https://comicarab.com", "ar", dateFormat = SimpleDateFormat("dd MMMM، yyyy", Locale("ar")), -) { - override fun searchPage(page: Int): String { - return if (page > 1) { - "page/$page/" - } else { - "" - } - } -} +) diff --git a/src/ar/empirewebtoon/src/eu/kanade/tachiyomi/extension/ar/empirewebtoon/EmpireWebtoon.kt b/src/ar/empirewebtoon/src/eu/kanade/tachiyomi/extension/ar/empirewebtoon/EmpireWebtoon.kt index 01c672433..f640172ac 100644 --- a/src/ar/empirewebtoon/src/eu/kanade/tachiyomi/extension/ar/empirewebtoon/EmpireWebtoon.kt +++ b/src/ar/empirewebtoon/src/eu/kanade/tachiyomi/extension/ar/empirewebtoon/EmpireWebtoon.kt @@ -6,17 +6,20 @@ import android.widget.Toast import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.extension.BuildConfig import eu.kanade.tachiyomi.multisrc.madara.Madara +import eu.kanade.tachiyomi.source.ConfigurableSource import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.text.SimpleDateFormat import java.util.Locale -class EmpireWebtoon : Madara( - "Empire Webtoon", - "https://webtoonsempireron.com", - "ar", - SimpleDateFormat("d MMMM، yyyy", Locale("ar")), -) { +class EmpireWebtoon : + Madara( + "Empire Webtoon", + "https://webtoonsempireron.com", + "ar", + SimpleDateFormat("d MMMM، yyyy", Locale("ar")), + ), + ConfigurableSource { private val defaultBaseUrl = "https://webtoonsempireron.com" @@ -30,8 +33,6 @@ class EmpireWebtoon : Madara( override val useNewChapterEndpoint = false - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" - companion object { private const val RESTART_TACHIYOMI = "Restart Tachiyomi to apply new setting." private const val BASE_URL_PREF_TITLE = "Override BaseUrl" @@ -53,8 +54,6 @@ class EmpireWebtoon : Madara( } } screen.addPreference(baseUrlPref) - - super.setupPreferenceScreen(screen) } private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!! diff --git a/src/ar/mangalek/src/eu/kanade/tachiyomi/extension/ar/mangalek/Mangalek.kt b/src/ar/mangalek/src/eu/kanade/tachiyomi/extension/ar/mangalek/Mangalek.kt index bc5611341..d8d589c36 100644 --- a/src/ar/mangalek/src/eu/kanade/tachiyomi/extension/ar/mangalek/Mangalek.kt +++ b/src/ar/mangalek/src/eu/kanade/tachiyomi/extension/ar/mangalek/Mangalek.kt @@ -6,14 +6,13 @@ import android.widget.Toast import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.extension.BuildConfig import eu.kanade.tachiyomi.multisrc.madara.Madara -import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString -import okhttp3.CacheControl import okhttp3.FormBody import okhttp3.Request import okhttp3.Response @@ -22,7 +21,16 @@ import uy.kohesive.injekt.api.get import java.text.SimpleDateFormat import java.util.Locale -class Mangalek : Madara("مانجا ليك", "https://manga-lek.net", "ar", SimpleDateFormat("MMMM dd, yyyy", Locale("ar"))) { +class Mangalek : + Madara( + "مانجا ليك", + "https://manga-lek.net", + "ar", + SimpleDateFormat("MMMM dd, yyyy", Locale("ar")), + ), + ConfigurableSource { + + override val fetchGenres = false override val chapterUrlSuffix = "" @@ -55,22 +63,10 @@ class Mangalek : Madara("مانجا ليك", "https://manga-lek.net", "ar", Simp } } screen.addPreference(baseUrlPref) - - super.setupPreferenceScreen(screen) } private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!! - override fun popularMangaRequest(page: Int): Request { - return GET( - url = "$baseUrl/$mangaSubString/${searchPage(page)}", - headers = headers, - cache = CacheControl.FORCE_NETWORK, - ) - } - - override fun latestUpdatesRequest(page: Int): Request = popularMangaRequest(page) - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = POST( "$baseUrl/wp-admin/admin-ajax.php", diff --git a/src/ar/mangalink/src/eu/kanade/tachiyomi/extension/ar/mangalink/Mangalink.kt b/src/ar/mangalink/src/eu/kanade/tachiyomi/extension/ar/mangalink/Mangalink.kt index c123bc0ce..00a0e05be 100644 --- a/src/ar/mangalink/src/eu/kanade/tachiyomi/extension/ar/mangalink/Mangalink.kt +++ b/src/ar/mangalink/src/eu/kanade/tachiyomi/extension/ar/mangalink/Mangalink.kt @@ -6,12 +6,20 @@ import android.widget.Toast import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.extension.BuildConfig import eu.kanade.tachiyomi.multisrc.madara.Madara +import eu.kanade.tachiyomi.source.ConfigurableSource import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.text.SimpleDateFormat import java.util.Locale -class Mangalink : Madara("مانجا لينك", "https://manga-link.com", "ar", SimpleDateFormat("MMMM dd, yyyy", Locale("ar"))) { +class Mangalink : + Madara( + "مانجا لينك", + "https://manga-link.com", + "ar", + SimpleDateFormat("MMMM dd, yyyy", Locale("ar")), + ), + ConfigurableSource { override val chapterUrlSuffix = "" @@ -44,8 +52,6 @@ class Mangalink : Madara("مانجا لينك", "https://manga-link.com", "ar", } } screen.addPreference(baseUrlPref) - - super.setupPreferenceScreen(screen) } private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!! } diff --git a/src/ar/mangalionz/src/eu/kanade/tachiyomi/extension/ar/mangalionz/MangaLionz.kt b/src/ar/mangalionz/src/eu/kanade/tachiyomi/extension/ar/mangalionz/MangaLionz.kt index 908bedc82..36a6cbbcc 100644 --- a/src/ar/mangalionz/src/eu/kanade/tachiyomi/extension/ar/mangalionz/MangaLionz.kt +++ b/src/ar/mangalionz/src/eu/kanade/tachiyomi/extension/ar/mangalionz/MangaLionz.kt @@ -9,12 +9,12 @@ class MangaLionz : Madara("MangaLionz", "https://mangalionz.org", "ar") { val manga = SManga.create() with(element) { - select(popularMangaUrlSelector).first()?.let { + selectFirst(popularMangaUrlSelector)!!.let { manga.setUrlWithoutDomain(it.attr("abs:href")) manga.title = it.ownText() } - select("img").first()?.let { + selectFirst("img")?.let { manga.thumbnail_url = imageFromElement(it)?.replace("mangalionz", "mangalek") } } diff --git a/src/ar/mangarose/src/eu/kanade/tachiyomi/extension/ar/mangarose/MangaRose.kt b/src/ar/mangarose/src/eu/kanade/tachiyomi/extension/ar/mangarose/MangaRose.kt index f6a988470..846d9ee5c 100644 --- a/src/ar/mangarose/src/eu/kanade/tachiyomi/extension/ar/mangarose/MangaRose.kt +++ b/src/ar/mangarose/src/eu/kanade/tachiyomi/extension/ar/mangarose/MangaRose.kt @@ -9,12 +9,4 @@ class MangaRose : Madara( "https://mangarose.net", "ar", dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")), -) { - override fun searchPage(page: Int): String { - return if (page > 1) { - "page/$page/" - } else { - "" - } - } -} +) diff --git a/src/ar/mangaspark/src/eu/kanade/tachiyomi/extension/ar/mangaspark/MangaSpark.kt b/src/ar/mangaspark/src/eu/kanade/tachiyomi/extension/ar/mangaspark/MangaSpark.kt index e35aaa4b0..c909ea6db 100644 --- a/src/ar/mangaspark/src/eu/kanade/tachiyomi/extension/ar/mangaspark/MangaSpark.kt +++ b/src/ar/mangaspark/src/eu/kanade/tachiyomi/extension/ar/mangaspark/MangaSpark.kt @@ -13,6 +13,4 @@ class MangaSpark : Madara( override val chapterUrlSuffix = "" override val useNewChapterEndpoint = false - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/ar/mangastarz/src/eu/kanade/tachiyomi/extension/ar/mangastarz/MangaStarz.kt b/src/ar/mangastarz/src/eu/kanade/tachiyomi/extension/ar/mangastarz/MangaStarz.kt index 4001e5888..433401911 100644 --- a/src/ar/mangastarz/src/eu/kanade/tachiyomi/extension/ar/mangastarz/MangaStarz.kt +++ b/src/ar/mangastarz/src/eu/kanade/tachiyomi/extension/ar/mangastarz/MangaStarz.kt @@ -13,6 +13,4 @@ class MangaStarz : Madara( override val chapterUrlSuffix = "" override val useNewChapterEndpoint = false - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/allporncomic/src/eu/kanade/tachiyomi/extension/en/allporncomic/AllPornComic.kt b/src/en/allporncomic/src/eu/kanade/tachiyomi/extension/en/allporncomic/AllPornComic.kt index 5b5e54767..971057270 100644 --- a/src/en/allporncomic/src/eu/kanade/tachiyomi/extension/en/allporncomic/AllPornComic.kt +++ b/src/en/allporncomic/src/eu/kanade/tachiyomi/extension/en/allporncomic/AllPornComic.kt @@ -1,11 +1,5 @@ package eu.kanade.tachiyomi.extension.en.allporncomic import eu.kanade.tachiyomi.multisrc.madara.Madara -import eu.kanade.tachiyomi.network.GET -import okhttp3.Request -class AllPornComic : Madara("AllPornComic", "https://allporncomic.com", "en") { - override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/manga/page/$page/?m_orderby=views", headers) - override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/manga/page/$page/?m_orderby=latest", headers) - override fun searchMangaNextPageSelector() = "a[rel=next]" -} +class AllPornComic : Madara("AllPornComic", "https://allporncomic.com", "en") diff --git a/src/en/aquamanga/src/eu/kanade/tachiyomi/extension/en/aquamanga/AquaManga.kt b/src/en/aquamanga/src/eu/kanade/tachiyomi/extension/en/aquamanga/AquaManga.kt index 3304e6eb9..992b0e248 100644 --- a/src/en/aquamanga/src/eu/kanade/tachiyomi/extension/en/aquamanga/AquaManga.kt +++ b/src/en/aquamanga/src/eu/kanade/tachiyomi/extension/en/aquamanga/AquaManga.kt @@ -8,8 +8,6 @@ import kotlin.random.Random class AquaManga : Madara("Aqua Manga", "https://aquamanga.org", "en") { override val useNewChapterEndpoint = false - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" - override fun headersBuilder(): Headers.Builder = super.headersBuilder() .add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") .add("Accept-Language", "en-US,en;q=0.5") diff --git a/src/en/asurascansus/src/eu/kanade/tachiyomi/extension/en/asurascansus/AsuraScansUs.kt b/src/en/asurascansus/src/eu/kanade/tachiyomi/extension/en/asurascansus/AsuraScansUs.kt index 5e1b63b87..4d565615a 100644 --- a/src/en/asurascansus/src/eu/kanade/tachiyomi/extension/en/asurascansus/AsuraScansUs.kt +++ b/src/en/asurascansus/src/eu/kanade/tachiyomi/extension/en/asurascansus/AsuraScansUs.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class AsuraScansUs : Madara("Asura Scans.us (unoriginal)", "https://asurascans.us", "en") { override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/babelwuxia/src/eu/kanade/tachiyomi/extension/en/babelwuxia/BabelWuxia.kt b/src/en/babelwuxia/src/eu/kanade/tachiyomi/extension/en/babelwuxia/BabelWuxia.kt index 832949a70..e169f23b1 100644 --- a/src/en/babelwuxia/src/eu/kanade/tachiyomi/extension/en/babelwuxia/BabelWuxia.kt +++ b/src/en/babelwuxia/src/eu/kanade/tachiyomi/extension/en/babelwuxia/BabelWuxia.kt @@ -1,37 +1,11 @@ package eu.kanade.tachiyomi.extension.en.babelwuxia import eu.kanade.tachiyomi.multisrc.madara.Madara -import eu.kanade.tachiyomi.source.model.MangasPage -import okhttp3.Response class BabelWuxia : Madara("Babel Wuxia", "https://babelwuxia.com", "en") { // moved from MangaThemesia override val versionId = 2 override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String { - return if (page > 1) { - "page/$page/" - } else { - "" - } - } - - override fun popularMangaParse(response: Response) = - super.popularMangaParse(response).fixNextPage() - - override fun latestUpdatesParse(response: Response) = - super.latestUpdatesParse(response).fixNextPage() - - override fun searchMangaParse(response: Response) = - super.searchMangaParse(response).fixNextPage() - - private fun MangasPage.fixNextPage(): MangasPage { - return if (mangas.size < 12) { - MangasPage(mangas, false) - } else { - this - } - } + override val useLoadMoreRequest = LoadMoreStrategy.Always } diff --git a/src/en/bananamanga/src/eu/kanade/tachiyomi/extension/en/bananamanga/BananaManga.kt b/src/en/bananamanga/src/eu/kanade/tachiyomi/extension/en/bananamanga/BananaManga.kt index dcadac1e9..014827502 100644 --- a/src/en/bananamanga/src/eu/kanade/tachiyomi/extension/en/bananamanga/BananaManga.kt +++ b/src/en/bananamanga/src/eu/kanade/tachiyomi/extension/en/bananamanga/BananaManga.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class BananaManga : Madara("Banana Manga", "https://bananamanga.net", "en") { override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/coffeemanga/src/eu/kanade/tachiyomi/extension/en/coffeemanga/CoffeeManga.kt b/src/en/coffeemanga/src/eu/kanade/tachiyomi/extension/en/coffeemanga/CoffeeManga.kt index dd652e198..4e82b4f33 100644 --- a/src/en/coffeemanga/src/eu/kanade/tachiyomi/extension/en/coffeemanga/CoffeeManga.kt +++ b/src/en/coffeemanga/src/eu/kanade/tachiyomi/extension/en/coffeemanga/CoffeeManga.kt @@ -6,8 +6,6 @@ import org.jsoup.nodes.Element class CoffeeManga : Madara("Coffee Manga", "https://coffeemanga.io", "en") { override val useNewChapterEndpoint = false - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" - override fun imageFromElement(element: Element): String? { return when { element.hasAttr("data-src") && element.attr("data-src").isNotEmpty() -> element.attr("abs:data-src") diff --git a/src/en/coloredmanga/src/eu/kanade/tachiyomi/extension/en/coloredmanga/ColoredManga.kt b/src/en/coloredmanga/src/eu/kanade/tachiyomi/extension/en/coloredmanga/ColoredManga.kt index be16c5d06..488c654b3 100644 --- a/src/en/coloredmanga/src/eu/kanade/tachiyomi/extension/en/coloredmanga/ColoredManga.kt +++ b/src/en/coloredmanga/src/eu/kanade/tachiyomi/extension/en/coloredmanga/ColoredManga.kt @@ -11,6 +11,4 @@ class ColoredManga : Madara( dateFormat = SimpleDateFormat("dd-MMM", Locale.ENGLISH), ) { override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/comicscans/src/eu/kanade/tachiyomi/extension/en/comicscans/ComicScans.kt b/src/en/comicscans/src/eu/kanade/tachiyomi/extension/en/comicscans/ComicScans.kt index 910b11d70..4203ed248 100644 --- a/src/en/comicscans/src/eu/kanade/tachiyomi/extension/en/comicscans/ComicScans.kt +++ b/src/en/comicscans/src/eu/kanade/tachiyomi/extension/en/comicscans/ComicScans.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class ComicScans : Madara("Comic Scans", "https://www.comicscans.org", "en") { override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/creepyscans/src/eu/kanade/tachiyomi/extension/en/creepyscans/CreepyScans.kt b/src/en/creepyscans/src/eu/kanade/tachiyomi/extension/en/creepyscans/CreepyScans.kt index 7289de59c..4836d793e 100644 --- a/src/en/creepyscans/src/eu/kanade/tachiyomi/extension/en/creepyscans/CreepyScans.kt +++ b/src/en/creepyscans/src/eu/kanade/tachiyomi/extension/en/creepyscans/CreepyScans.kt @@ -14,7 +14,6 @@ import kotlinx.serialization.json.boolean import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive -import okhttp3.CacheControl import okhttp3.FormBody import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient @@ -35,26 +34,6 @@ class CreepyScans : Madara( override val useNewChapterEndpoint = true - // Popular - - override fun popularMangaRequest(page: Int): Request { - return GET( - url = "$baseUrl/$mangaSubString/?m_orderby=views", - headers = headers, - cache = CacheControl.FORCE_NETWORK, - ) - } - - // Latest - - override fun latestUpdatesRequest(page: Int): Request { - return GET( - url = "$baseUrl/$mangaSubString/?m_orderby=latest", - headers = headers, - cache = CacheControl.FORCE_NETWORK, - ) - } - // Search override fun fetchSearchManga( @@ -142,11 +121,13 @@ class CreepyScans : Madara( Filter.Select("Genre", vals.map { it.first }.toTypedArray()) override fun getFilterList(): FilterList { + launchIO { fetchGenres() } + val filters = buildList(4) { add( OrderByFilter( - title = orderByFilterTitle, - options = orderByFilterOptions.zip(orderByFilterOptionsValues), + title = intl["order_by_filter_title"], + options = orderByFilterOptions.map { Pair(it.key, it.value) }, state = 0, ), ) diff --git a/src/en/darkscan/src/eu/kanade/tachiyomi/extension/en/darkscan/DarkScan.kt b/src/en/darkscan/src/eu/kanade/tachiyomi/extension/en/darkscan/DarkScan.kt index 3c890e1ed..cf2a260a7 100644 --- a/src/en/darkscan/src/eu/kanade/tachiyomi/extension/en/darkscan/DarkScan.kt +++ b/src/en/darkscan/src/eu/kanade/tachiyomi/extension/en/darkscan/DarkScan.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class DarkScan : Madara("Dark-scan", "https://dark-scan.com", "en") { override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/dragontea/src/eu/kanade/tachiyomi/extension/en/dragontea/DragonTea.kt b/src/en/dragontea/src/eu/kanade/tachiyomi/extension/en/dragontea/DragonTea.kt index 7632bcc59..6a3621579 100644 --- a/src/en/dragontea/src/eu/kanade/tachiyomi/extension/en/dragontea/DragonTea.kt +++ b/src/en/dragontea/src/eu/kanade/tachiyomi/extension/en/dragontea/DragonTea.kt @@ -27,14 +27,6 @@ class DragonTea : Madara( override val useNewChapterEndpoint = true - override fun searchPage(page: Int): String { - return if (page > 1) { - "page/$page/" - } else { - "" - } - } - private val pageIndexRegex = Regex("""image-(\d+)[a-z]+""", RegexOption.IGNORE_CASE) override fun pageListParse(document: Document): List { @@ -69,20 +61,8 @@ class DragonTea : Madara( val unsaltedCiphertext = Base64.decode(cipherData["ct"]!!.jsonPrimitive.content, Base64.DEFAULT) val salt = cipherData["s"]!!.jsonPrimitive.content.decodeHex() - val saltedCiphertext = SALTED + salt + unsaltedCiphertext + val saltedCiphertext = salted + salt + unsaltedCiphertext return json.parseToJsonElement(CryptoAES.decrypt(Base64.encodeToString(saltedCiphertext, Base64.DEFAULT), key)) } - - private fun String.decodeHex(): ByteArray { - check(length % 2 == 0) { "Must have an even length" } - - return chunked(2) - .map { it.toInt(16).toByte() } - .toByteArray() - } - - companion object { - private val SALTED = "Salted__".toByteArray(Charsets.UTF_8) - } } diff --git a/src/en/elitemanga/src/eu/kanade/tachiyomi/extension/en/elitemanga/EliteManga.kt b/src/en/elitemanga/src/eu/kanade/tachiyomi/extension/en/elitemanga/EliteManga.kt index 5f396483e..58bf5a868 100644 --- a/src/en/elitemanga/src/eu/kanade/tachiyomi/extension/en/elitemanga/EliteManga.kt +++ b/src/en/elitemanga/src/eu/kanade/tachiyomi/extension/en/elitemanga/EliteManga.kt @@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class EliteManga : Madara("Elite Manga", "https://www.elitemanga.org", "en") { override val useNewChapterEndpoint = true override val filterNonMangaItems = false - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/factmanga/src/eu/kanade/tachiyomi/extension/en/factmanga/FactManga.kt b/src/en/factmanga/src/eu/kanade/tachiyomi/extension/en/factmanga/FactManga.kt index af542a68e..72ec19bd9 100644 --- a/src/en/factmanga/src/eu/kanade/tachiyomi/extension/en/factmanga/FactManga.kt +++ b/src/en/factmanga/src/eu/kanade/tachiyomi/extension/en/factmanga/FactManga.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class FactManga : Madara("FactManga", "https://factmanga.com", "en") { override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/firescans/src/eu/kanade/tachiyomi/extension/en/firescans/FireScans.kt b/src/en/firescans/src/eu/kanade/tachiyomi/extension/en/firescans/FireScans.kt index a91394af4..805f83a3e 100644 --- a/src/en/firescans/src/eu/kanade/tachiyomi/extension/en/firescans/FireScans.kt +++ b/src/en/firescans/src/eu/kanade/tachiyomi/extension/en/firescans/FireScans.kt @@ -20,7 +20,7 @@ class FireScans : Madara("Fire Scans", "https://firescans.xyz", "en") { override val useNewChapterEndpoint: Boolean = true override fun pageListParse(document: Document): List { - countViews(document) + launchIO { countViews(document) } val chapterProtector = document.selectFirst(chapterProtectorSelector) ?: return document.select(pageListParseSelector).mapIndexed { index, element -> @@ -46,7 +46,7 @@ class FireScans : Madara("Fire Scans", "https://firescans.xyz", "en") { val unsaltedCiphertext = Base64.decode(chapterData["ct"]!!.jsonPrimitive.content, Base64.DEFAULT) val salt = chapterData["s"]!!.jsonPrimitive.content.decodeHex() - val ciphertext = SALTED + salt + unsaltedCiphertext + val ciphertext = salted + salt + unsaltedCiphertext val rawImgArray = CryptoAES.decrypt(Base64.encodeToString(ciphertext, Base64.DEFAULT), password) val imgArrayString = json.parseToJsonElement(rawImgArray).jsonPrimitive.content @@ -56,12 +56,4 @@ class FireScans : Madara("Fire Scans", "https://firescans.xyz", "en") { Page(idx, document.location(), it.jsonPrimitive.content) } } - - private fun String.decodeHex(): ByteArray { - check(length % 2 == 0) { "Must have an even length" } - - return chunked(2) - .map { it.toInt(16).toByte() } - .toByteArray() - } } diff --git a/src/en/firstkissdashmanga/src/eu/kanade/tachiyomi/extension/en/firstkissdashmanga/FirstKissDashManga.kt b/src/en/firstkissdashmanga/src/eu/kanade/tachiyomi/extension/en/firstkissdashmanga/FirstKissDashManga.kt index 6438932b5..c8a984264 100644 --- a/src/en/firstkissdashmanga/src/eu/kanade/tachiyomi/extension/en/firstkissdashmanga/FirstKissDashManga.kt +++ b/src/en/firstkissdashmanga/src/eu/kanade/tachiyomi/extension/en/firstkissdashmanga/FirstKissDashManga.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class FirstKissDashManga : Madara("1st Kiss-Manga (unoriginal)", "https://1stkiss-manga.com", "en") { override val useNewChapterEndpoint = false - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/firstmanhwa/src/eu/kanade/tachiyomi/extension/en/firstmanhwa/FirstManhwa.kt b/src/en/firstmanhwa/src/eu/kanade/tachiyomi/extension/en/firstmanhwa/FirstManhwa.kt index d7569cbd0..419f3f8c1 100644 --- a/src/en/firstmanhwa/src/eu/kanade/tachiyomi/extension/en/firstmanhwa/FirstManhwa.kt +++ b/src/en/firstmanhwa/src/eu/kanade/tachiyomi/extension/en/firstmanhwa/FirstManhwa.kt @@ -6,6 +6,4 @@ class FirstManhwa : Madara("1st Manhwa", "https://1stmanhwa.com", "en") { override val useNewChapterEndpoint = true override val filterNonMangaItems = false override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content" - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/freemanhwa/src/eu/kanade/tachiyomi/extension/en/freemanhwa/FreeManhwa.kt b/src/en/freemanhwa/src/eu/kanade/tachiyomi/extension/en/freemanhwa/FreeManhwa.kt index 3b86977e4..ec7b453ae 100644 --- a/src/en/freemanhwa/src/eu/kanade/tachiyomi/extension/en/freemanhwa/FreeManhwa.kt +++ b/src/en/freemanhwa/src/eu/kanade/tachiyomi/extension/en/freemanhwa/FreeManhwa.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class FreeManhwa : Madara("Free Manhwa", "https://manhwas.com", "en") { override val useNewChapterEndpoint = false - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/girlslovemanga/src/eu/kanade/tachiyomi/extension/en/girlslovemanga/GirlsLoveManga.kt b/src/en/girlslovemanga/src/eu/kanade/tachiyomi/extension/en/girlslovemanga/GirlsLoveManga.kt index 76ce55f5f..5dc30132a 100644 --- a/src/en/girlslovemanga/src/eu/kanade/tachiyomi/extension/en/girlslovemanga/GirlsLoveManga.kt +++ b/src/en/girlslovemanga/src/eu/kanade/tachiyomi/extension/en/girlslovemanga/GirlsLoveManga.kt @@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara class GirlsLoveManga : Madara("Girls Love Manga!", "https://glmanga.com", "en") { override val useNewChapterEndpoint = true - - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" } diff --git a/src/en/globalbloging/src/eu/kanade/tachiyomi/extension/en/globalbloging/GlobalBloging.kt b/src/en/globalbloging/src/eu/kanade/tachiyomi/extension/en/globalbloging/GlobalBloging.kt index 34ea81417..ad47279cf 100644 --- a/src/en/globalbloging/src/eu/kanade/tachiyomi/extension/en/globalbloging/GlobalBloging.kt +++ b/src/en/globalbloging/src/eu/kanade/tachiyomi/extension/en/globalbloging/GlobalBloging.kt @@ -12,8 +12,6 @@ class GlobalBloging : Madara( ) { override val useNewChapterEndpoint = true - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" - // =========================== Manga Details ============================ override val mangaDetailsSelectorThumbnail = "${super.mangaDetailsSelectorThumbnail}[src~=.]" diff --git a/src/en/goodgirlsscan/src/eu/kanade/tachiyomi/extension/en/goodgirlsscan/GoodGirlsScan.kt b/src/en/goodgirlsscan/src/eu/kanade/tachiyomi/extension/en/goodgirlsscan/GoodGirlsScan.kt index 0ec7c82bf..757923e42 100644 --- a/src/en/goodgirlsscan/src/eu/kanade/tachiyomi/extension/en/goodgirlsscan/GoodGirlsScan.kt +++ b/src/en/goodgirlsscan/src/eu/kanade/tachiyomi/extension/en/goodgirlsscan/GoodGirlsScan.kt @@ -2,72 +2,21 @@ package eu.kanade.tachiyomi.extension.en.goodgirlsscan import eu.kanade.tachiyomi.multisrc.madara.Madara import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.SManga -import okhttp3.FormBody import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Request import org.jsoup.nodes.Element class GoodGirlsScan : Madara("Good Girls Scan", "https://goodgirls.moe", "en") { - override val fetchGenres = false - override fun popularMangaNextPageSelector() = "body:not(:has(.no-posts))" + override val useLoadMoreRequest = LoadMoreStrategy.Always override fun searchMangaSelector() = "article.wp-manga" override fun searchMangaNextPageSelector() = "div.paginator .nav-next" override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content" override val mangaDetailsSelectorDescription = "div.summary-specialfields" override fun chapterListSelector() = "li.wp-manga-chapter:not(.vip-permission)" - private fun madaraLoadMoreRequest(page: Int, metaKey: String): Request { - val formBody = FormBody.Builder().apply { - add("action", "madara_load_more") - add("page", page.toString()) - add("template", "madara-core/content/content-archive") - add("vars[paged]", "1") - add("vars[orderby]", "meta_value_num") - add("vars[template]", "archive") - add("vars[sidebar]", "right") - add("vars[post_type]", "wp-manga") - add("vars[post_status]", "publish") - add("vars[meta_key]", metaKey) - add("vars[meta_query][0][paged]", "1") - add("vars[meta_query][0][orderby]", "meta_value_num") - add("vars[meta_query][0][template]", "archive") - add("vars[meta_query][0][sidebar]", "right") - add("vars[meta_query][0][post_type]", "wp-manga") - add("vars[meta_query][0][post_status]", "publish") - add("vars[meta_query][0][meta_key]", metaKey) - add("vars[meta_query][relation]", "AND") - add("vars[manga_archives_item_layout]", "default") - }.build() - - val xhrHeaders = headersBuilder() - .add("Content-Length", formBody.contentLength().toString()) - .add("Content-Type", formBody.contentType().toString()) - .add("X-Requested-With", "XMLHttpRequest") - .build() - - return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, formBody) - } - - override fun popularMangaRequest(page: Int): Request { - return madaraLoadMoreRequest(page - 1, "_wp_manga_views") - } - - override fun latestUpdatesRequest(page: Int): Request { - return madaraLoadMoreRequest(page - 1, "_latest_update") - } - - override fun searchPage(page: Int): String { - return if (page > 1) { - "page/$page/" - } else { - "" - } - } - // heavily modified madara theme, throws 5xx errors on any search filter override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { val url = "$baseUrl/${searchPage(page)}".toHttpUrl().newBuilder().apply { diff --git a/src/en/gourmetscans/src/eu/kanade/tachiyomi/extension/en/gourmetscans/GourmetScans.kt b/src/en/gourmetscans/src/eu/kanade/tachiyomi/extension/en/gourmetscans/GourmetScans.kt index 1821a4130..657a736f0 100644 --- a/src/en/gourmetscans/src/eu/kanade/tachiyomi/extension/en/gourmetscans/GourmetScans.kt +++ b/src/en/gourmetscans/src/eu/kanade/tachiyomi/extension/en/gourmetscans/GourmetScans.kt @@ -21,8 +21,6 @@ class GourmetScans : Madara( // Search - override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { val url = baseUrl.toHttpUrl().newBuilder() @@ -77,23 +75,23 @@ class GourmetScans : Madara( private var genresList: List> = emptyList() - class GenreFilter(val vals: List>) : + class GenreFilter(vals: List>) : UriPartFilter("Genre", vals.toTypedArray()) override fun getFilterList(): FilterList { val filters = buildList(4) { - add(YearFilter(yearFilterTitle)) + add(YearFilter(intl["year_filter_title"])) add( OrderByFilter( - title = orderByFilterTitle, - options = orderByFilterOptions.zip(orderByFilterOptionsValues), + title = intl["order_by_filter_title"], + options = orderByFilterOptions.map { Pair(it.key, it.value) }, state = 0, ), ) add(Filter.Separator()) if (genresList.isEmpty()) { - add(Filter.Header(genresMissingWarning)) + add(Filter.Header(intl["genre_missing_warning"])) } else { add(GenreFilter(listOf(Pair("