Update Newtoki Extension to v1.2.20 (#5917)

* Update Newtoki Extension to v1.2.20

* Better RateLimit
* New Search filter for ManaToki.

* Fix Page Selector and Filters

* Order was not worked on default sort due to missing value
* Page is now searchable over 10 pages. Seems site changed a bit.

* Backport Sort and Order to NewToki
This commit is contained in:
DitFranXX 2021-02-19 23:03:01 +09:00 committed by GitHub
parent 294aa0d4cd
commit cbe5dac026
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 85 additions and 44 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'NewToki / ManaToki' extName = 'NewToki / ManaToki'
pkgNameSuffix = 'ko.newtoki' pkgNameSuffix = 'ko.newtoki'
extClass = '.NewTokiFactory' extClass = '.NewTokiFactory'
extVersionCode = 19 extVersionCode = 20
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -16,7 +16,7 @@ import rx.Observable
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/* /*
* ManaToki Is too big to support in a Factory File., So split into separate file. * ManaToki is too big to support in a Factory File., So split into separate file.
*/ */
class ManaToki(domainNumber: Long) : NewToki("ManaToki", "https://manatoki$domainNumber.net", "comic") { class ManaToki(domainNumber: Long) : NewToki("ManaToki", "https://manatoki$domainNumber.net", "comic") {
@ -104,10 +104,7 @@ class ManaToki(domainNumber: Long) : NewToki("ManaToki", "https://manatoki$domai
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = HttpUrl.parse("$baseUrl/comic" + (if (page > 1) "/p$page" else ""))!!.newBuilder() val url = HttpUrl.parse("$baseUrl/comic" + (if (page > 1) "/p$page" else ""))!!.newBuilder()
if (!query.isBlank()) { val genres = mutableListOf<String>()
url.addQueryParameter("stx", query)
return GET(url.toString())
}
filters.forEach { filter -> filters.forEach { filter ->
when (filter) { when (filter) {
@ -124,33 +121,54 @@ class ManaToki(domainNumber: Long) : NewToki("ManaToki", "https://manatoki$domai
} }
is SearchGenreTypeList -> { is SearchGenreTypeList -> {
if (filter.state > 0) { filter.state.forEach {
url.addQueryParameter("tag", filter.values[filter.state]) if (it.state) {
genres.add(it.id)
} }
} }
} }
is SearchSortTypeList -> {
url.addQueryParameter("sst", listOf("wr_datetime", "wr_hit", "wr_good", "as_update")[filter.state])
} }
is SearchOrderTypeList -> {
url.addQueryParameter("sod", listOf("desc", "asc")[filter.state])
}
}
}
if (query.isNotBlank()) {
url.addQueryParameter("stx", query)
// Remove some filter QueryParams that not working with query
url.setQueryParameter("publish", null)
url.setQueryParameter("jaum", null)
return GET(url.toString()) return GET(url.toString())
} }
// [...document.querySelectorAll("form.form td")[2].querySelectorAll("a")].map((el, i) => `"${el.innerText.trim()}"`).join(',\n') url.addQueryParameter("tag", genres.joinToString(","))
return GET(url.toString())
}
private class SearchCheckBox(name: String, val id: String = name) : Filter.CheckBox(name)
// [...document.querySelectorAll("form.form td")[3].querySelectorAll("span.btn")].map((el, i) => `"${el.innerText.trim()}"`).join(',\n')
private class SearchPublishTypeList : Filter.Select<String>( private class SearchPublishTypeList : Filter.Select<String>(
"Publish", "Publish",
arrayOf( arrayOf(
"전체", "전체",
"미분류",
"주간", "주간",
"격주", "격주",
"월간", "월간",
"격월/비정기",
"단편", "단편",
"단행본", "단행본",
"완결" "완결"
) )
) )
// [...document.querySelectorAll("form.form td")[3].querySelectorAll("a")].map((el, i) => `"${el.innerText.trim()}"`).join(',\n') // [...document.querySelectorAll("form.form td")[4].querySelectorAll("span.btn")].map((el, i) => `"${el.innerText.trim()}"`).join(',\n')
private class SearchJaumTypeList : Filter.Select<String>( private class SearchJaumTypeList : Filter.Select<String>(
"Jaum", "Jaum",
arrayOf( arrayOf(
@ -174,9 +192,9 @@ class ManaToki(domainNumber: Long) : NewToki("ManaToki", "https://manatoki$domai
) )
) )
// [...document.querySelectorAll("form.form td")[4].querySelectorAll("a")].map((el, i) => `"${el.innerText.trim()}"`).join(',\n') // [...document.querySelectorAll("form.form td")[6].querySelectorAll("span.btn")].map((el, i) => `"${el.innerText.trim()}"`).join(',\n')
private class SearchGenreTypeList : Filter.Select<String>( private class SearchGenreTypeList : Filter.Group<SearchCheckBox>(
"Genre", "Genres",
arrayOf( arrayOf(
"전체", "전체",
"17", "17",
@ -185,40 +203,54 @@ class ManaToki(domainNumber: Long) : NewToki("ManaToki", "https://manatoki$domai
"TS", "TS",
"개그", "개그",
"게임", "게임",
"공포",
"도박", "도박",
"드라마", "드라마",
"라노벨", "라노벨",
"러브코미디", "러브코미디",
"로맨스",
"먹방", "먹방",
"미스터리",
"백합", "백합",
"붕탁", "붕탁",
"성인",
"순정", "순정",
"스릴러", "스릴러",
"스포츠", "스포츠",
"시대", "시대",
"애니화", "애니화",
"액션", "액션",
"역사",
"음악", "음악",
"이세계", "이세계",
"일상", "일상",
"일상+치유",
"전생", "전생",
"추리", "추리",
"판타지", "판타지",
"학원", "학원",
"호러" "호러"
).map { SearchCheckBox(it) }
)
private class SearchSortTypeList : Filter.Select<String>(
"Sort",
arrayOf(
"기본",
"인기순",
"추천순",
"업데이트순"
)
)
private class SearchOrderTypeList : Filter.Select<String>(
"Order",
arrayOf(
"Descending",
"Ascending"
) )
) )
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
Filter.Header("Filter can't use with query"), Filter.Header("Some filters can't use with query"),
SearchPublishTypeList(), SearchPublishTypeList(),
SearchJaumTypeList(), SearchJaumTypeList(),
SearchSortTypeList(),
SearchOrderTypeList(),
SearchGenreTypeList() SearchGenreTypeList()
) )
} }

View File

@ -42,7 +42,7 @@ open class NewToki(override val name: String, private val defaultBaseUrl: String
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient override val client: OkHttpClient = network.cloudflareClient
protected val rateLimitedClient: OkHttpClient = network.cloudflareClient.newBuilder() protected val rateLimitedClient: OkHttpClient = network.cloudflareClient.newBuilder()
.addNetworkInterceptor(RateLimitInterceptor(2, 5)) .addNetworkInterceptor(RateLimitInterceptor(1))
.build() .build()
override fun popularMangaSelector() = "div#webtoon-list > ul > li" override fun popularMangaSelector() = "div#webtoon-list > ul > li"
@ -57,31 +57,14 @@ open class NewToki(override val name: String, private val defaultBaseUrl: String
return manga return manga
} }
override fun popularMangaNextPageSelector() = "ul.pagination > li:not(.disabled)" override fun popularMangaNextPageSelector() = "ul.pagination > li:last-child:not(.disabled)"
// Do not add page parameter if page is 1 to prevent tracking. // Do not add page parameter if page is 1 to prevent tracking.
override fun popularMangaRequest(page: Int) = GET("$baseUrl/$boardName" + if (page > 1) "/p$page" else "") override fun popularMangaRequest(page: Int) = GET("$baseUrl/$boardName" + if (page > 1) "/p$page" else "")
override fun popularMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select(popularMangaSelector()).map { element ->
popularMangaFromElement(element)
}
val hasNextPage = try {
!document.select(popularMangaNextPageSelector()).last().hasClass("active")
} catch (_: Exception) {
false
}
return MangasPage(mangas, hasNextPage)
}
override fun searchMangaSelector() = popularMangaSelector() override fun searchMangaSelector() = popularMangaSelector()
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element) override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
override fun searchMangaNextPageSelector() = popularMangaSelector() override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaParse(response: Response) = popularMangaParse(response)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/$boardName" + (if (page > 1) "/p$page" else "") + "?stx=$query") override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/$boardName" + (if (page > 1) "/p$page" else "") + "?stx=$query")
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return if (query.startsWith(PREFIX_ID_SEARCH)) { return if (query.startsWith(PREFIX_ID_SEARCH)) {
@ -253,7 +236,6 @@ open class NewToki(override val name: String, private val defaultBaseUrl: String
override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element) override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element)
override fun latestUpdatesRequest(page: Int) = popularMangaRequest(page) override fun latestUpdatesRequest(page: Int) = popularMangaRequest(page)
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun latestUpdatesParse(response: Response) = popularMangaParse(response)
// We are able to get the image URL directly from the page list // We are able to get the image URL directly from the page list
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("This method should not be called!") override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("This method should not be called!")

View File

@ -42,10 +42,18 @@ class NewTokiWebtoon : NewToki("NewToki", "https://newtoki$domainNumber.com", "w
url.addQueryParameter("toon", filter.values[filter.state]) url.addQueryParameter("toon", filter.values[filter.state])
} }
} }
is SearchSortTypeList -> {
url.addQueryParameter("sst", listOf("as_update", "wr_hit", "wr_good")[filter.state])
}
is SearchOrderTypeList -> {
url.addQueryParameter("sod", listOf("desc", "asc")[filter.state])
}
} }
} }
// Imcompatible with Other Search Parametor // Incompatible with Other Search Parameter
if (!query.isBlank()) { if (!query.isBlank()) {
url.addQueryParameter("stx", query) url.addQueryParameter("stx", query)
} else { } else {
@ -135,8 +143,27 @@ class NewTokiWebtoon : NewToki("NewToki", "https://newtoki$domainNumber.com", "w
) )
) )
private class SearchSortTypeList : Filter.Select<String>(
"Sort",
arrayOf(
"기본",
"인기순",
"추천순",
)
)
private class SearchOrderTypeList : Filter.Select<String>(
"Order",
arrayOf(
"Descending",
"Ascending"
)
)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
SearchTargetTypeList(), SearchTargetTypeList(),
SearchSortTypeList(),
SearchOrderTypeList(),
Filter.Separator(), Filter.Separator(),
Filter.Header("Under 3 Filters can't use with query"), Filter.Header("Under 3 Filters can't use with query"),
SearchYoilTypeList(), SearchYoilTypeList(),