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