diff --git a/REMOVED_SOURCES.md b/REMOVED_SOURCES.md
index 54ef58300..d56c5dfff 100644
--- a/REMOVED_SOURCES.md
+++ b/REMOVED_SOURCES.md
@@ -66,3 +66,13 @@ Here is a list of known sources that were removed.
- SetsuScans https://github.com/tachiyomiorg/tachiyomi-extensions/issues/11040
- ShinobiScans https://github.com/tachiyomiorg/tachiyomi-extensions/issues/14457
- XXX Yaoi https://github.com/tachiyomiorg/tachiyomi-extensions/issues/9535
+
+### Requested removal by copyright holders
+
+By request of [Kakao Entertainment](https://www.kakaoent.com/):
+
+- 1st Kiss-Manga
+- Bato.to
+- Mangadex
+- NewToki / ManaToki
+- S2Manga
diff --git a/multisrc/overrides/madara/s2manga/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/madara/s2manga/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 78aed8f9d..000000000
Binary files a/multisrc/overrides/madara/s2manga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/madara/s2manga/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/madara/s2manga/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 57b0e935b..000000000
Binary files a/multisrc/overrides/madara/s2manga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/madara/s2manga/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/madara/s2manga/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 60ac860b9..000000000
Binary files a/multisrc/overrides/madara/s2manga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/madara/s2manga/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/madara/s2manga/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 6201c85ab..000000000
Binary files a/multisrc/overrides/madara/s2manga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/madara/s2manga/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/madara/s2manga/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index ed057db6b..000000000
Binary files a/multisrc/overrides/madara/s2manga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/madara/s2manga/res/web_hi_res_512.png b/multisrc/overrides/madara/s2manga/res/web_hi_res_512.png
deleted file mode 100644
index c39e43b09..000000000
Binary files a/multisrc/overrides/madara/s2manga/res/web_hi_res_512.png and /dev/null differ
diff --git a/multisrc/overrides/madara/s2manga/src/S2Manga.kt b/multisrc/overrides/madara/s2manga/src/S2Manga.kt
deleted file mode 100644
index 017949318..000000000
--- a/multisrc/overrides/madara/s2manga/src/S2Manga.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package eu.kanade.tachiyomi.extension.en.s2manga
-
-import eu.kanade.tachiyomi.multisrc.madara.Madara
-
-class S2Manga : Madara("S2Manga", "https://www.s2manga.com", "en") {
-
- override fun headersBuilder() = super.headersBuilder()
- .add("Referer", "$baseUrl/")
-
- override val pageListParseSelector = "div.page-break img[src*=\"https\"]"
-}
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt
index 5e347bac4..8e9be4445 100644
--- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt
@@ -422,7 +422,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("ROG Mangás", "https://rogmangas.com", "pt-BR", pkgName = "mangasoverall", className = "RogMangas", overrideVersionCode = 1),
SingleLang("Romantik Manga", "https://romantikmanga.com", "tr"),
SingleLang("Rüya Manga", "https://www.ruyamanga.com", "tr", className = "RuyaManga", overrideVersionCode = 1),
- SingleLang("S2Manga", "https://www.s2manga.com", "en", overrideVersionCode = 2),
SingleLang("Sagrado Império da Britannia", "https://imperiodabritannia.com", "pt-BR", className = "ImperioDaBritannia"),
SingleLang("SamuraiScan", "https://samuraiscan.com", "es", overrideVersionCode = 3),
SingleLang("Sawamics", "https://sawamics.com", "en"),
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 3e0631f9e..e1dbaa7e2 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -19,7 +19,7 @@ if (System.getenv("CI") == null || System.getenv("CI_MODULE_GEN") == "true") {
*/
loadAllIndividualExtensions()
loadAllGeneratedMultisrcExtensions()
- // loadIndividualExtension("all", "mangadex")
+ // loadIndividualExtension("all", "komga")
// loadGeneratedMultisrcExtension("en", "guya")
} else {
// Running in CI (GitHub Actions)
diff --git a/src/all/batoto/AndroidManifest.xml b/src/all/batoto/AndroidManifest.xml
deleted file mode 100644
index c4ca310dd..000000000
--- a/src/all/batoto/AndroidManifest.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/all/batoto/CHANGELOG.md b/src/all/batoto/CHANGELOG.md
deleted file mode 100644
index e240bf4e9..000000000
--- a/src/all/batoto/CHANGELOG.md
+++ /dev/null
@@ -1,201 +0,0 @@
-## 1.3.30
-
-### Refactor
-
-* Replace CryptoJS with Native Kotlin Functions
-* Remove QuickJS dependency
-
-## 1.3.29
-
-### Refactor
-
-* Cleanup pageListParse function
-* Replace Duktape with QuickJS
-
-## 1.3.28
-
-### Features
-
-* Add mirror `batocc.com`
-* Add mirror `batotwo.com`
-* Add mirror `mangatoto.net`
-* Add mirror `mangatoto.org`
-* Add mirror `mycordant.co.uk`
-* Add mirror `dto.to`
-* Add mirror `hto.to`
-* Add mirror `mto.to`
-* Add mirror `wto.to`
-* Remove mirror `mycdhands.com`
-
-## 1.3.27
-
-### Features
-
-* Change default popular sort by `Most Views Totally`
-
-## 1.3.26
-
-### Fix
-
-* Update author and artist parsing
-
-## 1.3.25
-
-### Fix
-
-* Status parsing
-* Artist name parsing
-
-## 1.3.24
-
-### Fix
-
-* Bump versions for individual extension with URL handler activities
-
-## 1.2.23
-
-### Fix
-
-* Update pageListParse logic to handle website changes
-
-## 1.2.22
-
-### Features
-
-* Add `CHANGELOG.md` & `README.md`
-
-## 1.2.21
-
-### Fix
-
-* Update lang codes
-
-## 1.2.20
-
-### Features
-
-* Rework of search
-
-## 1.2.19
-
-### Features
-
-* Support for alternative chapter list
-* Personal lists filter
-
-## 1.2.18
-
-### Features
-
-* Utils lists filter
-* Letter matching filter
-
-## 1.2.17
-
-### Features
-
-* Add mirror `mycdhands.com`
-
-## 1.2.16
-
-### Features
-
-* Mirror support
-* URL intent updates
-
-## 1.2.15
-
-### Fix
-
-* Manga description
-
-## 1.2.14
-
-### Features
-
-* Escape entities
-
-## 1.2.13
-
-### Refactor
-
-* Replace Gson with kotlinx.serialization
-
-## 1.2.12
-
-### Fix
-
-* Infinity search
-
-## 1.2.11
-
-### Fix
-
-* No search result
-
-## 1.2.10
-
-### Features
-
-* Support for URL intent
-* Updated filters
-
-## 1.2.9
-
-### Fix
-
-* Chapter parsing
-
-## 1.2.8
-
-### Features
-
-* More chapter filtering
-
-## 1.2.7
-
-### Fix
-
-* Language filtering in latest
-* Parsing of seconds
-
-## 1.2.6
-
-### Features
-
-* Scanlator support
-
-### Fix
-
-* Date parsing
-
-## 1.2.5
-
-### Features
-
-* Update supported Language list
-
-## 1.2.4
-
-### Features
-
-* Support for excluding genres
-
-## 1.2.3
-
-### Fix
-
-* Typo in some genres
-
-## 1.2.2
-
-### Features
-
-* Reworked filter option
-
-## 1.2.1
-
-### Features
-
-* Conversion from Emerald to Bato.to
-* First version
diff --git a/src/all/batoto/README.md b/src/all/batoto/README.md
deleted file mode 100644
index 8f7c39cc5..000000000
--- a/src/all/batoto/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Bato.to
-
-Table of Content
-- [FAQ](#FAQ)
- - [Why are there Manga of diffrent languge than the selected one in Personal & Utils lists?](#why-are-there-manga-of-diffrent-languge-than-the-selected-one-in-personal--utils-lists)
- - [Bato.to is not loading anything?](#batoto-is-not-loading-anything)
-
-[Uncomment this if needed; and replace ( and ) with ( and )]: <> (- [Guides](#Guides))
-
-Don't find the question you are look for go check out our general FAQs and Guides over at [Extension FAQ](https://tachiyomi.org/help/faq/#extensions) or [Getting Started](https://tachiyomi.org/help/guides/getting-started/#installation)
-
-## FAQ
-
-### Why are there Manga of diffrent languge than the selected one in Personal & Utils lists?
-Personol & Utils lists have no way to difritiate between langueges.
-
-### Bato.to is not loading anything?
-Bato.to get blocked by some ISPs, try using a diffrent mirror of Bato.to from the settings.
-
-[Uncomment this if needed]: <> (## Guides)
diff --git a/src/all/batoto/build.gradle b/src/all/batoto/build.gradle
deleted file mode 100644
index 3589fc1cd..000000000
--- a/src/all/batoto/build.gradle
+++ /dev/null
@@ -1,17 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlinx-serialization'
-
-ext {
- extName = 'Bato.to'
- pkgNameSuffix = 'all.batoto'
- extClass = '.BatoToFactory'
- extVersionCode = 32
- isNsfw = true
-}
-
-apply from: "$rootDir/common.gradle"
-
-dependencies {
- implementation(project(':lib-cryptoaes'))
-}
diff --git a/src/all/batoto/res/mipmap-hdpi/ic_launcher.png b/src/all/batoto/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 0c371b3be..000000000
Binary files a/src/all/batoto/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/src/all/batoto/res/mipmap-mdpi/ic_launcher.png b/src/all/batoto/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 718a3b8b1..000000000
Binary files a/src/all/batoto/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/src/all/batoto/res/mipmap-xhdpi/ic_launcher.png b/src/all/batoto/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index e705165fc..000000000
Binary files a/src/all/batoto/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/all/batoto/res/mipmap-xxhdpi/ic_launcher.png b/src/all/batoto/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 7f9d6a195..000000000
Binary files a/src/all/batoto/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/all/batoto/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/batoto/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index d7d91a0db..000000000
Binary files a/src/all/batoto/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/all/batoto/res/web_hi_res_512.png b/src/all/batoto/res/web_hi_res_512.png
deleted file mode 100644
index 973b65efa..000000000
Binary files a/src/all/batoto/res/web_hi_res_512.png and /dev/null differ
diff --git a/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoTo.kt b/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoTo.kt
deleted file mode 100644
index 8d04c0e6b..000000000
--- a/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoTo.kt
+++ /dev/null
@@ -1,974 +0,0 @@
-package eu.kanade.tachiyomi.extension.all.batoto
-
-import android.app.Application
-import android.content.SharedPreferences
-import androidx.preference.CheckBoxPreference
-import androidx.preference.ListPreference
-import androidx.preference.PreferenceScreen
-import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES
-import eu.kanade.tachiyomi.lib.cryptoaes.Deobfuscator
-import eu.kanade.tachiyomi.network.GET
-import eu.kanade.tachiyomi.network.POST
-import eu.kanade.tachiyomi.network.asObservableSuccess
-import eu.kanade.tachiyomi.source.ConfigurableSource
-import eu.kanade.tachiyomi.source.model.Filter
-import eu.kanade.tachiyomi.source.model.FilterList
-import eu.kanade.tachiyomi.source.model.MangasPage
-import eu.kanade.tachiyomi.source.model.Page
-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.serialization.decodeFromString
-import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonObject
-import kotlinx.serialization.json.jsonArray
-import kotlinx.serialization.json.jsonObject
-import kotlinx.serialization.json.jsonPrimitive
-import okhttp3.FormBody
-import okhttp3.HttpUrl.Companion.toHttpUrl
-import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.Response
-import org.jsoup.Jsoup
-import org.jsoup.nodes.Document
-import org.jsoup.nodes.Element
-import org.jsoup.parser.Parser
-import rx.Observable
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
-import uy.kohesive.injekt.injectLazy
-import java.text.SimpleDateFormat
-import java.util.Calendar
-import java.util.Locale
-import java.util.concurrent.TimeUnit
-
-open class BatoTo(
- final override val lang: String,
- private val siteLang: String,
-) : ConfigurableSource, ParsedHttpSource() {
-
- private val preferences: SharedPreferences by lazy {
- Injekt.get().getSharedPreferences("source_$id", 0x0000)
- }
-
- override val name: String = "Bato.to"
- override val baseUrl: String = getMirrorPref()!!
- override val id: Long = when (lang) {
- "zh-Hans" -> 2818874445640189582
- "zh-Hant" -> 38886079663327225
- "ro-MD" -> 8871355786189601023
- else -> super.id
- }
-
- override fun setupPreferenceScreen(screen: PreferenceScreen) {
- val mirrorPref = ListPreference(screen.context).apply {
- key = "${MIRROR_PREF_KEY}_$lang"
- title = MIRROR_PREF_TITLE
- entries = MIRROR_PREF_ENTRIES
- entryValues = MIRROR_PREF_ENTRY_VALUES
- setDefaultValue(MIRROR_PREF_DEFAULT_VALUE)
- summary = "%s"
-
- setOnPreferenceChangeListener { _, newValue ->
- val selected = newValue as String
- val index = findIndexOfValue(selected)
- val entry = entryValues[index] as String
- preferences.edit().putString("${MIRROR_PREF_KEY}_$lang", entry).commit()
- }
- }
- val altChapterListPref = CheckBoxPreference(screen.context).apply {
- key = "${ALT_CHAPTER_LIST_PREF_KEY}_$lang"
- title = ALT_CHAPTER_LIST_PREF_TITLE
- summary = ALT_CHAPTER_LIST_PREF_SUMMARY
- setDefaultValue(ALT_CHAPTER_LIST_PREF_DEFAULT_VALUE)
-
- setOnPreferenceChangeListener { _, newValue ->
- val checkValue = newValue as Boolean
- preferences.edit().putBoolean("${ALT_CHAPTER_LIST_PREF_KEY}_$lang", checkValue).commit()
- }
- }
- screen.addPreference(mirrorPref)
- screen.addPreference(altChapterListPref)
- }
-
- private fun getMirrorPref(): String? = preferences.getString("${MIRROR_PREF_KEY}_$lang", MIRROR_PREF_DEFAULT_VALUE)
- private fun getAltChapterListPref(): Boolean = preferences.getBoolean("${ALT_CHAPTER_LIST_PREF_KEY}_$lang", ALT_CHAPTER_LIST_PREF_DEFAULT_VALUE)
-
- override val supportsLatest = true
- private val json: Json by injectLazy()
- override val client: OkHttpClient = network.cloudflareClient.newBuilder()
- .connectTimeout(10, TimeUnit.SECONDS)
- .readTimeout(30, TimeUnit.SECONDS)
- .build()
-
- override fun latestUpdatesRequest(page: Int): Request {
- return GET("$baseUrl/browse?langs=$siteLang&sort=update&page=$page")
- }
-
- override fun latestUpdatesSelector(): String {
- return when (siteLang) {
- "" -> "div#series-list div.col"
- "en" -> "div#series-list div.col.no-flag"
- else -> "div#series-list div.col:has([data-lang=\"$siteLang\"])"
- }
- }
-
- override fun latestUpdatesFromElement(element: Element): SManga {
- val manga = SManga.create()
- val item = element.select("a.item-cover")
- val imgurl = item.select("img").attr("abs:src")
- manga.setUrlWithoutDomain(item.attr("href"))
- manga.title = element.select("a.item-title").text().removeEntities()
- manga.thumbnail_url = imgurl
- return manga
- }
-
- override fun latestUpdatesNextPageSelector() = "div#mainer nav.d-none .pagination .page-item:last-of-type:not(.disabled)"
-
- override fun popularMangaRequest(page: Int): Request {
- return GET("$baseUrl/browse?langs=$siteLang&sort=views_a&page=$page")
- }
-
- override fun popularMangaSelector() = latestUpdatesSelector()
-
- override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element)
-
- override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector()
-
- override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable {
- return when {
- query.startsWith("ID:") -> {
- val id = query.substringAfter("ID:")
- client.newCall(GET("$baseUrl/series/$id", headers)).asObservableSuccess()
- .map { response ->
- queryIDParse(response)
- }
- }
- query.isNotBlank() -> {
- val url = "$baseUrl/search".toHttpUrl().newBuilder()
- .addQueryParameter("word", query)
- .addQueryParameter("page", page.toString())
- filters.forEach { filter ->
- when (filter) {
- is LetterFilter -> {
- if (filter.state == 1) {
- url.addQueryParameter("mode", "letter")
- }
- }
- else -> { /* Do Nothing */ }
- }
- }
- client.newCall(GET(url.build().toString(), headers)).asObservableSuccess()
- .map { response ->
- queryParse(response)
- }
- }
- else -> {
- val url = "$baseUrl/browse".toHttpUrlOrNull()!!.newBuilder()
- var min = ""
- var max = ""
- filters.forEach { filter ->
- when (filter) {
- is UtilsFilter -> {
- if (filter.state != 0) {
- val filterUrl = "$baseUrl/_utils/comic-list?type=${filter.selected}"
- return client.newCall(GET(filterUrl, headers)).asObservableSuccess()
- .map { response ->
- queryUtilsParse(response)
- }
- }
- }
- is HistoryFilter -> {
- if (filter.state != 0) {
- val filterUrl = "$baseUrl/ajax.my.${filter.selected}.paging"
- return client.newCall(POST(filterUrl, headers, formBuilder().build())).asObservableSuccess()
- .map { response ->
- queryHistoryParse(response)
- }
- }
- }
- is LangGroupFilter -> {
- if (filter.selected.isEmpty()) {
- url.addQueryParameter("langs", siteLang)
- } else {
- val selection = "${filter.selected.joinToString(",")},$siteLang"
- url.addQueryParameter("langs", selection)
- }
- }
- is GenreGroupFilter -> {
- with(filter) {
- url.addQueryParameter(
- "genres",
- included.joinToString(",") + "|" + excluded.joinToString(","),
- )
- }
- }
- is StatusFilter -> url.addQueryParameter("release", filter.selected)
- is SortFilter -> {
- if (filter.state != null) {
- val sort = getSortFilter()[filter.state!!.index].value
- val value = when (filter.state!!.ascending) {
- true -> "az"
- false -> "za"
- }
- url.addQueryParameter("sort", "$sort.$value")
- }
- }
- is OriginGroupFilter -> {
- if (filter.selected.isNotEmpty()) {
- url.addQueryParameter("origs", filter.selected.joinToString(","))
- }
- }
- is MinChapterTextFilter -> min = filter.state
- is MaxChapterTextFilter -> max = filter.state
- else -> { /* Do Nothing */ }
- }
- }
- url.addQueryParameter("page", page.toString())
-
- if (max.isNotEmpty() or min.isNotEmpty()) {
- url.addQueryParameter("chapters", "$min-$max")
- }
-
- client.newCall(GET(url.build().toString(), headers)).asObservableSuccess()
- .map { response ->
- queryParse(response)
- }
- }
- }
- }
-
- private fun queryIDParse(response: Response): MangasPage {
- val document = response.asJsoup()
- val infoElement = document.select("div#mainer div.container-fluid")
- val manga = SManga.create()
- manga.title = infoElement.select("h3").text().removeEntities()
- manga.thumbnail_url = document.select("div.attr-cover img")
- .attr("abs:src")
- manga.url = infoElement.select("h3 a").attr("abs:href")
- return MangasPage(listOf(manga), false)
- }
-
- private fun queryParse(response: Response): MangasPage {
- val document = response.asJsoup()
- val mangas = document.select(latestUpdatesSelector())
- .map { element -> latestUpdatesFromElement(element) }
- val nextPage = document.select(latestUpdatesNextPageSelector()).first() != null
- return MangasPage(mangas, nextPage)
- }
-
- private fun queryUtilsParse(response: Response): MangasPage {
- val document = response.asJsoup()
- val mangas = document.select("tbody > tr")
- .map { element -> searchUtilsFromElement(element) }
- return MangasPage(mangas, false)
- }
-
- private fun queryHistoryParse(response: Response): MangasPage {
- val json = json.decodeFromString(response.body.string())
- val html = json.jsonObject["html"]!!.jsonPrimitive.content
-
- val document = Jsoup.parse(html, response.request.url.toString())
- val mangas = document.select(".my-history-item")
- .map { element -> searchHistoryFromElement(element) }
- return MangasPage(mangas, false)
- }
-
- private fun searchUtilsFromElement(element: Element): SManga {
- val manga = SManga.create()
- manga.setUrlWithoutDomain(element.select("td a").attr("href"))
- manga.title = element.select("td a").text()
- manga.thumbnail_url = element.select("img").attr("abs:src")
- return manga
- }
-
- private fun searchHistoryFromElement(element: Element): SManga {
- val manga = SManga.create()
- manga.setUrlWithoutDomain(element.select(".position-relative a").attr("href"))
- manga.title = element.select(".position-relative a").text()
- manga.thumbnail_url = element.select("img").attr("abs:src")
- return manga
- }
-
- open fun formBuilder() = FormBody.Builder().apply {
- add("_where", "browse")
- add("first", "0")
- add("limit", "0")
- add("prevPos", "null")
- }
-
- override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw UnsupportedOperationException("Not used")
- override fun searchMangaSelector() = throw UnsupportedOperationException("Not used")
- override fun searchMangaFromElement(element: Element) = throw UnsupportedOperationException("Not used")
- override fun searchMangaNextPageSelector() = throw UnsupportedOperationException("Not used")
-
- override fun mangaDetailsRequest(manga: SManga): Request {
- if (manga.url.startsWith("http")) {
- return GET(manga.url, headers)
- }
- return super.mangaDetailsRequest(manga)
- }
-
- override fun mangaDetailsParse(document: Document): SManga {
- val infoElement = document.select("div#mainer div.container-fluid")
- val manga = SManga.create()
- val workStatus = infoElement.select("div.attr-item:contains(original work) span").text()
- val uploadStatus = infoElement.select("div.attr-item:contains(upload status) span").text()
- manga.title = infoElement.select("h3").text().removeEntities()
- manga.author = infoElement.select("div.attr-item:contains(author) span").text()
- manga.artist = infoElement.select("div.attr-item:contains(artist) span").text()
- manga.status = parseStatus(workStatus, uploadStatus)
- manga.genre = infoElement.select(".attr-item b:contains(genres) + span ").joinToString { it.text() }
- manga.description = infoElement.select("div.limit-html").text() + "\n" + infoElement.select(".episode-list > .alert-warning").text().trim()
- manga.thumbnail_url = document.select("div.attr-cover img")
- .attr("abs:src")
- return manga
- }
-
- private fun parseStatus(workStatus: String?, uploadStatus: String?) = when {
- workStatus == null -> SManga.UNKNOWN
- workStatus.contains("Ongoing") -> SManga.ONGOING
- workStatus.contains("Cancelled") -> SManga.CANCELLED
- workStatus.contains("Hiatus") -> SManga.ON_HIATUS
- workStatus.contains("Completed") -> when {
- uploadStatus?.contains("Ongoing") == true -> SManga.PUBLISHING_FINISHED
- else -> SManga.COMPLETED
- }
- else -> SManga.UNKNOWN
- }
-
- override fun fetchChapterList(manga: SManga): Observable> {
- val url = client.newCall(
- GET(
- when {
- manga.url.startsWith("http") -> manga.url
- else -> "$baseUrl${manga.url}"
- },
- ),
- ).execute().asJsoup()
- if (getAltChapterListPref() || checkChapterLists(url)) {
- val id = manga.url.substringBeforeLast("/").substringAfterLast("/").trim()
- return client.newCall(GET("$baseUrl/rss/series/$id.xml"))
- .asObservableSuccess()
- .map { altChapterParse(it, manga.title) }
- }
- return super.fetchChapterList(manga)
- }
-
- private fun altChapterParse(response: Response, title: String): List {
- return Jsoup.parse(response.body.string(), response.request.url.toString(), Parser.xmlParser())
- .select("channel > item").map { item ->
- SChapter.create().apply {
- url = item.selectFirst("guid")!!.text()
- name = item.selectFirst("title")!!.text().substringAfter(title).trim()
- date_upload = SimpleDateFormat("E, dd MMM yyyy H:m:s Z", Locale.US).parse(item.selectFirst("pubDate")!!.text())?.time ?: 0L
- }
- }
- }
-
- private fun checkChapterLists(document: Document): Boolean {
- return document.select(".episode-list > .alert-warning").text().contains("This comic has been marked as deleted and the chapter list is not available.")
- }
-
- override fun chapterListRequest(manga: SManga): Request {
- if (manga.url.startsWith("http")) {
- return GET(manga.url, headers)
- }
- return super.chapterListRequest(manga)
- }
-
- override fun chapterListSelector() = "div.main div.p-2"
-
- override fun chapterFromElement(element: Element): SChapter {
- val chapter = SChapter.create()
- val urlElement = element.select("a.chapt")
- val group = element.select("div.extra > a:not(.ps-3)").text()
- val time = element.select("div.extra > i.ps-3").text()
- chapter.setUrlWithoutDomain(urlElement.attr("href"))
- chapter.name = urlElement.text()
- if (group != "") {
- chapter.scanlator = group
- }
- if (time != "") {
- chapter.date_upload = parseChapterDate(time)
- }
- return chapter
- }
-
- private fun parseChapterDate(date: String): Long {
- val value = date.split(' ')[0].toInt()
-
- return when {
- "secs" in date -> Calendar.getInstance().apply {
- add(Calendar.SECOND, value * -1)
- }.timeInMillis
- "mins" in date -> Calendar.getInstance().apply {
- add(Calendar.MINUTE, value * -1)
- }.timeInMillis
- "hours" in date -> Calendar.getInstance().apply {
- add(Calendar.HOUR_OF_DAY, value * -1)
- }.timeInMillis
- "days" in date -> Calendar.getInstance().apply {
- add(Calendar.DATE, value * -1)
- }.timeInMillis
- "weeks" in date -> Calendar.getInstance().apply {
- add(Calendar.DATE, value * 7 * -1)
- }.timeInMillis
- "months" in date -> Calendar.getInstance().apply {
- add(Calendar.MONTH, value * -1)
- }.timeInMillis
- "years" in date -> Calendar.getInstance().apply {
- add(Calendar.YEAR, value * -1)
- }.timeInMillis
- "sec" in date -> Calendar.getInstance().apply {
- add(Calendar.SECOND, value * -1)
- }.timeInMillis
- "min" in date -> Calendar.getInstance().apply {
- add(Calendar.MINUTE, value * -1)
- }.timeInMillis
- "hour" in date -> Calendar.getInstance().apply {
- add(Calendar.HOUR_OF_DAY, value * -1)
- }.timeInMillis
- "day" in date -> Calendar.getInstance().apply {
- add(Calendar.DATE, value * -1)
- }.timeInMillis
- "week" in date -> Calendar.getInstance().apply {
- add(Calendar.DATE, value * 7 * -1)
- }.timeInMillis
- "month" in date -> Calendar.getInstance().apply {
- add(Calendar.MONTH, value * -1)
- }.timeInMillis
- "year" in date -> Calendar.getInstance().apply {
- add(Calendar.YEAR, value * -1)
- }.timeInMillis
- else -> {
- return 0
- }
- }
- }
-
- override fun pageListRequest(chapter: SChapter): Request {
- if (chapter.url.startsWith("http")) {
- return GET(chapter.url, headers)
- }
- return super.pageListRequest(chapter)
- }
-
- override fun pageListParse(document: Document): List {
- val script = document.selectFirst("script:containsData(imgHttpLis):containsData(batoWord):containsData(batoPass)")?.html()
- ?: throw RuntimeException("Couldn't find script with image data.")
-
- val imgHttpLisString = script.substringAfter("const imgHttpLis =").substringBefore(";").trim()
- val imgHttpLis = json.parseToJsonElement(imgHttpLisString).jsonArray.map { it.jsonPrimitive.content }
- val batoWord = script.substringAfter("const batoWord =").substringBefore(";").trim()
- val batoPass = script.substringAfter("const batoPass =").substringBefore(";").trim()
-
- val evaluatedPass: String = Deobfuscator.deobfuscateJsPassword(batoPass)
- val imgAccListString = CryptoAES.decrypt(batoWord.removeSurrounding("\""), evaluatedPass)
- val imgAccList = json.parseToJsonElement(imgAccListString).jsonArray.map { it.jsonPrimitive.content }
-
- return imgHttpLis.zip(imgAccList).mapIndexed { i, (imgUrl, imgAcc) ->
- Page(i, imageUrl = "$imgUrl?$imgAcc")
- }
- }
-
- override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
-
- private fun String.removeEntities(): String = Parser.unescapeEntities(this, true)
-
- override fun getFilterList() = FilterList(
- LetterFilter(getLetterFilter(), 0),
- Filter.Separator(),
- Filter.Header("NOTE: Ignored if using text search!"),
- Filter.Separator(),
- SortFilter(getSortFilter().map { it.name }.toTypedArray()),
- StatusFilter(getStatusFilter(), 0),
- GenreGroupFilter(getGenreFilter()),
- OriginGroupFilter(getOrginFilter()),
- LangGroupFilter(getLangFilter()),
- MinChapterTextFilter(),
- MaxChapterTextFilter(),
- Filter.Separator(),
- Filter.Header("NOTE: Filters below are incompatible with any other filters!"),
- Filter.Header("NOTE: Login Required!"),
- Filter.Separator(),
- UtilsFilter(getUtilsFilter(), 0),
- HistoryFilter(getHistoryFilter(), 0),
- )
- class SelectFilterOption(val name: String, val value: String)
- class CheckboxFilterOption(val value: String, name: String, default: Boolean = false) : Filter.CheckBox(name, default)
- class TriStateFilterOption(val value: String, name: String, default: Int = 0) : Filter.TriState(name, default)
-
- abstract class SelectFilter(name: String, private val options: List, default: Int = 0) : Filter.Select(name, options.map { it.name }.toTypedArray(), default) {
- val selected: String
- get() = options[state].value
- }
-
- abstract class CheckboxGroupFilter(name: String, options: List) : Filter.Group(name, options) {
- val selected: List
- get() = state.filter { it.state }.map { it.value }
- }
-
- abstract class TriStateGroupFilter(name: String, options: List) : Filter.Group(name, options) {
- val included: List
- get() = state.filter { it.isIncluded() }.map { it.value }
-
- val excluded: List
- get() = state.filter { it.isExcluded() }.map { it.value }
- }
-
- abstract class TextFilter(name: String) : Filter.Text(name)
-
- class SortFilter(sortables: Array) : Filter.Sort("Sort", sortables, Selection(5, false))
- class StatusFilter(options: List, default: Int) : SelectFilter("Status", options, default)
- class OriginGroupFilter(options: List) : CheckboxGroupFilter("Origin", options)
- class GenreGroupFilter(options: List) : TriStateGroupFilter("Genre", options)
- class MinChapterTextFilter : TextFilter("Min. Chapters")
- class MaxChapterTextFilter : TextFilter("Max. Chapters")
- class LangGroupFilter(options: List) : CheckboxGroupFilter("Languages", options)
- class LetterFilter(options: List, default: Int) : SelectFilter("Letter matching mode (Slow)", options, default)
- class UtilsFilter(options: List, default: Int) : SelectFilter("Utils comic list", options, default)
- class HistoryFilter(options: List, default: Int) : SelectFilter("Personal list", options, default)
-
- private fun getLetterFilter() = listOf(
- SelectFilterOption("Disabled", "disabled"),
- SelectFilterOption("Enabled", "enabled"),
- )
-
- private fun getSortFilter() = listOf(
- SelectFilterOption("Z-A", "title"),
- SelectFilterOption("Last Updated", "update"),
- SelectFilterOption("Newest Added", "create"),
- SelectFilterOption("Most Views Totally", "views_a"),
- SelectFilterOption("Most Views 365 days", "views_y"),
- SelectFilterOption("Most Views 30 days", "views_m"),
- SelectFilterOption("Most Views 7 days", "views_w"),
- SelectFilterOption("Most Views 24 hours", "views_d"),
- SelectFilterOption("Most Views 60 minutes", "views_h"),
- )
-
- private fun getHistoryFilter() = listOf(
- SelectFilterOption("None", ""),
- SelectFilterOption("My History", "history"),
- SelectFilterOption("My Updates", "updates"),
- )
-
- private fun getUtilsFilter() = listOf(
- SelectFilterOption("None", ""),
- SelectFilterOption("Comics: I Created", "i-created"),
- SelectFilterOption("Comics: I Modified", "i-modified"),
- SelectFilterOption("Comics: I Uploaded", "i-uploaded"),
- SelectFilterOption("Comics: Authorized to me", "i-authorized"),
- SelectFilterOption("Comics: Draft Status", "status-draft"),
- SelectFilterOption("Comics: Hidden Status", "status-hidden"),
- SelectFilterOption("Ongoing and Not updated in 30-60 days", "not-updated-30-60"),
- SelectFilterOption("Ongoing and Not updated in 60-90 days", "not-updated-60-90"),
- SelectFilterOption("Ongoing and Not updated in 90-180 days", "not-updated-90-180"),
- SelectFilterOption("Ongoing and Not updated in 180-360 days", "not-updated-180-360"),
- SelectFilterOption("Ongoing and Not updated in 360-1000 days", "not-updated-360-1000"),
- SelectFilterOption("Ongoing and Not updated more than 1000 days", "not-updated-1000"),
- )
-
- private fun getStatusFilter() = listOf(
- SelectFilterOption("All", ""),
- SelectFilterOption("Pending", "pending"),
- SelectFilterOption("Ongoing", "ongoing"),
- SelectFilterOption("Completed", "completed"),
- SelectFilterOption("Hiatus", "hiatus"),
- SelectFilterOption("Cancelled", "cancelled"),
- )
-
- private fun getOrginFilter() = listOf(
- // Values exported from publish.bato.to
- CheckboxFilterOption("zh", "Chinese"),
- CheckboxFilterOption("en", "English"),
- CheckboxFilterOption("ja", "Japanese"),
- CheckboxFilterOption("ko", "Korean"),
- CheckboxFilterOption("af", "Afrikaans"),
- CheckboxFilterOption("sq", "Albanian"),
- CheckboxFilterOption("am", "Amharic"),
- CheckboxFilterOption("ar", "Arabic"),
- CheckboxFilterOption("hy", "Armenian"),
- CheckboxFilterOption("az", "Azerbaijani"),
- CheckboxFilterOption("be", "Belarusian"),
- CheckboxFilterOption("bn", "Bengali"),
- CheckboxFilterOption("bs", "Bosnian"),
- CheckboxFilterOption("bg", "Bulgarian"),
- CheckboxFilterOption("my", "Burmese"),
- CheckboxFilterOption("km", "Cambodian"),
- CheckboxFilterOption("ca", "Catalan"),
- CheckboxFilterOption("ceb", "Cebuano"),
- CheckboxFilterOption("zh_hk", "Chinese (Cantonese)"),
- CheckboxFilterOption("zh_tw", "Chinese (Traditional)"),
- CheckboxFilterOption("hr", "Croatian"),
- CheckboxFilterOption("cs", "Czech"),
- CheckboxFilterOption("da", "Danish"),
- CheckboxFilterOption("nl", "Dutch"),
- CheckboxFilterOption("en_us", "English (United States)"),
- CheckboxFilterOption("eo", "Esperanto"),
- CheckboxFilterOption("et", "Estonian"),
- CheckboxFilterOption("fo", "Faroese"),
- CheckboxFilterOption("fil", "Filipino"),
- CheckboxFilterOption("fi", "Finnish"),
- CheckboxFilterOption("fr", "French"),
- CheckboxFilterOption("ka", "Georgian"),
- CheckboxFilterOption("de", "German"),
- CheckboxFilterOption("el", "Greek"),
- CheckboxFilterOption("gn", "Guarani"),
- CheckboxFilterOption("gu", "Gujarati"),
- CheckboxFilterOption("ht", "Haitian Creole"),
- CheckboxFilterOption("ha", "Hausa"),
- CheckboxFilterOption("he", "Hebrew"),
- CheckboxFilterOption("hi", "Hindi"),
- CheckboxFilterOption("hu", "Hungarian"),
- CheckboxFilterOption("is", "Icelandic"),
- CheckboxFilterOption("ig", "Igbo"),
- CheckboxFilterOption("id", "Indonesian"),
- CheckboxFilterOption("ga", "Irish"),
- CheckboxFilterOption("it", "Italian"),
- CheckboxFilterOption("jv", "Javanese"),
- CheckboxFilterOption("kn", "Kannada"),
- CheckboxFilterOption("kk", "Kazakh"),
- CheckboxFilterOption("ku", "Kurdish"),
- CheckboxFilterOption("ky", "Kyrgyz"),
- CheckboxFilterOption("lo", "Laothian"),
- CheckboxFilterOption("lv", "Latvian"),
- CheckboxFilterOption("lt", "Lithuanian"),
- CheckboxFilterOption("lb", "Luxembourgish"),
- CheckboxFilterOption("mk", "Macedonian"),
- CheckboxFilterOption("mg", "Malagasy"),
- CheckboxFilterOption("ms", "Malay"),
- CheckboxFilterOption("ml", "Malayalam"),
- CheckboxFilterOption("mt", "Maltese"),
- CheckboxFilterOption("mi", "Maori"),
- CheckboxFilterOption("mr", "Marathi"),
- CheckboxFilterOption("mo", "Moldavian"),
- CheckboxFilterOption("mn", "Mongolian"),
- CheckboxFilterOption("ne", "Nepali"),
- CheckboxFilterOption("no", "Norwegian"),
- CheckboxFilterOption("ny", "Nyanja"),
- CheckboxFilterOption("ps", "Pashto"),
- CheckboxFilterOption("fa", "Persian"),
- CheckboxFilterOption("pl", "Polish"),
- CheckboxFilterOption("pt", "Portuguese"),
- CheckboxFilterOption("pt_br", "Portuguese (Brazil)"),
- CheckboxFilterOption("ro", "Romanian"),
- CheckboxFilterOption("rm", "Romansh"),
- CheckboxFilterOption("ru", "Russian"),
- CheckboxFilterOption("sm", "Samoan"),
- CheckboxFilterOption("sr", "Serbian"),
- CheckboxFilterOption("sh", "Serbo-Croatian"),
- CheckboxFilterOption("st", "Sesotho"),
- CheckboxFilterOption("sn", "Shona"),
- CheckboxFilterOption("sd", "Sindhi"),
- CheckboxFilterOption("si", "Sinhalese"),
- CheckboxFilterOption("sk", "Slovak"),
- CheckboxFilterOption("sl", "Slovenian"),
- CheckboxFilterOption("so", "Somali"),
- CheckboxFilterOption("es", "Spanish"),
- CheckboxFilterOption("es_419", "Spanish (Latin America)"),
- CheckboxFilterOption("sw", "Swahili"),
- CheckboxFilterOption("sv", "Swedish"),
- CheckboxFilterOption("tg", "Tajik"),
- CheckboxFilterOption("ta", "Tamil"),
- CheckboxFilterOption("th", "Thai"),
- CheckboxFilterOption("ti", "Tigrinya"),
- CheckboxFilterOption("to", "Tonga"),
- CheckboxFilterOption("tr", "Turkish"),
- CheckboxFilterOption("tk", "Turkmen"),
- CheckboxFilterOption("uk", "Ukrainian"),
- CheckboxFilterOption("ur", "Urdu"),
- CheckboxFilterOption("uz", "Uzbek"),
- CheckboxFilterOption("vi", "Vietnamese"),
- CheckboxFilterOption("yo", "Yoruba"),
- CheckboxFilterOption("zu", "Zulu"),
- CheckboxFilterOption("_t", "Other"),
- )
-
- private fun getGenreFilter() = listOf(
- TriStateFilterOption("artbook", "Artbook"),
- TriStateFilterOption("cartoon", "Cartoon"),
- TriStateFilterOption("comic", "Comic"),
- TriStateFilterOption("doujinshi", "Doujinshi"),
- TriStateFilterOption("imageset", "Imageset"),
- TriStateFilterOption("manga", "Manga"),
- TriStateFilterOption("manhua", "Manhua"),
- TriStateFilterOption("manhwa", "Manhwa"),
- TriStateFilterOption("webtoon", "Webtoon"),
- TriStateFilterOption("western", "Western"),
-
- TriStateFilterOption("shoujo", "Shoujo(G)"),
- TriStateFilterOption("shounen", "Shounen(B)"),
- TriStateFilterOption("josei", "Josei(W)"),
- TriStateFilterOption("seinen", "Seinen(M)"),
- TriStateFilterOption("yuri", "Yuri(GL)"),
- TriStateFilterOption("yaoi", "Yaoi(BL)"),
- TriStateFilterOption("futa", "Futa(WL)"),
- TriStateFilterOption("bara", "Bara(ML)"),
-
- TriStateFilterOption("gore", "Gore"),
- TriStateFilterOption("bloody", "Bloody"),
- TriStateFilterOption("violence", "Violence"),
- TriStateFilterOption("ecchi", "Ecchi"),
- TriStateFilterOption("adult", "Adult"),
- TriStateFilterOption("mature", "Mature"),
- TriStateFilterOption("smut", "Smut"),
- TriStateFilterOption("hentai", "Hentai"),
-
- TriStateFilterOption("_4_koma", "4-Koma"),
- TriStateFilterOption("action", "Action"),
- TriStateFilterOption("adaptation", "Adaptation"),
- TriStateFilterOption("adventure", "Adventure"),
- TriStateFilterOption("age_gap", "Age Gap"),
- TriStateFilterOption("aliens", "Aliens"),
- TriStateFilterOption("animals", "Animals"),
- TriStateFilterOption("anthology", "Anthology"),
- TriStateFilterOption("beasts", "Beasts"),
- TriStateFilterOption("bodyswap", "Bodyswap"),
- TriStateFilterOption("cars", "cars"),
- TriStateFilterOption("cheating_infidelity", "Cheating/Infidelity"),
- TriStateFilterOption("childhood_friends", "Childhood Friends"),
- TriStateFilterOption("college_life", "College Life"),
- TriStateFilterOption("comedy", "Comedy"),
- TriStateFilterOption("contest_winning", "Contest Winning"),
- TriStateFilterOption("cooking", "Cooking"),
- TriStateFilterOption("crime", "crime"),
- TriStateFilterOption("crossdressing", "Crossdressing"),
- TriStateFilterOption("delinquents", "Delinquents"),
- TriStateFilterOption("dementia", "Dementia"),
- TriStateFilterOption("demons", "Demons"),
- TriStateFilterOption("drama", "Drama"),
- TriStateFilterOption("dungeons", "Dungeons"),
- TriStateFilterOption("emperor_daughte", "Emperor's Daughter"),
- TriStateFilterOption("fantasy", "Fantasy"),
- TriStateFilterOption("fan_colored", "Fan-Colored"),
- TriStateFilterOption("fetish", "Fetish"),
- TriStateFilterOption("full_color", "Full Color"),
- TriStateFilterOption("game", "Game"),
- TriStateFilterOption("gender_bender", "Gender Bender"),
- TriStateFilterOption("genderswap", "Genderswap"),
- TriStateFilterOption("ghosts", "Ghosts"),
- TriStateFilterOption("gyaru", "Gyaru"),
- TriStateFilterOption("harem", "Harem"),
- TriStateFilterOption("harlequin", "Harlequin"),
- TriStateFilterOption("historical", "Historical"),
- TriStateFilterOption("horror", "Horror"),
- TriStateFilterOption("incest", "Incest"),
- TriStateFilterOption("isekai", "Isekai"),
- TriStateFilterOption("kids", "Kids"),
- TriStateFilterOption("loli", "Loli"),
- TriStateFilterOption("magic", "Magic"),
- TriStateFilterOption("magical_girls", "Magical Girls"),
- TriStateFilterOption("martial_arts", "Martial Arts"),
- TriStateFilterOption("mecha", "Mecha"),
- TriStateFilterOption("medical", "Medical"),
- TriStateFilterOption("military", "Military"),
- TriStateFilterOption("monster_girls", "Monster Girls"),
- TriStateFilterOption("monsters", "Monsters"),
- TriStateFilterOption("music", "Music"),
- TriStateFilterOption("mystery", "Mystery"),
- TriStateFilterOption("netorare", "Netorare/NTR"),
- TriStateFilterOption("ninja", "Ninja"),
- TriStateFilterOption("office_workers", "Office Workers"),
- TriStateFilterOption("omegaverse", "Omegaverse"),
- TriStateFilterOption("oneshot", "Oneshot"),
- TriStateFilterOption("parody", "parody"),
- TriStateFilterOption("philosophical", "Philosophical"),
- TriStateFilterOption("police", "Police"),
- TriStateFilterOption("post_apocalyptic", "Post-Apocalyptic"),
- TriStateFilterOption("psychological", "Psychological"),
- TriStateFilterOption("regression", "Regression"),
- TriStateFilterOption("reincarnation", "Reincarnation"),
- TriStateFilterOption("reverse_harem", "Reverse Harem"),
- TriStateFilterOption("reverse_isekai", "Reverse Isekai"),
- TriStateFilterOption("romance", "Romance"),
- TriStateFilterOption("royal_family", "Royal Family"),
- TriStateFilterOption("royalty", "Royalty"),
- TriStateFilterOption("samurai", "Samurai"),
- TriStateFilterOption("school_life", "School Life"),
- TriStateFilterOption("sci_fi", "Sci-Fi"),
- TriStateFilterOption("shota", "Shota"),
- TriStateFilterOption("shoujo_ai", "Shoujo Ai"),
- TriStateFilterOption("shounen_ai", "Shounen Ai"),
- TriStateFilterOption("showbiz", "Showbiz"),
- TriStateFilterOption("slice_of_life", "Slice of Life"),
- TriStateFilterOption("sm_bdsm", "SM/BDSM/SUB-DOM"),
- TriStateFilterOption("space", "Space"),
- TriStateFilterOption("sports", "Sports"),
- TriStateFilterOption("super_power", "Super Power"),
- TriStateFilterOption("superhero", "Superhero"),
- TriStateFilterOption("supernatural", "Supernatural"),
- TriStateFilterOption("survival", "Survival"),
- TriStateFilterOption("thriller", "Thriller"),
- TriStateFilterOption("time_travel", "Time Travel"),
- TriStateFilterOption("tower_climbing", "Tower Climbing"),
- TriStateFilterOption("traditional_games", "Traditional Games"),
- TriStateFilterOption("tragedy", "Tragedy"),
- TriStateFilterOption("transmigration", "Transmigration"),
- TriStateFilterOption("vampires", "Vampires"),
- TriStateFilterOption("villainess", "Villainess"),
- TriStateFilterOption("video_games", "Video Games"),
- TriStateFilterOption("virtual_reality", "Virtual Reality"),
- TriStateFilterOption("wuxia", "Wuxia"),
- TriStateFilterOption("xianxia", "Xianxia"),
- TriStateFilterOption("xuanhuan", "Xuanhuan"),
- TriStateFilterOption("zombies", "Zombies"),
- // Hidden Genres
- TriStateFilterOption("shotacon", "shotacon"),
- TriStateFilterOption("lolicon", "lolicon"),
- TriStateFilterOption("award_winning", "Award Winning"),
- TriStateFilterOption("youkai", "Youkai"),
- TriStateFilterOption("uncategorized", "Uncategorized"),
- )
-
- private fun getLangFilter() = listOf(
- // Values exported from publish.bato.to
- CheckboxFilterOption("en", "English"),
- CheckboxFilterOption("ar", "Arabic"),
- CheckboxFilterOption("bg", "Bulgarian"),
- CheckboxFilterOption("zh", "Chinese"),
- CheckboxFilterOption("cs", "Czech"),
- CheckboxFilterOption("da", "Danish"),
- CheckboxFilterOption("nl", "Dutch"),
- CheckboxFilterOption("fil", "Filipino"),
- CheckboxFilterOption("fi", "Finnish"),
- CheckboxFilterOption("fr", "French"),
- CheckboxFilterOption("de", "German"),
- CheckboxFilterOption("el", "Greek"),
- CheckboxFilterOption("he", "Hebrew"),
- CheckboxFilterOption("hi", "Hindi"),
- CheckboxFilterOption("hu", "Hungarian"),
- CheckboxFilterOption("id", "Indonesian"),
- CheckboxFilterOption("it", "Italian"),
- CheckboxFilterOption("ja", "Japanese"),
- CheckboxFilterOption("ko", "Korean"),
- CheckboxFilterOption("ms", "Malay"),
- CheckboxFilterOption("pl", "Polish"),
- CheckboxFilterOption("pt", "Portuguese"),
- CheckboxFilterOption("pt_br", "Portuguese (Brazil)"),
- CheckboxFilterOption("ro", "Romanian"),
- CheckboxFilterOption("ru", "Russian"),
- CheckboxFilterOption("es", "Spanish"),
- CheckboxFilterOption("es_419", "Spanish (Latin America)"),
- CheckboxFilterOption("sv", "Swedish"),
- CheckboxFilterOption("th", "Thai"),
- CheckboxFilterOption("tr", "Turkish"),
- CheckboxFilterOption("uk", "Ukrainian"),
- CheckboxFilterOption("vi", "Vietnamese"),
- CheckboxFilterOption("af", "Afrikaans"),
- CheckboxFilterOption("sq", "Albanian"),
- CheckboxFilterOption("am", "Amharic"),
- CheckboxFilterOption("hy", "Armenian"),
- CheckboxFilterOption("az", "Azerbaijani"),
- CheckboxFilterOption("be", "Belarusian"),
- CheckboxFilterOption("bn", "Bengali"),
- CheckboxFilterOption("bs", "Bosnian"),
- CheckboxFilterOption("my", "Burmese"),
- CheckboxFilterOption("km", "Cambodian"),
- CheckboxFilterOption("ca", "Catalan"),
- CheckboxFilterOption("ceb", "Cebuano"),
- CheckboxFilterOption("zh_hk", "Chinese (Cantonese)"),
- CheckboxFilterOption("zh_tw", "Chinese (Traditional)"),
- CheckboxFilterOption("hr", "Croatian"),
- CheckboxFilterOption("en_us", "English (United States)"),
- CheckboxFilterOption("eo", "Esperanto"),
- CheckboxFilterOption("et", "Estonian"),
- CheckboxFilterOption("fo", "Faroese"),
- CheckboxFilterOption("ka", "Georgian"),
- CheckboxFilterOption("gn", "Guarani"),
- CheckboxFilterOption("gu", "Gujarati"),
- CheckboxFilterOption("ht", "Haitian Creole"),
- CheckboxFilterOption("ha", "Hausa"),
- CheckboxFilterOption("is", "Icelandic"),
- CheckboxFilterOption("ig", "Igbo"),
- CheckboxFilterOption("ga", "Irish"),
- CheckboxFilterOption("jv", "Javanese"),
- CheckboxFilterOption("kn", "Kannada"),
- CheckboxFilterOption("kk", "Kazakh"),
- CheckboxFilterOption("ku", "Kurdish"),
- CheckboxFilterOption("ky", "Kyrgyz"),
- CheckboxFilterOption("lo", "Laothian"),
- CheckboxFilterOption("lv", "Latvian"),
- CheckboxFilterOption("lt", "Lithuanian"),
- CheckboxFilterOption("lb", "Luxembourgish"),
- CheckboxFilterOption("mk", "Macedonian"),
- CheckboxFilterOption("mg", "Malagasy"),
- CheckboxFilterOption("ml", "Malayalam"),
- CheckboxFilterOption("mt", "Maltese"),
- CheckboxFilterOption("mi", "Maori"),
- CheckboxFilterOption("mr", "Marathi"),
- CheckboxFilterOption("mo", "Moldavian"),
- CheckboxFilterOption("mn", "Mongolian"),
- CheckboxFilterOption("ne", "Nepali"),
- CheckboxFilterOption("no", "Norwegian"),
- CheckboxFilterOption("ny", "Nyanja"),
- CheckboxFilterOption("ps", "Pashto"),
- CheckboxFilterOption("fa", "Persian"),
- CheckboxFilterOption("rm", "Romansh"),
- CheckboxFilterOption("sm", "Samoan"),
- CheckboxFilterOption("sr", "Serbian"),
- CheckboxFilterOption("sh", "Serbo-Croatian"),
- CheckboxFilterOption("st", "Sesotho"),
- CheckboxFilterOption("sn", "Shona"),
- CheckboxFilterOption("sd", "Sindhi"),
- CheckboxFilterOption("si", "Sinhalese"),
- CheckboxFilterOption("sk", "Slovak"),
- CheckboxFilterOption("sl", "Slovenian"),
- CheckboxFilterOption("so", "Somali"),
- CheckboxFilterOption("sw", "Swahili"),
- CheckboxFilterOption("tg", "Tajik"),
- CheckboxFilterOption("ta", "Tamil"),
- CheckboxFilterOption("ti", "Tigrinya"),
- CheckboxFilterOption("to", "Tonga"),
- CheckboxFilterOption("tk", "Turkmen"),
- CheckboxFilterOption("ur", "Urdu"),
- CheckboxFilterOption("uz", "Uzbek"),
- CheckboxFilterOption("yo", "Yoruba"),
- CheckboxFilterOption("zu", "Zulu"),
- CheckboxFilterOption("_t", "Other"),
- // Lang options from bato.to brows not in publish.bato.to
- CheckboxFilterOption("eu", "Basque"),
- CheckboxFilterOption("pt-PT", "Portuguese (Portugal)"),
- ).filterNot { it.value == siteLang }
-
- companion object {
- private const val MIRROR_PREF_KEY = "MIRROR"
- private const val MIRROR_PREF_TITLE = "Mirror"
- private val MIRROR_PREF_ENTRIES = arrayOf(
- "bato.to",
- "batocomic.com",
- "batocomic.net",
- "batocomic.org",
- "batotoo.com",
- "batotwo.com",
- "battwo.com",
- "comiko.net",
- "comiko.org",
- "mangatoto.com",
- "mangatoto.net",
- "mangatoto.org",
- "readtoto.com",
- "readtoto.net",
- "readtoto.org",
- "dto.to",
- "hto.to",
- "mto.to",
- "wto.to",
- "xbato.com",
- "xbato.net",
- "xbato.org",
- "zbato.com",
- "zbato.net",
- "zbato.org",
- )
- private val MIRROR_PREF_ENTRY_VALUES = MIRROR_PREF_ENTRIES.map { "https://$it" }.toTypedArray()
- private val MIRROR_PREF_DEFAULT_VALUE = MIRROR_PREF_ENTRY_VALUES[0]
-
- private const val ALT_CHAPTER_LIST_PREF_KEY = "ALT_CHAPTER_LIST"
- private const val ALT_CHAPTER_LIST_PREF_TITLE = "Alternative Chapter List"
- private const val ALT_CHAPTER_LIST_PREF_SUMMARY = "If checked, uses an alternate chapter list"
- private const val ALT_CHAPTER_LIST_PREF_DEFAULT_VALUE = false
- }
-}
diff --git a/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoToFactory.kt b/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoToFactory.kt
deleted file mode 100644
index 2a4ee05ee..000000000
--- a/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoToFactory.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-package eu.kanade.tachiyomi.extension.all.batoto
-
-import eu.kanade.tachiyomi.source.Source
-import eu.kanade.tachiyomi.source.SourceFactory
-
-class BatoToFactory : SourceFactory {
- override fun createSources(): List