Mangathemesia refactor (#1637)

* remove randomua

* i18n

* add other language based selectors

* countviews in background

* small cleanup

* lint

* fix

* bump

* fix genre resetting

* use enqueue instead of coroutinescope

* fix build

* fix build x2

* add back genre missing warning

* Add ES translations

* lint

* Add available language

* lint

I hate lint

* review

- lowercase match for status
- callback on site

* review x2, also fix smol mistake

* lint

:)

* lowercase some translations

Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>

* lowercase some translations

Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>

* remove "人気"

* inline the labels

* lint

thank you lint, very cool

---------

Co-authored-by: bapeey <90949336+bapeey@users.noreply.github.com>
Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>
This commit is contained in:
AwkwardPeak7 2024-03-03 01:30:17 +05:00 committed by Draff
parent 8f18229563
commit 88dba59eef
21 changed files with 383 additions and 222 deletions

View File

@ -0,0 +1,30 @@
alt_names_heading=Alternative Names:
author_filter_title=Author
year_filter_title=Year
status_filter_title=Status
status_filter_option_all=All
status_filter_option_ongoing=Ongoing
status_filter_option_completed=Completed
status_filter_option_hiatus=Hiatus
status_filter_option_dropped=Dropped
type_filter_title=Type
type_filter_option_all=All
type_filter_option_manga=Manga
type_filter_option_manhwa=Manhwa
type_filter_option_manhua=Manhua
type_filter_option_comic=Comic
order_by_filter_title=Sort By
order_by_filter_default=Default
order_by_filter_az=A-Z
order_by_filter_za=Z-A
order_by_filter_latest_update=Latest Update
order_by_filter_latest_added=Latest Added
order_by_filter_popular=Popular
project_filter_title=Filter Project
project_filter_all_manga=Show all manga
project_filter_only_project=Show only project manga
genre_filter_title=Genre
genre_missing_warning=Press 'Reset' to attempt to show the genres
genre_exclusion_warning=Genre exclusion is not available for all sources
project_filter_warning=NOTE: Can't be used with other filter!
project_filter_name=%s Project List page

View File

@ -0,0 +1,23 @@
alt_names_heading=Nombres alternativos:
author_filter_title=Autor
year_filter_title=Año
status_filter_title=Estado
status_filter_option_all=Todos
status_filter_option_ongoing=En curso
status_filter_option_completed=Completado
status_filter_option_hiatus=En pausa
status_filter_option_dropped=Abandonado
type_filter_title=Tipo
type_filter_option_all=Todos
order_by_filter_title=Ordenar por
order_by_filter_default=Por defecto
order_by_filter_latest_update=Última actualización
order_by_filter_latest_added=Último añadido
project_filter_title=Filtrar proyectos
project_filter_all_manga=Mostrar todos los mangas
project_filter_only_project=Mostrar solo los proyectos
genre_filter_title=Género
genre_missing_warning=Presione 'Restablecer' para intentar cargar los géneros
genre_exclusion_warning=La exclusión de géneros puede no funcionar correctamente
project_filter_warning=NOTA: ¡No se puede usar con otros filtros!
project_filter_name=%s Página de proyectos

View File

@ -2,8 +2,8 @@ plugins {
id("lib-multisrc") id("lib-multisrc")
} }
baseVersionCode = 28 baseVersionCode = 29
dependencies { dependencies {
api(project(":lib:randomua")) api(project(":lib:i18n"))
} }

View File

@ -1,15 +1,8 @@
package eu.kanade.tachiyomi.multisrc.mangathemesia package eu.kanade.tachiyomi.multisrc.mangathemesia
import android.app.Application import eu.kanade.tachiyomi.lib.i18n.Intl
import android.content.SharedPreferences
import androidx.preference.PreferenceScreen
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.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -21,64 +14,56 @@ import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Call
import okhttp3.Callback
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.lang.IllegalArgumentException import java.io.IOException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit
// Formerly WPMangaStream & WPMangaReader -> MangaThemesia // Formerly WPMangaStream & WPMangaReader -> MangaThemesia
abstract class MangaThemesia( abstract class MangaThemesia(
override val name: String, override val name: String,
override val baseUrl: String, override val baseUrl: String,
override val lang: String, final override val lang: String,
val mangaUrlDirectory: String = "/manga", val mangaUrlDirectory: String = "/manga",
val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US), val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US),
) : ParsedHttpSource(), ConfigurableSource { ) : ParsedHttpSource() {
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
protected open val json: Json by injectLazy() protected open val json: Json by injectLazy()
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient by lazy { override val client = network.cloudflareClient
network.cloudflareClient.newBuilder()
.setRandomUserAgent(
preferences.getPrefUAType(),
preferences.getPrefCustomUA(),
)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
}
override fun headersBuilder() = super.headersBuilder() override fun headersBuilder() = super.headersBuilder()
.set("Referer", "$baseUrl/") .set("Referer", "$baseUrl/")
protected val intl = Intl(
language = lang,
baseLanguage = "en",
availableLanguages = setOf("en", "es"),
classLoader = javaClass.classLoader!!,
)
open val projectPageString = "/project" open val projectPageString = "/project"
// Popular (Search with popular order and nothing else) // Popular (Search with popular order and nothing else)
override fun popularMangaRequest(page: Int) = searchMangaRequest(page, "", FilterList(OrderByFilter("popular"))) override fun popularMangaRequest(page: Int) = searchMangaRequest(page, "", popularFilter)
override fun popularMangaParse(response: Response) = searchMangaParse(response) override fun popularMangaParse(response: Response) = searchMangaParse(response)
// Latest (Search with update order and nothing else) // Latest (Search with update order and nothing else)
override fun latestUpdatesRequest(page: Int) = searchMangaRequest(page, "", FilterList(OrderByFilter("update"))) override fun latestUpdatesRequest(page: Int) = searchMangaRequest(page, "", latestFilter)
override fun latestUpdatesParse(response: Response) = searchMangaParse(response) override fun latestUpdatesParse(response: Response) = searchMangaParse(response)
// Search // Search
@ -166,22 +151,96 @@ abstract class MangaThemesia(
override fun searchMangaNextPageSelector() = "div.pagination .next, div.hpage .r" override fun searchMangaNextPageSelector() = "div.pagination .next, div.hpage .r"
// Manga details // Manga details
private fun selector(selector: String, contains: List<String>): String {
return contains.joinToString(", ") { selector.replace("%s", it) }
}
open val seriesDetailsSelector = "div.bigcontent, div.animefull, div.main-info, div.postbody" open val seriesDetailsSelector = "div.bigcontent, div.animefull, div.main-info, div.postbody"
open val seriesTitleSelector = "h1.entry-title"
open val seriesArtistSelector = ".infotable tr:contains(artist) td:last-child, .tsinfo .imptdt:contains(artist) i, .fmed b:contains(artist)+span, span:contains(artist)" open val seriesTitleSelector = "h1.entry-title, .ts-breadcrumb li:last-child span"
open val seriesAuthorSelector = ".infotable tr:contains(author) td:last-child, .tsinfo .imptdt:contains(author) i, .fmed b:contains(author)+span, span:contains(author)"
open val seriesArtistSelector = selector(
".infotable tr:contains(%s) td:last-child, .tsinfo .imptdt:contains(%s) i, .fmed b:contains(%s)+span, span:contains(%s)",
listOf(
"artist",
"Artiste",
"Artista",
"الرسام",
"الناشر",
"İllüstratör",
"Çizer",
),
)
open val seriesAuthorSelector = selector(
".infotable tr:contains(%s) td:last-child, .tsinfo .imptdt:contains(%s) i, .fmed b:contains(%s)+span, span:contains(%s)",
listOf(
"Author",
"Auteur",
"autor",
"المؤلف",
"Mangaka",
"seniman",
"Pengarang",
"Yazar",
),
)
open val seriesDescriptionSelector = ".desc, .entry-content[itemprop=description]" open val seriesDescriptionSelector = ".desc, .entry-content[itemprop=description]"
open val seriesAltNameSelector = ".alternative, .wd-full:contains(alt) span, .alter, .seriestualt"
open val seriesGenreSelector = "div.gnr a, .mgen a, .seriestugenre a, span:contains(genre)" open val seriesAltNameSelector = ".alternative, .wd-full:contains(alt) span, .alter, .seriestualt, " +
open val seriesTypeSelector = ".infotable tr:contains(type) td:last-child, .tsinfo .imptdt:contains(type) i, .tsinfo .imptdt:contains(type) a, .fmed b:contains(type)+span, span:contains(type) a, a[href*=type\\=]" selector(
open val seriesStatusSelector = ".infotable tr:contains(status) td:last-child, .tsinfo .imptdt:contains(status) i, .fmed b:contains(status)+span span:contains(status)" ".infotable tr:contains(%s) td:last-child",
listOf(
"Alternative",
"Alternatif",
"الأسماء الثانوية",
),
)
open val seriesGenreSelector = "div.gnr a, .mgen a, .seriestugenre a, " +
selector(
"span:contains(%s)",
listOf(
"genre",
"التصنيف",
),
)
open val seriesTypeSelector = selector(
".infotable tr:contains(%s) td:last-child, .tsinfo .imptdt:contains(%s) i, .tsinfo .imptdt:contains(%s) a, .fmed b:contains(%s)+span, span:contains(%s) a",
listOf(
"type",
"ประเภท",
"النوع",
"tipe",
"Türü",
),
) + ", a[href*=type\\=]"
open val seriesStatusSelector = selector(
".infotable tr:contains(%s) td:last-child, .tsinfo .imptdt:contains(%s) i, .fmed b:contains(%s)+span span:contains(%s)",
listOf(
"status",
"Statut",
"Durum",
"連載状況",
"Estado",
"الحالة",
"حالة العمل",
"สถานะ",
"stato",
"Statüsü",
),
)
open val seriesThumbnailSelector = ".infomanga > div[itemprop=image] img, .thumb img" open val seriesThumbnailSelector = ".infomanga > div[itemprop=image] img, .thumb img"
open val altNamePrefix = "Alternative Name: " open val altNamePrefix = "${intl["alt_names_heading"]} "
override fun mangaDetailsParse(document: Document) = SManga.create().apply { override fun mangaDetailsParse(document: Document) = SManga.create().apply {
document.selectFirst(seriesDetailsSelector)?.let { seriesDetails -> document.selectFirst(seriesDetailsSelector)?.let { seriesDetails ->
title = seriesDetails.selectFirst(seriesTitleSelector)?.text().orEmpty() title = seriesDetails.selectFirst(seriesTitleSelector)!!.text()
artist = seriesDetails.selectFirst(seriesArtistSelector)?.ownText().removeEmptyPlaceholder() artist = seriesDetails.selectFirst(seriesArtistSelector)?.ownText().removeEmptyPlaceholder()
author = seriesDetails.selectFirst(seriesAuthorSelector)?.ownText().removeEmptyPlaceholder() author = seriesDetails.selectFirst(seriesAuthorSelector)?.ownText().removeEmptyPlaceholder()
description = seriesDetails.select(seriesDescriptionSelector).joinToString("\n") { it.text() }.trim() description = seriesDetails.select(seriesDescriptionSelector).joinToString("\n") { it.text() }.trim()
@ -210,16 +269,32 @@ abstract class MangaThemesia(
} }
protected fun String?.removeEmptyPlaceholder(): String? { protected fun String?.removeEmptyPlaceholder(): String? {
return if (this.isNullOrBlank() || this == "-" || this == "N/A") null else this return if (this.isNullOrBlank() || this == "-" || this == "N/A" || this == "n/a") null else this
} }
open fun String?.parseStatus(): Int = when { open fun String?.parseStatus(): Int {
this == null -> SManga.UNKNOWN if (this == null) return SManga.UNKNOWN
listOf("ongoing", "publishing").any { this.contains(it, ignoreCase = true) } -> SManga.ONGOING
this.contains("hiatus", ignoreCase = true) -> SManga.ON_HIATUS return when (this.lowercase().trim()) {
this.contains("completed", ignoreCase = true) -> SManga.COMPLETED "مستمرة", "en curso", "ongoing", "on going", "ativo", "en cours",
listOf("dropped", "cancelled").any { this.contains(it, ignoreCase = true) } -> SManga.CANCELLED "en cours de publication", "đang tiến hành", "em lançamento", "онгоінг", "publishing",
else -> SManga.UNKNOWN "devam ediyor", "em andamento", "in corso", "güncel", "berjalan", "продолжается", "updating", "lançando", "in arrivo", "emision",
"en emision", "مستمر", "curso", "en marcha", "publicandose", "publicando", "连载中", "devam etmekte", "連載中",
-> SManga.ONGOING
"completed", "completo", "complété", "fini", "achevé", "terminé", "tamamlandı", "đã hoàn thành", "hoàn thành",
"مكتملة", "завершено", "finished", "finalizado", "completata", "one-shot", "bitti", "tamat", "completado", "concluído", "完結",
"concluido", "已完结", "bitmiş",
-> SManga.COMPLETED
"canceled", "cancelled", "cancelado", "cancellato", "cancelados", "dropped", "discontinued", "abandonné",
-> SManga.CANCELLED
"hiatus", "on hold", "pausado", "en espera", "en pause", "en attente",
-> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}
} }
// Chapter list // Chapter list
@ -227,6 +302,9 @@ abstract class MangaThemesia(
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup() val document = response.asJsoup()
countViews(document)
val chapters = document.select(chapterListSelector()).map { chapterFromElement(it) } val chapters = document.select(chapterListSelector()).map { chapterFromElement(it) }
// Add timestamp to latest chapter, taken from "Updated On". // Add timestamp to latest chapter, taken from "Updated On".
@ -238,8 +316,6 @@ abstract class MangaThemesia(
if (date.isNotEmpty()) chapters.first().date_upload = parseUpdatedOnDate(date) if (date.isNotEmpty()) chapters.first().date_upload = parseUpdatedOnDate(date)
} }
countViews(document)
return chapters return chapters
} }
@ -267,13 +343,13 @@ abstract class MangaThemesia(
open val pageSelector = "div#readerarea img" open val pageSelector = "div#readerarea img"
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
countViews(document)
val chapterUrl = document.location() val chapterUrl = document.location()
val htmlPages = document.select(pageSelector) val htmlPages = document.select(pageSelector)
.filterNot { it.imgAttr().isEmpty() } .filterNot { it.imgAttr().isEmpty() }
.mapIndexed { i, img -> Page(i, chapterUrl, img.imgAttr()) } .mapIndexed { i, img -> Page(i, chapterUrl, img.imgAttr()) }
countViews(document)
// Some sites also loads pages via javascript // Some sites also loads pages via javascript
if (htmlPages.isNotEmpty()) { return htmlPages } if (htmlPages.isNotEmpty()) { return htmlPages }
@ -320,8 +396,6 @@ abstract class MangaThemesia(
.build() .build()
val newHeaders = headersBuilder() val newHeaders = headersBuilder()
.set("Content-Length", formBody.contentLength().toString())
.set("Content-Type", formBody.contentType().toString())
.set("Referer", document.location()) .set("Referer", document.location())
.build() .build()
@ -339,17 +413,22 @@ abstract class MangaThemesia(
} }
val request = countViewsRequest(document) ?: return val request = countViewsRequest(document) ?: return
runCatching { client.newCall(request).execute().close() } val callback = object : Callback {
override fun onResponse(call: Call, response: Response) = response.close()
override fun onFailure(call: Call, e: IOException) = Unit
}
client.newCall(request).enqueue(callback)
} }
// Filters // Filters
protected class AuthorFilter : Filter.Text("Author") protected class AuthorFilter(name: String) : Filter.Text(name)
protected class YearFilter : Filter.Text("Year") protected class YearFilter(name: String) : Filter.Text(name)
open class SelectFilter( open class SelectFilter(
displayName: String, displayName: String,
val vals: Array<Pair<String, String>>, private val vals: Array<Pair<String, String>>,
defaultValue: String? = null, defaultValue: String? = null,
) : Filter.Select<String>( ) : Filter.Select<String>(
displayName, displayName,
@ -359,63 +438,91 @@ abstract class MangaThemesia(
fun selectedValue() = vals[state].second fun selectedValue() = vals[state].second
} }
protected class StatusFilter : SelectFilter( protected class StatusFilter(
"Status", name: String,
arrayOf( options: Array<Pair<String, String>>,
Pair("All", ""), ) : SelectFilter(
Pair("Ongoing", "ongoing"), name,
Pair("Completed", "completed"), options,
Pair("Hiatus", "hiatus"),
Pair("Dropped", "dropped"),
),
) )
protected class TypeFilter : SelectFilter( protected open val statusOptions = arrayOf(
"Type", Pair(intl["status_filter_option_all"], ""),
arrayOf( Pair(intl["status_filter_option_ongoing"], "ongoing"),
Pair("All", ""), Pair(intl["status_filter_option_completed"], "completed"),
Pair("Manga", "Manga"), Pair(intl["status_filter_option_hiatus"], "hiatus"),
Pair("Manhwa", "Manhwa"), Pair(intl["status_filter_option_dropped"], "dropped"),
Pair("Manhua", "Manhua"),
Pair("Comic", "Comic"),
),
) )
protected class OrderByFilter(defaultOrder: String? = null) : SelectFilter( protected class TypeFilter(
"Sort By", name: String,
arrayOf( options: Array<Pair<String, String>>,
Pair("Default", ""), ) : SelectFilter(
Pair("A-Z", "title"), name,
Pair("Z-A", "titlereverse"), options,
Pair("Latest Update", "update"), )
Pair("Latest Added", "latest"),
Pair("Popular", "popular"), protected open val typeFilterOptions = arrayOf(
), Pair(intl["type_filter_option_all"], ""),
Pair(intl["type_filter_option_manga"], "Manga"),
Pair(intl["type_filter_option_manhwa"], "Manhwa"),
Pair(intl["type_filter_option_manhua"], "Manhua"),
Pair(intl["type_filter_option_comic"], "Comic"),
)
protected class OrderByFilter(
name: String,
options: Array<Pair<String, String>>,
defaultOrder: String? = null,
) : SelectFilter(
name,
options,
defaultOrder, defaultOrder,
) )
protected class ProjectFilter : SelectFilter( protected open val orderByFilterOptions = arrayOf(
"Filter Project", Pair(intl["order_by_filter_default"], ""),
arrayOf( Pair(intl["order_by_filter_az"], "title"),
Pair("Show all manga", ""), Pair(intl["order_by_filter_za"], "titlereverse"),
Pair("Show only project manga", "project-filter-on"), Pair(intl["order_by_filter_latest_update"], "update"),
), Pair(intl["order_by_filter_latest_added"], "latest"),
Pair(intl["order_by_filter_popular"], "popular"),
)
protected val popularFilter by lazy { FilterList(OrderByFilter("", orderByFilterOptions, "popular")) }
protected val latestFilter by lazy { FilterList(OrderByFilter("", orderByFilterOptions, "update")) }
protected class ProjectFilter(
name: String,
options: Array<Pair<String, String>>,
) : SelectFilter(
name,
options,
)
protected open val projectFilterOptions = arrayOf(
Pair(intl["project_filter_all_manga"], ""),
Pair(intl["project_filter_only_project"], "project-filter-on"),
)
protected class GenreData(
val name: String,
val value: String,
val state: Int = Filter.TriState.STATE_IGNORE,
) )
protected class Genre( protected class Genre(
name: String, name: String,
val value: String, val value: String,
state: Int = STATE_IGNORE, state: Int,
) : Filter.TriState(name, state) ) : Filter.TriState(name, state)
protected class GenreListFilter(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres) protected class GenreListFilter(name: String, genres: List<Genre>) : Filter.Group<Genre>(name, genres)
protected var genrelist: List<GenreData>? = null
private var genrelist: List<Genre>? = null
protected open fun getGenreList(): List<Genre> { protected open fun getGenreList(): List<Genre> {
// Filters are fetched immediately once an extension loads return genrelist?.map { Genre(it.name, it.value, it.state) }.orEmpty()
// We're only able to get filters after a loading the manga directory,
// and resetting the filters is the only thing that seems to reinflate the view
return genrelist ?: listOf(Genre("Press reset to attempt to fetch genres", ""))
} }
open val hasProjectPage = false open val hasProjectPage = false
@ -423,21 +530,31 @@ abstract class MangaThemesia(
override fun getFilterList(): FilterList { override fun getFilterList(): FilterList {
val filters = mutableListOf<Filter<*>>( val filters = mutableListOf<Filter<*>>(
Filter.Separator(), Filter.Separator(),
AuthorFilter(), AuthorFilter(intl["author_filter_title"]),
YearFilter(), YearFilter(intl["year_filter_title"]),
StatusFilter(), StatusFilter(intl["status_filter_title"], statusOptions),
TypeFilter(), TypeFilter(intl["type_filter_title"], typeFilterOptions),
OrderByFilter(), OrderByFilter(intl["order_by_filter_title"], orderByFilterOptions),
Filter.Header("Genre exclusion is not available for all sources"),
GenreListFilter(getGenreList()),
) )
if (!genrelist.isNullOrEmpty()) {
filters.addAll(
listOf(
Filter.Header(intl["genre_exclusion_warning"]),
GenreListFilter(intl["genre_filter_title"], getGenreList()),
),
)
} else {
filters.add(
Filter.Header(intl["genre_missing_warning"]),
)
}
if (hasProjectPage) { if (hasProjectPage) {
filters.addAll( filters.addAll(
mutableListOf<Filter<*>>( mutableListOf<Filter<*>>(
Filter.Separator(), Filter.Separator(),
Filter.Header("NOTE: Can't be used with other filter!"), Filter.Header(intl["project_filter_warning"]),
Filter.Header("$name Project List page"), Filter.Header(intl.format("project_filter_name", name)),
ProjectFilter(), ProjectFilter(intl["project_filter_title"], projectFilterOptions),
), ),
) )
} }
@ -485,9 +602,9 @@ abstract class MangaThemesia(
(!strict && url.pathSegments.size == n + 1 && url.pathSegments[n].isEmpty()) (!strict && url.pathSegments.size == n + 1 && url.pathSegments[n].isEmpty())
} }
private fun parseGenres(document: Document): List<Genre>? { private fun parseGenres(document: Document): List<GenreData>? {
return document.selectFirst("ul.genrez")?.select("li")?.map { li -> return document.selectFirst("ul.genrez")?.select("li")?.map { li ->
Genre( GenreData(
li.selectFirst("label")!!.text(), li.selectFirst("label")!!.text(),
li.selectFirst("input[type=checkbox]")!!.attr("value"), li.selectFirst("input[type=checkbox]")!!.attr("value"),
) )
@ -514,15 +631,10 @@ abstract class MangaThemesia(
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException() override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
override fun setupPreferenceScreen(screen: PreferenceScreen) {
addRandomUAPreferenceToScreen(screen)
}
companion object { companion object {
const val URL_SEARCH_PREFIX = "url:" const val URL_SEARCH_PREFIX = "url:"
// More info: https://issuetracker.google.com/issues/36970498 // More info: https://issuetracker.google.com/issues/36970498
@Suppress("RegExpRedundantEscape")
private val MANGA_PAGE_ID_REGEX = "post_id\\s*:\\s*(\\d+)\\}".toRegex() private val MANGA_PAGE_ID_REGEX = "post_id\\s*:\\s*(\\d+)\\}".toRegex()
private val CHAPTER_PAGE_ID_REGEX = "chapter_id\\s*=\\s*(\\d+);".toRegex() private val CHAPTER_PAGE_ID_REGEX = "chapter_id\\s*=\\s*(\\d+);".toRegex()

View File

@ -33,10 +33,11 @@ open class MiauScan(lang: String) : MangaThemesia(
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val genreFilterIndex = filters.indexOfFirst { it is GenreListFilter } val genreFilterIndex = filters.indexOfFirst { it is GenreListFilter }
val genreFilter = filters.getOrNull(genreFilterIndex) as? GenreListFilter val genreFilter = filters.getOrNull(genreFilterIndex) as? GenreListFilter
?: GenreListFilter(emptyList()) ?: GenreListFilter("", emptyList())
val overloadedGenreFilter = GenreListFilter( val overloadedGenreFilter = GenreListFilter(
genres = genreFilter.state + listOf( genreFilter.name,
genreFilter.state + listOf(
Genre("", PORTUGUESE_GENRE_ID, portugueseMode), Genre("", PORTUGUESE_GENRE_ID, portugueseMode),
), ),
) )

View File

@ -31,8 +31,8 @@ class Mihentai : MangaThemesia("Mihentai", "https://mihentai.com", "all") {
listOf( listOf(
StatusFilter(), StatusFilter(),
TypeFilter(), TypeFilter(),
OrderByFilter(), OrderByFilter(intl["order_by_filter_title"], orderByFilterOptions),
GenreListFilter(getGenreList()), GenreListFilter(intl["genre_filter_title"], getGenreList()),
), ),
) )
} }

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.ar.areamanga package eu.kanade.tachiyomi.extension.ar.areamanga
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.source.model.SManga
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -10,21 +9,4 @@ class AreaManga : MangaThemesia(
"https://www.areascans.net", "https://www.areascans.net",
"ar", "ar",
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")), dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
) { )
override val seriesArtistSelector =
".tsinfo .imptdt:contains(الرسام) i, ${super.seriesArtistSelector}"
override val seriesAuthorSelector =
".tsinfo .imptdt:contains(المؤلف) i, ${super.seriesAuthorSelector}"
override val seriesStatusSelector =
".tsinfo .imptdt:contains(الحالة) i, ${super.seriesStatusSelector}"
override val seriesTypeSelector =
".tsinfo .imptdt:contains(النوع) i, ${super.seriesTypeSelector}"
override fun String?.parseStatus() = when {
this == null -> SManga.UNKNOWN
this.contains("مستمر", ignoreCase = true) -> SManga.ONGOING
this.contains("مكتمل", ignoreCase = true) -> SManga.COMPLETED
this.contains("متوقف", ignoreCase = true) -> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}
}

View File

@ -7,6 +7,7 @@ import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.extension.BuildConfig import eu.kanade.tachiyomi.extension.BuildConfig
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
@ -23,12 +24,14 @@ import java.util.Locale
private const val swatUrl = "https://swatmanhua.com" private const val swatUrl = "https://swatmanhua.com"
class MangaSwat : MangaThemesia( class MangaSwat :
"MangaSwat", MangaThemesia(
swatUrl, "MangaSwat",
"ar", swatUrl,
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")), "ar",
) { dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
),
ConfigurableSource {
private val defaultBaseUrl = swatUrl private val defaultBaseUrl = swatUrl
override val baseUrl by lazy { getPrefBaseUrl() } override val baseUrl by lazy { getPrefBaseUrl() }
@ -113,8 +116,6 @@ class MangaSwat : MangaThemesia(
} }
} }
screen.addPreference(baseUrlPref) screen.addPreference(baseUrlPref)
super.setupPreferenceScreen(screen)
} }
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!! private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!!

View File

@ -6,6 +6,7 @@ import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -26,12 +27,14 @@ import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class AsuraScans : MangaThemesia( class AsuraScans :
"Asura Scans", MangaThemesia(
"https://asuratoon.com", "Asura Scans",
"en", "https://asuratoon.com",
dateFormat = SimpleDateFormat("MMM d, yyyy", Locale.US), "en",
) { dateFormat = SimpleDateFormat("MMM d, yyyy", Locale.US),
),
ConfigurableSource {
private val preferences by lazy { private val preferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
@ -281,8 +284,6 @@ class AsuraScans : MangaThemesia(
summary = PREF_PERM_MANGA_URL_SUMMARY summary = PREF_PERM_MANGA_URL_SUMMARY
setDefaultValue(true) setDefaultValue(true)
}.also(screen::addPreference) }.also(screen::addPreference)
super.setupPreferenceScreen(screen)
} }
private val SharedPreferences.permaUrlPref private val SharedPreferences.permaUrlPref

View File

@ -8,3 +8,7 @@ ext {
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(":lib:randomua"))
}

View File

@ -2,11 +2,14 @@ package eu.kanade.tachiyomi.extension.en.constellarscans
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.lib.randomua.addRandomUAPreferenceToScreen
import eu.kanade.tachiyomi.lib.randomua.getPrefCustomUA import eu.kanade.tachiyomi.lib.randomua.getPrefCustomUA
import eu.kanade.tachiyomi.lib.randomua.getPrefUAType import eu.kanade.tachiyomi.lib.randomua.getPrefUAType
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
@ -19,22 +22,29 @@ import okhttp3.Request
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.concurrent.TimeUnit
class ConstellarScans : MangaThemesia("Constellar Scans", "https://constellarcomic.com", "en") { class ConstellarScans :
MangaThemesia(
"Constellar Scans",
"https://constellarcomic.com",
"en",
),
ConfigurableSource {
private val preferences: SharedPreferences by lazy { private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) {
addRandomUAPreferenceToScreen(screen)
}
override val client: OkHttpClient by lazy { override val client: OkHttpClient by lazy {
network.cloudflareClient.newBuilder() network.cloudflareClient.newBuilder()
.setRandomUserAgent( .setRandomUserAgent(
preferences.getPrefUAType(), preferences.getPrefUAType(),
preferences.getPrefCustomUA(), preferences.getPrefCustomUA(),
) )
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.rateLimit(1, 1) .rateLimit(1, 1)
.build() .build()
} }
@ -61,6 +71,8 @@ class ConstellarScans : MangaThemesia("Constellar Scans", "https://constellarcom
.build() .build()
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
countViews(document)
val html = document.toString() val html = document.toString()
if (!html.contains("ts_rea_der_._run(\"")) { if (!html.contains("ts_rea_der_._run(\"")) {
return super.pageListParse(document) return super.pageListParse(document)
@ -80,7 +92,6 @@ class ConstellarScans : MangaThemesia("Constellar Scans", "https://constellarcom
} }
.joinToString("") .joinToString("")
countViews(document)
return json.parseToJsonElement(tsReaderRawData).jsonObject["sources"]!!.jsonArray[0].jsonObject["images"]!!.jsonArray.mapIndexed { idx, it -> return json.parseToJsonElement(tsReaderRawData).jsonObject["sources"]!!.jsonArray[0].jsonObject["images"]!!.jsonArray.mapIndexed { idx, it ->
Page(idx, imageUrl = it.jsonPrimitive.content) Page(idx, imageUrl = it.jsonPrimitive.content)
} }

View File

@ -9,6 +9,7 @@ import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -25,12 +26,14 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
class FlameComics : MangaThemesia( class FlameComics :
"Flame Comics", MangaThemesia(
"https://flamecomics.com", "Flame Comics",
"en", "https://flamecomics.com",
mangaUrlDirectory = "/series", "en",
) { mangaUrlDirectory = "/series",
),
ConfigurableSource {
// Flame Scans -> Flame Comics // Flame Scans -> Flame Comics
override val id = 6350607071566689772 override val id = 6350607071566689772

View File

@ -6,6 +6,7 @@ import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
@ -20,7 +21,15 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException import java.io.IOException
class LuminousScans : MangaThemesia("Luminous Scans", "https://lumitoon.com", "en", mangaUrlDirectory = "/series") { class LuminousScans :
MangaThemesia(
"Luminous Scans",
"https://lumitoon.com",
"en",
mangaUrlDirectory = "/series",
),
ConfigurableSource {
override val client = super.client.newBuilder() override val client = super.client.newBuilder()
.addInterceptor(::urlChangeInterceptor) .addInterceptor(::urlChangeInterceptor)
.rateLimit(2) .rateLimit(2)
@ -201,8 +210,6 @@ class LuminousScans : MangaThemesia("Luminous Scans", "https://lumitoon.com", "e
summary = PREF_PERM_MANGA_URL_SUMMARY summary = PREF_PERM_MANGA_URL_SUMMARY
setDefaultValue(true) setDefaultValue(true)
}.also(screen::addPreference) }.also(screen::addPreference)
super.setupPreferenceScreen(screen)
} }
private val SharedPreferences.permaUrlPref private val SharedPreferences.permaUrlPref

View File

@ -33,19 +33,29 @@ class LunarScans : MangaThemesia(
val filters = mutableListOf<Filter<*>>( val filters = mutableListOf<Filter<*>>(
Filter.Header("Note: Can't be used with text search!"), Filter.Header("Note: Can't be used with text search!"),
Filter.Separator(), Filter.Separator(),
StatusFilter(), StatusFilter(intl["status_filter_title"], statusOptions),
TypeFilter(), TypeFilter(intl["type_filter_title"], typeFilterOptions),
OrderByFilter(), OrderByFilter(intl["order_by_filter_title"], orderByFilterOptions),
Filter.Header("Genre exclusion is not available for all sources"),
GenreListFilter(getGenreList()),
) )
if (!genrelist.isNullOrEmpty()) {
filters.addAll(
listOf(
Filter.Header(intl["genre_exclusion_warning"]),
GenreListFilter(intl["genre_filter_title"], getGenreList()),
),
)
} else {
filters.add(
Filter.Header(intl["genre_missing_warning"]),
)
}
if (hasProjectPage) { if (hasProjectPage) {
filters.addAll( filters.addAll(
mutableListOf<Filter<*>>( mutableListOf<Filter<*>>(
Filter.Separator(), Filter.Separator(),
Filter.Header("NOTE: Can't be used with other filter!"), Filter.Header(intl["project_filter_warning"]),
Filter.Header("$name Project List page"), Filter.Header(intl.format("project_filter_name", name)),
ProjectFilter(), ProjectFilter(intl["project_filter_title"], projectFilterOptions),
), ),
) )
} }

View File

@ -17,14 +17,4 @@ class CarteldeManhwas : MangaThemesia(
override fun searchMangaSelector() = ".utao .uta .imgu:not(:has(span.novelabel)), " + override fun searchMangaSelector() = ".utao .uta .imgu:not(:has(span.novelabel)), " +
".listupd .bs .bsx:not(:has(span.novelabel)), " + ".listupd .bs .bsx:not(:has(span.novelabel)), " +
".listo .bs .bsx:not(:has(span.novelabel))" ".listo .bs .bsx:not(:has(span.novelabel))"
private class StatusFilter : SelectFilter(
"Status",
arrayOf(
Pair("All", ""),
Pair("Ongoing", "ongoing"),
Pair("Completed", "completed"),
Pair("Hiatus", "hiatus"),
),
)
} }

View File

@ -1,5 +1,12 @@
package eu.kanade.tachiyomi.extension.es.gremorymangas package eu.kanade.tachiyomi.extension.es.gremorymangas
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import java.text.SimpleDateFormat
import java.util.Locale
class GremoryMangas : MangaThemesia("Gremory Mangas", "https://gremorymangas.com", "es") class GremoryMangas : MangaThemesia(
"Gremory Mangas",
"https://gremorymangas.com",
"es",
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("es")),
)

View File

@ -25,13 +25,13 @@ class NekoScans : MangaThemesia(
override val seriesStatusSelector = ".tsinfo .imptdt:contains(estado) i" override val seriesStatusSelector = ".tsinfo .imptdt:contains(estado) i"
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
countViews(document)
val chapterUrl = document.location() val chapterUrl = document.location()
val htmlPages = document.select(pageSelector) val htmlPages = document.select(pageSelector)
.filterNot { it.imgAttr().isEmpty() } .filterNot { it.imgAttr().isEmpty() }
.mapIndexed { i, img -> Page(i, chapterUrl, img.imgAttr()) } .mapIndexed { i, img -> Page(i, chapterUrl, img.imgAttr()) }
countViews(document)
// Some sites also loads pages via javascript // Some sites also loads pages via javascript
if (htmlPages.isNotEmpty()) { return htmlPages } if (htmlPages.isNotEmpty()) { return htmlPages }

View File

@ -1,26 +1,14 @@
package eu.kanade.tachiyomi.extension.es.senpaiediciones package eu.kanade.tachiyomi.extension.es.senpaiediciones
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.source.model.SManga
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
class SenpaiEdiciones : MangaThemesia( class SenpaiEdiciones : MangaThemesia(
"Senpai Ediciones", "Senpai Ediciones",
"http://senpaiediciones.com", "https://senpaiediciones.com",
"es", "es",
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("es")), dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("es")),
) { ) {
override val seriesAuthorSelector = ".imptdt:contains(Autor) i"
override val seriesStatusSelector = ".imptdt:contains(Estado) i"
override val pageSelector = "div#readerarea img:not(noscript img)" override val pageSelector = "div#readerarea img:not(noscript img)"
override fun String?.parseStatus(): Int = when {
this == null -> SManga.UNKNOWN
listOf("curso").any { this.contains(it, ignoreCase = true) } -> SManga.ONGOING
this.contains("hiatus", ignoreCase = true) -> SManga.ON_HIATUS
this.contains("finalizado", ignoreCase = true) -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
} }

View File

@ -19,7 +19,7 @@ class CosmicScansID : MangaThemesia("CosmicScans.id", "https://cosmicscans.id",
override val hasProjectPage = true override val hasProjectPage = true
override val projectPageString = "/semua-komik" override val projectPageString = "/semua-komik"
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl" + if (page > 1) "/page/$page" else "", headers) override fun latestUpdatesRequest(page: Int) = GET(baseUrl + if (page > 1) "/page/$page" else "", headers)
// search // search
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
@ -47,8 +47,8 @@ class CosmicScansID : MangaThemesia("CosmicScans.id", "https://cosmicscans.id",
val filters = mutableListOf<Filter<*>>( val filters = mutableListOf<Filter<*>>(
Filter.Separator(), Filter.Separator(),
Filter.Header("$name Project List page"), Filter.Header("$name Project List page"),
ProjectFilter(), ProjectFilter(intl["project_filter_title"], projectFilterOptions),
OrderByFilter(), OrderByFilter(intl["order_by_filter_title"], orderByFilterOptions),
) )
return FilterList(filters) return FilterList(filters)
} }

View File

@ -241,12 +241,12 @@ class KomikCast : MangaThemesia("Komik Cast", "https://komikcast.lol", "id", "/d
StatusFilter(), StatusFilter(),
TypeFilter(), TypeFilter(),
OrderByFilter(), OrderByFilter(),
Filter.Header("Genre exclusion is not available for all sources"), Filter.Header(intl["genre_exclusion_warning"]),
GenreListFilter(getGenreList()), GenreListFilter(intl["genre_filter_title"], getGenreList()),
Filter.Separator(), Filter.Separator(),
Filter.Header("NOTE: Can't be used with other filter!"), Filter.Header(intl["project_filter_warning"]),
Filter.Header("$name Project List page"), Filter.Header(intl.format("project_filter_name", name)),
ProjectFilter(), ProjectFilter(intl["project_filter_title"], projectFilterOptions),
) )
return FilterList(filters) return FilterList(filters)
} }

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.ja.mangamate package eu.kanade.tachiyomi.extension.ja.mangamate
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.source.model.SManga
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -12,12 +11,4 @@ class MangaMate : MangaThemesia(
dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ja")), dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ja")),
) { ) {
override val seriesAuthorSelector = ".fmed b:contains(作者) + span" override val seriesAuthorSelector = ".fmed b:contains(作者) + span"
override val seriesStatusSelector = ".tsinfo .imptdt:contains(連載状況) i"
override fun String?.parseStatus(): Int = when (this) {
"連載中" -> SManga.ONGOING
"完結" -> SManga.COMPLETED
"人気" -> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}
} }