From d463a0900aa618721fc2bbf8657acc8885ee12fa Mon Sep 17 00:00:00 2001 From: "D@ddyBunz" <pon3kub@gmail.com> Date: Sun, 25 Sep 2022 01:53:29 +0700 Subject: [PATCH] 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> --- src/th/niceoppai/build.gradle | 2 +- .../extension/th/niceoppai/Niceoppai.kt | 185 +++++++++--------- 2 files changed, 95 insertions(+), 92 deletions(-) diff --git a/src/th/niceoppai/build.gradle b/src/th/niceoppai/build.gradle index dda595ae3..cb1e3af11 100644 --- a/src/th/niceoppai/build.gradle +++ b/src/th/niceoppai/build.gradle @@ -5,7 +5,7 @@ ext { extName = 'Niceoppai' pkgNameSuffix = 'th.niceoppai' extClass = '.Niceoppai' - extVersionCode = 25 + extVersionCode = 26 isNsfw = true } diff --git a/src/th/niceoppai/src/eu/kanade/tachiyomi/extension/th/niceoppai/Niceoppai.kt b/src/th/niceoppai/src/eu/kanade/tachiyomi/extension/th/niceoppai/Niceoppai.kt index f27bcd312..f860a351d 100644 --- a/src/th/niceoppai/src/eu/kanade/tachiyomi/extension/th/niceoppai/Niceoppai.kt +++ b/src/th/niceoppai/src/eu/kanade/tachiyomi/extension/th/niceoppai/Niceoppai.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.th.niceoppai import eu.kanade.tachiyomi.network.GET 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.MangasPage 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 okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element import rx.Observable @@ -22,7 +24,7 @@ import java.util.concurrent.TimeUnit 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 lang: String = "th" @@ -37,17 +39,13 @@ class Niceoppai : ParsedHttpSource() { .build() // Popular - 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 popularMangaFromElement(element: Element): SManga { val manga = SManga.create() - - manga.title = element.select("div.det a").text() + manga.title = "title : " + element.select("div.det a").text() element.select("div.cvr").let { manga.setUrlWithoutDomain(it.select("div.img_wrp a").attr("href")) @@ -57,88 +55,66 @@ class Niceoppai : ParsedHttpSource() { return manga } - override fun popularMangaNextPageSelector() = "ul.pgg li a" // Latest - override fun latestUpdatesRequest(page: Int): Request { return GET("$baseUrl/manga_list/all/any/last-updated/$page", headers) } - 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 searchMangaRequest(page: Int, query: String, filters: FilterList): Request = - throw Exception("Unused") + // Search + 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") - - override fun searchMangaFromElement(element: Element): SManga = throw Exception("Unused") - - override fun searchMangaNextPageSelector(): String = throw Exception("Unused") - - override fun fetchSearchManga( - page: Int, - query: String, - filters: FilterList - ): Observable<MangasPage> { - val searchMethod = query.startsWith("http") - return client.newCall( - GET("$baseUrl/manga_list/category/$query/name-az/$page") - ) + return if (isOrderByFilter) GET("$baseUrl/manga_list/all/any/$orderByString/$page", headers) + else GET("$baseUrl/manga_list/search/$query/$orderByString/$page", headers) + } + override fun searchMangaSelector(): String = popularMangaSelector() + override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) + override fun searchMangaNextPageSelector(): String = popularMangaNextPageSelector() + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { + return client.newCall(searchMangaRequest(page, query, filters)) .asObservableSuccess() .map { val document = it.asJsoup() - val mangas: List<SManga> = if (searchMethod) { - listOf( - SManga.create().apply { - 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) + val mangas: List<SManga> = + document.select(searchMangaSelector()).map { element -> + searchMangaFromElement(element) } - } - MangasPage(mangas, !searchMethod) + MangasPage(mangas, false) + } } // Manga summary page - private fun getStatus(status: String) = when (status) { "ยังไม่จบ" -> SManga.ONGOING "จบแล้ว" -> SManga.COMPLETED else -> SManga.UNKNOWN } - override fun mangaDetailsParse(document: Document): SManga { val infoElement = document.select("div.det").first() + val titleElement = document.select("h1.ttl").first() return SManga.create().apply { - title = document.title() + infoElement.select("p")[2].ownText() - author = infoElement.select("p")[3].ownText() + title = titleElement.text() + author = infoElement.select("p")[2].select("a").text() artist = author - status = getStatus(infoElement.select("p")[10].ownText()) - genre = infoElement.select("p")[6].select("a").joinToString { it.ownText() } - description = infoElement.select("p").first().ownText() + status = getStatus(infoElement.select("p")[9].ownText().replace(": ", "")) + genre = infoElement.select("p")[5].select("a").joinToString { it.text() } + description = infoElement.select("p").first().ownText().replace(": ", "") thumbnail_url = document.select("div.mng_ifo div.cvr_ara img").first().attr("abs:src") initialized = true } } // Chapters - private fun parseChapterDate(date: String?): Long { date ?: return 0 @@ -196,7 +172,6 @@ class Niceoppai : ParsedHttpSource() { else -> dateFormat.tryParse(date) } } - // Parses dates in this form: // 21 horas ago private fun parseRelativeDate(date: String): Long { @@ -214,64 +189,70 @@ class Niceoppai : ParsedHttpSource() { else -> 0 } } - override fun chapterListSelector() = "ul.lst li.lng_" - override fun chapterFromElement(element: Element): SChapter = throw Exception("Unused") - private fun chapterFromElementWithIndex(element: Element, idx: Int, manga: SManga): SChapter { val chapter = SChapter.create() - with(element) { - val btn = element.select("a.lst") - chapter.setUrlWithoutDomain(btn.attr("href")) - chapter.name = btn.select("b.val").text() - val dateText = btn.select("b.dte").text() - chapter.date_upload = parseChapterDate(dateText) + val btn = element.select("a.lst") + chapter.setUrlWithoutDomain(btn.attr("href")) + chapter.name = btn.select("b.val").text() + val dateText = btn.select("b.dte").text() + chapter.date_upload = parseChapterDate(dateText) - if (chapter.name.isEmpty()) { - chapter.chapter_number = 0.0f - } else { - val wordsChapter = chapter.name.replace("ตอนที่. ", "").split(" - ") - try { - chapter.chapter_number = wordsChapter[0].toFloat() - } catch (ex: NumberFormatException) { - chapter.chapter_number = (idx + 1).toFloat() - } + if (chapter.name.isEmpty()) { + chapter.chapter_number = 0.0f + } else { + val wordsChapter = chapter.name.replace("ตอนที่. ", "").split(" - ") + try { + chapter.chapter_number = wordsChapter[0].toFloat() + } catch (ex: NumberFormatException) { + chapter.chapter_number = (idx + 1).toFloat() } } 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}")) - .asObservableSuccess() - .map { - val chList: List<SChapter> - val mangaDocument = it.asJsoup() + override fun chapterListParse(response: Response): List<SChapter> { + val document = response.asJsoup() + val listPage = document.select("ul.pgg li a") + .filter { it.text() != "Next" && it.text() != "Last" } + .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()) { - manga.status = SManga.COMPLETED val createdChapter = SChapter.create().apply { - url = manga.url name = "Chapter 1" chapter_number = 1.0f } - chList = listOf(createdChapter) + chList += listOf(createdChapter) } else { - chList = + chList += 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 - override fun pageListParse(document: Document): List<Page> { return document.select("div.mng_rdr div#image-container img").mapIndexed { i, img -> if (img.hasAttr("data-src")) { @@ -281,15 +262,37 @@ class Niceoppai : ParsedHttpSource() { } } } - override fun imageUrlParse(document: Document): String = 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) { - fun anyWordIn(dateString: String): Boolean = words.any { dateString.contains(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) } + fun anyWordIn(dateString: String): Boolean = + words.any { dateString.contains(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) } }