Henchan: Added sorting things (based on Mangachan because they're similar), (#973)
Sorting by tags and some fixes for "Henchan", new russian source "Nude-Moon"
This commit is contained in:
parent
2beb568f03
commit
a0d60768c0
|
@ -5,7 +5,7 @@ ext {
|
||||||
appName = 'Tachiyomi: Henchan'
|
appName = 'Tachiyomi: Henchan'
|
||||||
pkgNameSuffix = 'ru.henchan'
|
pkgNameSuffix = 'ru.henchan'
|
||||||
extClass = '.Henchan'
|
extClass = '.Henchan'
|
||||||
extVersionCode = 6
|
extVersionCode = 7
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@ import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class Henchan : ParsedHttpSource() {
|
class Henchan : ParsedHttpSource() {
|
||||||
|
|
||||||
|
@ -28,7 +31,56 @@ class Henchan : ParsedHttpSource() {
|
||||||
GET("$baseUrl/manga/new?offset=${20 * (page - 1)}", headers)
|
GET("$baseUrl/manga/new?offset=${20 * (page - 1)}", headers)
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
val url = "$baseUrl/?do=search&subaction=search&story=$query"
|
var pageNum = 1
|
||||||
|
when {
|
||||||
|
page < 1 -> pageNum = 1
|
||||||
|
page >= 1 -> pageNum = page
|
||||||
|
}
|
||||||
|
val url = if (query.isNotEmpty()) {
|
||||||
|
"$baseUrl/?do=search&subaction=search&story=$query&search_start=$pageNum"
|
||||||
|
} else {
|
||||||
|
var genres = ""
|
||||||
|
var order = ""
|
||||||
|
for (filter in if (filters.isEmpty()) getFilterList() else filters) {
|
||||||
|
when(filter){
|
||||||
|
is GenreList -> {
|
||||||
|
filter.state.forEach { f ->
|
||||||
|
if (!f.isIgnored()) {
|
||||||
|
genres += (if (f.isExcluded()) "-" else "") + f.id + '+'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (genres.isNotEmpty()) {
|
||||||
|
for (filter in filters) {
|
||||||
|
when (filter) {
|
||||||
|
is OrderBy -> {
|
||||||
|
order = if (filter.state!!.ascending) {
|
||||||
|
arrayOf("&n=dateasc", "&n=favasc", "&n=abcdesc")[filter.state!!.index]
|
||||||
|
} else {
|
||||||
|
arrayOf("", "&n=favdesc", "&n=abcasc")[filter.state!!.index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"$baseUrl/tags/${genres.dropLast(1)}&sort=manga$order?offset=${20 * (pageNum - 1)}"
|
||||||
|
}else{
|
||||||
|
for (filter in filters) {
|
||||||
|
when (filter) {
|
||||||
|
is OrderBy -> {
|
||||||
|
order = if (filter.state!!.ascending) {
|
||||||
|
arrayOf("manga/new&n=dateasc", "manga/new&n=favasc", "manga/new&n=abcdesc")[filter.state!!.index]
|
||||||
|
} else {
|
||||||
|
arrayOf("manga/new", "mostfavorites&sort=manga", "manga/new&n=abcasc")[filter.state!!.index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"$baseUrl/$order?offset=${20 * (pageNum - 1)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
return GET(url, headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,36 +88,21 @@ class Henchan : ParsedHttpSource() {
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = popularMangaSelector()
|
override fun latestUpdatesSelector() = popularMangaSelector()
|
||||||
|
|
||||||
override fun searchMangaSelector() = popularMangaSelector()
|
override fun searchMangaSelector() = ".content_row:not(:has(div.item:containsOwn(Тип)))"
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
private fun String.getHQThumbnail(): String = this
|
||||||
val document = response.asJsoup()
|
.replace("manganew_thumbs", "showfull_retina/manga")
|
||||||
|
.replace("img.", "imgcover.")
|
||||||
val mangas = mutableListOf<SManga>()
|
.replace("_henchan.me", "_hentaichan.ru")
|
||||||
document.select(searchMangaSelector()).forEach { element ->
|
|
||||||
val manga = searchMangaFromElement(element)
|
|
||||||
if (manga.url != "") {
|
|
||||||
mangas.add(manga)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MangasPage(mangas, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.getHQThumbnail(): String = this.replace("manganew_thumbs", "showfull_retina/manga").replace("img.", "imgcover.")
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.thumbnail_url = element.select("img").first().attr("src").getHQThumbnail()
|
manga.thumbnail_url = element.select("img").first().attr("src").getHQThumbnail()
|
||||||
element.select("h2 > a").first().let {
|
|
||||||
val url = it.attr("href")
|
val urlElem = element.select("h2 > a").first()
|
||||||
if (url.contains("/manga/")) {
|
manga.setUrlWithoutDomain(urlElem.attr("href"))
|
||||||
manga.setUrlWithoutDomain(url)
|
manga.title = urlElem.text()
|
||||||
manga.title = it.text()
|
|
||||||
} else {
|
|
||||||
manga.url = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return manga
|
return manga
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,8 +116,7 @@ class Henchan : ParsedHttpSource() {
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = throw Exception("Not Used")
|
override fun searchMangaNextPageSelector() = "#nextlink, ${popularMangaNextPageSelector()}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
|
@ -110,8 +146,12 @@ class Henchan : ParsedHttpSource() {
|
||||||
val chap = SChapter.create()
|
val chap = SChapter.create()
|
||||||
chap.setUrlWithoutDomain(responseUrl.removePrefix(baseUrl))
|
chap.setUrlWithoutDomain(responseUrl.removePrefix(baseUrl))
|
||||||
chap.name = document.select("a.title_top_a").text()
|
chap.name = document.select("a.title_top_a").text()
|
||||||
chap.chapter_number = 0.0F
|
chap.chapter_number = 1F
|
||||||
chap.date_upload = 0L
|
|
||||||
|
val date = document.select("div.row4_right b")?.text()?.let {
|
||||||
|
SimpleDateFormat("dd MMMM yyyy", Locale("ru")).parse(it).time
|
||||||
|
} ?: 0
|
||||||
|
chap.date_upload = date
|
||||||
return listOf(chap)
|
return listOf(chap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,15 +159,15 @@ class Henchan : ParsedHttpSource() {
|
||||||
val chap = SChapter.create()
|
val chap = SChapter.create()
|
||||||
chap.setUrlWithoutDomain(document.select("#left > div > a").attr("href"))
|
chap.setUrlWithoutDomain(document.select("#left > div > a").attr("href"))
|
||||||
chap.name = document.select("#right > div:nth-child(4)").text().split(" похожий на ")[1]
|
chap.name = document.select("#right > div:nth-child(4)").text().split(" похожий на ")[1]
|
||||||
chap.chapter_number = 0.0F
|
chap.chapter_number = 1F
|
||||||
chap.date_upload = 0L
|
chap.date_upload = 0L
|
||||||
return listOf(chap)
|
return listOf(chap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val result = mutableListOf<SChapter>()
|
val result = mutableListOf<SChapter>()
|
||||||
result.addAll(document.select(chapterListSelector()).mapIndexed { index, element ->
|
result.addAll(document.select(chapterListSelector()).map {
|
||||||
chapterFromElement(index, element)
|
chapterFromElement(it)
|
||||||
})
|
})
|
||||||
|
|
||||||
var url = document.select("div#pagination_related a:contains(Вперед)").attr("href")
|
var url = document.select("div#pagination_related a:contains(Вперед)").attr("href")
|
||||||
|
@ -137,9 +177,8 @@ class Henchan : ParsedHttpSource() {
|
||||||
headers = headers
|
headers = headers
|
||||||
)
|
)
|
||||||
val nextPage = client.newCall(get).execute().asJsoup()
|
val nextPage = client.newCall(get).execute().asJsoup()
|
||||||
result.addAll(nextPage.select(chapterListSelector()).mapIndexed {
|
result.addAll(nextPage.select(chapterListSelector()).map {
|
||||||
index, element ->
|
chapterFromElement(it)
|
||||||
chapterFromElement(index, element)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
url = nextPage.select("div#pagination_related a:contains(Вперед)").attr("href")
|
url = nextPage.select("div#pagination_related a:contains(Вперед)").attr("href")
|
||||||
|
@ -148,17 +187,16 @@ class Henchan : ParsedHttpSource() {
|
||||||
return result.reversed()
|
return result.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun chapterFromElement(index: Int, element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
chapter.setUrlWithoutDomain(element.select("h2 a").attr("href"))
|
chapter.setUrlWithoutDomain(element.select("h2 a").attr("href"))
|
||||||
chapter.name = element.select("h2 a").attr("title")
|
val chapterName = element.select("h2 a").attr("title")
|
||||||
chapter.chapter_number = index.toFloat()
|
chapter.name = chapterName
|
||||||
|
chapter.chapter_number = "(глава\\s|часть\\s)(\\d+)".toRegex(RegexOption.IGNORE_CASE).find(chapterName)?.groupValues?.get(2)?.toFloat() ?: 0F
|
||||||
chapter.date_upload = 0L
|
chapter.date_upload = 0L
|
||||||
return chapter
|
return chapter
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter = throw Exception("Not Used")
|
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
return GET(exhentaiBaseUrl + chapter.url.replace("/manga/", "/online/") + "?development_access=true", headers)
|
return GET(exhentaiBaseUrl + chapter.url.replace("/manga/", "/online/") + "?development_access=true", headers)
|
||||||
}
|
}
|
||||||
|
@ -169,7 +207,7 @@ class Henchan : ParsedHttpSource() {
|
||||||
val resPages = mutableListOf<Page>()
|
val resPages = mutableListOf<Page>()
|
||||||
val imgs = imgString.split(",")
|
val imgs = imgString.split(",")
|
||||||
imgs.forEachIndexed { index, s ->
|
imgs.forEachIndexed { index, s ->
|
||||||
resPages.add(Page(index, imageUrl = s.trim('"', '\'', '[', ' ')))
|
resPages.add(Page(index, imageUrl = s.trim('"', '\'', ' ')))
|
||||||
}
|
}
|
||||||
return resPages
|
return resPages
|
||||||
}
|
}
|
||||||
|
@ -177,4 +215,168 @@ class Henchan : ParsedHttpSource() {
|
||||||
override fun imageUrlParse(document: Document) = throw Exception("Not Used")
|
override fun imageUrlParse(document: Document) = throw Exception("Not Used")
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> = throw Exception("Not Used")
|
override fun pageListParse(document: Document): List<Page> = throw Exception("Not Used")
|
||||||
|
|
||||||
|
private class Genre(val id: String, name: String = id.replace('_', ' ').capitalize()) : Filter.TriState(name)
|
||||||
|
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Тэги", genres)
|
||||||
|
private class OrderBy : Filter.Sort("Сортировка",
|
||||||
|
arrayOf("Дата", "Популярность", "Алфавит"),
|
||||||
|
Filter.Sort.Selection(1, false))
|
||||||
|
|
||||||
|
override fun getFilterList() = FilterList(
|
||||||
|
OrderBy(),
|
||||||
|
GenreList(getGenreList())
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getGenreList() = listOf(
|
||||||
|
Genre("3D"),
|
||||||
|
Genre("action"),
|
||||||
|
Genre("ahegao"),
|
||||||
|
Genre("bdsm"),
|
||||||
|
Genre("foot_fetish"),
|
||||||
|
Genre("footfuck"),
|
||||||
|
Genre("gender_bender"),
|
||||||
|
Genre("live"),
|
||||||
|
Genre("lolcon"),
|
||||||
|
Genre("megane"),
|
||||||
|
Genre("mind_break"),
|
||||||
|
Genre("monstergirl"),
|
||||||
|
Genre("netorare"),
|
||||||
|
Genre("netori"),
|
||||||
|
Genre("nipple_penetration"),
|
||||||
|
Genre("paizuri_(titsfuck)"),
|
||||||
|
Genre("rpg"),
|
||||||
|
Genre("scat"),
|
||||||
|
Genre("shemale"),
|
||||||
|
Genre("shooter"),
|
||||||
|
Genre("simulation"),
|
||||||
|
Genre("tomboy"),
|
||||||
|
Genre("алкоголь"),
|
||||||
|
Genre("анал"),
|
||||||
|
Genre("андроид"),
|
||||||
|
Genre("анилингус"),
|
||||||
|
Genre("аркада"),
|
||||||
|
Genre("арт"),
|
||||||
|
Genre("бабушка"),
|
||||||
|
Genre("без_текста"),
|
||||||
|
Genre("без_трусиков"),
|
||||||
|
Genre("без_цензуры"),
|
||||||
|
Genre("беременность"),
|
||||||
|
Genre("бикини"),
|
||||||
|
Genre("близнецы"),
|
||||||
|
Genre("боди-арт"),
|
||||||
|
Genre("больница"),
|
||||||
|
Genre("большая_грудь"),
|
||||||
|
Genre("большие_попки"),
|
||||||
|
Genre("буккаке"),
|
||||||
|
Genre("в_ванной"),
|
||||||
|
Genre("в_общественном_месте"),
|
||||||
|
Genre("в_первый_раз"),
|
||||||
|
Genre("в_цвете"),
|
||||||
|
Genre("в_школе"),
|
||||||
|
Genre("веб"),
|
||||||
|
Genre("вибратор"),
|
||||||
|
Genre("визуальная_новелла"),
|
||||||
|
Genre("внучка"),
|
||||||
|
Genre("волосатые_женщины"),
|
||||||
|
Genre("гаремник"),
|
||||||
|
Genre("гипноз"),
|
||||||
|
Genre("глубокий_минет"),
|
||||||
|
Genre("горячий_источник"),
|
||||||
|
Genre("групповой_секс"),
|
||||||
|
Genre("гяру_и_гангуро"),
|
||||||
|
Genre("двойное_проникновение"),
|
||||||
|
Genre("девочки_волшебницы"),
|
||||||
|
Genre("девушка_туалет"),
|
||||||
|
Genre("демоны"),
|
||||||
|
Genre("дилдо"),
|
||||||
|
Genre("дочь"),
|
||||||
|
Genre("драма"),
|
||||||
|
Genre("дыра_в_стене"),
|
||||||
|
Genre("жестокость"),
|
||||||
|
Genre("за_деньги"),
|
||||||
|
Genre("зомби"),
|
||||||
|
Genre("зрелые_женщины"),
|
||||||
|
Genre("измена"),
|
||||||
|
Genre("изнасилование"),
|
||||||
|
Genre("инопланетяне"),
|
||||||
|
Genre("инцест"),
|
||||||
|
Genre("исполнение_желаний"),
|
||||||
|
Genre("камера"),
|
||||||
|
Genre("квест"),
|
||||||
|
Genre("колготки"),
|
||||||
|
Genre("комиксы"),
|
||||||
|
Genre("косплей"),
|
||||||
|
Genre("кузина"),
|
||||||
|
Genre("купальники"),
|
||||||
|
Genre("латекс_и_кожа"),
|
||||||
|
Genre("магия"),
|
||||||
|
Genre("маленькая_грудь"),
|
||||||
|
Genre("мастурбация"),
|
||||||
|
Genre("мать"),
|
||||||
|
Genre("мейдочки"),
|
||||||
|
Genre("мерзкий_дядька"),
|
||||||
|
Genre("много_девушек"),
|
||||||
|
Genre("молоко"),
|
||||||
|
Genre("монстры"),
|
||||||
|
Genre("мочеиспускание"),
|
||||||
|
Genre("мужская_озвучка"),
|
||||||
|
Genre("на_природе"),
|
||||||
|
Genre("наблюдение"),
|
||||||
|
Genre("непрямой_инцест"),
|
||||||
|
Genre("огромная_грудь"),
|
||||||
|
Genre("огромный_член"),
|
||||||
|
Genre("остановка_времени"),
|
||||||
|
Genre("парень_пассив"),
|
||||||
|
Genre("переодевание"),
|
||||||
|
Genre("песочница"),
|
||||||
|
Genre("племянница"),
|
||||||
|
Genre("пляж"),
|
||||||
|
Genre("подглядывание"),
|
||||||
|
Genre("подчинение"),
|
||||||
|
Genre("похищение"),
|
||||||
|
Genre("принуждение"),
|
||||||
|
Genre("прозрачная_одежда"),
|
||||||
|
Genre("психические_отклонения"),
|
||||||
|
Genre("публично"),
|
||||||
|
Genre("рабыни"),
|
||||||
|
Genre("романтика"),
|
||||||
|
Genre("сверхъестественное"),
|
||||||
|
Genre("секс_игрушки"),
|
||||||
|
Genre("сестра"),
|
||||||
|
Genre("сетакон"),
|
||||||
|
Genre("спортивная_форма"),
|
||||||
|
Genre("спящие"),
|
||||||
|
Genre("страпон"),
|
||||||
|
Genre("темнокожие"),
|
||||||
|
Genre("тентакли"),
|
||||||
|
Genre("толстушки"),
|
||||||
|
Genre("трап"),
|
||||||
|
Genre("тётя"),
|
||||||
|
Genre("учитель_и_ученик"),
|
||||||
|
Genre("ушастые"),
|
||||||
|
Genre("фантазии"),
|
||||||
|
Genre("фантастика"),
|
||||||
|
Genre("фемдом"),
|
||||||
|
Genre("фестиваль"),
|
||||||
|
Genre("фистинг"),
|
||||||
|
Genre("фурри"),
|
||||||
|
Genre("футанари"),
|
||||||
|
Genre("футанари_имеет_парня"),
|
||||||
|
Genre("фэнтези"),
|
||||||
|
Genre("хоррор"),
|
||||||
|
Genre("цундере"),
|
||||||
|
Genre("чикан"),
|
||||||
|
Genre("чирлидеры"),
|
||||||
|
Genre("чулки"),
|
||||||
|
Genre("школьники"),
|
||||||
|
Genre("школьницы"),
|
||||||
|
Genre("школьный_купальник"),
|
||||||
|
Genre("эксгибиционизм"),
|
||||||
|
Genre("эльфы"),
|
||||||
|
Genre("эччи"),
|
||||||
|
Genre("юмор"),
|
||||||
|
Genre("юри"),
|
||||||
|
Genre("яндере"),
|
||||||
|
Genre("яой")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
appName = 'Tachiyomi: Nude-Moon'
|
||||||
|
pkgNameSuffix = 'ru.nudemoon'
|
||||||
|
extClass = '.Nudemoon'
|
||||||
|
extVersionCode = 1
|
||||||
|
libVersion = '1.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
|
@ -0,0 +1,282 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.ru.nudemoon
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.source.model.*
|
||||||
|
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import org.jsoup.nodes.TextNode
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class Nudemoon : ParsedHttpSource() {
|
||||||
|
|
||||||
|
override val name = "Nude-Moon"
|
||||||
|
|
||||||
|
override val baseUrl = "http://nude-moon.me"
|
||||||
|
|
||||||
|
override val lang = "ru"
|
||||||
|
|
||||||
|
override val supportsLatest = true
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int): Request =
|
||||||
|
GET("$baseUrl/all_manga?views&rowstart=${30 * (page - 1)}", headers)
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request =
|
||||||
|
GET("$baseUrl/all_manga?date&rowstart=${30 * (page - 1)}", headers)
|
||||||
|
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
//Search by query on this site works really badly, i don't even sure of the need to implement it
|
||||||
|
val url = if (query.isNotEmpty()) {
|
||||||
|
"$baseUrl/search?stext=${URLEncoder.encode(query, "CP1251")}&rowstart=${30 * (page - 1)}"
|
||||||
|
}else{
|
||||||
|
var genres = ""
|
||||||
|
var order = ""
|
||||||
|
for (filter in if (filters.isEmpty()) getFilterList() else filters) {
|
||||||
|
when(filter){
|
||||||
|
is GenreList -> {
|
||||||
|
filter.state.forEach { f ->
|
||||||
|
if (f.state) {
|
||||||
|
genres += f.id + '+'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (genres.isNotEmpty()) {
|
||||||
|
for (filter in filters) {
|
||||||
|
when (filter) {
|
||||||
|
is OrderBy -> {
|
||||||
|
//The site has no ascending order
|
||||||
|
order = arrayOf("&date", "&views", "&like")[filter.state!!.index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"$baseUrl/tags/${genres.dropLast(1)}$order&rowstart=${30 * (page - 1)}"
|
||||||
|
}else{
|
||||||
|
for (filter in filters) {
|
||||||
|
when (filter) {
|
||||||
|
is OrderBy -> {
|
||||||
|
//The site has no ascending order
|
||||||
|
order = arrayOf("all_manga?date", "all_manga?views", "all_manga?like")[filter.state!!.index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"$baseUrl/$order&rowstart=${30 * (page - 1)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GET(url, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularMangaSelector() = "table[cellspacing=\"2\"].news_pic2"
|
||||||
|
|
||||||
|
override fun latestUpdatesSelector() = popularMangaSelector()
|
||||||
|
|
||||||
|
override fun searchMangaSelector() = popularMangaSelector()
|
||||||
|
|
||||||
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
|
val manga = SManga.create()
|
||||||
|
|
||||||
|
val thumbnailElem = element.select("img.news_pic2").first()
|
||||||
|
val parentElem = thumbnailElem.parent()
|
||||||
|
|
||||||
|
manga.thumbnail_url = baseUrl + thumbnailElem.attr("src")
|
||||||
|
manga.title = parentElem.attr("title")
|
||||||
|
manga.setUrlWithoutDomain(parentElem.attr("href"))
|
||||||
|
|
||||||
|
return manga
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesFromElement(element: Element): SManga =
|
||||||
|
popularMangaFromElement(element)
|
||||||
|
|
||||||
|
override fun searchMangaFromElement(element: Element): SManga =
|
||||||
|
popularMangaFromElement(element)
|
||||||
|
|
||||||
|
override fun popularMangaNextPageSelector() = "a.small:contains(Следующая)"
|
||||||
|
|
||||||
|
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
|
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
|
val manga = SManga.create()
|
||||||
|
manga.author = document.select("a[title^=Показать всю мангу от]").first().text()
|
||||||
|
manga.genre = document.select("div.tbl2[align] > a").joinToString { it.text() }
|
||||||
|
manga.description = document.select(".description").text()
|
||||||
|
return manga
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterListRequest(manga: SManga): Request {
|
||||||
|
|
||||||
|
val chapterUrl = if(manga.title.contains("\\s#\\d+".toRegex()))
|
||||||
|
"/vse_glavy/" + manga.title.split("\\s#\\d+".toRegex())[0].replace("\\W".toRegex(), "_")
|
||||||
|
else
|
||||||
|
manga.url
|
||||||
|
|
||||||
|
return GET(baseUrl + chapterUrl, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterListSelector() = popularMangaSelector()
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
val responseUrl = response.request().url().toString()
|
||||||
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
if(!responseUrl.contains("/vse_glavy/")){
|
||||||
|
return listOf(chapterFromElement(document))
|
||||||
|
}
|
||||||
|
|
||||||
|
//Order chapters by its number 'cause on the site they are in random order
|
||||||
|
return document.select(chapterListSelector()).sortedByDescending {
|
||||||
|
val regex = "#(\\d+)".toRegex()
|
||||||
|
val chapterName = it.select("img.news_pic2").first().parent().attr("title")
|
||||||
|
regex.find(chapterName)?.groupValues?.get(1)?.toInt() ?: 0
|
||||||
|
}.map { chapterFromElement(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
|
val chapter = SChapter.create()
|
||||||
|
|
||||||
|
val infoElem = element.select("img.news_pic2").first().parent()
|
||||||
|
val chapterName = infoElem.attr("title")
|
||||||
|
var chapterUrl = infoElem.attr("href")
|
||||||
|
if(!chapterUrl.contains("-online")) {
|
||||||
|
chapterUrl = chapterUrl.replace("/\\d+".toRegex(), "$0-online")
|
||||||
|
} else {
|
||||||
|
chapter.chapter_number = 1F
|
||||||
|
}
|
||||||
|
|
||||||
|
chapter.setUrlWithoutDomain(if(!chapterUrl.startsWith("/")) "/$chapterUrl" else chapterUrl)
|
||||||
|
chapter.name = chapterName
|
||||||
|
chapter.date_upload = (element.select("font:containsOwn(Дата:)")?.first()?.nextSibling() as? TextNode)?.text()?.let {
|
||||||
|
SimpleDateFormat("dd MMMM yyyy", Locale("ru")).parse(it).time
|
||||||
|
} ?: 0
|
||||||
|
|
||||||
|
return chapter
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
|
return GET(baseUrl + chapter.url, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val resPages = mutableListOf<Page>()
|
||||||
|
val imgScript = document.select("script:containsData(var images)").first().html()
|
||||||
|
|
||||||
|
Regex("images\\[(\\d+)].src\\s=\\s'.(.*)'").findAll(imgScript).forEach {
|
||||||
|
resPages.add(Page(it.groupValues[1].toInt(), imageUrl = baseUrl + it.groupValues[2]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resPages
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun imageUrlParse(document: Document) = throw Exception("Not Used")
|
||||||
|
|
||||||
|
override fun pageListParse(document: Document): List<Page> = throw Exception("Not Used")
|
||||||
|
|
||||||
|
private class Genre(name: String, val id: String = name.replace(' ', '_')) : Filter.CheckBox(name.capitalize())
|
||||||
|
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Тэги", genres)
|
||||||
|
private class OrderBy : Filter.Sort("Сортировка",
|
||||||
|
arrayOf("Дата", "Просмотры", "Лайки"),
|
||||||
|
Filter.Sort.Selection(1, false))
|
||||||
|
|
||||||
|
override fun getFilterList() = FilterList(
|
||||||
|
OrderBy(),
|
||||||
|
GenreList(getGenreList())
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getGenreList() = listOf(
|
||||||
|
Genre("анал"),
|
||||||
|
Genre("без цензуры"),
|
||||||
|
Genre("беременные"),
|
||||||
|
Genre("близняшки"),
|
||||||
|
Genre("большие груди"),
|
||||||
|
Genre("в бассейне"),
|
||||||
|
Genre("в больнице"),
|
||||||
|
Genre("в ванной"),
|
||||||
|
Genre("в общественном месте"),
|
||||||
|
Genre("в первый раз"),
|
||||||
|
Genre("в транспорте"),
|
||||||
|
Genre("в туалете"),
|
||||||
|
Genre("гарем"),
|
||||||
|
Genre("гипноз"),
|
||||||
|
Genre("горничные"),
|
||||||
|
Genre("горячий источник"),
|
||||||
|
Genre("групповой секс"),
|
||||||
|
Genre("драма"),
|
||||||
|
Genre("запредельное"),
|
||||||
|
Genre("золотой дождь"),
|
||||||
|
Genre("зрелые женщины"),
|
||||||
|
Genre("идолы"),
|
||||||
|
Genre("извращение"),
|
||||||
|
Genre("измена"),
|
||||||
|
Genre("имеют парня"),
|
||||||
|
Genre("клизма"),
|
||||||
|
Genre("колготки"),
|
||||||
|
Genre("комиксы"),
|
||||||
|
Genre("комиксы 3D"),
|
||||||
|
Genre("косплей"),
|
||||||
|
Genre("мастурбация"),
|
||||||
|
Genre("мерзкий мужик"),
|
||||||
|
Genre("много спермы"),
|
||||||
|
Genre("молоко"),
|
||||||
|
Genre("монстры"),
|
||||||
|
Genre("на камеру"),
|
||||||
|
Genre("на природе"),
|
||||||
|
Genre("обычный секс"),
|
||||||
|
Genre("огромный член"),
|
||||||
|
Genre("пляж"),
|
||||||
|
Genre("подглядывание"),
|
||||||
|
Genre("принуждение"),
|
||||||
|
Genre("продажность"),
|
||||||
|
Genre("пьяные"),
|
||||||
|
Genre("рабыни"),
|
||||||
|
Genre("романтика"),
|
||||||
|
Genre("с ушками"),
|
||||||
|
Genre("секс игрушки"),
|
||||||
|
Genre("спящие"),
|
||||||
|
Genre("страпон"),
|
||||||
|
Genre("студенты"),
|
||||||
|
Genre("суккуб"),
|
||||||
|
Genre("тентакли"),
|
||||||
|
Genre("толстушки"),
|
||||||
|
Genre("трапы"),
|
||||||
|
Genre("ужасы"),
|
||||||
|
Genre("униформа"),
|
||||||
|
Genre("учитель и ученик"),
|
||||||
|
Genre("фемдом"),
|
||||||
|
Genre("фетиш"),
|
||||||
|
Genre("фурри"),
|
||||||
|
Genre("футанари"),
|
||||||
|
Genre("футфетиш"),
|
||||||
|
Genre("фэнтези"),
|
||||||
|
Genre("цветная"),
|
||||||
|
Genre("чикан"),
|
||||||
|
Genre("чулки"),
|
||||||
|
Genre("шимейл"),
|
||||||
|
Genre("эксгибиционизм"),
|
||||||
|
Genre("юмор"),
|
||||||
|
Genre("юри"),
|
||||||
|
Genre("ahegao"),
|
||||||
|
Genre("BDSM"),
|
||||||
|
Genre("ganguro"),
|
||||||
|
Genre("gender bender"),
|
||||||
|
Genre("megane"),
|
||||||
|
Genre("mind break"),
|
||||||
|
Genre("monstergirl"),
|
||||||
|
Genre("netorare"),
|
||||||
|
Genre("nipple penetration"),
|
||||||
|
Genre("titsfuck"),
|
||||||
|
Genre("x-ray")
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue