Add Xgmn Source (#10067)
* init * complete * complete * fix * apply commit * move to all
This commit is contained in:
parent
f9e6919908
commit
d514463edd
8
src/all/xgmn/build.gradle
Normal file
8
src/all/xgmn/build.gradle
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
ext {
|
||||||
|
extName = 'XGMN'
|
||||||
|
extClass = '.XGMN'
|
||||||
|
extVersionCode = 1
|
||||||
|
isNsfw = true
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
BIN
src/all/xgmn/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/all/xgmn/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
src/all/xgmn/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/all/xgmn/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
src/all/xgmn/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/all/xgmn/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
src/all/xgmn/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/all/xgmn/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
BIN
src/all/xgmn/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/all/xgmn/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
@ -0,0 +1,86 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.all.xgmn
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
|
||||||
|
fun buildFilterList(): FilterList {
|
||||||
|
return FilterList(
|
||||||
|
CategoryFilter(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CategoryFilter : Filter.Select<String>(
|
||||||
|
"分类(搜索时无效)",
|
||||||
|
arrayOf(
|
||||||
|
"秀人网", "美媛馆", "尤物馆", "爱蜜社", "蜜桃社", "优星馆", "嗲囡囡",
|
||||||
|
"魅妍社", "兔几盟", "影私荟", "星乐园", "顽味生活", "模范学院",
|
||||||
|
"花の颜", "御女郎", "网红馆", "尤蜜荟", "薄荷叶", "瑞丝馆", "模特联盟",
|
||||||
|
"花漾", "星颜社", "画语界", "推女郎", "尤果网", "青豆客", "头条女神",
|
||||||
|
"果团网", "喵糖映画", "爱尤物", "波萝社", "猎女神", "尤蜜", "潘多拉",
|
||||||
|
"Artgravia", "DJAWA", "丝袜美腿", "美腿宝贝", "蜜丝", "妖精社",
|
||||||
|
"性感尤物", "国产美女", "港台美女", "日韩美女", "欧美美女", "丝袜美腿",
|
||||||
|
"内衣尤物", "Cosplay",
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
override fun toString() = arrayOf(
|
||||||
|
"Xiuren/", "MyGirl/", "YouWu/", "IMiss/", "MiiTao/", "Uxing/", "FeiLin/",
|
||||||
|
"MiStar/", "Tukmo/", "WingS/", "LeYuan/", "Taste/", "MFStar/", "Huayan/",
|
||||||
|
"DKGirl/", "Candy/", "YouMi/", "MintYe/", "Micat/", "Mtmeng/", "HuaYang/",
|
||||||
|
"XingYan/", "XiaoYu/", "Tuigirl/", "Ugirls/", "Tgod/", "TouTiao/", "Girlt/",
|
||||||
|
"Mtcos/", "Aiyouwu/", "BoLoli/", "Slady/", "YouMei/", "Pdl/", "Artgravia/",
|
||||||
|
"DJAWA/", "Siwameitui/", "LEGBABY/", "MissLeg/", "YaoJingShe/", "Xgyw/",
|
||||||
|
"Guochanmeinv/", "Gangtaimeinv/", "Rihanmeinv/", "Oumeimeinv/",
|
||||||
|
"Siwameitui/", "Neiyiyouwu/", "Cosplay/",
|
||||||
|
)[state]
|
||||||
|
}
|
||||||
|
|
||||||
|
// class XiurenFilter : Filter.Select<String>(
|
||||||
|
// "秀人系列",
|
||||||
|
// arrayOf(
|
||||||
|
// "秀人网", "美媛馆", "尤物馆", "爱蜜社", "蜜桃社", "优星馆", "嗲囡囡",
|
||||||
|
// "魅妍社", "兔几盟", "影私荟", "星乐园", "顽味生活", "模范学院",
|
||||||
|
// "花の颜", "御女郎", "网红馆", "尤蜜荟", "薄荷叶", "瑞丝馆", "模特联盟",
|
||||||
|
// "花漾", "星颜社", "画语界",
|
||||||
|
// ),
|
||||||
|
// ) {
|
||||||
|
// val value
|
||||||
|
// get() = arrayOf(
|
||||||
|
// "Xiuren", "MyGirl", "YouWu", "IMiss", "MiiTao", "Uxing", "FeiLin",
|
||||||
|
// "MiStar", "Tukmo", "WingS", "LeYuan", "Taste", "MFStar", "Huayan",
|
||||||
|
// "DKGirl", "Candy", "YouMi", "MintYe", "Micat", "Mtmeng", "HuaYang",
|
||||||
|
// "XingYan", "XiaoYu",
|
||||||
|
// )[state]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// class MingzhanFilter : Filter.Select<String>(
|
||||||
|
// "名站系列",
|
||||||
|
// arrayOf(
|
||||||
|
// "推女郎", "尤果网", "青豆客", "头条女神", "果团网", "喵糖映画",
|
||||||
|
// "爱尤物", "波萝社", "猎女神", "尤蜜", "潘多拉", "Artgravia", "DJAWA",
|
||||||
|
// ),
|
||||||
|
// ) {
|
||||||
|
// val value
|
||||||
|
// get() = arrayOf(
|
||||||
|
// "Tuigirl", "Ugirls", "Tgod", "TouTiao", "Girlt", "Mtcos", "Aiyouwu",
|
||||||
|
// "BoLoli", "Slady", "YouMei", "Pdl", "Artgravia", "DJAWA",
|
||||||
|
// )[state]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// class SiwameituiFilter :
|
||||||
|
// Filter.Select<String>("丝袜美腿", arrayOf("丝袜美腿", "美腿宝贝", "蜜丝", "妖精社")) {
|
||||||
|
// val value get() = arrayOf("siwametui", "LEGBABY", "MissLeg", "YaoJingShe")[state]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// class JingpinFilter : Filter.Select<String>(
|
||||||
|
// "精品散图",
|
||||||
|
// arrayOf(
|
||||||
|
// "性感尤物", "国产美女", "港台美女", "日韩美女",
|
||||||
|
// "欧美美女", "丝袜美腿", "内衣尤物", "Cosplay",
|
||||||
|
// ),
|
||||||
|
// ) {
|
||||||
|
// val value
|
||||||
|
// get() = arrayOf(
|
||||||
|
// "Xgyw", "Guochanmeinv", "Gangtaimeinv", "Rihanmeinv",
|
||||||
|
// "Oumeimeinv", "Siwameitui", "Neiyiyouwu", "Cosplay",
|
||||||
|
// )[state]
|
||||||
|
// }
|
149
src/all/xgmn/src/eu/kanade/tachiyomi/extension/all/xgmn/XGMN.kt
Normal file
149
src/all/xgmn/src/eu/kanade/tachiyomi/extension/all/xgmn/XGMN.kt
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.all.xgmn
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
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.model.UpdateStrategy
|
||||||
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import keiyoushi.utils.tryParse
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
class XGMN : HttpSource() {
|
||||||
|
override val baseUrl get() = redirectUrl ?: "http://xgmn8.vip"
|
||||||
|
override val lang = "all"
|
||||||
|
override val name = "性感美女"
|
||||||
|
override val supportsLatest = true
|
||||||
|
private var redirectUrl: String? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID_REGEX = Regex("\\d+(?=\\.html)")
|
||||||
|
val PAGE_SIZE_REGEX = Regex("\\d+(?=P)")
|
||||||
|
val DATE_FORMAT = SimpleDateFormat("yyyy.MM.dd", Locale.CHINA)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getUrlWithoutDomain(url: String): String {
|
||||||
|
val prefix = listOf("http://", "https://").firstOrNull(url::startsWith)
|
||||||
|
return url.substringAfter(prefix ?: "").substringAfter('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Popular Page
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int) = GET("$baseUrl/top.html", headers)
|
||||||
|
|
||||||
|
override fun popularMangaParse(response: Response) = response.asJsoup().let { doc ->
|
||||||
|
redirectUrl = redirectUrl ?: doc.location().toHttpUrl().let { "${it.scheme}://${it.host}" }
|
||||||
|
MangasPage(
|
||||||
|
doc.select(".related_box").map {
|
||||||
|
SManga.create().apply {
|
||||||
|
thumbnail_url = it.selectFirst("img")?.absUrl("src")
|
||||||
|
it.selectFirst("a")!!.let {
|
||||||
|
title = it.attr("title")
|
||||||
|
setUrlWithoutDomain(it.absUrl("href"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latest Page
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/new.html", headers)
|
||||||
|
|
||||||
|
override fun latestUpdatesParse(response: Response) = popularMangaParse(response)
|
||||||
|
|
||||||
|
// Search Page
|
||||||
|
|
||||||
|
override fun getFilterList() = buildFilterList()
|
||||||
|
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
val url = baseUrl.toHttpUrl().newBuilder()
|
||||||
|
if (query.isNotBlank()) {
|
||||||
|
url.addPathSegments("/plus/search/index.asp")
|
||||||
|
.addQueryParameter("keyword", query)
|
||||||
|
.addQueryParameter("p", page.toString())
|
||||||
|
} else {
|
||||||
|
url.addPathSegments(filters.first().toString())
|
||||||
|
if (page > 1) url.addPathSegment("page_$page.html")
|
||||||
|
}
|
||||||
|
return GET(url.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchMangaParse(response: Response) =
|
||||||
|
if (response.request.url.pathSegments.contains("search")) {
|
||||||
|
val doc = response.asJsoup()
|
||||||
|
redirectUrl = redirectUrl ?: doc.location().toHttpUrl().let { "${it.scheme}://${it.host}" }
|
||||||
|
val current = doc.selectFirst(".current")!!.text().toInt()
|
||||||
|
MangasPage(
|
||||||
|
doc.select(".node > p > a").map {
|
||||||
|
SManga.create().apply {
|
||||||
|
title = it.text()
|
||||||
|
setUrlWithoutDomain(it.absUrl("href"))
|
||||||
|
thumbnail_url = "$baseUrl/uploadfile/pic/${ID_REGEX.find(url)?.value}.jpg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
current < doc.select(".list .pagination a").size,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
popularMangaParse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manga Detail Page
|
||||||
|
|
||||||
|
override fun mangaDetailsParse(response: Response) = response.asJsoup().let { doc ->
|
||||||
|
redirectUrl = redirectUrl ?: doc.location().toHttpUrl().let { "${it.scheme}://${it.host}" }
|
||||||
|
SManga.create().apply {
|
||||||
|
author = doc.selectFirst(".item-2")?.text()?.substringAfter("模特:")
|
||||||
|
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
|
||||||
|
status = SManga.COMPLETED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manga Detail Page / Chapters Page (Separate)
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response) = response.asJsoup().let { doc ->
|
||||||
|
redirectUrl = redirectUrl ?: doc.location().toHttpUrl().let { "${it.scheme}://${it.host}" }
|
||||||
|
listOf(
|
||||||
|
SChapter.create().apply {
|
||||||
|
setUrlWithoutDomain(doc.selectFirst(".current")!!.absUrl("href"))
|
||||||
|
name = doc.selectFirst(".article-title")!!.text()
|
||||||
|
chapter_number = 1F
|
||||||
|
date_upload = DATE_FORMAT.tryParse(
|
||||||
|
doc.selectFirst(".item-1")?.text()?.substringAfter("更新:"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manga View Page
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response) = response.asJsoup().let { doc ->
|
||||||
|
val prefix = doc.selectFirst(".current")!!.absUrl("href").substringBeforeLast(".html")
|
||||||
|
val total = PAGE_SIZE_REGEX.find(doc.selectFirst(".article-title")!!.text())!!.value
|
||||||
|
val size = doc.select(".article-content > p[style] > img").size
|
||||||
|
List(total.toInt()) {
|
||||||
|
Page(
|
||||||
|
it,
|
||||||
|
prefix + (it / size).let { v -> if (v == 0) "" else "_$v" } + ".html#${it % size + 1}",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image
|
||||||
|
|
||||||
|
override fun imageUrlParse(response: Response): String {
|
||||||
|
val seq = response.request.url.fragment!!
|
||||||
|
val url = response.asJsoup()
|
||||||
|
.selectXpath("//*[contains(@class,'article-content')]/p[@*[contains(.,'center')]]/img[position()=$seq]")
|
||||||
|
.first() ?: throw Exception("没找到图片")
|
||||||
|
return "$baseUrl/${getUrlWithoutDomain(url.absUrl("src"))}"
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user