Misc code cleanup
This commit is contained in:
parent
170c382b15
commit
40de8b9723
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: ComiCake'
|
||||
pkgNameSuffix = 'all.comicake'
|
||||
extClass = '.ComiCakeFactory'
|
||||
extVersionCode = 6
|
||||
extVersionCode = 7
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package eu.kanade.tachiyomi.extension.all.comicake
|
||||
|
||||
import android.os.Build
|
||||
import eu.kanade.tachiyomi.extension.BuildConfig
|
||||
import eu.kanade.tachiyomi.extensions.BuildConfig
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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.HttpSource
|
||||
import okhttp3.Headers
|
||||
import okhttp3.Request
|
||||
|
@ -12,23 +16,22 @@ import org.json.JSONArray
|
|||
import org.json.JSONObject
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
const val COMICAKE_DEFAULT_API_ENDPOINT = "/api" // Highly unlikely to change
|
||||
const val COMICAKE_DEFAULT_READER_ENDPOINT = "/r" // Can change based on CC config
|
||||
abstract class ComiCake(
|
||||
override val name: String,
|
||||
final override val baseUrl: String,
|
||||
override val lang: String,
|
||||
readerEndpoint: String = COMICAKE_DEFAULT_READER_ENDPOINT,
|
||||
apiEndpoint: String = COMICAKE_DEFAULT_API_ENDPOINT
|
||||
) : HttpSource() {
|
||||
|
||||
open class ComiCake(override val name: String,
|
||||
final override val baseUrl: String,
|
||||
override val lang: String,
|
||||
readerEndpoint: String = COMICAKE_DEFAULT_READER_ENDPOINT,
|
||||
apiEndpoint: String = COMICAKE_DEFAULT_API_ENDPOINT) : HttpSource() {
|
||||
override val versionId = 1
|
||||
override val supportsLatest = true
|
||||
private val readerBase = baseUrl + readerEndpoint
|
||||
private var apiBase = baseUrl + apiEndpoint
|
||||
|
||||
|
||||
private val userAgent = "Mozilla/5.0 (" +
|
||||
"Android ${Build.VERSION.RELEASE}; Mobile) " +
|
||||
"Tachiyomi/${BuildConfig.VERSION_NAME}"
|
||||
"Android ${Build.VERSION.RELEASE}; Mobile) " +
|
||||
"Tachiyomi/${BuildConfig.VERSION_NAME}"
|
||||
|
||||
override fun headersBuilder() = Headers.Builder().apply {
|
||||
add("User-Agent", userAgent)
|
||||
|
@ -69,6 +72,7 @@ open class ComiCake(override val name: String,
|
|||
mangas.add(parseComicJson(obj))
|
||||
}
|
||||
}
|
||||
|
||||
return MangasPage(mangas, !(response.getString("next").isNullOrEmpty() || response.getString("next") == "null"))
|
||||
}
|
||||
|
||||
|
@ -156,4 +160,9 @@ open class ComiCake(override val name: String,
|
|||
}
|
||||
|
||||
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("This method should not be called!")
|
||||
|
||||
companion object {
|
||||
private const val COMICAKE_DEFAULT_API_ENDPOINT = "/api" // Highly unlikely to change
|
||||
private const val COMICAKE_DEFAULT_READER_ENDPOINT = "/r" // Can change based on CC config
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,13 @@ import eu.kanade.tachiyomi.source.Source
|
|||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
||||
class ComiCakeFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = getAllComiCake()
|
||||
}
|
||||
|
||||
fun getAllComiCake(): List<Source> {
|
||||
return listOf(
|
||||
WhimSubs(),
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
LetItGoScans(),
|
||||
PTScans(),
|
||||
LetItGoScans()
|
||||
WhimSubs()
|
||||
)
|
||||
}
|
||||
|
||||
class WhimSubs : ComiCake("WhimSubs", "https://whimsubs.xyz", "en")
|
||||
|
||||
class PTScans : ComiCake("ProjectTime Scans", "https://read.ptscans.com", "en", "/")
|
||||
|
||||
class LetItGoScans : ComiCake("LetItGo Scans", "https://reader.letitgo.scans.today", "en", "/")
|
||||
class PTScans : ComiCake("ProjectTime Scans", "https://read.ptscans.com", "en", "/")
|
||||
class WhimSubs : ComiCake("WhimSubs", "https://whimsubs.xyz", "en")
|
||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: FMReader (multiple aggregators)'
|
||||
pkgNameSuffix = 'all.fmreader'
|
||||
extClass = '.FMReaderFactory'
|
||||
extVersionCode = 2
|
||||
extVersionCode = 3
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,27 @@
|
|||
package eu.kanade.tachiyomi.extension.all.fmreader
|
||||
|
||||
// For sites based on the Flat-Manga CMS
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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 okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.*
|
||||
import java.util.*
|
||||
import java.util.Calendar
|
||||
|
||||
abstract class FMReader (
|
||||
/**
|
||||
* For sites based on the Flat-Manga CMS
|
||||
*/
|
||||
abstract class FMReader(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String
|
||||
|
@ -43,10 +53,8 @@ abstract class FMReader (
|
|||
}
|
||||
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
||||
is GenreList -> {
|
||||
|
||||
var genre = String()
|
||||
var ungenre = String()
|
||||
|
||||
filter.state.forEach {
|
||||
if (it.isIncluded()) genre += ",${it.name}"
|
||||
if (it.isExcluded()) ungenre += ",${it.name}"
|
||||
|
@ -79,7 +87,7 @@ abstract class FMReader (
|
|||
val mangas = mutableListOf<SManga>()
|
||||
var hasNextPage = true
|
||||
|
||||
document.select(popularMangaSelector()).map{ mangas.add(popularMangaFromElement(it)) }
|
||||
document.select(popularMangaSelector()).map { mangas.add(popularMangaFromElement(it)) }
|
||||
|
||||
// check if there's a next page
|
||||
document.select(popularMangaNextPageSelector()).first().text().split(" ").let {
|
||||
|
@ -108,7 +116,7 @@ abstract class FMReader (
|
|||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
manga.title = it.text()
|
||||
}
|
||||
manga.thumbnail_url = element.select("img").let{
|
||||
manga.thumbnail_url = element.select("img").let {
|
||||
if (it.hasAttr("src")) {
|
||||
it.attr("abs:src")
|
||||
} else {
|
||||
|
@ -160,11 +168,11 @@ abstract class FMReader (
|
|||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val chapter = SChapter.create()
|
||||
|
||||
element.select(chapterUrlSelector).first().let{
|
||||
element.select(chapterUrlSelector).first().let {
|
||||
chapter.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
chapter.name = it.text()
|
||||
}
|
||||
chapter.date_upload = element.select(chapterTimeSelector).let{ if(it.hasText()) parseChapterDate(it.text()) else 0 }
|
||||
chapter.date_upload = element.select(chapterTimeSelector).let { if (it.hasText()) parseChapterDate(it.text()) else 0 }
|
||||
|
||||
return chapter
|
||||
}
|
||||
|
@ -177,7 +185,7 @@ abstract class FMReader (
|
|||
|
||||
private fun parseChapterDate(date: String): Long {
|
||||
val value = date.split(' ')[dateValueIndex].toInt()
|
||||
val dateWord = date.split(' ')[dateWordIndex].let{
|
||||
val dateWord = date.split(' ')[dateWordIndex].let {
|
||||
if (it.contains("(")) {
|
||||
it.substringBefore("(")
|
||||
} else {
|
||||
|
@ -227,7 +235,7 @@ abstract class FMReader (
|
|||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("img.chapter-img").forEachIndexed { i, img ->
|
||||
pages.add(Page(i, "", img.attr("abs:data-src").let{ if (it.isNotEmpty()) it else img.attr("abs:src") }))
|
||||
pages.add(Page(i, "", img.attr("abs:data-src").let { if (it.isNotEmpty()) it else img.attr("abs:src") }))
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
|
|
@ -5,9 +5,17 @@ import eu.kanade.tachiyomi.network.POST
|
|||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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.util.asJsoup
|
||||
import okhttp3.*
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
|
@ -40,6 +48,7 @@ class FMReaderFactory : SourceFactory {
|
|||
* most likely the fix is to override popularMangaNextPageSelector() */
|
||||
|
||||
class LHTranslation : FMReader("LHTranslation", "https://lhtranslation.net", "en")
|
||||
|
||||
class MangaHato : FMReader("MangaHato", "https://mangahato.com", "ja")
|
||||
class ManhwaScan : FMReader("ManhwaScan", "https://manhwascan.com", "en")
|
||||
class MangaTiki : FMReader("MangaTiki", "https://mangatiki.com", "ja")
|
||||
|
@ -47,16 +56,20 @@ class MangaBone : FMReader("MangaBone", "https://mangabone.com", "en")
|
|||
class YoloManga : FMReader("Yolo Manga", "https://yolomanga.ca", "es") {
|
||||
override fun chapterListSelector() = "div#tab-chapper ~ div#tab-chapper table tr"
|
||||
}
|
||||
|
||||
class MangaLeer : FMReader("MangaLeer", "https://mangaleer.com", "es") {
|
||||
override val dateValueIndex = 1
|
||||
override val dateWordIndex = 2
|
||||
}
|
||||
|
||||
class AiLoveManga : FMReader("AiLoveManga", "https://ailovemanga.com", "vi") {
|
||||
override val requestPath = "danh-sach-truyen.html"
|
||||
// TODO: could add a genre search (different URL paths for genres)
|
||||
override fun getFilterList() = FilterList()
|
||||
|
||||
// I don't know why, but I have to override searchMangaRequest to make it work for this source
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = GET("$baseUrl/$requestPath?name=$query&page=$page")
|
||||
|
||||
override fun chapterListSelector() = "div#tab-chapper table tr"
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
|
@ -72,10 +85,12 @@ class AiLoveManga : FMReader("AiLoveManga", "https://ailovemanga.com", "vi") {
|
|||
return manga
|
||||
}
|
||||
}
|
||||
|
||||
class ReadComicOnlineOrg : FMReader("ReadComicOnline.org", "https://readcomiconline.org", "en") {
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor { requestIntercept(it) }
|
||||
.build()
|
||||
|
||||
private fun requestIntercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
val response = chain.proceed(request)
|
||||
|
@ -85,46 +100,55 @@ class ReadComicOnlineOrg : FMReader("ReadComicOnline.org", "https://readcomiconl
|
|||
.add("dqh_firewall", "%2F")
|
||||
.build()
|
||||
val cookie = mutableListOf<String>()
|
||||
response.headers("set-cookie").map{ cookie.add(it.substringBefore(" ")) }
|
||||
response.headers("set-cookie").map { cookie.add(it.substringBefore(" ")) }
|
||||
headers.newBuilder().add("Cookie", cookie.joinToString { " " }).build()
|
||||
client.newCall(POST(request.url().toString(), headers, body)).execute()
|
||||
} else {
|
||||
response
|
||||
}
|
||||
}
|
||||
|
||||
override val requestPath = "comic-list.html"
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("div#divImage > select:first-of-type option").forEachIndexed{ i, imgPage ->
|
||||
document.select("div#divImage > select:first-of-type option").forEachIndexed { i, imgPage ->
|
||||
pages.add(Page(i, imgPage.attr("value"), ""))
|
||||
}
|
||||
return pages.dropLast(1) // last page is a comments page
|
||||
}
|
||||
|
||||
override fun imageUrlRequest(page: Page): Request = GET(baseUrl + page.url, headers)
|
||||
override fun imageUrlParse(document: Document): String = document.select("img.chapter-img").attr("abs:src").trim()
|
||||
override fun getGenreList() = getComicsGenreList()
|
||||
}
|
||||
|
||||
class MangaWeek : FMReader("MangaWeek", "https://mangaweek.com", "en")
|
||||
class HanaScan : FMReader("HanaScan (RawQQ)", "http://rawqq.com", "ja") {
|
||||
override fun popularMangaNextPageSelector() = "div.col-md-8 button"
|
||||
}
|
||||
|
||||
class RawLH : FMReader("RawLH", "https://lhscan.net", "ja") {
|
||||
override fun popularMangaNextPageSelector() = "div.col-md-8 button"
|
||||
}
|
||||
|
||||
class Manhwa18 : FMReader("Manhwa18", "https://manhwa18.com", "en") {
|
||||
override fun getGenreList() = getAdultGenreList()
|
||||
}
|
||||
|
||||
class TruyenTranhLH : FMReader("TruyenTranhLH", "https://truyentranhlh.net", "vi") {
|
||||
override val requestPath = "danh-sach-truyen.html"
|
||||
}
|
||||
|
||||
class EighteenLHPlus : FMReader("18LHPlus", "https://18lhplus.com", "en") {
|
||||
override fun getGenreList() = getAdultGenreList()
|
||||
}
|
||||
|
||||
class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
override fun popularMangaNextPageSelector() = "div.btn-group:not(div.btn-block) button.btn-info"
|
||||
// TODO: genre search possible but a bit of a pain
|
||||
override fun getFilterList() = FilterList()
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/arama.html?icerik=$query", headers)
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
val mangas = mutableListOf<SManga>()
|
||||
|
@ -135,6 +159,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
|||
|
||||
return MangasPage(mangas, false)
|
||||
}
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
|
||||
|
@ -143,6 +168,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
|||
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
val infoElement = document.select("div#tab1").first()
|
||||
|
@ -156,6 +182,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
|||
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = "tr.table-bordered"
|
||||
override val chapterUrlSelector = "td[align=left] > a"
|
||||
override val chapterTimeSelector = "td[align=right]"
|
||||
|
@ -172,6 +199,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
|||
Observable.error(Exception("Licensed - No chapters to show"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun chapterListParse(response: Response, requestUrl: String): List<SChapter> {
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
var document = response.asJsoup()
|
||||
|
@ -180,7 +208,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
|||
|
||||
// chapters are paginated
|
||||
while (moreChapters) {
|
||||
document.select(chapterListSelector()).map{ chapters.add(chapterFromElement(it)) }
|
||||
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
|
||||
if (document.select("a[data-page=$nextPage]").isNotEmpty()) {
|
||||
val body = FormBody.Builder()
|
||||
.add("page", nextPage.toString())
|
||||
|
@ -193,21 +221,25 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
|||
}
|
||||
return chapters
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request = GET("$baseUrl/${chapter.url.substringAfter("cek/")}", headers)
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("div.chapter-content select:first-of-type option").forEachIndexed{ i, imgPage ->
|
||||
document.select("div.chapter-content select:first-of-type option").forEachIndexed { i, imgPage ->
|
||||
pages.add(Page(i, "$baseUrl/${imgPage.attr("value")}", ""))
|
||||
}
|
||||
return pages.dropLast(1) // last page is a comments page
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document): String = document.select("img.chapter-img").attr("abs:src").trim()
|
||||
}
|
||||
|
||||
class Comicastle : FMReader("Comicastle", "https://www.comicastle.org", "en") {
|
||||
override val requestPath = "comic-dir"
|
||||
// this source doesn't have the "page x of y" element
|
||||
override fun popularMangaNextPageSelector() = "li:contains(»)"
|
||||
|
||||
override fun popularMangaParse(response: Response) = defaultMangaParse(response)
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/comic-dir?q=$query", headers)
|
||||
override fun searchMangaParse(response: Response): MangasPage = defaultMangaParse(response)
|
||||
|
@ -224,39 +256,43 @@ class Comicastle : FMReader("Comicastle", "https://www.comicastle.org", "en") {
|
|||
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = "div.col-md-9 table:last-of-type tr"
|
||||
override fun chapterListParse(response: Response): List<SChapter> = super.chapterListParse(response).reversed()
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("div.text-center select option").forEachIndexed{ i, imgPage ->
|
||||
document.select("div.text-center select option").forEachIndexed { i, imgPage ->
|
||||
pages.add(Page(i, imgPage.attr("value"), ""))
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document): String = document.select("img.chapter-img").attr("abs:src").trim()
|
||||
override fun getGenreList() = getComicsGenreList()
|
||||
}
|
||||
|
||||
class Manhwa18Net : FMReader("Manhwa18.net", "https://manhwa18.net", "en") {
|
||||
override fun popularMangaRequest(page: Int): Request =
|
||||
GET("$baseUrl/$requestPath?listType=pagination&page=$page&sort=views&sort_type=DESC&ungenre=raw", headers)
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request =
|
||||
GET("$baseUrl/$requestPath?listType=pagination&page=$page&sort=last_update&sort_type=DESC&ungenre=raw", headers)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val noRawsUrl = super.searchMangaRequest(page, query, filters).url().newBuilder().addQueryParameter("ungenre", "raw").toString()
|
||||
return GET(noRawsUrl, headers)
|
||||
}
|
||||
|
||||
override fun getGenreList() = getAdultGenreList()
|
||||
}
|
||||
|
||||
class Manhwa18NetRaw : FMReader("Manhwa18.net Raw", "https://manhwa18.net", "ko") {
|
||||
override val requestPath = "manga-list-genre-raw.html"
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val onlyRawsUrl = super.searchMangaRequest(page, query, filters).url().newBuilder().addQueryParameter("genre", "raw").toString()
|
||||
return GET(onlyRawsUrl, headers)
|
||||
}
|
||||
|
||||
override fun getFilterList() = FilterList(super.getFilterList().filterNot { it == GenreList(getGenreList()) })
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: FoolSlide (multiple sources)'
|
||||
pkgNameSuffix = 'all.foolslide'
|
||||
extClass = '.FoolSlideFactory'
|
||||
extVersionCode = 28
|
||||
extVersionCode = 29
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@ import com.github.salomonbrys.kotson.get
|
|||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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 okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
|
@ -13,13 +17,17 @@ import org.jsoup.nodes.Document
|
|||
import org.jsoup.nodes.Element
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.HashSet
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
open class FoolSlide(override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String,
|
||||
val urlModifier: String = "") : ParsedHttpSource() {
|
||||
abstract class FoolSlide(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String,
|
||||
val urlModifier: String = ""
|
||||
) : ParsedHttpSource() {
|
||||
|
||||
protected open val dedupeLatestUpdates = true
|
||||
|
||||
|
@ -81,7 +89,7 @@ open class FoolSlide(override val name: String,
|
|||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val form = FormBody.Builder()
|
||||
.add("search", query)
|
||||
.add("search", query)
|
||||
|
||||
return POST("$baseUrl$urlModifier/search/", headers, form.build())
|
||||
}
|
||||
|
@ -123,8 +131,8 @@ open class FoolSlide(override val name: String,
|
|||
|
||||
private fun allowAdult(url: String): Request {
|
||||
return POST(url, body = FormBody.Builder()
|
||||
.add("adult", "true")
|
||||
.build())
|
||||
.add("adult", "true")
|
||||
.build())
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga) = allowAdult(super.chapterListRequest(manga))
|
||||
|
@ -142,7 +150,7 @@ open class FoolSlide(override val name: String,
|
|||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||
chapter.name = urlElement.text()
|
||||
chapter.date_upload = dateElement.text()?.let { parseChapterDate(it.substringAfter(", ")) }
|
||||
?: 0
|
||||
?: 0
|
||||
return chapter
|
||||
}
|
||||
|
||||
|
@ -247,8 +255,8 @@ open class FoolSlide(override val name: String,
|
|||
json.forEach {
|
||||
// Create dummy element to resolve relative URL
|
||||
val absUrl = document.createElement("a")
|
||||
.attr("href", it["url"].asString)
|
||||
.absUrl("href")
|
||||
.attr("href", it["url"].asString)
|
||||
.absUrl("href")
|
||||
|
||||
pages.add(Page(pages.size, "", absUrl))
|
||||
}
|
||||
|
|
|
@ -12,41 +12,36 @@ import okhttp3.Request
|
|||
import org.jsoup.nodes.Document
|
||||
|
||||
class FoolSlideFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = getAllFoolSlide()
|
||||
}
|
||||
|
||||
fun getAllFoolSlide(): List<Source> {
|
||||
return listOf(
|
||||
JaminisBox(),
|
||||
SenseScans(),
|
||||
KireiCake(),
|
||||
SilentSky(),
|
||||
Mangatellers(),
|
||||
IskultripScans(),
|
||||
AnataNoMotokare(),
|
||||
DeathTollScans(),
|
||||
DKThias(),
|
||||
WorldThree(),
|
||||
DokiFansubs(),
|
||||
YuriIsm(),
|
||||
AjiaNoScantrad(),
|
||||
OneTimeScans(),
|
||||
TsubasaSociety(),
|
||||
MangaScouts(),
|
||||
StormInHeaven(),
|
||||
Lilyreader(),
|
||||
Russification(),
|
||||
EvilFlowers(),
|
||||
AkaiYuhiMunTeam(),
|
||||
LupiTeam(),
|
||||
HentaiCafe(),
|
||||
TheCatScans(),
|
||||
ZandynoFansub()
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
JaminisBox(),
|
||||
SenseScans(),
|
||||
KireiCake(),
|
||||
SilentSky(),
|
||||
Mangatellers(),
|
||||
IskultripScans(),
|
||||
AnataNoMotokare(),
|
||||
DeathTollScans(),
|
||||
DKThias(),
|
||||
WorldThree(),
|
||||
DokiFansubs(),
|
||||
YuriIsm(),
|
||||
AjiaNoScantrad(),
|
||||
OneTimeScans(),
|
||||
TsubasaSociety(),
|
||||
MangaScouts(),
|
||||
StormInHeaven(),
|
||||
Lilyreader(),
|
||||
Russification(),
|
||||
EvilFlowers(),
|
||||
AkaiYuhiMunTeam(),
|
||||
LupiTeam(),
|
||||
HentaiCafe(),
|
||||
TheCatScans(),
|
||||
ZandynoFansub()
|
||||
)
|
||||
}
|
||||
|
||||
class JaminisBox : FoolSlide("Jaimini's Box", "https://jaiminisbox.com", "en", "/reader") {
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val doc = document.toString()
|
||||
var jsonstr = doc.substringAfter("var pages = ").substringBefore(";")
|
||||
|
@ -132,7 +127,6 @@ class LupiTeam : FoolSlide("LupiTeam", "https://lupiteam.net", "it", "/reader")
|
|||
|
||||
return manga
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ZandynoFansub : FoolSlide("Zandy no Fansub", "http://zandynofansub.aishiteru.org", "en", "/reader")
|
||||
|
|
|
@ -2,7 +2,11 @@ package eu.kanade.tachiyomi.extension.all.foolslide
|
|||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
|
@ -56,11 +60,11 @@ class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga
|
|||
// we still need to parse the manga info page
|
||||
// Example: https://hentai.cafe/aiya-youngest-daughters-circumstances/
|
||||
override fun chapterListParse(response: Response) = listOf(
|
||||
SChapter.create().apply {
|
||||
setUrlWithoutDomain(response.asJsoup().select("[title=Read]").attr("href"))
|
||||
name = "Chapter"
|
||||
chapter_number = 1f
|
||||
}
|
||||
SChapter.create().apply {
|
||||
setUrlWithoutDomain(response.asJsoup().select("[title=Read]").attr("href"))
|
||||
name = "Chapter"
|
||||
chapter_number = 1f
|
||||
}
|
||||
)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
|
@ -74,9 +78,9 @@ class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga
|
|||
if (f.state.isNotBlank()) {
|
||||
requireNoUrl()
|
||||
url = "/hc.fyi/artist/${f.state
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(ARTIST_INVALID_CHAR_REGEX, "-")}/"
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(ARTIST_INVALID_CHAR_REGEX, "-")}/"
|
||||
}
|
||||
}
|
||||
filters.findInstance<BookFilter>()?.let { f ->
|
||||
|
@ -113,79 +117,79 @@ class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga
|
|||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
return client.newCall(searchMangaRequest(page, query, filters))
|
||||
.asObservable().doOnNext { response ->
|
||||
if (!response.isSuccessful) {
|
||||
response.close()
|
||||
// Better error message for invalid artist
|
||||
if (response.code() == 404
|
||||
&& !filters.findInstance<ArtistFilter>()?.state.isNullOrBlank())
|
||||
error("Invalid artist!")
|
||||
else throw Exception("HTTP error ${response.code()}")
|
||||
}
|
||||
}
|
||||
.map { response ->
|
||||
searchMangaParse(response)
|
||||
.asObservable().doOnNext { response ->
|
||||
if (!response.isSuccessful) {
|
||||
response.close()
|
||||
// Better error message for invalid artist
|
||||
if (response.code() == 404
|
||||
&& !filters.findInstance<ArtistFilter>()?.state.isNullOrBlank())
|
||||
error("Invalid artist!")
|
||||
else throw Exception("HTTP error ${response.code()}")
|
||||
}
|
||||
}
|
||||
.map { response ->
|
||||
searchMangaParse(response)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFilterList() = FilterList(
|
||||
Filter.Header("Filters cannot be used while searching."),
|
||||
Filter.Header("Only one filter may be used at a time."),
|
||||
Filter.Separator(),
|
||||
ArtistFilter(),
|
||||
BookFilter(),
|
||||
TagFilter()
|
||||
Filter.Header("Filters cannot be used while searching."),
|
||||
Filter.Header("Only one filter may be used at a time."),
|
||||
Filter.Separator(),
|
||||
ArtistFilter(),
|
||||
BookFilter(),
|
||||
TagFilter()
|
||||
)
|
||||
|
||||
class ArtistFilter : Filter.Text("Artist (must be exact match)")
|
||||
class BookFilter : Filter.CheckBox("Show books only", false)
|
||||
class TagFilter : Filter.Select<Tag>("Tag", arrayOf(
|
||||
Tag("", "<select>"),
|
||||
Tag("ahegao", "Ahegao"),
|
||||
Tag("anal", "Anal"),
|
||||
Tag("big-ass", "Big ass"),
|
||||
Tag("big-breast", "Big breast"),
|
||||
Tag("big-dick", "Big dick"),
|
||||
Tag("bondage", "Bondage"),
|
||||
Tag("cheating", "Cheating"),
|
||||
Tag("chubby", "Chubby"),
|
||||
Tag("color", "Color"),
|
||||
Tag("condom", "Condom"),
|
||||
Tag("cosplay", "Cosplay"),
|
||||
Tag("cunnilingus", "Cunnilingus"),
|
||||
Tag("dark-skin", "Dark skin"),
|
||||
Tag("exhibitionism", "Exhibitionism"),
|
||||
Tag("fellatio", "Fellatio"),
|
||||
Tag("femdom", "Femdom"),
|
||||
Tag("flat-chest", "Flat chest"),
|
||||
Tag("full-color", "Full color"),
|
||||
Tag("glasses", "Glasses"),
|
||||
Tag("group", "Group"),
|
||||
Tag("hairy", "Hairy"),
|
||||
Tag("handjob", "Handjob"),
|
||||
Tag("heart-pupils", "Heart pupils"),
|
||||
Tag("housewife", "Housewife"),
|
||||
Tag("incest", "Incest"),
|
||||
Tag("lingerie", "Lingerie"),
|
||||
Tag("loli", "Loli"),
|
||||
Tag("masturbation", "Masturbation"),
|
||||
Tag("nakadashi", "Nakadashi"),
|
||||
Tag("osananajimi", "Osananajimi"),
|
||||
Tag("paizuri", "Paizuri"),
|
||||
Tag("pettanko", "Pettanko"),
|
||||
Tag("rape", "Rape"),
|
||||
Tag("schoolgirl", "Schoolgirl"),
|
||||
Tag("sex-toys", "Sex toys"),
|
||||
Tag("shota", "Shota"),
|
||||
Tag("socks", "Socks"),
|
||||
Tag("stocking", "Stocking"),
|
||||
Tag("stockings", "Stockings"),
|
||||
Tag("swimsuit", "Swimsuit"),
|
||||
Tag("teacher", "Teacher"),
|
||||
Tag("tsundere", "Tsundere"),
|
||||
Tag("uncensored", "Uncensored"),
|
||||
Tag("vanilla", "Vanilla"),
|
||||
Tag("x-ray", "X-Ray")
|
||||
Tag("", "<select>"),
|
||||
Tag("ahegao", "Ahegao"),
|
||||
Tag("anal", "Anal"),
|
||||
Tag("big-ass", "Big ass"),
|
||||
Tag("big-breast", "Big breast"),
|
||||
Tag("big-dick", "Big dick"),
|
||||
Tag("bondage", "Bondage"),
|
||||
Tag("cheating", "Cheating"),
|
||||
Tag("chubby", "Chubby"),
|
||||
Tag("color", "Color"),
|
||||
Tag("condom", "Condom"),
|
||||
Tag("cosplay", "Cosplay"),
|
||||
Tag("cunnilingus", "Cunnilingus"),
|
||||
Tag("dark-skin", "Dark skin"),
|
||||
Tag("exhibitionism", "Exhibitionism"),
|
||||
Tag("fellatio", "Fellatio"),
|
||||
Tag("femdom", "Femdom"),
|
||||
Tag("flat-chest", "Flat chest"),
|
||||
Tag("full-color", "Full color"),
|
||||
Tag("glasses", "Glasses"),
|
||||
Tag("group", "Group"),
|
||||
Tag("hairy", "Hairy"),
|
||||
Tag("handjob", "Handjob"),
|
||||
Tag("heart-pupils", "Heart pupils"),
|
||||
Tag("housewife", "Housewife"),
|
||||
Tag("incest", "Incest"),
|
||||
Tag("lingerie", "Lingerie"),
|
||||
Tag("loli", "Loli"),
|
||||
Tag("masturbation", "Masturbation"),
|
||||
Tag("nakadashi", "Nakadashi"),
|
||||
Tag("osananajimi", "Osananajimi"),
|
||||
Tag("paizuri", "Paizuri"),
|
||||
Tag("pettanko", "Pettanko"),
|
||||
Tag("rape", "Rape"),
|
||||
Tag("schoolgirl", "Schoolgirl"),
|
||||
Tag("sex-toys", "Sex toys"),
|
||||
Tag("shota", "Shota"),
|
||||
Tag("socks", "Socks"),
|
||||
Tag("stocking", "Stocking"),
|
||||
Tag("stockings", "Stockings"),
|
||||
Tag("swimsuit", "Swimsuit"),
|
||||
Tag("teacher", "Teacher"),
|
||||
Tag("tsundere", "Tsundere"),
|
||||
Tag("uncensored", "Uncensored"),
|
||||
Tag("vanilla", "Vanilla"),
|
||||
Tag("x-ray", "X-Ray")
|
||||
))
|
||||
|
||||
class Tag(val name: String, private val displayName: String) {
|
||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: Genkan (multiple sources)'
|
||||
pkgNameSuffix = 'all.genkan'
|
||||
extClass = '.GenkanFactory'
|
||||
extVersionCode = 7
|
||||
extVersionCode = 8
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package eu.kanade.tachiyomi.extension.all.genkan
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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 okhttp3.OkHttpClient
|
||||
|
@ -11,12 +15,13 @@ import org.jsoup.nodes.Document
|
|||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.select.Elements
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
|
||||
abstract class Genkan(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String
|
||||
) : ParsedHttpSource() {
|
||||
|
||||
override val supportsLatest = true
|
||||
|
@ -88,7 +93,7 @@ abstract class Genkan(
|
|||
|
||||
private fun styleToUrl(element: Element): String {
|
||||
return element.attr("style").substringAfter("(").substringBefore(")")
|
||||
.let{ if (it.startsWith("http")) it else baseUrl + it }
|
||||
.let { if (it.startsWith("http")) it else baseUrl + it }
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
|
@ -155,11 +160,11 @@ abstract class Genkan(
|
|||
val pages = mutableListOf<Page>()
|
||||
|
||||
val allImages = document.select("div#pages-container + script").first().data()
|
||||
.substringAfter("[").substringBefore("];")
|
||||
.replace(Regex("""["\\]"""), "")
|
||||
.split(",")
|
||||
.substringAfter("[").substringBefore("];")
|
||||
.replace(Regex("""["\\]"""), "")
|
||||
.split(",")
|
||||
|
||||
for (i in 0 until allImages.size) {
|
||||
for (i in allImages.indices) {
|
||||
pages.add(Page(i, "", allImages[i]))
|
||||
}
|
||||
|
||||
|
@ -178,9 +183,9 @@ abstract class Genkan(
|
|||
// For sites using the older Genkan CMS that didn't have a search function
|
||||
|
||||
abstract class GenkanOriginal(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String
|
||||
) : Genkan(name, baseUrl, lang) {
|
||||
|
||||
private var searchQuery = ""
|
||||
|
@ -223,7 +228,7 @@ abstract class GenkanOriginal(
|
|||
// search additional pages if called
|
||||
private fun searchMorePages(): MutableList<SManga> {
|
||||
searchPage++
|
||||
val nextPage = client.newCall(popularMangaRequest(searchPage)).execute().asJsoup()
|
||||
val nextPage = client.newCall(popularMangaRequest(searchPage)).execute().asJsoup()
|
||||
val searchMatches = mutableListOf<SManga>()
|
||||
searchMatches.addAll(getMatchesFrom(nextPage))
|
||||
nextPageSelectorElement = nextPage.select(searchMangaNextPageSelector())
|
||||
|
@ -238,4 +243,3 @@ abstract class GenkanOriginal(
|
|||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,14 @@ import eu.kanade.tachiyomi.source.SourceFactory
|
|||
|
||||
class GenkanFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
LeviatanScans(),
|
||||
LeviatanScansES(),
|
||||
PsychoPlay(),
|
||||
OneShotScans(),
|
||||
KaguyaDex(),
|
||||
KomiScans(),
|
||||
HunlightScans(),
|
||||
WoweScans()
|
||||
LeviatanScans(),
|
||||
LeviatanScansES(),
|
||||
PsychoPlay(),
|
||||
OneShotScans(),
|
||||
KaguyaDex(),
|
||||
KomiScans(),
|
||||
HunlightScans(),
|
||||
WoweScans()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: Madara (multiple sources)'
|
||||
pkgNameSuffix = "all.madara"
|
||||
extClass = '.MadaraFactory'
|
||||
extVersionCode = 22
|
||||
extVersionCode = 23
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -3,31 +3,43 @@ package eu.kanade.tachiyomi.extension.all.madara
|
|||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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 okhttp3.*
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
open class Madara(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String,
|
||||
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US)
|
||||
abstract class Madara(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String,
|
||||
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US)
|
||||
) : ParsedHttpSource() {
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
// Popular Manga
|
||||
|
||||
override fun popularMangaSelector() = "div.page-item-detail"
|
||||
|
@ -42,7 +54,7 @@ open class Madara(
|
|||
}
|
||||
|
||||
select("img").first()?.let {
|
||||
manga.thumbnail_url = it.absUrl(if(it.hasAttr("data-src")) "data-src" else "src")
|
||||
manga.thumbnail_url = it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +64,7 @@ open class Madara(
|
|||
override fun popularMangaRequest(page: Int): Request {
|
||||
val form = FormBody.Builder().apply {
|
||||
add("action", "madara_load_more")
|
||||
add("page", (page-1).toString())
|
||||
add("page", (page - 1).toString())
|
||||
add("template", "madara-core/content/content-archive")
|
||||
add("vars[orderby]", "meta_value_num")
|
||||
add("vars[paged]", "1")
|
||||
|
@ -81,7 +93,7 @@ open class Madara(
|
|||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
val form = FormBody.Builder().apply {
|
||||
add("action", "madara_load_more")
|
||||
add("page", (page-1).toString())
|
||||
add("page", (page - 1).toString())
|
||||
add("template", "madara-core/content/content-archive")
|
||||
add("vars[orderby]", "meta_value_num")
|
||||
add("vars[paged]", "1")
|
||||
|
@ -107,7 +119,7 @@ open class Madara(
|
|||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
return client.newCall(searchMangaRequest(page, query, filters))
|
||||
.asObservable().doOnNext { response ->
|
||||
if(!response.isSuccessful) {
|
||||
if (!response.isSuccessful) {
|
||||
response.close()
|
||||
// Error message for exceeding last page
|
||||
if (response.code() == 404)
|
||||
|
@ -129,17 +141,17 @@ open class Madara(
|
|||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is AuthorFilter -> {
|
||||
if(filter.state.isNotBlank()) {
|
||||
if (filter.state.isNotBlank()) {
|
||||
url.addQueryParameter("author", filter.state)
|
||||
}
|
||||
}
|
||||
is ArtistFilter -> {
|
||||
if(filter.state.isNotBlank()) {
|
||||
if (filter.state.isNotBlank()) {
|
||||
url.addQueryParameter("artist", filter.state)
|
||||
}
|
||||
}
|
||||
is YearFilter -> {
|
||||
if(filter.state.isNotBlank()) {
|
||||
if (filter.state.isNotBlank()) {
|
||||
url.addQueryParameter("release", filter.state)
|
||||
}
|
||||
}
|
||||
|
@ -151,7 +163,7 @@ open class Madara(
|
|||
}
|
||||
}
|
||||
is OrderByFilter -> {
|
||||
if(filter.state != 0) {
|
||||
if (filter.state != 0) {
|
||||
url.addQueryParameter("m_orderby", filter.toUriPart())
|
||||
}
|
||||
}
|
||||
|
@ -165,28 +177,28 @@ open class Madara(
|
|||
private class YearFilter : Filter.Text("Year of Released")
|
||||
private class StatusFilter(status: List<Tag>) : Filter.Group<Tag>("Status", status)
|
||||
private class OrderByFilter : UriPartFilter("Order By", arrayOf(
|
||||
Pair("<select>", ""),
|
||||
Pair("Latest", "latest"),
|
||||
Pair("A-Z", "alphabet"),
|
||||
Pair("Rating", "rating"),
|
||||
Pair("Trending", "trending"),
|
||||
Pair("Most Views", "views"),
|
||||
Pair("New", "new-manga")
|
||||
Pair("<select>", ""),
|
||||
Pair("Latest", "latest"),
|
||||
Pair("A-Z", "alphabet"),
|
||||
Pair("Rating", "rating"),
|
||||
Pair("Trending", "trending"),
|
||||
Pair("Most Views", "views"),
|
||||
Pair("New", "new-manga")
|
||||
))
|
||||
|
||||
override fun getFilterList() = FilterList(
|
||||
AuthorFilter(),
|
||||
ArtistFilter(),
|
||||
YearFilter(),
|
||||
StatusFilter(getStatusList()),
|
||||
OrderByFilter()
|
||||
AuthorFilter(),
|
||||
ArtistFilter(),
|
||||
YearFilter(),
|
||||
StatusFilter(getStatusList()),
|
||||
OrderByFilter()
|
||||
)
|
||||
|
||||
private fun getStatusList() = listOf(
|
||||
Tag("end" , "Completed"),
|
||||
Tag("on-going" , "Ongoing"),
|
||||
Tag("canceled" , "Canceled"),
|
||||
Tag("on-hold" , "On Hold")
|
||||
Tag("end", "Completed"),
|
||||
Tag("on-going", "Ongoing"),
|
||||
Tag("canceled", "Canceled"),
|
||||
Tag("on-hold", "On Hold")
|
||||
)
|
||||
|
||||
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
||||
|
@ -207,7 +219,7 @@ open class Madara(
|
|||
manga.title = it.ownText()
|
||||
}
|
||||
select("img").first()?.let {
|
||||
manga.thumbnail_url = it.absUrl(if(it.hasAttr("data-src")) "data-src" else "src")
|
||||
manga.thumbnail_url = it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,10 +253,10 @@ open class Madara(
|
|||
}
|
||||
}
|
||||
select("div.summary_image img").first()?.let {
|
||||
manga.thumbnail_url = it.absUrl(if(it.hasAttr("data-src")) "data-src" else "src")
|
||||
manga.thumbnail_url = it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
|
||||
}
|
||||
select("div.summary-content").last()?.let {
|
||||
manga.status = when(it.text()) {
|
||||
manga.status = when (it.text()) {
|
||||
// I don't know what's the corresponding for COMPLETED and LICENSED
|
||||
// There's no support for "Canceled" or "On Hold"
|
||||
"Completed" -> SManga.COMPLETED
|
||||
|
@ -271,7 +283,7 @@ open class Madara(
|
|||
with(element) {
|
||||
select("a").first()?.let { urlElement ->
|
||||
chapter.url = urlElement.attr("abs:href").let {
|
||||
it.substringBefore("?style=paged") + if(!it.endsWith("?style=list")) "?style=list" else ""
|
||||
it.substringBefore("?style=paged") + if (!it.endsWith("?style=list")) "?style=list" else ""
|
||||
}
|
||||
chapter.name = urlElement.text()
|
||||
}
|
||||
|
@ -353,8 +365,8 @@ open class Madara(
|
|||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
return document.select(pageListParseSelector).mapIndexed { index, element ->
|
||||
Page(index, "", element.select("img").first()?.let{
|
||||
it.absUrl(if(it.hasAttr("data-src")) "data-src" else "src")
|
||||
Page(index, "", element.select("img").first()?.let {
|
||||
it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.all.madara
|
||||
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
@ -11,10 +10,10 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import okhttp3.Response
|
||||
import okhttp3.Request
|
||||
|
||||
class MadaraFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
|
@ -56,11 +55,13 @@ class MadaraFactory : SourceFactory {
|
|||
class Mangasushi : Madara("Mangasushi", "https://mangasushi.net", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class NinjaScans : Madara("NinjaScans", "https://ninjascans.com", "en")
|
||||
class ReadManhua : Madara("ReadManhua", "https://readmanhua.net", "en",
|
||||
dateFormat = SimpleDateFormat("dd MMM yy", Locale.US)) {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class ZeroScans : Madara("ZeroScans", "https://zeroscans.com", "en")
|
||||
class IsekaiScanCom : Madara("IsekaiScan.com", "https://isekaiscan.com/", "en")
|
||||
class HappyTeaScans : Madara("Happy Tea Scans", "https://happyteascans.com/", "en")
|
||||
|
@ -68,7 +69,8 @@ class JustForFun : Madara("Just For Fun", "https://just-for-fun.ru/", "ru",
|
|||
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)) {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
class AoCTranslations : Madara("Agent of Change Translations", "https://aoc.moe/", "en"){
|
||||
|
||||
class AoCTranslations : Madara("Agent of Change Translations", "https://aoc.moe/", "en") {
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
val document = response.asJsoup()
|
||||
|
@ -80,7 +82,7 @@ class AoCTranslations : Madara("Agent of Change Translations", "https://aoc.moe/
|
|||
} else {
|
||||
// For their "fancy" volume/chapter lists
|
||||
document.select("div.wpb_wrapper:contains(volume) a")
|
||||
.filter { it.attr("href").contains(baseUrl) && !it.attr("href").contains("imgur")}
|
||||
.filter { it.attr("href").contains(baseUrl) && !it.attr("href").contains("imgur") }
|
||||
.map { it ->
|
||||
val chapter = SChapter.create()
|
||||
if (it.attr("href").contains("volume")) {
|
||||
|
@ -99,9 +101,11 @@ class AoCTranslations : Madara("Agent of Change Translations", "https://aoc.moe/
|
|||
return chapters.reversed()
|
||||
}
|
||||
}
|
||||
|
||||
class KomikGo : Madara("KomikGo", "https://komikgo.com", "id") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class LuxyScans : Madara("Luxy Scans", "https://luxyscans.com/", "en")
|
||||
class TritiniaScans : Madara("Tritinia Scans", "http://ghajik.ml/", "en",
|
||||
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)) {
|
||||
|
@ -110,25 +114,32 @@ class TritiniaScans : Madara("Tritinia Scans", "http://ghajik.ml/", "en",
|
|||
override fun latestUpdatesNextPageSelector(): String? = null
|
||||
override fun popularMangaNextPageSelector(): String? = null
|
||||
}
|
||||
|
||||
class TsubakiNoScan : Madara("Tsubaki No Scan", "https://tsubakinoscan.com/",
|
||||
"fr", dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US))
|
||||
|
||||
class YokaiJump : Madara("Yokai Jump", "https://yokaijump.fr/", "fr",
|
||||
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)) {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class ZManga : Madara("ZManga", "https://zmanga.org/", "es") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class MangazukiMe : Madara("Mangazuki.me", "https://mangazuki.me/", "en")
|
||||
class MangazukiOnline : Madara("Mangazuki.online", "https://www.mangazuki.online/", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class MangazukiClubJP : Madara("Mangazuki.club", "https://mangazuki.club/", "ja") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class MangazukiClubKO : Madara("Mangazuki.club", "https://mangazuki.club/", "ko") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class FirstKissManga : Madara("1st Kiss", "https://1stkissmanga.com/", "en") {
|
||||
override val pageListParseSelector = "div.reading-content img"
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
|
@ -141,12 +152,15 @@ class FirstKissManga : Madara("1st Kiss", "https://1stkissmanga.com/", "en") {
|
|||
return if (page.imageUrl!!.contains(cdnUrl)) GET(page.imageUrl!!, cdnHeaders) else GET(page.imageUrl!!, headers)
|
||||
}
|
||||
}
|
||||
|
||||
class MangaKomi : Madara("MangaKomi", "https://mangakomi.com/", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class MangaSY : Madara("Manga SY", "https://www.mangasy.com/", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class ManwhaClub : Madara("Manwha Club", "https://manhwa.club/", "en")
|
||||
class WuxiaWorld : Madara("WuxiaWorld", "https://wuxiaworld.site/", "en") {
|
||||
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/tag/webcomic/page/$page/?m_orderby=views", headers)
|
||||
|
@ -154,6 +168,7 @@ class WuxiaWorld : Madara("WuxiaWorld", "https://wuxiaworld.site/", "en") {
|
|||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = super.searchMangaRequest(page, "$query comics", filters)
|
||||
override fun popularMangaNextPageSelector() = "div.nav-previous.float-left"
|
||||
}
|
||||
|
||||
class WordRain : Madara("WordRain Translation", "https://wordrain69.com", "en") {
|
||||
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/manga-genre/manga/page/$page/?m_orderby=views", headers)
|
||||
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/manga-genre/manga/page/$page/?m_orderby=latest", headers)
|
||||
|
@ -167,24 +182,31 @@ class WordRain : Madara("WordRain Translation", "https://wordrain69.com", "en")
|
|||
return super.searchMangaParse(res)
|
||||
}
|
||||
}
|
||||
|
||||
class YoManga : Madara("Yo Manga", "https://yomanga.info/", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class ManyToon : Madara("ManyToon", "https://manytoon.com/", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class ChibiManga : Madara("Chibi Manga", "http://www.cmreader.info/", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class ZinManga : Madara("Zin Translator", "https://zinmanga.com/", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
|
||||
class ManwahentaiMe : Madara("Manwahentai.me", "https://manhwahentai.me", "en")
|
||||
|
||||
class Manga3asq: Madara("مانجا العاشق", "https://3asq.org", "ar") {
|
||||
class Manga3asq : Madara("مانجا العاشق", "https://3asq.org", "ar") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
class NManhwa: Madara("N Manhwa", "https://nmanhwa.com", "en") {
|
||||
|
||||
class NManhwa : Madara("N Manhwa", "https://nmanhwa.com", "en") {
|
||||
override fun searchMangaNextPageSelector() = "nav.navigation-ajax"
|
||||
}
|
||||
class Indiancomicsonline: Madara("Indian Comics Online", "http://www.indiancomicsonline.com", "hi")
|
||||
|
||||
class Indiancomicsonline : Madara("Indian Comics Online", "http://www.indiancomicsonline.com", "hi")
|
||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: MangaCards (Valhalla, NANI?)'
|
||||
pkgNameSuffix = 'all.mangacards'
|
||||
extClass = '.MangaCardsFactory'
|
||||
extVersionCode = 4
|
||||
extVersionCode = 5
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,23 @@ package eu.kanade.tachiyomi.extension.all.mangacards
|
|||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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 okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
abstract class MangaCards (
|
||||
abstract class MangaCards(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String
|
||||
|
|
|
@ -14,4 +14,3 @@ class MangaCardsFactory : SourceFactory {
|
|||
class ValhallaScans : MangaCards("Valhalla Scans", "https://valhallascans.com", "en")
|
||||
class NaniScans : MangaCards("NANI? Scans", "https://naniscans.xyz", "en")
|
||||
class IneptBastards : MangaCards("Inept Bastards", "https://ineptbastards.xyz", "en")
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: MangaDex'
|
||||
pkgNameSuffix = 'all.mangadex'
|
||||
extClass = '.MangadexFactory'
|
||||
extVersionCode = 68
|
||||
extVersionCode = 69
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,11 @@ import java.util.Date
|
|||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.collections.set
|
||||
|
||||
open class Mangadex(override val lang: String, private val internalLang: String, private val langCode: Int) : ConfigurableSource, ParsedHttpSource() {
|
||||
abstract class Mangadex(
|
||||
override val lang: String,
|
||||
private val internalLang: String,
|
||||
private val langCode: Int
|
||||
) : ConfigurableSource, ParsedHttpSource() {
|
||||
|
||||
override val name = "MangaDex"
|
||||
|
||||
|
@ -60,27 +64,27 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
private val rateLimitInterceptor = RateLimitInterceptor(4)
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addNetworkInterceptor(rateLimitInterceptor)
|
||||
.build()
|
||||
.addNetworkInterceptor(rateLimitInterceptor)
|
||||
.build()
|
||||
|
||||
private fun clientBuilder(): OkHttpClient = clientBuilder(getShowR18())
|
||||
|
||||
private fun clientBuilder(r18Toggle: Int): OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.addNetworkInterceptor(rateLimitInterceptor)
|
||||
.addNetworkInterceptor { chain ->
|
||||
val originalCookies = chain.request().header("Cookie") ?: ""
|
||||
val newReq = chain
|
||||
.request()
|
||||
.newBuilder()
|
||||
.header("Cookie", "$originalCookies; ${cookiesHeader(r18Toggle, langCode)}")
|
||||
.build()
|
||||
chain.proceed(newReq)
|
||||
}.build()!!
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.addNetworkInterceptor(rateLimitInterceptor)
|
||||
.addNetworkInterceptor { chain ->
|
||||
val originalCookies = chain.request().header("Cookie") ?: ""
|
||||
val newReq = chain
|
||||
.request()
|
||||
.newBuilder()
|
||||
.header("Cookie", "$originalCookies; ${cookiesHeader(r18Toggle, langCode)}")
|
||||
.build()
|
||||
chain.proceed(newReq)
|
||||
}.build()!!
|
||||
|
||||
override fun headersBuilder() = Headers.Builder().apply {
|
||||
add("User-Agent", "Tachiyomi "+ System.getProperty("http.agent"))
|
||||
add("User-Agent", "Tachiyomi " + System.getProperty("http.agent"))
|
||||
}
|
||||
|
||||
private fun cookiesHeader(r18Toggle: Int, langCode: Int): String {
|
||||
|
@ -150,36 +154,36 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
|
||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||
return clientBuilder().newCall(popularMangaRequest(page))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
popularMangaParse(response)
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
popularMangaParse(response)
|
||||
}
|
||||
}
|
||||
|
||||
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
|
||||
return clientBuilder().newCall(latestUpdatesRequest(page))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
latestUpdatesParse(response)
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
latestUpdatesParse(response)
|
||||
}
|
||||
}
|
||||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
return if (query.startsWith(PREFIX_ID_SEARCH)) {
|
||||
val realQuery = query.removePrefix(PREFIX_ID_SEARCH)
|
||||
client.newCall(searchMangaByIdRequest(realQuery))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val details = mangaDetailsParse(response)
|
||||
details.url = "/manga/$realQuery/"
|
||||
MangasPage(listOf(details), false)
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val details = mangaDetailsParse(response)
|
||||
details.url = "/manga/$realQuery/"
|
||||
MangasPage(listOf(details), false)
|
||||
}
|
||||
} else {
|
||||
getSearchClient(filters).newCall(searchMangaRequest(page, query, filters))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
searchMangaParse(response)
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
searchMangaParse(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,8 +209,8 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
|
||||
// Do traditional search
|
||||
val url = HttpUrl.parse("$baseUrl/?page=search")!!.newBuilder()
|
||||
.addQueryParameter("p", page.toString())
|
||||
.addQueryParameter("title", query.replace(WHITESPACE_REGEX, " "))
|
||||
.addQueryParameter("p", page.toString())
|
||||
.addQueryParameter("title", query.replace(WHITESPACE_REGEX, " "))
|
||||
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
|
@ -323,10 +327,10 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
return clientBuilder().newCall(apiRequest(manga))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
mangaDetailsParse(response).apply { initialized = true }
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
mangaDetailsParse(response).apply { initialized = true }
|
||||
}
|
||||
}
|
||||
|
||||
private fun apiRequest(manga: SManga): Request {
|
||||
|
@ -362,14 +366,14 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
val finalChapterNumber = getFinalChapter(mangaJson)
|
||||
if ((status == 2 || status == 3) && chapterJson != null && isMangaCompleted(chapterJson, finalChapterNumber)) {
|
||||
manga.status = SManga.COMPLETED
|
||||
} else if (status == 2 && chapterJson != null && isOneshot(chapterJson, finalChapterNumber)){
|
||||
} else if (status == 2 && chapterJson != null && isOneshot(chapterJson, finalChapterNumber)) {
|
||||
manga.status = SManga.COMPLETED
|
||||
} else {
|
||||
manga.status = parseStatus(status)
|
||||
}
|
||||
|
||||
val genres = (if (mangaJson.get("hentai").int == 1) listOf("Hentai") else listOf()) +
|
||||
mangaJson.get("genres").asJsonArray.mapNotNull { GENRES[it.toString()] }
|
||||
mangaJson.get("genres").asJsonArray.mapNotNull { GENRES[it.toString()] }
|
||||
manga.genre = genres.joinToString(", ")
|
||||
|
||||
return manga
|
||||
|
@ -395,10 +399,10 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
return clientBuilder().newCall(apiRequest(manga))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
chapterListParse(response)
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
chapterListParse(response)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFinalChapter(jsonObj: JsonObject): String = jsonObj.get("last_chapter").string.trim()
|
||||
|
@ -414,8 +418,8 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
|
||||
private fun isMangaCompleted(chapterJson: JsonObject, finalChapterNumber: String): Boolean {
|
||||
val count = chapterJson.entrySet()
|
||||
.filter { it.value.asJsonObject.get("lang_code").string == internalLang }
|
||||
.filter { doesFinalChapterExist(finalChapterNumber, it.value) }.count()
|
||||
.filter { it.value.asJsonObject.get("lang_code").string == internalLang }
|
||||
.filter { doesFinalChapterExist(finalChapterNumber, it.value) }.count()
|
||||
return count != 0
|
||||
}
|
||||
|
||||
|
@ -460,7 +464,7 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
chapterName.add(chapterJson.get("title").string)
|
||||
}
|
||||
//if volume, chapter and title is empty its a oneshot
|
||||
if(chapterName.isEmpty()){
|
||||
if (chapterName.isEmpty()) {
|
||||
chapterName.add("Oneshot")
|
||||
}
|
||||
if ((status == 2 || status == 3) && doesFinalChapterExist(finalChapterNumber, chapterJson)) {
|
||||
|
@ -611,17 +615,17 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
private class R18 : Filter.Select<String>("R18+", arrayOf("Default", "Show all", "Show only", "Show none"))
|
||||
|
||||
private fun getDemographic() = listOf(
|
||||
Tag("1", "Shounen"),
|
||||
Tag("2", "Shoujo"),
|
||||
Tag("3", "Seinen"),
|
||||
Tag("4", "Josei")
|
||||
Tag("1", "Shounen"),
|
||||
Tag("2", "Shoujo"),
|
||||
Tag("3", "Seinen"),
|
||||
Tag("4", "Josei")
|
||||
).sortedWith(compareBy { it.name })
|
||||
|
||||
private fun getPublicationStatus() = listOf(
|
||||
Tag("1", "Ongoing"),
|
||||
Tag("2", "Completed"),
|
||||
Tag("3", "Cancelled"),
|
||||
Tag("4", "Hiatus")
|
||||
Tag("1", "Ongoing"),
|
||||
Tag("2", "Completed"),
|
||||
Tag("3", "Cancelled"),
|
||||
Tag("4", "Hiatus")
|
||||
).sortedWith(compareBy { it.name })
|
||||
|
||||
private class ThemeList(themes: List<Tag>) : Filter.Group<Tag>("Themes", themes)
|
||||
|
@ -630,115 +634,115 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
|
||||
// default selection (Rating Descending) matches popularMangaRequest url
|
||||
class SortFilter : Filter.Sort("Sort",
|
||||
sortables.map { it.first }.toTypedArray(),
|
||||
Selection(3, false))
|
||||
sortables.map { it.first }.toTypedArray(),
|
||||
Selection(3, false))
|
||||
|
||||
private class OriginalLanguage : Filter.Select<String>("Original Language", SOURCE_LANG_LIST.map { it.first }.toTypedArray())
|
||||
|
||||
override fun getFilterList() = FilterList(
|
||||
TextField("Author", "author"),
|
||||
TextField("Artist", "artist"),
|
||||
R18(),
|
||||
SortFilter(),
|
||||
Demographic(getDemographic()),
|
||||
PublicationStatus(getPublicationStatus()),
|
||||
OriginalLanguage(),
|
||||
ContentList(getContentList()),
|
||||
FormatList(getFormatList()),
|
||||
GenreList(getGenreList()),
|
||||
ThemeList(getThemeList()),
|
||||
TagInclusionMode(),
|
||||
TagExclusionMode()
|
||||
TextField("Author", "author"),
|
||||
TextField("Artist", "artist"),
|
||||
R18(),
|
||||
SortFilter(),
|
||||
Demographic(getDemographic()),
|
||||
PublicationStatus(getPublicationStatus()),
|
||||
OriginalLanguage(),
|
||||
ContentList(getContentList()),
|
||||
FormatList(getFormatList()),
|
||||
GenreList(getGenreList()),
|
||||
ThemeList(getThemeList()),
|
||||
TagInclusionMode(),
|
||||
TagExclusionMode()
|
||||
)
|
||||
|
||||
private fun getContentList() = listOf(
|
||||
Tag("9", "Ecchi"),
|
||||
Tag("32", "Smut"),
|
||||
Tag("49", "Gore"),
|
||||
Tag("50", "Sexual Violence")
|
||||
Tag("9", "Ecchi"),
|
||||
Tag("32", "Smut"),
|
||||
Tag("49", "Gore"),
|
||||
Tag("50", "Sexual Violence")
|
||||
).sortedWith(compareBy { it.name })
|
||||
|
||||
private fun getFormatList() = listOf(
|
||||
Tag("1", "4-koma"),
|
||||
Tag("4", "Award Winning"),
|
||||
Tag("7", "Doujinshi"),
|
||||
Tag("21", "Oneshot"),
|
||||
Tag("36", "Long Strip"),
|
||||
Tag("42", "Adaptation"),
|
||||
Tag("43", "Anthology"),
|
||||
Tag("44", "Web Comic"),
|
||||
Tag("45", "Full Color"),
|
||||
Tag("46", "User Created"),
|
||||
Tag("47", "Official Colored"),
|
||||
Tag("48", "Fan Colored")
|
||||
Tag("1", "4-koma"),
|
||||
Tag("4", "Award Winning"),
|
||||
Tag("7", "Doujinshi"),
|
||||
Tag("21", "Oneshot"),
|
||||
Tag("36", "Long Strip"),
|
||||
Tag("42", "Adaptation"),
|
||||
Tag("43", "Anthology"),
|
||||
Tag("44", "Web Comic"),
|
||||
Tag("45", "Full Color"),
|
||||
Tag("46", "User Created"),
|
||||
Tag("47", "Official Colored"),
|
||||
Tag("48", "Fan Colored")
|
||||
).sortedWith(compareBy { it.name })
|
||||
|
||||
private fun getGenreList() = listOf(
|
||||
Tag("2", "Action"),
|
||||
Tag("3", "Adventure"),
|
||||
Tag("5", "Comedy"),
|
||||
Tag("8", "Drama"),
|
||||
Tag("10", "Fantasy"),
|
||||
Tag("13", "Historical"),
|
||||
Tag("14", "Horror"),
|
||||
Tag("17", "Mecha"),
|
||||
Tag("18", "Medical"),
|
||||
Tag("20", "Mystery"),
|
||||
Tag("22", "Psychological"),
|
||||
Tag("23", "Romance"),
|
||||
Tag("25", "Sci-Fi"),
|
||||
Tag("28", "Shoujo Ai"),
|
||||
Tag("30", "Shounen Ai"),
|
||||
Tag("31", "Slice of Life"),
|
||||
Tag("33", "Sports"),
|
||||
Tag("35", "Tragedy"),
|
||||
Tag("37", "Yaoi"),
|
||||
Tag("38", "Yuri"),
|
||||
Tag("41", "Isekai"),
|
||||
Tag("51", "Crime"),
|
||||
Tag("52", "Magical Girls"),
|
||||
Tag("53", "Philosophical"),
|
||||
Tag("54", "Superhero"),
|
||||
Tag("55", "Thriller"),
|
||||
Tag("56", "Wuxia")
|
||||
Tag("2", "Action"),
|
||||
Tag("3", "Adventure"),
|
||||
Tag("5", "Comedy"),
|
||||
Tag("8", "Drama"),
|
||||
Tag("10", "Fantasy"),
|
||||
Tag("13", "Historical"),
|
||||
Tag("14", "Horror"),
|
||||
Tag("17", "Mecha"),
|
||||
Tag("18", "Medical"),
|
||||
Tag("20", "Mystery"),
|
||||
Tag("22", "Psychological"),
|
||||
Tag("23", "Romance"),
|
||||
Tag("25", "Sci-Fi"),
|
||||
Tag("28", "Shoujo Ai"),
|
||||
Tag("30", "Shounen Ai"),
|
||||
Tag("31", "Slice of Life"),
|
||||
Tag("33", "Sports"),
|
||||
Tag("35", "Tragedy"),
|
||||
Tag("37", "Yaoi"),
|
||||
Tag("38", "Yuri"),
|
||||
Tag("41", "Isekai"),
|
||||
Tag("51", "Crime"),
|
||||
Tag("52", "Magical Girls"),
|
||||
Tag("53", "Philosophical"),
|
||||
Tag("54", "Superhero"),
|
||||
Tag("55", "Thriller"),
|
||||
Tag("56", "Wuxia")
|
||||
).sortedWith(compareBy { it.name })
|
||||
|
||||
private fun getThemeList() = listOf(
|
||||
Tag("6", "Cooking"),
|
||||
Tag("11", "Gyaru"),
|
||||
Tag("12", "Harem"),
|
||||
Tag("16", "Martial Arts"),
|
||||
Tag("19", "Music"),
|
||||
Tag("24", "School Life"),
|
||||
Tag("34", "Supernatural"),
|
||||
Tag("40", "Video Games"),
|
||||
Tag("57", "Aliens"),
|
||||
Tag("58", "Animals"),
|
||||
Tag("59", "Crossdressing"),
|
||||
Tag("60", "Demons"),
|
||||
Tag("61", "Delinquents"),
|
||||
Tag("62", "Genderswap"),
|
||||
Tag("63", "Ghosts"),
|
||||
Tag("64", "Monster Girls"),
|
||||
Tag("65", "Loli"),
|
||||
Tag("66", "Magic"),
|
||||
Tag("67", "Military"),
|
||||
Tag("68", "Monsters"),
|
||||
Tag("69", "Ninja"),
|
||||
Tag("70", "Office Workers"),
|
||||
Tag("71", "Police"),
|
||||
Tag("72", "Post-Apocalyptic"),
|
||||
Tag("73", "Reincarnation"),
|
||||
Tag("74", "Reverse Harem"),
|
||||
Tag("75", "Samurai"),
|
||||
Tag("76", "Shota"),
|
||||
Tag("77", "Survival"),
|
||||
Tag("78", "Time Travel"),
|
||||
Tag("79", "Vampires"),
|
||||
Tag("80", "Traditional Games"),
|
||||
Tag("81", "Virtual Reality"),
|
||||
Tag("82", "Zombies"),
|
||||
Tag("83", "Incest")
|
||||
Tag("6", "Cooking"),
|
||||
Tag("11", "Gyaru"),
|
||||
Tag("12", "Harem"),
|
||||
Tag("16", "Martial Arts"),
|
||||
Tag("19", "Music"),
|
||||
Tag("24", "School Life"),
|
||||
Tag("34", "Supernatural"),
|
||||
Tag("40", "Video Games"),
|
||||
Tag("57", "Aliens"),
|
||||
Tag("58", "Animals"),
|
||||
Tag("59", "Crossdressing"),
|
||||
Tag("60", "Demons"),
|
||||
Tag("61", "Delinquents"),
|
||||
Tag("62", "Genderswap"),
|
||||
Tag("63", "Ghosts"),
|
||||
Tag("64", "Monster Girls"),
|
||||
Tag("65", "Loli"),
|
||||
Tag("66", "Magic"),
|
||||
Tag("67", "Military"),
|
||||
Tag("68", "Monsters"),
|
||||
Tag("69", "Ninja"),
|
||||
Tag("70", "Office Workers"),
|
||||
Tag("71", "Police"),
|
||||
Tag("72", "Post-Apocalyptic"),
|
||||
Tag("73", "Reincarnation"),
|
||||
Tag("74", "Reverse Harem"),
|
||||
Tag("75", "Samurai"),
|
||||
Tag("76", "Shota"),
|
||||
Tag("77", "Survival"),
|
||||
Tag("78", "Time Travel"),
|
||||
Tag("79", "Vampires"),
|
||||
Tag("80", "Traditional Games"),
|
||||
Tag("81", "Virtual Reality"),
|
||||
Tag("82", "Zombies"),
|
||||
Tag("83", "Incest")
|
||||
).sortedWith(compareBy { it.name })
|
||||
|
||||
private val GENRES = (getContentList() + getFormatList() + getGenreList() + getThemeList()).map { it.id to it.name }.toMap()
|
||||
|
@ -768,26 +772,26 @@ open class Mangadex(override val lang: String, private val internalLang: String,
|
|||
const val PREFIX_ID_SEARCH = "id:"
|
||||
|
||||
private val sortables = listOf(
|
||||
Triple("Update date", 0, 1),
|
||||
Triple("Alphabetically", 2, 3),
|
||||
Triple("Number of comments", 4, 5),
|
||||
Triple("Rating", 6, 7),
|
||||
Triple("Views", 8, 9),
|
||||
Triple("Follows", 10, 11))
|
||||
Triple("Update date", 0, 1),
|
||||
Triple("Alphabetically", 2, 3),
|
||||
Triple("Number of comments", 4, 5),
|
||||
Triple("Rating", 6, 7),
|
||||
Triple("Views", 8, 9),
|
||||
Triple("Follows", 10, 11))
|
||||
|
||||
private val SOURCE_LANG_LIST = listOf(
|
||||
Pair("All", "0"),
|
||||
Pair("Japanese", "2"),
|
||||
Pair("English", "1"),
|
||||
Pair("Polish", "3"),
|
||||
Pair("German", "8"),
|
||||
Pair("French", "10"),
|
||||
Pair("Vietnamese", "12"),
|
||||
Pair("Chinese", "21"),
|
||||
Pair("Indonesian", "27"),
|
||||
Pair("Korean", "28"),
|
||||
Pair("Spanish (LATAM)", "29"),
|
||||
Pair("Thai", "32"),
|
||||
Pair("Filipino", "34"))
|
||||
Pair("All", "0"),
|
||||
Pair("Japanese", "2"),
|
||||
Pair("English", "1"),
|
||||
Pair("Polish", "3"),
|
||||
Pair("German", "8"),
|
||||
Pair("French", "10"),
|
||||
Pair("Vietnamese", "12"),
|
||||
Pair("Chinese", "21"),
|
||||
Pair("Indonesian", "27"),
|
||||
Pair("Korean", "28"),
|
||||
Pair("Spanish (LATAM)", "29"),
|
||||
Pair("Thai", "32"),
|
||||
Pair("Filipino", "34"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,83 @@ package eu.kanade.tachiyomi.extension.all.mangadex
|
|||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
||||
|
||||
class MangadexFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = getAllMangaDexLanguages()
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
MangaDexEnglish(),
|
||||
MangaDexPolish(),
|
||||
MangaDexItalian(),
|
||||
MangaDexRussian(),
|
||||
MangaDexGerman(),
|
||||
MangaDexFrench(),
|
||||
MangaDexVietnamese(),
|
||||
MangaDexSpanishSpain(),
|
||||
MangaDexSpanishLTAM(),
|
||||
MangaDexCatalan(),
|
||||
MangaDexPortuguesePortugal(),
|
||||
MangaDexPortugueseBrazil(),
|
||||
MangaDexSwedish(),
|
||||
MangaDexTurkish(),
|
||||
MangaDexIndonesian(),
|
||||
MangaDexHungarian(),
|
||||
MangaDexBulgarian(),
|
||||
MangaDexFilipino(),
|
||||
MangaDexDutch(),
|
||||
MangaDexArabic(),
|
||||
MangaDexChineseSimp(),
|
||||
MangaDexChineseTrad(),
|
||||
MangaDexThai(),
|
||||
MangaDexBengali(),
|
||||
MangaDexBurmese(),
|
||||
MangaDexCzech(),
|
||||
MangaDexDanish(),
|
||||
MangaDexFinnish(),
|
||||
MangaDexGreek(),
|
||||
MangaDexJapanese(),
|
||||
MangaDexKorean(),
|
||||
MangaDexLithuanian(),
|
||||
MangaDexMalay(),
|
||||
MangaDexMongolian(),
|
||||
MangaDexPersian(),
|
||||
MangaDexRomanian(),
|
||||
MangaDexSerboCroatian(),
|
||||
MangaDexUkrainian()
|
||||
)
|
||||
}
|
||||
|
||||
class MangaDexPolish : Mangadex("pl", "pl", 3)
|
||||
class MangaDexItalian : Mangadex("it", "it", 6)
|
||||
class MangaDexRussian : Mangadex("ru", "ru", 7)
|
||||
class MangaDexGerman : Mangadex("de", "de", 8)
|
||||
class MangaDexFrench : Mangadex("fr", "fr", 10)
|
||||
class MangaDexVietnamese : Mangadex("vi", "vn", 12)
|
||||
class MangaDexSpanishSpain : Mangadex("es", "es", 15)
|
||||
class MangaDexSpanishLTAM : Mangadex("es-419", "mx", 29)
|
||||
class MangaDexCatalan : Mangadex("ca", "ct", 33)
|
||||
class MangaDexPortuguesePortugal : Mangadex("pt", "pt", 17)
|
||||
class MangaDexPortugueseBrazil : Mangadex("pt-BR", "br", 16)
|
||||
class MangaDexSwedish : Mangadex("sv", "se", 18)
|
||||
class MangaDexTurkish : Mangadex("tr", "tr", 26)
|
||||
class MangaDexIndonesian : Mangadex("id", "id", 27)
|
||||
class MangaDexHungarian : Mangadex("hu", "hu", 9)
|
||||
class MangaDexBulgarian : Mangadex("bg", "bg", 14)
|
||||
class MangaDexFilipino : Mangadex("fil", "ph", 34)
|
||||
class MangaDexDutch : Mangadex("nl", "nl", 5)
|
||||
class MangaDexArabic : Mangadex("ar", "sa", 19)
|
||||
class MangaDexChineseSimp : Mangadex("zh-Hans", "cn", 21)
|
||||
class MangaDexChineseTrad : Mangadex("zh-Hant", "hk", 35)
|
||||
class MangaDexThai : Mangadex("th", "th", 32)
|
||||
class MangaDexBengali : Mangadex("bn", "bd", 22)
|
||||
class MangaDexBurmese : Mangadex("my", "mm", 37)
|
||||
class MangaDexCzech : Mangadex("cs", "cz", 24)
|
||||
class MangaDexDanish : Mangadex("da", "dk", 20)
|
||||
class MangaDexFinnish : Mangadex("fi", "fi", 11)
|
||||
class MangaDexGreek : Mangadex("el", "gr", 13)
|
||||
class MangaDexJapanese : Mangadex("ja", "jp", 2)
|
||||
class MangaDexKorean : Mangadex("ko", "kr", 28)
|
||||
class MangaDexLithuanian : Mangadex("lt", "lt", 38)
|
||||
class MangaDexMalay : Mangadex("ms", "my", 31)
|
||||
class MangaDexMongolian : Mangadex("mn", "mn", 25)
|
||||
class MangaDexPersian : Mangadex("fa", "ir", 30)
|
||||
class MangaDexRomanian : Mangadex("ro", "ro", 23)
|
||||
class MangaDexSerboCroatian : Mangadex("sh", "rs", 4)
|
||||
class MangaDexUkrainian : Mangadex("uk", "ua", 36)
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.all.mangadex
|
||||
|
||||
/**
|
||||
* Mangadex languages
|
||||
*/
|
||||
|
||||
class MangaDexPolish : Mangadex("pl", "pl", 3)
|
||||
class MangaDexItalian : Mangadex("it", "it", 6)
|
||||
class MangaDexRussian : Mangadex("ru", "ru", 7)
|
||||
class MangaDexGerman : Mangadex("de", "de", 8)
|
||||
class MangaDexFrench : Mangadex("fr", "fr", 10)
|
||||
class MangaDexVietnamese : Mangadex("vi", "vn", 12)
|
||||
class MangaDexSpanishSpain : Mangadex("es", "es", 15)
|
||||
class MangaDexSpanishLTAM : Mangadex("es-419", "mx", 29)
|
||||
class MangaDexCatalan : Mangadex("ca", "ct", 33)
|
||||
class MangaDexPortuguesePortugal : Mangadex("pt", "pt", 17)
|
||||
class MangaDexPortugueseBrazil : Mangadex("pt-BR", "br", 16)
|
||||
class MangaDexSwedish : Mangadex("sv", "se", 18)
|
||||
class MangaDexTurkish : Mangadex("tr", "tr", 26)
|
||||
class MangaDexIndonesian : Mangadex("id", "id", 27)
|
||||
class MangaDexHungarian : Mangadex("hu", "hu", 9)
|
||||
class MangaDexBulgarian : Mangadex("bg", "bg", 14)
|
||||
class MangaDexFilipino : Mangadex("fil", "ph", 34)
|
||||
class MangaDexDutch : Mangadex("nl", "nl", 5)
|
||||
class MangaDexArabic : Mangadex("ar", "sa", 19)
|
||||
class MangaDexChineseSimp : Mangadex("zh-Hans", "cn", 21)
|
||||
class MangaDexChineseTrad : Mangadex("zh-Hant", "hk", 35)
|
||||
class MangaDexThai : Mangadex("th", "th", 32)
|
||||
class MangaDexBengali : Mangadex("bn", "bd", 22)
|
||||
class MangaDexBurmese : Mangadex("my", "mm", 37)
|
||||
class MangaDexCzech : Mangadex("cs", "cz", 24)
|
||||
class MangaDexDanish : Mangadex("da", "dk", 20)
|
||||
class MangaDexFinnish : Mangadex("fi", "fi", 11)
|
||||
class MangaDexGreek : Mangadex("el", "gr", 13)
|
||||
class MangaDexJapanese : Mangadex("ja", "jp", 2)
|
||||
class MangaDexKorean : Mangadex("ko", "kr", 28)
|
||||
class MangaDexLithuanian : Mangadex("lt", "lt", 38)
|
||||
class MangaDexMalay : Mangadex("ms", "my", 31)
|
||||
class MangaDexMongolian : Mangadex("mn", "mn", 25)
|
||||
class MangaDexPersian : Mangadex("fa", "ir", 30)
|
||||
class MangaDexRomanian : Mangadex("ro", "ro", 23)
|
||||
class MangaDexSerboCroatian : Mangadex("sh", "rs", 4)
|
||||
class MangaDexUkrainian : Mangadex("uk", "ua", 36)
|
||||
|
||||
fun getAllMangaDexLanguages() = listOf(
|
||||
MangaDexEnglish(),
|
||||
MangaDexPolish(),
|
||||
MangaDexItalian(),
|
||||
MangaDexRussian(),
|
||||
MangaDexGerman(),
|
||||
MangaDexFrench(),
|
||||
MangaDexVietnamese(),
|
||||
MangaDexSpanishSpain(),
|
||||
MangaDexSpanishLTAM(),
|
||||
MangaDexCatalan(),
|
||||
MangaDexPortuguesePortugal(),
|
||||
MangaDexPortugueseBrazil(),
|
||||
MangaDexSwedish(),
|
||||
MangaDexTurkish(),
|
||||
MangaDexIndonesian(),
|
||||
MangaDexHungarian(),
|
||||
MangaDexBulgarian(),
|
||||
MangaDexFilipino(),
|
||||
MangaDexDutch(),
|
||||
MangaDexArabic(),
|
||||
MangaDexChineseSimp(),
|
||||
MangaDexChineseTrad(),
|
||||
MangaDexThai(),
|
||||
MangaDexBengali(),
|
||||
MangaDexBurmese(),
|
||||
MangaDexCzech(),
|
||||
MangaDexDanish(),
|
||||
MangaDexFinnish(),
|
||||
MangaDexGreek(),
|
||||
MangaDexJapanese(),
|
||||
MangaDexKorean(),
|
||||
MangaDexLithuanian(),
|
||||
MangaDexMalay(),
|
||||
MangaDexMongolian(),
|
||||
MangaDexPersian(),
|
||||
MangaDexRomanian(),
|
||||
MangaDexSerboCroatian(),
|
||||
MangaDexUkrainian()
|
||||
)
|
|
@ -5,6 +5,7 @@ import android.content.ActivityNotFoundException
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
/**
|
||||
* Springboard that accepts https://mangadex.com/title/xxx intents and redirects them to
|
||||
|
@ -38,7 +39,7 @@ class MangadexUrlActivity : Activity() {
|
|||
}
|
||||
|
||||
finish()
|
||||
System.exit(0)
|
||||
exitProcess(0)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: MangAdventure'
|
||||
pkgNameSuffix = 'all.mangadventure'
|
||||
extClass = '.MangAdventureFactory'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import java.util.Locale
|
|||
*
|
||||
* @property categories the available manga categories of the site.
|
||||
*/
|
||||
open class MangAdventure(
|
||||
abstract class MangAdventure(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
val categories: Array<String> = DEFAULT_CATEGORIES
|
||||
|
|
|
@ -31,7 +31,7 @@ class MangAdventureActivity : Activity() {
|
|||
}
|
||||
|
||||
private fun logInvalidIntent(intent: Intent) {
|
||||
val msg = "Failed to parse URI from intent"
|
||||
Log.e("MangAdventureActivity", "$msg $intent")
|
||||
Log.e("MangAdventureActivity", "Failed to parse URI from intent: $intent")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.all.mangadventure
|
|||
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
||||
/** [MangAdventure] source factory. */
|
||||
class MangAdventureFactory : SourceFactory {
|
||||
override fun createSources() = listOf(
|
||||
ArcRelight()
|
||||
|
@ -11,22 +10,22 @@ class MangAdventureFactory : SourceFactory {
|
|||
/** Arc-Relight source. */
|
||||
class ArcRelight : MangAdventure(
|
||||
"Arc-Relight", "https://arc-relight.com", arrayOf(
|
||||
"4-Koma",
|
||||
"Chaos;Head",
|
||||
"Collection",
|
||||
"Comedy",
|
||||
"Drama",
|
||||
"Jubilee",
|
||||
"Mystery",
|
||||
"Psychological",
|
||||
"Robotics;Notes",
|
||||
"Romance",
|
||||
"Sci-Fi",
|
||||
"Seinen",
|
||||
"Shounen",
|
||||
"Steins;Gate",
|
||||
"Supernatural",
|
||||
"Tragedy"
|
||||
)
|
||||
"4-Koma",
|
||||
"Chaos;Head",
|
||||
"Collection",
|
||||
"Comedy",
|
||||
"Drama",
|
||||
"Jubilee",
|
||||
"Mystery",
|
||||
"Psychological",
|
||||
"Robotics;Notes",
|
||||
"Romance",
|
||||
"Sci-Fi",
|
||||
"Seinen",
|
||||
"Shounen",
|
||||
"Steins;Gate",
|
||||
"Supernatural",
|
||||
"Tragedy"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: Mangatensei'
|
||||
pkgNameSuffix = 'all.mangatensei'
|
||||
extClass = '.MangatenseiFactory'
|
||||
extVersionCode = 2
|
||||
extVersionCode = 3
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package eu.kanade.tachiyomi.extension.all.mangatensei
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
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 okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
|
@ -9,7 +13,7 @@ import okhttp3.Request
|
|||
import org.json.JSONObject
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.*
|
||||
import java.util.Calendar
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
open class Mangatensei(override val lang: String, private val Mtlang: String) : ParsedHttpSource() {
|
||||
|
@ -25,7 +29,7 @@ open class Mangatensei(override val lang: String, private val Mtlang: String) :
|
|||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
// The site redirects page 1 -> url-without-page so we do this redirect early for optimization
|
||||
val builtUrl = "$baseUrl/browse?langs=$Mtlang&sort=update&page=$page"
|
||||
return GET(builtUrl)
|
||||
|
@ -45,7 +49,7 @@ open class Mangatensei(override val lang: String, private val Mtlang: String) :
|
|||
|
||||
override fun latestUpdatesNextPageSelector() = "div.browse-pager:contains(order) a.page-link:contains(»)"
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
val builtUrl = "$baseUrl/browse?langs=$Mtlang&sort=views_w&page=$page"
|
||||
return GET(builtUrl)
|
||||
}
|
||||
|
@ -64,7 +68,7 @@ open class Mangatensei(override val lang: String, private val Mtlang: String) :
|
|||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is AuthorFilter -> {
|
||||
author = filter.state
|
||||
author = filter.state
|
||||
}
|
||||
is StyleFilter -> {
|
||||
val styleToInclude = mutableListOf<String>()
|
||||
|
@ -96,7 +100,7 @@ open class Mangatensei(override val lang: String, private val Mtlang: String) :
|
|||
Filter.TriState.STATE_EXCLUDE -> "0"
|
||||
else -> ""
|
||||
}
|
||||
if(status.isNotEmpty()) {
|
||||
if (status.isNotEmpty()) {
|
||||
url.addQueryParameter("status", status)
|
||||
}
|
||||
}
|
||||
|
@ -113,23 +117,23 @@ open class Mangatensei(override val lang: String, private val Mtlang: String) :
|
|||
}
|
||||
}
|
||||
is StarFilter -> {
|
||||
if(filter.state != 0) {
|
||||
if (filter.state != 0) {
|
||||
url.addQueryParameter("stars", filter.toUriPart())
|
||||
}
|
||||
}
|
||||
is ChapterFilter -> {
|
||||
if(filter.state != 0) {
|
||||
if (filter.state != 0) {
|
||||
url.addQueryParameter("chapters", filter.toUriPart())
|
||||
}
|
||||
}
|
||||
is SortBy -> {
|
||||
if(filter.state != 0) {
|
||||
if (filter.state != 0) {
|
||||
url.addQueryParameter("sort", filter.toUriPart())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return if(query.isNotBlank() || author!!.isNotBlank()) {
|
||||
return if (query.isNotBlank() || author!!.isNotBlank()) {
|
||||
GET("$baseUrl/search?q=$query&a=$author")
|
||||
} else GET(url.build().toString(), headers)
|
||||
}
|
||||
|
@ -257,7 +261,7 @@ open class Mangatensei(override val lang: String, private val Mtlang: String) :
|
|||
val imgJson = JSONObject(script)
|
||||
val imgNames = imgJson.names()
|
||||
|
||||
for( i in 0 until imgNames.length()) {
|
||||
for (i in 0 until imgNames.length()) {
|
||||
val imgKey = imgNames.getString(i)
|
||||
val imgUrl = imgJson.getString(imgKey)
|
||||
pages.add(Page(i, "", imgUrl))
|
||||
|
@ -275,111 +279,111 @@ open class Mangatensei(override val lang: String, private val Mtlang: String) :
|
|||
private class StatusFilter : Filter.TriState("Completed")
|
||||
|
||||
private class StarFilter : UriPartFilter("Stars", arrayOf(
|
||||
Pair("<select>", ""),
|
||||
Pair("5 Stars", "5"),
|
||||
Pair("4 Stars", "4"),
|
||||
Pair("3 Stars", "3"),
|
||||
Pair("2 Stars", "2"),
|
||||
Pair("1 Stars", "1")
|
||||
Pair("<select>", ""),
|
||||
Pair("5 Stars", "5"),
|
||||
Pair("4 Stars", "4"),
|
||||
Pair("3 Stars", "3"),
|
||||
Pair("2 Stars", "2"),
|
||||
Pair("1 Stars", "1")
|
||||
))
|
||||
|
||||
private class ChapterFilter : UriPartFilter("Chapters", arrayOf(
|
||||
Pair("<select>", ""),
|
||||
Pair("1 ~ 9", "1-9"),
|
||||
Pair("10 ~ 29", "10-29"),
|
||||
Pair("30 ~ 99", "30-99"),
|
||||
Pair("100 ~ 199", "100-199"),
|
||||
Pair("200+", "200"),
|
||||
Pair("100+", "100"),
|
||||
Pair("50+", "50"),
|
||||
Pair("10+", "10"),
|
||||
Pair("1+", "1")
|
||||
Pair("<select>", ""),
|
||||
Pair("1 ~ 9", "1-9"),
|
||||
Pair("10 ~ 29", "10-29"),
|
||||
Pair("30 ~ 99", "30-99"),
|
||||
Pair("100 ~ 199", "100-199"),
|
||||
Pair("200+", "200"),
|
||||
Pair("100+", "100"),
|
||||
Pair("50+", "50"),
|
||||
Pair("10+", "10"),
|
||||
Pair("1+", "1")
|
||||
))
|
||||
|
||||
private class SortBy : UriPartFilter("Sorts By", arrayOf(
|
||||
Pair("<select>", ""),
|
||||
Pair("Totally", "views_t"),
|
||||
Pair("365 days", "views_y"),
|
||||
Pair("30 days", "views_m"),
|
||||
Pair("7 days", "views_w"),
|
||||
Pair("24 hours", "views_d"),
|
||||
Pair("60 minutes", "views_h"),
|
||||
Pair("A-Z", "title"),
|
||||
Pair("Update time", "update"),
|
||||
Pair("Add time", "create")
|
||||
Pair("<select>", ""),
|
||||
Pair("Totally", "views_t"),
|
||||
Pair("365 days", "views_y"),
|
||||
Pair("30 days", "views_m"),
|
||||
Pair("7 days", "views_w"),
|
||||
Pair("24 hours", "views_d"),
|
||||
Pair("60 minutes", "views_h"),
|
||||
Pair("A-Z", "title"),
|
||||
Pair("Update time", "update"),
|
||||
Pair("Add time", "create")
|
||||
))
|
||||
|
||||
override fun getFilterList() = FilterList(
|
||||
Filter.Header("NOTE: Ignored if using text search!"),
|
||||
AuthorFilter(),
|
||||
Filter.Separator(),
|
||||
StatusFilter(),
|
||||
StarFilter(),
|
||||
ChapterFilter(),
|
||||
SortBy(),
|
||||
StyleFilter(getStyleList()),
|
||||
DemographicFilter(getDemographicList()),
|
||||
GenreFilter(getGenreList())
|
||||
Filter.Header("NOTE: Ignored if using text search!"),
|
||||
AuthorFilter(),
|
||||
Filter.Separator(),
|
||||
StatusFilter(),
|
||||
StarFilter(),
|
||||
ChapterFilter(),
|
||||
SortBy(),
|
||||
StyleFilter(getStyleList()),
|
||||
DemographicFilter(getDemographicList()),
|
||||
GenreFilter(getGenreList())
|
||||
)
|
||||
|
||||
private fun getStyleList() = listOf(
|
||||
Tag("manga"),
|
||||
Tag("manhwa"),
|
||||
Tag("manhua"),
|
||||
Tag("webtoon")
|
||||
Tag("manga"),
|
||||
Tag("manhwa"),
|
||||
Tag("manhua"),
|
||||
Tag("webtoon")
|
||||
)
|
||||
|
||||
private fun getDemographicList() = listOf(
|
||||
Tag("josei"),
|
||||
Tag("seinen"),
|
||||
Tag("shoujo"),
|
||||
Tag("shoujo ai"),
|
||||
Tag("shounen"),
|
||||
Tag("shounen ai"),
|
||||
Tag("yaoi"),
|
||||
Tag("yuri")
|
||||
Tag("josei"),
|
||||
Tag("seinen"),
|
||||
Tag("shoujo"),
|
||||
Tag("shoujo ai"),
|
||||
Tag("shounen"),
|
||||
Tag("shounen ai"),
|
||||
Tag("yaoi"),
|
||||
Tag("yuri")
|
||||
)
|
||||
|
||||
private fun getGenreList() = listOf(
|
||||
Tag("action"),
|
||||
Tag("adventure"),
|
||||
Tag("award winning"),
|
||||
Tag("comedy"),
|
||||
Tag("cooking"),
|
||||
Tag("demons"),
|
||||
Tag("doujinshi"),
|
||||
Tag("drama"),
|
||||
Tag("ecchi"),
|
||||
Tag("fantasy"),
|
||||
Tag("gender bender"),
|
||||
Tag("harem"),
|
||||
Tag("historical"),
|
||||
Tag("horror"),
|
||||
Tag("isekai"),
|
||||
Tag("magic"),
|
||||
Tag("martial arts"),
|
||||
Tag("mature"),
|
||||
Tag("mecha"),
|
||||
Tag("medical"),
|
||||
Tag("military"),
|
||||
Tag("music"),
|
||||
Tag("mystery"),
|
||||
Tag("one shot"),
|
||||
Tag("psychological"),
|
||||
Tag("reverse harem"),
|
||||
Tag("romance"),
|
||||
Tag("school life"),
|
||||
Tag("sci fi"),
|
||||
Tag("shotacon"),
|
||||
Tag("slice of life"),
|
||||
Tag("smut"),
|
||||
Tag("sports"),
|
||||
Tag("super power"),
|
||||
Tag("supernatural"),
|
||||
Tag("tragedy"),
|
||||
Tag("uncategorized"),
|
||||
Tag("vampire"),
|
||||
Tag("youkai")
|
||||
Tag("action"),
|
||||
Tag("adventure"),
|
||||
Tag("award winning"),
|
||||
Tag("comedy"),
|
||||
Tag("cooking"),
|
||||
Tag("demons"),
|
||||
Tag("doujinshi"),
|
||||
Tag("drama"),
|
||||
Tag("ecchi"),
|
||||
Tag("fantasy"),
|
||||
Tag("gender bender"),
|
||||
Tag("harem"),
|
||||
Tag("historical"),
|
||||
Tag("horror"),
|
||||
Tag("isekai"),
|
||||
Tag("magic"),
|
||||
Tag("martial arts"),
|
||||
Tag("mature"),
|
||||
Tag("mecha"),
|
||||
Tag("medical"),
|
||||
Tag("military"),
|
||||
Tag("music"),
|
||||
Tag("mystery"),
|
||||
Tag("one shot"),
|
||||
Tag("psychological"),
|
||||
Tag("reverse harem"),
|
||||
Tag("romance"),
|
||||
Tag("school life"),
|
||||
Tag("sci fi"),
|
||||
Tag("shotacon"),
|
||||
Tag("slice of life"),
|
||||
Tag("smut"),
|
||||
Tag("sports"),
|
||||
Tag("super power"),
|
||||
Tag("supernatural"),
|
||||
Tag("tragedy"),
|
||||
Tag("uncategorized"),
|
||||
Tag("vampire"),
|
||||
Tag("youkai")
|
||||
)
|
||||
|
||||
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
||||
|
|
|
@ -3,7 +3,54 @@ package eu.kanade.tachiyomi.extension.all.mangatensei
|
|||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
||||
|
||||
class MangatenseiFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = getAllMangatenseiLanguages()
|
||||
}
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
MangatenseiArabic(),
|
||||
MangatenseiBrazilian(),
|
||||
MangatenseiCzech(),
|
||||
MangatenseiDanish(),
|
||||
MangatenseiDutch(),
|
||||
MangatenseiEnglish(),
|
||||
MangatenseiFilipino(),
|
||||
MangatenseiFrench(),
|
||||
MangatenseiGerman(),
|
||||
MangatenseiGreek(),
|
||||
MangatenseiHebrew(),
|
||||
MangatenseiHungarian(),
|
||||
MangatenseiIndonesian(),
|
||||
MangatenseiItalian(),
|
||||
MangatenseiMalay(),
|
||||
MangatenseiPolish(),
|
||||
MangatenseiPortuguese(),
|
||||
MangatenseiRomanian(),
|
||||
MangatenseiRussian(),
|
||||
MangatenseiSpanish(),
|
||||
MangatenseiThai(),
|
||||
MangatenseiTurkish(),
|
||||
MangatenseiVietnamese()
|
||||
)
|
||||
}
|
||||
|
||||
class MangatenseiArabic : Mangatensei("ar", "arabic")
|
||||
class MangatenseiBrazilian : Mangatensei("pt-BR", "brazilian")
|
||||
class MangatenseiCzech : Mangatensei("cs", "czech")
|
||||
class MangatenseiDanish : Mangatensei("da", "danish")
|
||||
class MangatenseiDutch : Mangatensei("nl", "dutch")
|
||||
class MangatenseiEnglish : Mangatensei("en", "english")
|
||||
class MangatenseiFilipino : Mangatensei("fil", "filipino")
|
||||
class MangatenseiFrench : Mangatensei("fr", "french")
|
||||
class MangatenseiGerman : Mangatensei("de", "german")
|
||||
class MangatenseiGreek : Mangatensei("el", "greek")
|
||||
class MangatenseiHebrew : Mangatensei("iw", "hebrew")
|
||||
class MangatenseiHungarian : Mangatensei("hu", "hungarian")
|
||||
class MangatenseiIndonesian : Mangatensei("id", "indonesian")
|
||||
class MangatenseiItalian : Mangatensei("it", "italian")
|
||||
class MangatenseiMalay : Mangatensei("ms", "malay")
|
||||
class MangatenseiPolish : Mangatensei("pl", "polish")
|
||||
class MangatenseiPortuguese : Mangatensei("pt", "portuguese")
|
||||
class MangatenseiRomanian : Mangatensei("ro", "romanian")
|
||||
class MangatenseiRussian : Mangatensei("ru", "russian")
|
||||
class MangatenseiSpanish : Mangatensei("es", "spanish")
|
||||
class MangatenseiThai : Mangatensei("th", "thai")
|
||||
class MangatenseiTurkish : Mangatensei("tr", "turkish")
|
||||
class MangatenseiVietnamese : Mangatensei("vi", "vietnamese")
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.all.mangatensei
|
||||
|
||||
/**
|
||||
* Mangatensei languages
|
||||
*/
|
||||
|
||||
class MangatenseiArabic : Mangatensei("ar", "arabic")
|
||||
class MangatenseiBrazilian : Mangatensei("pt-BR", "brazilian")
|
||||
class MangatenseiCzech : Mangatensei("cs", "czech")
|
||||
class MangatenseiDanish : Mangatensei("da", "danish")
|
||||
class MangatenseiDutch : Mangatensei("nl", "dutch")
|
||||
class MangatenseiEnglish : Mangatensei("en", "english")
|
||||
class MangatenseiFilipino : Mangatensei("fil", "filipino")
|
||||
class MangatenseiFrench : Mangatensei("fr", "french")
|
||||
class MangatenseiGerman : Mangatensei("de", "german")
|
||||
class MangatenseiGreek : Mangatensei("el", "greek")
|
||||
class MangatenseiHebrew : Mangatensei("iw", "hebrew")
|
||||
class MangatenseiHungarian : Mangatensei("hu", "hungarian")
|
||||
class MangatenseiIndonesian : Mangatensei("id", "indonesian")
|
||||
class MangatenseiItalian : Mangatensei("it", "italian")
|
||||
class MangatenseiMalay : Mangatensei("ms", "malay")
|
||||
class MangatenseiPolish : Mangatensei("pl", "polish")
|
||||
class MangatenseiPortuguese : Mangatensei("pt", "portuguese")
|
||||
class MangatenseiRomanian : Mangatensei("ro", "romanian")
|
||||
class MangatenseiRussian : Mangatensei("ru", "russian")
|
||||
class MangatenseiSpanish : Mangatensei("es", "spanish")
|
||||
class MangatenseiThai : Mangatensei("th", "thai")
|
||||
class MangatenseiTurkish : Mangatensei("tr", "turkish")
|
||||
class MangatenseiVietnamese : Mangatensei("vi", "vietnamese")
|
||||
|
||||
fun getAllMangatenseiLanguages() = listOf(
|
||||
MangatenseiArabic(),
|
||||
MangatenseiBrazilian(),
|
||||
MangatenseiCzech(),
|
||||
MangatenseiDanish(),
|
||||
MangatenseiDutch(),
|
||||
MangatenseiEnglish(),
|
||||
MangatenseiFilipino(),
|
||||
MangatenseiFrench(),
|
||||
MangatenseiGerman(),
|
||||
MangatenseiGreek(),
|
||||
MangatenseiHebrew(),
|
||||
MangatenseiHungarian(),
|
||||
MangatenseiIndonesian(),
|
||||
MangatenseiItalian(),
|
||||
MangatenseiMalay(),
|
||||
MangatenseiPolish(),
|
||||
MangatenseiPortuguese(),
|
||||
MangatenseiRomanian(),
|
||||
MangatenseiRussian(),
|
||||
MangatenseiSpanish(),
|
||||
MangatenseiThai(),
|
||||
MangatenseiTurkish(),
|
||||
MangatenseiVietnamese()
|
||||
)
|
Loading…
Reference in New Issue