The website is 18comic.vip, Chinese (#4123)
* The website is 18comic.vip, Chinese website The reason why I submitted the two versions is: if the Internet user in Mainland China needs to access the URL 18comic2.biz to log in to the website, if it is a non-Mainland China Internet user needs to access 18comic.vip, I cannot judge the user's IP * Revert "The website is 18comic.vip, Chinese website" This reverts commit 47a74ca7e92eeda2bb7cf1676a89a26081d47132. * 18comic * Delete illegal information * Keep one extension, and delete illegal information
							
								
								
									
										12
									
								
								src/zh/jinmantiantang/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,12 @@
 | 
			
		||||
apply plugin: 'com.android.application'
 | 
			
		||||
apply plugin: 'kotlin-android'
 | 
			
		||||
 | 
			
		||||
ext {
 | 
			
		||||
    extName = 'Jinmantiantang'
 | 
			
		||||
    pkgNameSuffix = 'zh.jinmantiantang'
 | 
			
		||||
    extClass = '.Jinmantiantang'
 | 
			
		||||
    extVersionCode = 1
 | 
			
		||||
    libVersion = '1.2'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply from: "$rootDir/common.gradle"
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/zh/jinmantiantang/res/mipmap-hdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 113 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/zh/jinmantiantang/res/mipmap-ldpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 113 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/zh/jinmantiantang/res/mipmap-mdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 113 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/zh/jinmantiantang/res/mipmap-xhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 113 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/zh/jinmantiantang/res/mipmap-xxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 113 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/zh/jinmantiantang/res/mipmap-xxxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 113 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/zh/jinmantiantang/res/web_hi_res_512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 113 KiB  | 
@ -0,0 +1,258 @@
 | 
			
		||||
package eu.kanade.tachiyomi.extension.zh.jinmantiantang
 | 
			
		||||
 | 
			
		||||
import eu.kanade.tachiyomi.network.GET
 | 
			
		||||
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.Request
 | 
			
		||||
import okhttp3.Response
 | 
			
		||||
import org.jsoup.nodes.Document
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
import org.jsoup.select.Elements
 | 
			
		||||
 | 
			
		||||
class Jinmantiantang : ParsedHttpSource() {
 | 
			
		||||
    override val baseUrl: String = "https://18comic2.biz"
 | 
			
		||||
    override val lang: String = "zh"
 | 
			
		||||
    override val name: String = "禁漫天堂"
 | 
			
		||||
    override val supportsLatest: Boolean = true
 | 
			
		||||
 | 
			
		||||
    private var chapterArea = "a[class=col btn btn-primary dropdown-toggle reading]"
 | 
			
		||||
 | 
			
		||||
    // 点击量排序(人气)
 | 
			
		||||
    override fun popularMangaRequest(page: Int): Request {
 | 
			
		||||
        return GET("$baseUrl/albums?o=mv&page=$page", headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun popularMangaNextPageSelector(): String? = "a.prevnext"
 | 
			
		||||
    override fun popularMangaSelector(): String = "div.col-xs-6.col-sm-6.col-md-4.col-lg-3.list-col div.well.well-sm"
 | 
			
		||||
    override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
 | 
			
		||||
        title = element.select("span.video-title").text()
 | 
			
		||||
        setUrlWithoutDomain(element.select("a").first().attr("href"))
 | 
			
		||||
        thumbnail_url = element.select("img").attr("data-original").split("\\?")[0]
 | 
			
		||||
        author = element.select("div.title-truncate").select("a").first().text()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 最新排序
 | 
			
		||||
    override fun latestUpdatesRequest(page: Int): Request {
 | 
			
		||||
        return GET("$baseUrl/albums?o=mr&page=$page", headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun latestUpdatesNextPageSelector(): String? = popularMangaNextPageSelector()
 | 
			
		||||
    override fun latestUpdatesSelector(): String = popularMangaSelector()
 | 
			
		||||
    override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
 | 
			
		||||
 | 
			
		||||
    // 查询信息
 | 
			
		||||
    override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
 | 
			
		||||
        return if (query != "") {
 | 
			
		||||
            val url = HttpUrl.parse("$baseUrl/search/photos?search_query=$query&page=$page")?.newBuilder()
 | 
			
		||||
            GET(url.toString(), headers)
 | 
			
		||||
        } else {
 | 
			
		||||
            val params = filters.map {
 | 
			
		||||
                if (it is UriPartFilter) {
 | 
			
		||||
                    it.toUriPart()
 | 
			
		||||
                } else ""
 | 
			
		||||
            }.filter { it != "" }.joinToString("")
 | 
			
		||||
            val url = HttpUrl.parse("$baseUrl" + "$params&page=$page")?.newBuilder()
 | 
			
		||||
            GET(url.toString(), headers)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun searchMangaNextPageSelector(): String? = popularMangaNextPageSelector()
 | 
			
		||||
    override fun searchMangaSelector(): String = popularMangaSelector()
 | 
			
		||||
    override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
 | 
			
		||||
 | 
			
		||||
    // 漫画详情
 | 
			
		||||
    // url网址 , title标题 , artist艺术家 , author作者 , description描述 , genre类型 , thumbnail_url缩图网址 , initialized是否初始化
 | 
			
		||||
    // status状态 0未知,1连载,2完结,3领取牌照
 | 
			
		||||
 | 
			
		||||
    override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
 | 
			
		||||
        determineChapterInfo(document)
 | 
			
		||||
        title = document.select("div.panel-heading").select("div.pull-left").first().text()
 | 
			
		||||
        thumbnail_url = document.select("img.lazy_img.img-responsive").attr("src").split("\\?")[0]
 | 
			
		||||
        author = selectAuthor(document)
 | 
			
		||||
        artist = author
 | 
			
		||||
        genre = selectDetailsStatusAndGenre(document, 0)
 | 
			
		||||
        status = selectDetailsStatusAndGenre(document, 1).trim()!!.toInt() // When the index passed by the "selectDetailsStatusAndGenre(document: Document, index: Int)" index is 1, it will definitely return a String type of 0, 1 or 2. This warning can be ignored
 | 
			
		||||
        description = document.select("div.p-t-5.p-b-5").get(7).text()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 查询作者信息
 | 
			
		||||
    private fun selectAuthor(document: Document): String {
 | 
			
		||||
        var element = document.select("div.tag-block").get(9)
 | 
			
		||||
        if (element.select("a").size == 0) {
 | 
			
		||||
            return "未知"
 | 
			
		||||
        } else {
 | 
			
		||||
            return element.select("a").first().text()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 查询漫画状态和类别信息
 | 
			
		||||
    private fun selectDetailsStatusAndGenre(document: Document, index: Int): String {
 | 
			
		||||
        determineChapterInfo(document)
 | 
			
		||||
        var status: String = "0"
 | 
			
		||||
        var genre: String = ""
 | 
			
		||||
        if (document.select("span[itemprop=genre] a").size == 0) {
 | 
			
		||||
            if (index == 1) {
 | 
			
		||||
                return status
 | 
			
		||||
            } else {
 | 
			
		||||
                return genre
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        var elements: Elements = document.select("span[itemprop=genre]").first().select("a")
 | 
			
		||||
        for (value in elements) {
 | 
			
		||||
            var vote: String = value.select("a").text()
 | 
			
		||||
            if (vote.equals("連載中")) {
 | 
			
		||||
                status = "1"
 | 
			
		||||
            } else if (vote.equals("完結")) {
 | 
			
		||||
                status = "2"
 | 
			
		||||
            } else {
 | 
			
		||||
                genre = genre + "$vote "
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (index == 1) {
 | 
			
		||||
            return status
 | 
			
		||||
        } else {
 | 
			
		||||
            return genre
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 漫画章节信息
 | 
			
		||||
    override fun chapterListSelector(): String = chapterArea
 | 
			
		||||
    override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
 | 
			
		||||
 | 
			
		||||
        if (chapterArea == "a[class=col btn btn-primary dropdown-toggle reading]") {
 | 
			
		||||
            name = element.select("a[class=col btn btn-primary dropdown-toggle reading]").text()
 | 
			
		||||
            url = element.select("a[class=col btn btn-primary dropdown-toggle reading]").attr("href")
 | 
			
		||||
        } else {
 | 
			
		||||
            url = element.select("a").attr("href")
 | 
			
		||||
            name = element.select("a li").first().ownText()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun determineChapterInfo(document: Document) {
 | 
			
		||||
        if (document.select("div[id=episode-block] a li").size == 0) {
 | 
			
		||||
            chapterArea = "a[class=col btn btn-primary dropdown-toggle reading]"
 | 
			
		||||
        } else {
 | 
			
		||||
            chapterArea = "div[id=episode-block] a[href^=/photo/]"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun chapterListParse(response: Response): List<SChapter> {
 | 
			
		||||
        return super.chapterListParse(response).asReversed()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 漫画图片信息
 | 
			
		||||
    override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
 | 
			
		||||
        var elements = document.select("div[style=text-align:center;][id*=0]")
 | 
			
		||||
        for (element in elements) {
 | 
			
		||||
            if (element.select("div[style=text-align:center;][id*=0] img").attr("src").indexOf("blank.jpg") >= 0) {
 | 
			
		||||
                add(Page(size, "", element.select("div[style=text-align:center;][id*=0] img").attr("data-original").split("\\?")[0]))
 | 
			
		||||
            } else {
 | 
			
		||||
                add(Page(size, "", element.select("div[style=text-align:center;][id*=0] img").attr("src").split("\\?")[0]))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun imageUrlParse(document: Document): String = throw Exception("Not Used")
 | 
			
		||||
 | 
			
		||||
    // Filters
 | 
			
		||||
    // 按照类别信息进行检索
 | 
			
		||||
 | 
			
		||||
    override fun getFilterList() = FilterList(
 | 
			
		||||
        CategoryGroup(),
 | 
			
		||||
        ProgressGroup()
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    private class CategoryGroup : UriPartFilter("按类型", arrayOf(
 | 
			
		||||
        Pair("全部", "/albums?"),
 | 
			
		||||
        Pair("其他", "/albums/another?"),
 | 
			
		||||
        Pair("同人", "/albums/doujin?"),
 | 
			
		||||
        Pair("韩漫", "/albums/hanman?"),
 | 
			
		||||
        Pair("美漫", "/albums/meiman?"),
 | 
			
		||||
        Pair("短篇", "/albums/short?"),
 | 
			
		||||
        Pair("单本", "/albums/single?"),
 | 
			
		||||
 | 
			
		||||
        Pair("中文", "/search/photos?search_query=中文&"),
 | 
			
		||||
        Pair("汉化", "/search/photos?search_query=漢化&"),
 | 
			
		||||
        Pair("P站", "/search/photos?search_query=PIXIV&"),
 | 
			
		||||
        Pair("图集", "/search/photos?search_query=CG&"),
 | 
			
		||||
 | 
			
		||||
        Pair("剧情", "/search/photos?search_query=劇情&"),
 | 
			
		||||
        Pair("校园", "/search/photos?search_query=校園&"),
 | 
			
		||||
        Pair("纯爱", "/search/photos?search_query=純愛&"),
 | 
			
		||||
        Pair("人妻", "/search/photos?search_query=人妻&"),
 | 
			
		||||
        Pair("师生", "/search/photos?search_query=師生&"),
 | 
			
		||||
        Pair("近亲", "/search/photos?search_query=近親&"),
 | 
			
		||||
        Pair("百合", "/search/photos?search_query=百合&"),
 | 
			
		||||
        Pair("男同", "/search/photos?search_query=YAOI&"),
 | 
			
		||||
        Pair("性转换", "/search/photos?search_query=性轉換&"),
 | 
			
		||||
        Pair("暴力", "/search/photos?search_query=NTR&"),
 | 
			
		||||
        Pair("偽娘", "/search/photos?search_query=偽娘&"),
 | 
			
		||||
        Pair("痴女", "/search/photos?search_query=癡女&"),
 | 
			
		||||
        Pair("全彩", "/search/photos?search_query=全彩&"),
 | 
			
		||||
 | 
			
		||||
        Pair("萝莉", "/search/photos?search_query=蘿莉&"),
 | 
			
		||||
        Pair("御姐", "/search/photos?search_query=御姐&"),
 | 
			
		||||
        Pair("熟女", "/search/photos?search_query=熟女&"),
 | 
			
		||||
        Pair("正太", "/search/photos?search_query=正太&"),
 | 
			
		||||
        Pair("巨乳", "/search/photos?search_query=巨乳&"),
 | 
			
		||||
        Pair("贫乳", "/search/photos?search_query=貧乳&"),
 | 
			
		||||
        Pair("女王", "/search/photos?search_query=女王&"),
 | 
			
		||||
        Pair("教室", "/search/photos?search_query=教師&"),
 | 
			
		||||
        Pair("女仆", "/search/photos?search_query=女僕&"),
 | 
			
		||||
        Pair("护士", "/search/photos?search_query=護士&"),
 | 
			
		||||
        Pair("泳裝", "/search/photos?search_query=泳裝&"),
 | 
			
		||||
        Pair("眼睛", "/search/photos?search_query=眼鏡&"),
 | 
			
		||||
        Pair("丝袜", "/search/photos?search_query=絲襪&"),
 | 
			
		||||
        Pair("制服", "/search/photos?search_query=制服&"),
 | 
			
		||||
 | 
			
		||||
        Pair("群交", "/search/photos?search_query=群交&"),
 | 
			
		||||
        Pair("足交", "/search/photos?search_query=足交&"),
 | 
			
		||||
        Pair("SM", "/search/photos?search_query=SM&"),
 | 
			
		||||
        Pair("肛交", "/search/photos?search_query=肛交&"),
 | 
			
		||||
        Pair("阿黑颜", "/search/photos?search_query=阿黑顏&"),
 | 
			
		||||
        Pair("药物", "/search/photos?search_query=藥物&"),
 | 
			
		||||
        Pair("扶他", "/search/photos?search_query=扶他&"),
 | 
			
		||||
        Pair("调教", "/search/photos?search_query=調教&"),
 | 
			
		||||
        Pair("野外", "/search/photos?search_query=野外&"),
 | 
			
		||||
        Pair("露出", "/search/photos?search_query=露出&"),
 | 
			
		||||
        Pair("催眠", "/search/photos?search_query=催眠&"),
 | 
			
		||||
        Pair("自慰", "/search/photos?search_query=自慰&"),
 | 
			
		||||
        Pair("触手", "/search/photos?search_query=觸手&"),
 | 
			
		||||
        Pair("兽交", "/search/photos?search_query=獸交&"),
 | 
			
		||||
        Pair("亞人", "/search/photos?search_query=亞人&"),
 | 
			
		||||
        Pair("魔物", "/search/photos?search_query=魔物&"),
 | 
			
		||||
 | 
			
		||||
        Pair("重口", "/search/photos?search_query=重口&"),
 | 
			
		||||
        Pair("猎奇", "/search/photos?search_query=獵奇&"),
 | 
			
		||||
        Pair("非H", "/search/photos?search_query=非H&"),
 | 
			
		||||
        Pair("血腥", "/search/photos?search_query=血腥&"),
 | 
			
		||||
        Pair("暴力", "/search/photos?search_query=暴力&")
 | 
			
		||||
    ))
 | 
			
		||||
 | 
			
		||||
    private class ProgressGroup : UriPartFilter("按进度", arrayOf(
 | 
			
		||||
        Pair("最新", "o=mr"),
 | 
			
		||||
        Pair("最多点阅", "o=mv"),
 | 
			
		||||
        Pair("最多图片", "o=mp"),
 | 
			
		||||
        Pair("最多爱心", "o=tf")
 | 
			
		||||
    ))
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *创建选择过滤器的类。 下拉菜单中的每个条目都有一个名称和一个显示名称。
 | 
			
		||||
     *如果选择了一个条目,它将作为查询参数附加到URI的末尾。
 | 
			
		||||
     *如果将firstIsUnspecified设置为true,则如果选择了第一个条目,则URI不会附加任何内容。
 | 
			
		||||
     */
 | 
			
		||||
    // vals: <name, display>
 | 
			
		||||
    private open class UriPartFilter(
 | 
			
		||||
        displayName: String,
 | 
			
		||||
        val vals: Array<Pair<String, String>>,
 | 
			
		||||
        defaultValue: Int = 0
 | 
			
		||||
    ) :
 | 
			
		||||
        Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray(), defaultValue) {
 | 
			
		||||
        open fun toUriPart() = vals[state].second
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||