Update search , manga detail , chapterlist (#13567)

* Update Niceoppai.kt

* update overrideVersionCode

* remove comment code

* Update MadaraGenerator.kt

* Update Niceoppai.kt

* formating code

* remaster code and change type extention

* remove niceoppai form madaraGenerator

* Update src/th/niceoppai/build.gradle

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>

* uppdate search, filter, mange detail

* update load chapter

* Updated extVersionCode

* fix error

* fix error

* Update src/th/niceoppai/src/eu/kanade/tachiyomi/extension/th/niceoppai/Niceoppai.kt

Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com>

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>
Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com>
This commit is contained in:
D@ddyBunz 2022-09-25 01:53:29 +07:00 committed by GitHub
parent 445af0f144
commit d463a0900a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 95 additions and 92 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Niceoppai' extName = 'Niceoppai'
pkgNameSuffix = 'th.niceoppai' pkgNameSuffix = 'th.niceoppai'
extClass = '.Niceoppai' extClass = '.Niceoppai'
extVersionCode = 25 extVersionCode = 26
isNsfw = true isNsfw = true
} }

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.th.niceoppai
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -11,6 +12,7 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
@ -22,7 +24,7 @@ import java.util.concurrent.TimeUnit
class Niceoppai : ParsedHttpSource() { class Niceoppai : ParsedHttpSource() {
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MM dd, yyyy", Locale.US) private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.US)
override val baseUrl: String = "https://www.niceoppai.net" override val baseUrl: String = "https://www.niceoppai.net"
override val lang: String = "th" override val lang: String = "th"
@ -37,17 +39,13 @@ class Niceoppai : ParsedHttpSource() {
.build() .build()
// Popular // Popular
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/manga_list/all/any/most-popular-weekly/$page", headers) return GET("$baseUrl/manga_list/all/any/most-popular-monthly/$page", headers)
} }
override fun popularMangaSelector() = "div.nde" override fun popularMangaSelector() = "div.nde"
override fun popularMangaFromElement(element: Element): SManga { override fun popularMangaFromElement(element: Element): SManga {
val manga = SManga.create() val manga = SManga.create()
manga.title = "title : " + element.select("div.det a").text()
manga.title = element.select("div.det a").text()
element.select("div.cvr").let { element.select("div.cvr").let {
manga.setUrlWithoutDomain(it.select("div.img_wrp a").attr("href")) manga.setUrlWithoutDomain(it.select("div.img_wrp a").attr("href"))
@ -57,88 +55,66 @@ class Niceoppai : ParsedHttpSource() {
return manga return manga
} }
override fun popularMangaNextPageSelector() = "ul.pgg li a" override fun popularMangaNextPageSelector() = "ul.pgg li a"
// Latest // Latest
override fun latestUpdatesRequest(page: Int): Request { override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/manga_list/all/any/last-updated/$page", headers) return GET("$baseUrl/manga_list/all/any/last-updated/$page", headers)
} }
override fun latestUpdatesSelector() = popularMangaSelector() override fun latestUpdatesSelector() = popularMangaSelector()
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun latestUpdatesFromElement(element: Element): SManga =
popularMangaFromElement(element)
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = // Search
throw Exception("Unused") override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val isOrderByFilter = filters.list.first().state != 0
val orderByState = if (filters.list.first().state != null) filters.first().state.toString().toInt() else 0
val orderByString = orderByFilterOptionsValues[orderByState]
override fun searchMangaSelector(): String = throw Exception("Unused") return if (isOrderByFilter) GET("$baseUrl/manga_list/all/any/$orderByString/$page", headers)
else GET("$baseUrl/manga_list/search/$query/$orderByString/$page", headers)
override fun searchMangaFromElement(element: Element): SManga = throw Exception("Unused") }
override fun searchMangaSelector(): String = popularMangaSelector()
override fun searchMangaNextPageSelector(): String = throw Exception("Unused") override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun searchMangaNextPageSelector(): String = popularMangaNextPageSelector()
override fun fetchSearchManga( override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
page: Int, return client.newCall(searchMangaRequest(page, query, filters))
query: String,
filters: FilterList
): Observable<MangasPage> {
val searchMethod = query.startsWith("http")
return client.newCall(
GET("$baseUrl/manga_list/category/$query/name-az/$page")
)
.asObservableSuccess() .asObservableSuccess()
.map { .map {
val document = it.asJsoup() val document = it.asJsoup()
val mangas: List<SManga> = if (searchMethod) { val mangas: List<SManga> =
listOf( document.select(searchMangaSelector()).map { element ->
SManga.create().apply { searchMangaFromElement(element)
url = query.substringAfter(baseUrl)
title = document.select("h1.ttl").text()
thumbnail_url =
document.select("div.cvr_ara imag.cvr").attr("abs:src")
initialized = false
}
)
} else {
document.select(popularMangaSelector()).map { element ->
popularMangaFromElement(element)
}
} }
MangasPage(mangas, !searchMethod) MangasPage(mangas, false)
} }
} }
// Manga summary page // Manga summary page
private fun getStatus(status: String) = when (status) { private fun getStatus(status: String) = when (status) {
"ยังไม่จบ" -> SManga.ONGOING "ยังไม่จบ" -> SManga.ONGOING
"จบแล้ว" -> SManga.COMPLETED "จบแล้ว" -> SManga.COMPLETED
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("div.det").first() val infoElement = document.select("div.det").first()
val titleElement = document.select("h1.ttl").first()
return SManga.create().apply { return SManga.create().apply {
title = document.title() + infoElement.select("p")[2].ownText() title = titleElement.text()
author = infoElement.select("p")[3].ownText() author = infoElement.select("p")[2].select("a").text()
artist = author artist = author
status = getStatus(infoElement.select("p")[10].ownText()) status = getStatus(infoElement.select("p")[9].ownText().replace(": ", ""))
genre = infoElement.select("p")[6].select("a").joinToString { it.ownText() } genre = infoElement.select("p")[5].select("a").joinToString { it.text() }
description = infoElement.select("p").first().ownText() description = infoElement.select("p").first().ownText().replace(": ", "")
thumbnail_url = document.select("div.mng_ifo div.cvr_ara img").first().attr("abs:src") thumbnail_url = document.select("div.mng_ifo div.cvr_ara img").first().attr("abs:src")
initialized = true initialized = true
} }
} }
// Chapters // Chapters
private fun parseChapterDate(date: String?): Long { private fun parseChapterDate(date: String?): Long {
date ?: return 0 date ?: return 0
@ -196,7 +172,6 @@ class Niceoppai : ParsedHttpSource() {
else -> dateFormat.tryParse(date) else -> dateFormat.tryParse(date)
} }
} }
// Parses dates in this form: // Parses dates in this form:
// 21 horas ago // 21 horas ago
private fun parseRelativeDate(date: String): Long { private fun parseRelativeDate(date: String): Long {
@ -214,15 +189,11 @@ class Niceoppai : ParsedHttpSource() {
else -> 0 else -> 0
} }
} }
override fun chapterListSelector() = "ul.lst li.lng_" override fun chapterListSelector() = "ul.lst li.lng_"
override fun chapterFromElement(element: Element): SChapter = throw Exception("Unused") override fun chapterFromElement(element: Element): SChapter = throw Exception("Unused")
private fun chapterFromElementWithIndex(element: Element, idx: Int, manga: SManga): SChapter { private fun chapterFromElementWithIndex(element: Element, idx: Int, manga: SManga): SChapter {
val chapter = SChapter.create() val chapter = SChapter.create()
with(element) {
val btn = element.select("a.lst") val btn = element.select("a.lst")
chapter.setUrlWithoutDomain(btn.attr("href")) chapter.setUrlWithoutDomain(btn.attr("href"))
chapter.name = btn.select("b.val").text() chapter.name = btn.select("b.val").text()
@ -239,39 +210,49 @@ class Niceoppai : ParsedHttpSource() {
chapter.chapter_number = (idx + 1).toFloat() chapter.chapter_number = (idx + 1).toFloat()
} }
} }
}
return chapter return chapter
} }
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { override fun chapterListRequest(manga: SManga): Request {
return GET("$baseUrl/${manga.url}", headers)
}
return client.newCall(GET("$baseUrl/${manga.url}")) override fun chapterListParse(response: Response): List<SChapter> {
.asObservableSuccess() val document = response.asJsoup()
.map { val listPage = document.select("ul.pgg li a")
val chList: List<SChapter> .filter { it.text() != "Next" && it.text() != "Last" }
val mangaDocument = it.asJsoup() .map { it.select("a").attr("href") }
.distinct()
val chList: MutableList<SChapter> = mutableListOf()
if (listPage.isNotEmpty()) {
listPage.forEach { urlPage ->
val res: Response = client.newCall(GET(urlPage, headers)).execute()
val mangaDocument = res.asJsoup()
if (mangaDocument.select(chapterListSelector()).isEmpty()) { if (mangaDocument.select(chapterListSelector()).isEmpty()) {
manga.status = SManga.COMPLETED
val createdChapter = SChapter.create().apply { val createdChapter = SChapter.create().apply {
url = manga.url
name = "Chapter 1" name = "Chapter 1"
chapter_number = 1.0f chapter_number = 1.0f
} }
chList = listOf(createdChapter) chList += listOf(createdChapter)
} else { } else {
chList = chList +=
mangaDocument.select(chapterListSelector()).mapIndexed { idx, Chapter -> mangaDocument.select(chapterListSelector()).mapIndexed { idx, Chapter ->
chapterFromElementWithIndex(Chapter, idx, manga) chapterFromElementWithIndex(Chapter, idx, SManga.create())
} }
} }
chList
} }
} else {
chList +=
document.select(chapterListSelector()).mapIndexed { idx, Chapter ->
chapterFromElementWithIndex(Chapter, idx, SManga.create())
}
}
return chList
} }
// Pages // Pages
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
return document.select("div.mng_rdr div#image-container img").mapIndexed { i, img -> return document.select("div.mng_rdr div#image-container img").mapIndexed { i, img ->
if (img.hasAttr("data-src")) { if (img.hasAttr("data-src")) {
@ -281,15 +262,37 @@ class Niceoppai : ParsedHttpSource() {
} }
} }
} }
override fun imageUrlParse(document: Document): String = override fun imageUrlParse(document: Document): String =
throw UnsupportedOperationException("Not used") throw UnsupportedOperationException("Not used")
override fun getFilterList() = FilterList() // Filter
protected open val orderByFilterTitle: String = "Order By เรียกตาม"
private val orderByFilterOptions: Array<String> = arrayOf("Name (A-Z)", "Name (Z-A)", "Last Updated", "Oldest Updated", "Most Popular", "Most Popular (Weekly)", "Most Popular (Monthly)", "Least Popular", "Last Added", "Early Added", "Top Rating", "Lowest Rating")
private val orderByFilterOptionsValues: Array<String> = arrayOf("name-az", "name-za", "last-updated", "oldest-updated", "most-popular", "most-popular-weekly", "most-popular-monthly", "least-popular", "last-added", "early-added", "top-rating", "lowest-rating")
protected class OrderByFilter(title: String, options: List<Pair<String, String>>, state: Int = 0) : UriPartFilter(title, options.toTypedArray(), state)
override fun getFilterList(): FilterList {
val filters = mutableListOf(
OrderByFilter(
orderByFilterTitle,
orderByFilterOptions.zip(orderByFilterOptionsValues),
0
)
)
return FilterList(filters)
}
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>, state: Int = 0) : Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray(), state) {
fun toUriPart() = vals[state].second
}
} }
class WordSet(private vararg val words: String) { class WordSet(private vararg val words: String) {
fun anyWordIn(dateString: String): Boolean = words.any { dateString.contains(it, ignoreCase = true) } fun anyWordIn(dateString: String): Boolean =
fun startsWith(dateString: String): Boolean = words.any { dateString.startsWith(it, ignoreCase = true) } words.any { dateString.contains(it, ignoreCase = true) }
fun endsWith(dateString: String): Boolean = words.any { dateString.endsWith(it, ignoreCase = true) }
fun startsWith(dateString: String): Boolean =
words.any { dateString.startsWith(it, ignoreCase = true) }
fun endsWith(dateString: String): Boolean =
words.any { dateString.endsWith(it, ignoreCase = true) }
} }