NhatTruyen update domain & fix missing chapter & fix search (#9175)
* bump version * Update domain and Fix missing chapter * fix build * Use suggest * Fix Search no results * ¯\_(ツ)_/¯ * Change fetchChapterList to chaplistRequest
This commit is contained in:
parent
205bf49af7
commit
a9176c529b
@ -2,8 +2,8 @@ ext {
|
|||||||
extName = 'NhatTruyen'
|
extName = 'NhatTruyen'
|
||||||
extClass = '.NhatTruyen'
|
extClass = '.NhatTruyen'
|
||||||
themePkg = 'wpcomics'
|
themePkg = 'wpcomics'
|
||||||
baseUrl = 'https://nhattruyenv.com'
|
baseUrl = 'https://nhattruyenqq.com'
|
||||||
overrideVersionCode = 20
|
overrideVersionCode = 21
|
||||||
isNsfw = false
|
isNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.vi.nhattruyen
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class ChapterDTO(
|
||||||
|
val data: ArrayList<Data> = arrayListOf(),
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class Data(
|
||||||
|
val chapter_name: String,
|
||||||
|
val chapter_slug: String,
|
||||||
|
val updated_at: String,
|
||||||
|
|
||||||
|
)
|
@ -4,177 +4,99 @@ import eu.kanade.tachiyomi.multisrc.wpcomics.WPComics
|
|||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
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.SChapter
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import keiyoushi.utils.parseAs
|
||||||
|
import keiyoushi.utils.tryParse
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class NhatTruyen : WPComics(
|
class NhatTruyen : WPComics(
|
||||||
"NhatTruyen",
|
"NhatTruyen",
|
||||||
"https://nhattruyenv.com",
|
"https://nhattruyenqq.com",
|
||||||
"vi",
|
"vi",
|
||||||
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.getDefault()),
|
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.getDefault()),
|
||||||
gmtOffset = null,
|
gmtOffset = null,
|
||||||
) {
|
) {
|
||||||
override val searchPath = "tim-truyen"
|
override val searchPath = "tim-truyen"
|
||||||
|
|
||||||
|
override val popularPath = "truyen-tranh-hot"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetTruyen/NhatTruyen redirect back to catalog page if searching query is not found.
|
* NetTruyen/NhatTruyen redirect back to catalog page if searching query is not found.
|
||||||
* That makes both sites always return un-relevant results when searching should return empty.
|
* That makes both sites always return un-relevant results when searching should return empty.
|
||||||
*/
|
*/
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
|
||||||
if (response.request.url.toString().endsWith("/$searchPath")) {
|
|
||||||
return MangasPage(mangas = emptyList(), hasNextPage = false)
|
|
||||||
}
|
|
||||||
return super.searchMangaParse(response)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advanced search
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
if (query.isBlank()) {
|
val url = "$baseUrl/$searchPath".toHttpUrl().newBuilder()
|
||||||
val url = "$baseUrl/tim-truyen-nang-cao".toHttpUrl().newBuilder()
|
|
||||||
|
|
||||||
filters.forEach { filter ->
|
filters.forEach { filter ->
|
||||||
when (filter) {
|
when (filter) {
|
||||||
is AdvancedGenreFilter -> {
|
is GenreFilter -> filter.toUriPart()?.let { url.addPathSegment(it) }
|
||||||
filter.included.let { url.addQueryParameter("genres", it.joinToString(",")) }
|
is StatusFilter -> filter.toUriPart()?.let { url.addQueryParameter("status", it) }
|
||||||
filter.excluded.let { url.addQueryParameter("notgenres", it.joinToString(",")) }
|
is OrderByFilter -> filter.toUriPart()?.let { url.addQueryParameter("sort", it) }
|
||||||
}
|
else -> {}
|
||||||
is AdvancedStatusFilter -> filter.toUriPart()?.let { url.addQueryParameter("status", it) }
|
|
||||||
is ChaptersNumFilter -> filter.toUriPart()?.let { url.addQueryParameter("minchapter", it) }
|
|
||||||
is GenderFilter -> filter.toUriPart()?.let { url.addQueryParameter("gender", it) }
|
|
||||||
is OrderFilter -> filter.toUriPart()?.let { url.addQueryParameter("sort", it) }
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
url.apply {
|
|
||||||
addQueryParameter("page", page.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
return GET(url.toString(), headers)
|
|
||||||
} else {
|
|
||||||
return super.searchMangaRequest(page, query, filters)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AdvancedGenre(val id: String, name: String) : Filter.TriState(name)
|
|
||||||
|
|
||||||
private class AdvancedGenreFilter(name: String, advancedGenres: List<AdvancedGenre>) : Filter.Group<AdvancedGenre>(
|
|
||||||
name,
|
|
||||||
advancedGenres.map { AdvancedGenre(it.id, it.name) },
|
|
||||||
) {
|
|
||||||
val included: List<String>
|
|
||||||
get() = state.filter { it.isIncluded() }.map { it.id }
|
|
||||||
|
|
||||||
val excluded: List<String>
|
|
||||||
get() = state.filter { it.isExcluded() }.map { it.id }
|
|
||||||
}
|
|
||||||
|
|
||||||
private var advancedGenresList: List<AdvancedGenre> = emptyList()
|
|
||||||
|
|
||||||
private var fetchAdvancedGenresAttempts: Int = 0
|
|
||||||
|
|
||||||
private fun fetchAdvancedGenres() {
|
|
||||||
if (fetchAdvancedGenresAttempts < 3 && advancedGenresList.isEmpty()) {
|
|
||||||
try {
|
|
||||||
advancedGenresList =
|
|
||||||
client.newCall(advancedGenresRequest()).execute()
|
|
||||||
.asJsoup()
|
|
||||||
.let(::parseAdvancedGenres)
|
|
||||||
} catch (_: Exception) {
|
|
||||||
} finally {
|
|
||||||
fetchAdvancedGenresAttempts++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun advancedGenresRequest() = GET("$baseUrl/tim-truyen-nang-cao", headers)
|
url.apply {
|
||||||
|
addQueryParameter(queryParam, query)
|
||||||
private fun parseAdvancedGenres(document: Document): List<AdvancedGenre> {
|
addQueryParameter("page", page.toString())
|
||||||
val items = document.select(".advsearch-form .genre-item")
|
|
||||||
return buildList(items.size) {
|
|
||||||
items.mapTo(this) {
|
|
||||||
AdvancedGenre(
|
|
||||||
it.select("span").attr("data-id"),
|
|
||||||
it.ownText(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return GET(url.toString(), headers)
|
||||||
}
|
}
|
||||||
|
private class OrderByFilter : UriPartFilter(
|
||||||
private class ChaptersNumFilter : UriPartFilter(
|
|
||||||
"Số lượng chapter",
|
|
||||||
listOf(
|
|
||||||
Pair("1", "> 0 chapter"),
|
|
||||||
Pair("50", ">= 50 chapter"),
|
|
||||||
Pair("100", ">= 100 chapter"),
|
|
||||||
Pair("200", ">= 200 chapter"),
|
|
||||||
Pair("300", ">= 300 chapter"),
|
|
||||||
Pair("400", ">= 400 chapter"),
|
|
||||||
Pair("500", ">= 500 chapter"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
private class AdvancedStatusFilter(name: String, pairs: List<Pair<String?, String>>) : UriPartFilter(name, pairs)
|
|
||||||
|
|
||||||
private fun getAdvancedStatusList(): List<Pair<String?, String>> =
|
|
||||||
listOf(
|
|
||||||
Pair("-1", intl["STATUS_ALL"]),
|
|
||||||
Pair("1", intl["STATUS_ONGOING"]),
|
|
||||||
Pair("2", intl["STATUS_COMPLETED"]),
|
|
||||||
)
|
|
||||||
|
|
||||||
private class GenderFilter : UriPartFilter(
|
|
||||||
"Dành cho",
|
|
||||||
listOf(
|
|
||||||
Pair("-1", "Tất cả"),
|
|
||||||
Pair("1", "Con gái"),
|
|
||||||
Pair("2", "Con trai"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
private class OrderFilter : UriPartFilter(
|
|
||||||
"Sắp xếp theo",
|
"Sắp xếp theo",
|
||||||
listOf(
|
listOf(
|
||||||
Pair("0", "Chapter mới"),
|
Pair("0", "Ngày cập nhật"),
|
||||||
Pair("15", "Truyện mới"),
|
Pair("15", "Truyện mới"),
|
||||||
Pair("10", "Xem nhiều nhất"),
|
Pair("10", "Top all"),
|
||||||
Pair("11", "Xem nhiều nhất tháng"),
|
Pair("11", "Top tháng"),
|
||||||
Pair("12", "Xem nhiều nhất tuần"),
|
Pair("12", "Top tuần"),
|
||||||
Pair("13", "Xem nhiều nhất hôm nay"),
|
Pair("13", "Top ngày"),
|
||||||
Pair("20", "Theo dõi nhiều nhất"),
|
Pair("20", "Top theo dõi"),
|
||||||
Pair("25", "Bình luận nhiều nhất"),
|
Pair("25", "Bình luận"),
|
||||||
Pair("30", "Số chapter nhiều nhất"),
|
Pair("30", "Số chapter"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun getFilterList(): FilterList {
|
override fun getFilterList(): FilterList {
|
||||||
launchIO { fetchAdvancedGenres() }
|
|
||||||
launchIO { fetchGenres() }
|
launchIO { fetchGenres() }
|
||||||
return FilterList(
|
return FilterList(
|
||||||
Filter.Header("Filter cho hộp tìm kiếm"),
|
|
||||||
StatusFilter(intl["STATUS"], getStatusList()),
|
StatusFilter(intl["STATUS"], getStatusList()),
|
||||||
|
OrderByFilter(),
|
||||||
if (genreList.isEmpty()) {
|
if (genreList.isEmpty()) {
|
||||||
Filter.Header(intl["GENRES_RESET"])
|
Filter.Header(intl["GENRES_RESET"])
|
||||||
} else {
|
} else {
|
||||||
GenreFilter(intl["GENRE"], genreList)
|
GenreFilter(intl["GENRE"], genreList)
|
||||||
},
|
},
|
||||||
Filter.Separator(),
|
|
||||||
Filter.Header("Tìm truyện nâng cao\n(Không sử dụng cùng với hộp tìm kiếm)"),
|
|
||||||
if (advancedGenresList.isEmpty()) {
|
|
||||||
Filter.Header(intl["GENRES_RESET"])
|
|
||||||
} else {
|
|
||||||
AdvancedGenreFilter(intl["GENRE"], advancedGenresList)
|
|
||||||
},
|
|
||||||
AdvancedStatusFilter(intl["STATUS"], getAdvancedStatusList()),
|
|
||||||
ChaptersNumFilter(),
|
|
||||||
GenderFilter(),
|
|
||||||
OrderFilter(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun chapterListRequest(manga: SManga): Request {
|
||||||
|
val slug = manga.url.substringAfterLast("/") // slug
|
||||||
|
val url = baseUrl.toHttpUrl().newBuilder()
|
||||||
|
.addPathSegment("Comic/Services/ComicService.asmx/ChapterList")
|
||||||
|
.addQueryParameter("slug", slug)
|
||||||
|
.build()
|
||||||
|
return GET(url, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
val json = response.parseAs<ChapterDTO>()
|
||||||
|
val slug = response.request.url.queryParameter("slug")!!
|
||||||
|
val chapter = json.data.map {
|
||||||
|
SChapter.create().apply {
|
||||||
|
setUrlWithoutDomain("$baseUrl/truyen-tranh/$slug/${it.chapter_slug}")
|
||||||
|
name = it.chapter_name
|
||||||
|
date_upload = dateFormatChapter.tryParse(it.updated_at)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chapter
|
||||||
|
}
|
||||||
|
|
||||||
|
private val dateFormatChapter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user