Add support to string l10n in Madara (#10814)

* Localize the Madara strings.

* Lint some overrides.

* Add missing comma.

* Fix build error due to final in multilang sources.

* Fix typo in author string.

* Fix a merge conflict.
This commit is contained in:
Alessandro Jean 2022-02-28 18:37:21 -03:00 committed by GitHub
parent 3e6aba7609
commit 219bf0b1d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 148 additions and 244 deletions

View File

@ -47,7 +47,7 @@ class HentaiHandFactory : SourceFactory {
abstract class HentaiHandCommon( abstract class HentaiHandCommon(
override val lang: String, override val lang: String,
hhLangId: List<Int> = emptyList(), hhLangId: List<Int> = emptyList(),
//altLangId: Int? = null // altLangId: Int? = null
) : HentaiHand("HentaiHand", "https://hentaihand.com", lang, false, hhLangId) { ) : HentaiHand("HentaiHand", "https://hentaihand.com", lang, false, hhLangId) {
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor { authIntercept(it) } .addInterceptor { authIntercept(it) }

View File

@ -47,7 +47,7 @@ class NHentaiComFactory : SourceFactory {
abstract class NHentaiComCommon( abstract class NHentaiComCommon(
override val lang: String, override val lang: String,
hhLangId: List<Int> = emptyList(), hhLangId: List<Int> = emptyList(),
//altLangId: Int? = null // altLangId: Int? = null
) : HentaiHand("nHentai.com (unoriginal)", "https://nhentai.com", lang, false, hhLangId) { ) : HentaiHand("nHentai.com (unoriginal)", "https://nhentai.com", lang, false, hhLangId) {
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor { authIntercept(it) } .addInterceptor { authIntercept(it) }

View File

@ -19,8 +19,4 @@ class AiinScan : Madara(
.build() .build()
override val useNewChapterEndpoint: Boolean = true override val useNewChapterEndpoint: Boolean = true
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class AnimeCenterScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -18,9 +18,5 @@ class ArthurScan : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -21,7 +21,4 @@ class BananaCitrica : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class BorutoExplorer : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class CeriseScans : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override fun popularMangaSelector() = "div.page-item-detail.manga"
override val altName: String = "Nome alternativo: "
} }

View File

@ -17,8 +17,4 @@ class CronosScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class DiskusScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -22,10 +22,6 @@ class DreamUnionScan : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
private fun authWarningIntercept(chain: Interceptor.Chain): Response { private fun authWarningIntercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request()) val response = chain.proceed(chain.request())

View File

@ -22,8 +22,6 @@ class DropeScan : Madara(
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override val altName = "Nome alternativo: "
override fun popularMangaRequest(page: Int): Request = override fun popularMangaRequest(page: Int): Request =
GET("$baseUrl/manga/page/$page/?m_orderby=views", headers) GET("$baseUrl/manga/page/$page/?m_orderby=views", headers)

View File

@ -17,8 +17,4 @@ class FinalScans : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -22,10 +22,6 @@ class FleurBlanche : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
private fun authWarningIntercept(chain: Interceptor.Chain): Response { private fun authWarningIntercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request()) val response = chain.proceed(chain.request())

View File

@ -18,9 +18,5 @@ class FurioScans : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -23,12 +23,6 @@ class OkamishiScans : Madara(
override val useNewChapterEndpoint: Boolean = true override val useNewChapterEndpoint: Boolean = true
override val altName: String = "Nome alternativo: "
override val mangaDetailsSelectorTitle: String = "div.post-title h1"
// Tags are full of garbage, so remove them. // Tags are full of garbage, so remove them.
override val mangaDetailsSelectorTag: String = "" override val mangaDetailsSelectorTag: String = ""
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class HentaiTeca : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,6 +17,4 @@ class HuntersScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
} }

View File

@ -38,7 +38,7 @@ class ImperfectComics : Madara("Imperfect Comics", "https://imperfectcomic.com",
val chapterRegex = """input\[data-id=\"$chapterId\"(?:.|\n)*?(?=\})""".toRegex() val chapterRegex = """input\[data-id=\"$chapterId\"(?:.|\n)*?(?=\})""".toRegex()
val css = document.selectFirst("#wp-custom-css").html() val css = document.selectFirst("#wp-custom-css").html()
//Checking for chapter first to handle mirrored manga with specific un-mirrored chapters // Checking for chapter first to handle mirrored manga with specific un-mirrored chapters
val props = chapterRegex.find(css).let { cId -> val props = chapterRegex.find(css).let { cId ->
cId?.value ?: mangaRegex.find(css).let { mId -> cId?.value ?: mangaRegex.find(css).let { mId ->
mId?.value ?: "" mId?.value ?: ""

View File

@ -17,8 +17,4 @@ class ImperioScans : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class KamiSamaExplorer : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -21,10 +21,6 @@ class LimaScans : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
override fun mangaDetailsRequest(manga: SManga): Request { override fun mangaDetailsRequest(manga: SManga): Request {
return GET(baseUrl + manga.url.removePrefix("/v2"), headers) return GET(baseUrl + manga.url.removePrefix("/v2"), headers)
} }

View File

@ -25,7 +25,7 @@ class MangaForFreeALL : MangaForFree("MangaForFree.net", "https://mangaforfree.n
abstract class MangaForFree( abstract class MangaForFree(
override val name: String, override val name: String,
override val baseUrl: String, override val baseUrl: String,
override val lang: String lang: String
) : Madara(name, baseUrl, lang) { ) : Madara(name, baseUrl, lang) {
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()

View File

@ -29,7 +29,7 @@ class Manhwa18CcALL : Manhwa18Cc("Manhwa18.cc", "https://manhwa18.cc", "all")
abstract class Manhwa18Cc( abstract class Manhwa18Cc(
override val name: String, override val name: String,
override val baseUrl: String, override val baseUrl: String,
override val lang: String lang: String
) : Madara(name, baseUrl, lang) { ) : Madara(name, baseUrl, lang) {
override fun popularMangaSelector() = "div.manga-item" override fun popularMangaSelector() = "div.manga-item"

View File

@ -17,8 +17,4 @@ class MiniTwoScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class MiradScanlator : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -18,9 +18,5 @@ class MomoNoHanaScan : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class NekoBreakerScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -44,8 +44,6 @@ class NeoxScanlator :
override val altNameSelector = ".post-content_item:contains(Alternativo) .summary-content" override val altNameSelector = ".post-content_item:contains(Alternativo) .summary-content"
override val altName = "Nome alternativo: "
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)
} }
@ -59,9 +57,6 @@ class NeoxScanlator :
.add("Accept-Language", ACCEPT_LANGUAGE) .add("Accept-Language", ACCEPT_LANGUAGE)
.add("Referer", REFERER) .add("Referer", REFERER)
// Filter the novels in pure text format.
override fun popularMangaSelector() = "div.page-item-detail.manga"
override fun searchMangaParse(response: Response): MangasPage { override fun searchMangaParse(response: Response): MangasPage {
val mangaPage = super.searchMangaParse(response) val mangaPage = super.searchMangaParse(response)
val filteredResult = mangaPage.mangas.filter { it.title.contains(NOVEL_REGEX).not() } val filteredResult = mangaPage.mangas.filter { it.title.contains(NOVEL_REGEX).not() }

View File

@ -17,8 +17,4 @@ class NinjaScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -18,9 +18,5 @@ class OlhoDaLua : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName = "Nome alternativo: "
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class OtksScanlator : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -10,8 +10,4 @@ class OwScan : Madara("Ow Scan", "https://owscan.com", "pt-BR") {
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -77,16 +77,16 @@ class PojokManga : Madara("Pojok Manga", "https://pojokmanga.com", "id", SimpleD
) )
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
AuthorFilter(), AuthorFilter(authorFilterTitle),
ArtistFilter(), ArtistFilter(artistFilterTitle),
YearFilter(), YearFilter(yearFilterTitle),
StatusFilter(getStatusList()), StatusFilter(statusFilterTitle, getStatusList()),
OrderByFilter(), OrderByFilter(orderByFilterTitle, orderByFilterOptions.zip(orderByFilterOptionsValues)),
AdultContentFilter(), AdultContentFilter(adultContentFilterTitle, adultContentFilterOptions),
Filter.Separator(), Filter.Separator(),
Filter.Header("Genres may not work for all sources"), Filter.Header(genreFilterHeader),
GenreConditionFilter(), GenreConditionFilter(genreConditionFilterTitle, genreConditionFilterOptions),
GenreList(getGenreList()), GenreList(genreFilterTitle, getGenreList()),
Filter.Separator(), Filter.Separator(),
Filter.Header("NOTE: cant be used with other filter!"), Filter.Header("NOTE: cant be used with other filter!"),
Filter.Header("$name Project List page"), Filter.Header("$name Project List page"),

View File

@ -18,9 +18,5 @@ class PrismaScans : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName = "Nome alternativo: "
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class RachelScanlator : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -19,12 +19,10 @@ class ReaperScansFactory : SourceFactory {
abstract class ReaperScans( abstract class ReaperScans(
override val baseUrl: String, override val baseUrl: String,
override val lang: String, lang: String,
dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US) dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US)
) : Madara("Reaper Scans", baseUrl, lang, dateFormat) { ) : Madara("Reaper Scans", baseUrl, lang, dateFormat) {
override fun popularMangaSelector() = "div.page-item-detail.manga"
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create() val chapter = SChapter.create()
@ -53,8 +51,6 @@ class ReaperScansBr : ReaperScans("https://reaperscans.com.br", "pt-BR", SimpleD
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create() val chapter = SChapter.create()
with(element) { with(element) {

View File

@ -18,9 +18,5 @@ class ScanlatorHunters : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -18,9 +18,5 @@ class SeikouScans : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -18,9 +18,5 @@ class SensainaYuri : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override val useNewChapterEndpoint = true override val useNewChapterEndpoint = true
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class Sinensis : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class SodaScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -20,8 +20,6 @@ class StageComics : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override fun popularMangaSelector() = "div.page-item-detail.manga"
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
val parsedChapter = super.chapterFromElement(element) val parsedChapter = super.chapterFromElement(element)

View File

@ -21,8 +21,6 @@ class SweetTimeScan : Madara(
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override fun popularMangaSelector() = "div.page-item-detail.manga"
// The source has novels in text format, so we need to filter them. // The source has novels in text format, so we need to filter them.
override fun searchMangaParse(response: Response): MangasPage { override fun searchMangaParse(response: Response): MangasPage {
val mangaPage = super.searchMangaParse(response) val mangaPage = super.searchMangaParse(response)

View File

@ -17,8 +17,4 @@ class TatakaeScan : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -17,8 +17,4 @@ class Visbellum : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override val altName: String = "Nome alternativo: "
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -20,6 +20,4 @@ class WarQueenScan : Madara(
.readTimeout(1, TimeUnit.MINUTES) .readTimeout(1, TimeUnit.MINUTES)
.writeTimeout(1, TimeUnit.MINUTES) .writeTimeout(1, TimeUnit.MINUTES)
.build() .build()
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -20,12 +20,10 @@ class YugenMangasFactory : SourceFactory {
abstract class YugenMangas( abstract class YugenMangas(
override val baseUrl: String, override val baseUrl: String,
override val lang: String, lang: String,
dateFormat: SimpleDateFormat = SimpleDateFormat("MMMMM dd, yyyy", Locale.US) dateFormat: SimpleDateFormat = SimpleDateFormat("MMMMM dd, yyyy", Locale.US)
) : Madara("YugenMangas", baseUrl, lang, dateFormat) { ) : Madara("YugenMangas", baseUrl, lang, dateFormat) {
override fun popularMangaSelector() = "div.page-item-detail.manga"
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
name = element.selectFirst("a")!!.ownText() name = element.selectFirst("a")!!.ownText()
date_upload = parseChapterDate(element.selectFirst("span.chapter-release-date i")?.text()) date_upload = parseChapterDate(element.selectFirst("span.chapter-release-date i")?.text())
@ -53,7 +51,5 @@ class YugenMangasBr : YugenMangas(
override fun headersBuilder(): Headers.Builder = Headers.Builder() override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Referer", baseUrl) .add("Referer", baseUrl)
override val altName: String = "Nomes alternativos: "
override val useNewChapterEndpoint: Boolean = true override val useNewChapterEndpoint: Boolean = true
} }

View File

@ -17,6 +17,4 @@ class YuriVerso : Madara(
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override fun popularMangaSelector() = "div.page-item-detail.manga"
} }

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangafoxfun
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaFoxFun : MangaHub( class MangaFoxFun : MangaHub(
"MangaFox.fun", "MangaFox.fun",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangahereonl
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaHereOnl : MangaHub( class MangaHereOnl : MangaHub(
"MangaHere.onl", "MangaHere.onl",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangahubio
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaHubIo : MangaHub( class MangaHubIo : MangaHub(
"MangaHub", "MangaHub",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangakakalotfun
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangakakalotFun : MangaHub( class MangakakalotFun : MangaHub(
"Mangakakalot.fun", "Mangakakalot.fun",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.manganel
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaNel : MangaHub( class MangaNel : MangaHub(
"MangaNel", "MangaNel",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangaonlinefun
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaOnlineFun : MangaHub( class MangaOnlineFun : MangaHub(
"MangaOnline.fun", "MangaOnline.fun",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangapandaonl
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaPandaOnl : MangaHub( class MangaPandaOnl : MangaHub(
"MangaPanda.onl", "MangaPanda.onl",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangareadersite
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaReaderSite : MangaHub( class MangaReaderSite : MangaHub(
"MangaReader.site", "MangaReader.site",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangatoday
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaToday : MangaHub( class MangaToday : MangaHub(
"MangaToday", "MangaToday",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.mangatownhub
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class MangaTownHub : MangaHub( class MangaTownHub : MangaHub(
"MangaTown (unoriginal)", "MangaTown (unoriginal)",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.onemangaco
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class OneMangaCo : MangaHub( class OneMangaCo : MangaHub(
"1Manga.co", "1Manga.co",

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.en.onemangainfo
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub import eu.kanade.tachiyomi.multisrc.mangahub.MangaHub
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
class OneMangaInfo : MangaHub( class OneMangaInfo : MangaHub(
"OneManga.info", "OneManga.info",

View File

@ -36,7 +36,7 @@ import kotlin.random.Random
abstract class Madara( abstract class Madara(
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,
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US) private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US)
) : ParsedHttpSource() { ) : ParsedHttpSource() {
@ -59,7 +59,7 @@ abstract class Madara(
// Popular Manga // Popular Manga
// exclude/filter bilibili manga from list // exclude/filter bilibili manga from list
override fun popularMangaSelector() = "div.page-item-detail:not(:has(a[href*='bilibilicomics.com']))" override fun popularMangaSelector() = "div.page-item-detail.manga:not(:has(a[href*='bilibilicomics.com']))"
open val popularMangaUrlSelector = "div.post-title a" open val popularMangaUrlSelector = "div.post-title a"
@ -222,42 +222,110 @@ abstract class Madara(
return GET(url.toString(), headers) return GET(url.toString(), headers)
} }
protected class AuthorFilter : Filter.Text("Author") protected open val authorFilterTitle: String = when (lang) {
protected class ArtistFilter : Filter.Text("Artist") "pt-BR" -> "Autor"
protected class YearFilter : Filter.Text("Year of Released") else -> "Author"
protected class StatusFilter(status: List<Tag>) : Filter.Group<Tag>("Status", status) }
protected class OrderByFilter : UriPartFilter( protected open val artistFilterTitle: String = when (lang) {
"Order By", "pt-BR" -> "Artista"
arrayOf( else -> "Artist"
Pair("<select>", ""), }
Pair("Latest", "latest"),
Pair("A-Z", "alphabet"), protected open val yearFilterTitle: String = when (lang) {
Pair("Rating", "rating"), "pt-BR" -> "Ano de lançamento"
Pair("Trending", "trending"), else -> "Year of Released"
Pair("Most Views", "views"), }
Pair("New", "new-manga")
) protected open val statusFilterTitle: String = when (lang) {
"pt-BR" -> "Estado"
else -> "Status"
}
protected open val statusFilterOptions: Array<String> = when (lang) {
"pt-BR" -> arrayOf("Completo", "Em andamento", "Cancelado", "Pausado")
else -> arrayOf("Completed", "Ongoing", "Canceled", "On Hold")
}
protected val statusFilterOptionsValues: Array<String> = arrayOf(
"end", "on-going", "canceled", "on-hold"
) )
protected class GenreConditionFilter : UriPartFilter( protected open val orderByFilterTitle: String = when (lang) {
"Genre condition", "pt-BR" -> "Ordenar por"
arrayOf( else -> "Order By"
Pair("or", ""), }
Pair("and", "1")
protected open val orderByFilterOptions: Array<String> = when (lang) {
"pt-BR" -> arrayOf(
"<selecione>", "Recentes", "A-Z", "Avaliação",
"Tendência", "Visualizações", "Novos"
) )
else -> arrayOf(
"<select>", "Latest", "A-Z", "Rating",
"Trending", "Most Views", "New"
)
}
protected val orderByFilterOptionsValues: Array<String> = arrayOf(
"", "latest", "alphabet", "rating", "trending", "views", "new-manga"
) )
protected class AdultContentFilter : UriPartFilter( protected open val genreConditionFilterTitle: String = when (lang) {
"Adult Content", "pt-BR" -> "Operador dos gêneros"
arrayOf( else -> "Genre condition"
Pair("All", ""), }
Pair("None", "0"),
Pair("Only", "1") protected open val genreConditionFilterOptions: Array<String> = 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<String> = 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 em algumas fontes"
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 genreFilterResetWarning: String = when (lang) {
"pt-BR" -> "Aperte redefinir para tentar carregar os gêneros"
else -> "Press reset to attempt to fetch genres"
}
protected class AuthorFilter(title: String) : Filter.Text(title)
protected class ArtistFilter(title: String) : Filter.Text(title)
protected class YearFilter(title: String) : Filter.Text(title)
protected class StatusFilter(title: String, status: List<Tag>) :
Filter.Group<Tag>(title, status)
protected class OrderByFilter(title: String, options: List<Pair<String, String>>) :
UriPartFilter(title, options.toTypedArray())
protected class GenreConditionFilter(title: String, options: Array<String>) : UriPartFilter(
title,
options.zip(arrayOf("", "1")).toTypedArray()
) )
protected class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) protected class AdultContentFilter(title: String, options: Array<String>) : UriPartFilter(
title,
options.zip(arrayOf("", "0", "1")).toTypedArray()
)
protected class GenreList(title: String, genres: List<Genre>) : Filter.Group<Genre>(title, genres)
class Genre(name: String, val id: String = name) : Filter.CheckBox(name) class Genre(name: String, val id: String = name) : Filter.CheckBox(name)
private var genresList: List<Genre>? = null private var genresList: List<Genre>? = null
@ -266,28 +334,25 @@ abstract class Madara(
// Filters are fetched immediately once an extension loads // Filters are fetched immediately once an extension loads
// We're only able to get filters after a loading the manga directory, and resetting // 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 // the filters is the only thing that seems to reinflate the view
return genresList ?: listOf(Genre("Press reset to attempt to fetch genres", "")) return genresList ?: listOf(Genre(genreFilterResetWarning, ""))
} }
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
AuthorFilter(), AuthorFilter(authorFilterTitle),
ArtistFilter(), ArtistFilter(artistFilterTitle),
YearFilter(), YearFilter(yearFilterTitle),
StatusFilter(getStatusList()), StatusFilter(statusFilterTitle, getStatusList()),
OrderByFilter(), OrderByFilter(orderByFilterTitle, orderByFilterOptions.zip(orderByFilterOptionsValues)),
AdultContentFilter(), AdultContentFilter(adultContentFilterTitle, adultContentFilterOptions),
Filter.Separator(), Filter.Separator(),
Filter.Header("Genres may not work for all sources"), Filter.Header(genreFilterHeader),
GenreConditionFilter(), GenreConditionFilter(genreConditionFilterTitle, genreConditionFilterOptions),
GenreList(getGenreList()) GenreList(genreFilterTitle, getGenreList())
) )
protected fun getStatusList() = listOf( protected fun getStatusList() = statusFilterOptionsValues
Tag("end", "Completed"), .zip(statusFilterOptions)
Tag("on-going", "Ongoing"), .map { Tag(it.first, it.second) }
Tag("canceled", "Canceled"),
Tag("on-hold", "On Hold")
)
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>) : open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
@ -318,6 +383,16 @@ abstract class Madara(
// Manga Details Parse // Manga Details Parse
protected val completedStatusList: Array<String> = arrayOf(
"Completed", "Completo", "Concluído", "Concluido", "Terminé", "Hoàn Thành"
)
protected val ongoingStatusList: Array<String> = arrayOf(
"OnGoing", "Продолжается", "Updating", "Em Lançamento", "Em andamento", "Em Andamento",
"En cours", "Ativo", "Lançando", "Đang Tiến Hành", "Devam Ediyor", "Devam ediyor",
"In Corso", "In Arrivo"
)
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {
val manga = SManga.create() val manga = SManga.create()
with(document) { with(document) {
@ -350,8 +425,8 @@ abstract class Madara(
manga.status = when (it.text()) { manga.status = when (it.text()) {
// I don't know what's the corresponding for COMPLETED and LICENSED // I don't know what's the corresponding for COMPLETED and LICENSED
// There's no support for "Canceled" or "On Hold" // There's no support for "Canceled" or "On Hold"
"Completed", "Completo", "Concluído", "Concluido", "Terminé", "Hoàn Thành" -> SManga.COMPLETED in completedStatusList -> SManga.COMPLETED
"OnGoing", "Продолжается", "Updating", "Em Lançamento", "Em andamento", "Em Andamento", "En cours", "Ativo", "Lançando", "Đang Tiến Hành", "Devam Ediyor", "Devam ediyor", "In Corso", "In Arrivo" -> SManga.ONGOING in ongoingStatusList -> SManga.ONGOING
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
} }
@ -392,7 +467,7 @@ abstract class Madara(
} }
// Manga Details Selector // Manga Details Selector
open val mangaDetailsSelectorTitle = "div.post-title h3" open val mangaDetailsSelectorTitle = "div.post-title h3, div.post-title h1"
open val mangaDetailsSelectorAuthor = "div.author-content > a" open val mangaDetailsSelectorAuthor = "div.author-content > a"
open val mangaDetailsSelectorArtist = "div.artist-content > a" open val mangaDetailsSelectorArtist = "div.artist-content > a"
open val mangaDetailsSelectorStatus = "div.summary-content" open val mangaDetailsSelectorStatus = "div.summary-content"
@ -403,7 +478,10 @@ abstract class Madara(
open val seriesTypeSelector = ".post-content_item:contains(Type) .summary-content" open val seriesTypeSelector = ".post-content_item:contains(Type) .summary-content"
open val altNameSelector = ".post-content_item:contains(Alt) .summary-content" open val altNameSelector = ".post-content_item:contains(Alt) .summary-content"
open val altName = "Alternative Name" + ": " open val altName = when (lang) {
"pt-BR" -> "Nomes alternativos: "
else -> "Alternative Names: "
}
open val updatingRegex = "Updating|Atualizando".toRegex(RegexOption.IGNORE_CASE) open val updatingRegex = "Updating|Atualizando".toRegex(RegexOption.IGNORE_CASE)
public fun String.notUpdating(): Boolean { public fun String.notUpdating(): Boolean {
@ -619,7 +697,7 @@ abstract class Madara(
return GET(page.imageUrl!!, headers.newBuilder().set("Referer", page.url).build()) return GET(page.imageUrl!!, headers.newBuilder().set("Referer", page.url).build())
} }
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used") override fun imageUrlParse(document: Document) = ""
/** /**
* Set it to false if you want to disable the extension reporting the view count * Set it to false if you want to disable the extension reporting the view count

View File

@ -10,7 +10,7 @@ class MadaraGenerator : ThemeSourceGenerator {
override val themeClass = "Madara" override val themeClass = "Madara"
override val baseVersionCode: Int = 15 override val baseVersionCode: Int = 16
override val sources = listOf( override val sources = listOf(
MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 9), MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 9),