Mangakakalot, Manganato: Updated Domain, Selectors and Filters (#7781)
* Mangakakalot - updated domain paths * Mangakakalot - Fixed description query and filters Also fixed certain cases that could result in 403 when opening chapters * Mangakakalot - Updated baseUrl * Manganato - Updated domain, selector, and filters Manganato essentially became an exact copy mangakakalot so all changes (except for URLs) are the same with mangakakalot * review changes, fixed upload date * Replaced duplicated `GET` request logic with `super.imageRequest(page)` to avoid redundancy * review changes, moved `SimpleDateFormat` outside the function
This commit is contained in:
parent
e8fed7ce6d
commit
ffd98958ee
@ -199,7 +199,7 @@ abstract class MangaBox(
|
|||||||
|
|
||||||
protected open val alternateChapterDateSelector = String()
|
protected open val alternateChapterDateSelector = String()
|
||||||
|
|
||||||
private fun Element.selectDateFromElement(): Element {
|
protected fun Element.selectDateFromElement(): Element {
|
||||||
val defaultChapterDateSelector = "span"
|
val defaultChapterDateSelector = "span"
|
||||||
return this.select(defaultChapterDateSelector).lastOrNull() ?: this.select(alternateChapterDateSelector).last()!!
|
return this.select(defaultChapterDateSelector).lastOrNull() ?: this.select(alternateChapterDateSelector).last()!!
|
||||||
}
|
}
|
||||||
@ -305,10 +305,11 @@ abstract class MangaBox(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class KeywordFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Keyword search ", vals)
|
// Technically, only Sort, Status, and Genre need to be non-private for Mangakakalot and Manganato, but I'll include Keyword to make it uniform.
|
||||||
private class SortFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Order by", vals)
|
protected class KeywordFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Keyword search ", vals)
|
||||||
private class StatusFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Status", vals)
|
protected class SortFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Order by", vals)
|
||||||
private class GenreFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Category", vals)
|
protected class StatusFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Status", vals)
|
||||||
|
protected class GenreFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Category", vals)
|
||||||
|
|
||||||
// For advanced search, specifically tri-state genres
|
// For advanced search, specifically tri-state genres
|
||||||
private class AdvGenreFilter(vals: List<AdvGenre>) : Filter.Group<AdvGenre>("Category", vals)
|
private class AdvGenreFilter(vals: List<AdvGenre>) : Filter.Group<AdvGenre>("Category", vals)
|
||||||
|
@ -2,8 +2,8 @@ ext {
|
|||||||
extName = 'Mangakakalot'
|
extName = 'Mangakakalot'
|
||||||
extClass = '.Mangakakalot'
|
extClass = '.Mangakakalot'
|
||||||
themePkg = 'mangabox'
|
themePkg = 'mangabox'
|
||||||
baseUrl = 'https://mangakakalot.com'
|
baseUrl = 'https://www.mangakakalot.gg'
|
||||||
overrideVersionCode = 3
|
overrideVersionCode = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -1,10 +1,115 @@
|
|||||||
package eu.kanade.tachiyomi.extension.en.mangakakalot
|
package eu.kanade.tachiyomi.extension.en.mangakakalot
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.mangabox.MangaBox
|
import eu.kanade.tachiyomi.multisrc.mangabox.MangaBox
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import okhttp3.Request
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import java.text.ParseException
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class Mangakakalot : MangaBox("Mangakakalot", "https://mangakakalot.com", "en") {
|
class Mangakakalot : MangaBox("Mangakakalot", "https://www.mangakakalot.gg", "en") {
|
||||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder().set("Referer", "https://manganato.com") // for covers
|
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM-dd-yyyy HH:mm", Locale.ENGLISH)
|
||||||
|
|
||||||
|
override fun headersBuilder(): Headers.Builder = super.headersBuilder().set("Referer", "$baseUrl/") // for covers
|
||||||
|
override val popularUrlPath = "manga-list/hot-manga?page="
|
||||||
|
override val latestUrlPath = "manga-list/latest-manga?page="
|
||||||
override val simpleQueryPath = "search/story/"
|
override val simpleQueryPath = "search/story/"
|
||||||
override fun searchMangaSelector() = "${super.searchMangaSelector()}, div.list-truyen-item-wrap"
|
override fun searchMangaSelector() = "${super.searchMangaSelector()}, div.list-truyen-item-wrap"
|
||||||
|
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
return if (query.isNotBlank() && getAdvancedGenreFilters().isEmpty()) {
|
||||||
|
val url = "$baseUrl/$simpleQueryPath".toHttpUrl().newBuilder()
|
||||||
|
.addPathSegment(normalizeSearchQuery(query))
|
||||||
|
.addQueryParameter("page", page.toString())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return GET(url, headers)
|
||||||
|
} else {
|
||||||
|
val url = "$baseUrl/genre".toHttpUrl().newBuilder()
|
||||||
|
url.addQueryParameter("page", page.toString())
|
||||||
|
filters.forEach { filter ->
|
||||||
|
when (filter) {
|
||||||
|
is SortFilter -> url.addQueryParameter("type", filter.toUriPart())
|
||||||
|
is StatusFilter -> url.addQueryParameter("state", filter.toUriPart())
|
||||||
|
is GenreFilter -> url.addPathSegment(filter.toUriPart()!!)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GET(url.build(), headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
|
// parse on title attribute rather than the value
|
||||||
|
val dateUploadAttr: Long? = try {
|
||||||
|
dateFormat.parse(element.selectDateFromElement().attr("title"))?.time
|
||||||
|
} catch (e: ParseException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.chapterFromElement(element).apply {
|
||||||
|
date_upload = dateUploadAttr ?: date_upload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val descriptionSelector = "div#contentBox"
|
||||||
|
|
||||||
|
override fun imageRequest(page: Page): Request {
|
||||||
|
return if (page.url.contains(baseUrl)) {
|
||||||
|
GET(page.imageUrl!!, headersBuilder().build())
|
||||||
|
} else { // Avoid 403 errors on non-migrated mangas
|
||||||
|
super.imageRequest(page)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getGenreFilters(): Array<Pair<String?, String>> = arrayOf(
|
||||||
|
Pair("all", "ALL"),
|
||||||
|
Pair("action", "Action"),
|
||||||
|
Pair("adult", "Adult"),
|
||||||
|
Pair("adventure", "Adventure"),
|
||||||
|
Pair("comedy", "Comedy"),
|
||||||
|
Pair("cooking", "Cooking"),
|
||||||
|
Pair("doujinshi", "Doujinshi"),
|
||||||
|
Pair("drama", "Drama"),
|
||||||
|
Pair("ecchi", "Ecchi"),
|
||||||
|
Pair("fantasy", "Fantasy"),
|
||||||
|
Pair("gender-bender", "Gender bender"),
|
||||||
|
Pair("harem", "Harem"),
|
||||||
|
Pair("historical", "Historical"),
|
||||||
|
Pair("horror", "Horror"),
|
||||||
|
Pair("isekai", "Isekai"),
|
||||||
|
Pair("josei", "Josei"),
|
||||||
|
Pair("manhua", "Manhua"),
|
||||||
|
Pair("manhwa", "Manhwa"),
|
||||||
|
Pair("martial-arts", "Martial arts"),
|
||||||
|
Pair("mature", "Mature"),
|
||||||
|
Pair("mecha", "Mecha"),
|
||||||
|
Pair("medical", "Medical"),
|
||||||
|
Pair("mystery", "Mystery"),
|
||||||
|
Pair("one-shot", "One shot"),
|
||||||
|
Pair("psychological", "Psychological"),
|
||||||
|
Pair("romance", "Romance"),
|
||||||
|
Pair("school-life", "School life"),
|
||||||
|
Pair("sci-fi", "Sci fi"),
|
||||||
|
Pair("seinen", "Seinen"),
|
||||||
|
Pair("shoujo", "Shoujo"),
|
||||||
|
Pair("shoujo-ai", "Shoujo ai"),
|
||||||
|
Pair("shounen", "Shounen"),
|
||||||
|
Pair("shounen-ai", "Shounen ai"),
|
||||||
|
Pair("slice-of-life", "Slice of life"),
|
||||||
|
Pair("smut", "Smut"),
|
||||||
|
Pair("sports", "Sports"),
|
||||||
|
Pair("supernatural", "Supernatural"),
|
||||||
|
Pair("tragedy", "Tragedy"),
|
||||||
|
Pair("webtoons", "Webtoons"),
|
||||||
|
Pair("yaoi", "Yaoi"),
|
||||||
|
Pair("yuri", "Yuri"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ ext {
|
|||||||
extName = 'Manganato'
|
extName = 'Manganato'
|
||||||
extClass = '.Manganato'
|
extClass = '.Manganato'
|
||||||
themePkg = 'mangabox'
|
themePkg = 'mangabox'
|
||||||
baseUrl = 'https://manganato.com'
|
baseUrl = 'https://www.natomanga.com'
|
||||||
overrideVersionCode = 2
|
overrideVersionCode = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -2,20 +2,116 @@ package eu.kanade.tachiyomi.extension.en.manganelo
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.mangabox.MangaBox
|
import eu.kanade.tachiyomi.multisrc.mangabox.MangaBox
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import okhttp3.Headers
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import java.text.ParseException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class Manganato : MangaBox("Manganato", "https://manganato.com", "en", SimpleDateFormat("MMM dd,yy", Locale.ENGLISH)) {
|
class Manganato : MangaBox("Manganato", "https://www.natomanga.com", "en") {
|
||||||
override val id: Long = 1024627298672457456
|
override val id: Long = 1024627298672457456
|
||||||
|
|
||||||
// Nelo's date format is part of the base class
|
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM-dd-yyyy HH:mm", Locale.ENGLISH)
|
||||||
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/genre-all/$page?type=topview", headers)
|
|
||||||
override fun popularMangaSelector() = "div.content-genres-item"
|
override fun headersBuilder(): Headers.Builder = super.headersBuilder().set("Referer", "$baseUrl/") // for covers
|
||||||
override val latestUrlPath = "genre-all/"
|
override val popularUrlPath = "manga-list/hot-manga?page="
|
||||||
|
override val latestUrlPath = "manga-list/latest-manga?page="
|
||||||
override val simpleQueryPath = "search/story/"
|
override val simpleQueryPath = "search/story/"
|
||||||
override fun searchMangaSelector() = "div.search-story-item, div.content-genres-item"
|
override fun searchMangaSelector() = "${super.searchMangaSelector()}, div.list-truyen-item-wrap"
|
||||||
override fun getAdvancedGenreFilters(): List<AdvGenre> = getGenreFilters()
|
|
||||||
.drop(1)
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
.map { AdvGenre(it.first, it.second) }
|
return if (query.isNotBlank() && getAdvancedGenreFilters().isEmpty()) {
|
||||||
|
val url = "$baseUrl/$simpleQueryPath".toHttpUrl().newBuilder()
|
||||||
|
.addPathSegment(normalizeSearchQuery(query))
|
||||||
|
.addQueryParameter("page", page.toString())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return GET(url, headers)
|
||||||
|
} else {
|
||||||
|
val url = "$baseUrl/genre".toHttpUrl().newBuilder()
|
||||||
|
url.addQueryParameter("page", page.toString())
|
||||||
|
filters.forEach { filter ->
|
||||||
|
when (filter) {
|
||||||
|
is SortFilter -> url.addQueryParameter("type", filter.toUriPart())
|
||||||
|
is StatusFilter -> url.addQueryParameter("state", filter.toUriPart())
|
||||||
|
is GenreFilter -> url.addPathSegment(filter.toUriPart()!!)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GET(url.build(), headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
|
// parse on title attribute rather than the value
|
||||||
|
val dateUploadAttr: Long? = try {
|
||||||
|
dateFormat.parse(element.selectDateFromElement().attr("title"))?.time
|
||||||
|
} catch (e: ParseException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.chapterFromElement(element).apply {
|
||||||
|
date_upload = dateUploadAttr ?: date_upload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val descriptionSelector = "div#contentBox"
|
||||||
|
|
||||||
|
override fun imageRequest(page: Page): Request {
|
||||||
|
return if (page.url.contains(baseUrl)) {
|
||||||
|
GET(page.imageUrl!!, headersBuilder().build())
|
||||||
|
} else { // Avoid 403 errors on non-migrated mangas
|
||||||
|
super.imageRequest(page)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getGenreFilters(): Array<Pair<String?, String>> = arrayOf(
|
||||||
|
Pair("all", "ALL"),
|
||||||
|
Pair("action", "Action"),
|
||||||
|
Pair("adult", "Adult"),
|
||||||
|
Pair("adventure", "Adventure"),
|
||||||
|
Pair("comedy", "Comedy"),
|
||||||
|
Pair("cooking", "Cooking"),
|
||||||
|
Pair("doujinshi", "Doujinshi"),
|
||||||
|
Pair("drama", "Drama"),
|
||||||
|
Pair("ecchi", "Ecchi"),
|
||||||
|
Pair("fantasy", "Fantasy"),
|
||||||
|
Pair("gender-bender", "Gender bender"),
|
||||||
|
Pair("harem", "Harem"),
|
||||||
|
Pair("historical", "Historical"),
|
||||||
|
Pair("horror", "Horror"),
|
||||||
|
Pair("isekai", "Isekai"),
|
||||||
|
Pair("josei", "Josei"),
|
||||||
|
Pair("manhua", "Manhua"),
|
||||||
|
Pair("manhwa", "Manhwa"),
|
||||||
|
Pair("martial-arts", "Martial arts"),
|
||||||
|
Pair("mature", "Mature"),
|
||||||
|
Pair("mecha", "Mecha"),
|
||||||
|
Pair("medical", "Medical"),
|
||||||
|
Pair("mystery", "Mystery"),
|
||||||
|
Pair("one-shot", "One shot"),
|
||||||
|
Pair("psychological", "Psychological"),
|
||||||
|
Pair("romance", "Romance"),
|
||||||
|
Pair("school-life", "School life"),
|
||||||
|
Pair("sci-fi", "Sci fi"),
|
||||||
|
Pair("seinen", "Seinen"),
|
||||||
|
Pair("shoujo", "Shoujo"),
|
||||||
|
Pair("shoujo-ai", "Shoujo ai"),
|
||||||
|
Pair("shounen", "Shounen"),
|
||||||
|
Pair("shounen-ai", "Shounen ai"),
|
||||||
|
Pair("slice-of-life", "Slice of life"),
|
||||||
|
Pair("smut", "Smut"),
|
||||||
|
Pair("sports", "Sports"),
|
||||||
|
Pair("supernatural", "Supernatural"),
|
||||||
|
Pair("tragedy", "Tragedy"),
|
||||||
|
Pair("webtoons", "Webtoons"),
|
||||||
|
Pair("yaoi", "Yaoi"),
|
||||||
|
Pair("yuri", "Yuri"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user