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