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