KomikIndoID: fix error 404 (#13629)

* KomikIndoID: fix error 404

closes #13604

* remove deprecated toLowerCase
This commit is contained in:
Riztard Lanthorn 2022-10-01 00:09:58 +07:00 committed by GitHub
parent dfbad68d4c
commit 6cc6686d4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 279 additions and 279 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'KomikIndoID' extName = 'KomikIndoID'
pkgNameSuffix = 'id.komikindoid' pkgNameSuffix = 'id.komikindoid'
extClass = '.KomikIndoID' extClass = '.KomikIndoID'
extVersionCode = 4 extVersionCode = 5
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -1,278 +1,278 @@
package eu.kanade.tachiyomi.extension.id.komikindoid package eu.kanade.tachiyomi.extension.id.komikindoid
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.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Locale import java.util.Locale
class KomikIndoID : ParsedHttpSource() { class KomikIndoID : ParsedHttpSource() {
override val name = "KomikIndoID" override val name = "KomikIndoID"
override val baseUrl = "https://komikindo.id" override val baseUrl = "https://komikindo.id"
override val lang = "id" override val lang = "id"
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient override val client: OkHttpClient = network.cloudflareClient
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.US) private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.US)
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/daftar-komik/page/$page/?order=popular", headers) return GET("$baseUrl/daftar-manga/page/$page/?order=popular", headers)
} }
override fun latestUpdatesRequest(page: Int): Request { override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/daftar-komik/page/$page/?order=update", headers) return GET("$baseUrl/daftar-manga/page/$page/?order=update", headers)
} }
override fun popularMangaSelector() = "div.animepost" override fun popularMangaSelector() = "div.animepost"
override fun latestUpdatesSelector() = popularMangaSelector() override fun latestUpdatesSelector() = popularMangaSelector()
override fun searchMangaSelector() = popularMangaSelector() override fun searchMangaSelector() = popularMangaSelector()
override fun popularMangaFromElement(element: Element): SManga = searchMangaFromElement(element) override fun popularMangaFromElement(element: Element): SManga = searchMangaFromElement(element)
override fun latestUpdatesFromElement(element: Element): SManga = searchMangaFromElement(element) override fun latestUpdatesFromElement(element: Element): SManga = searchMangaFromElement(element)
override fun popularMangaNextPageSelector() = "a.next.page-numbers" override fun popularMangaNextPageSelector() = "a.next.page-numbers"
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaFromElement(element: Element): SManga { override fun searchMangaFromElement(element: Element): SManga {
val manga = SManga.create() val manga = SManga.create()
manga.thumbnail_url = element.select("div.limit img").attr("src") manga.thumbnail_url = element.select("div.limit img").attr("src")
manga.title = element.select("div.tt h4").text() manga.title = element.select("div.tt h4").text()
element.select("div.animposx > a").first().let { element.select("div.animposx > a").first().let {
manga.setUrlWithoutDomain(it.attr("href")) manga.setUrlWithoutDomain(it.attr("href"))
} }
return manga return manga
} }
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val builtUrl = if (page == 1) "$baseUrl/daftar-komik/" else "$baseUrl/daftar-komik/page/$page/?order=" val builtUrl = if (page == 1) "$baseUrl/daftar-komik/" else "$baseUrl/daftar-komik/page/$page/?order="
val url = builtUrl.toHttpUrlOrNull()!!.newBuilder() val url = builtUrl.toHttpUrlOrNull()!!.newBuilder()
url.addQueryParameter("title", query) url.addQueryParameter("title", query)
url.addQueryParameter("page", page.toString()) url.addQueryParameter("page", page.toString())
filters.forEach { filter -> filters.forEach { filter ->
when (filter) { when (filter) {
is AuthorFilter -> { is AuthorFilter -> {
url.addQueryParameter("author", filter.state) url.addQueryParameter("author", filter.state)
} }
is YearFilter -> { is YearFilter -> {
url.addQueryParameter("yearx", filter.state) url.addQueryParameter("yearx", filter.state)
} }
is StatusFilter -> { is StatusFilter -> {
val status = when (filter.state) { val status = when (filter.state) {
Filter.TriState.STATE_INCLUDE -> "completed" Filter.TriState.STATE_INCLUDE -> "completed"
Filter.TriState.STATE_EXCLUDE -> "ongoing" Filter.TriState.STATE_EXCLUDE -> "ongoing"
else -> "" else -> ""
} }
url.addQueryParameter("status", status) url.addQueryParameter("status", status)
} }
is TypeFilter -> { is TypeFilter -> {
url.addQueryParameter("type", filter.toUriPart()) url.addQueryParameter("type", filter.toUriPart())
} }
is SortByFilter -> { is SortByFilter -> {
url.addQueryParameter("order", filter.toUriPart()) url.addQueryParameter("order", filter.toUriPart())
} }
is GenreListFilter -> { is GenreListFilter -> {
filter.state filter.state
.filter { it.state != Filter.TriState.STATE_IGNORE } .filter { it.state != Filter.TriState.STATE_IGNORE }
.forEach { url.addQueryParameter("genre[]", it.id) } .forEach { url.addQueryParameter("genre[]", it.id) }
} }
} }
} }
return GET(url.build().toString(), headers) return GET(url.build().toString(), headers)
} }
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("div.infoanime").first() val infoElement = document.select("div.infoanime").first()
val descElement = document.select("div.desc > .entry-content.entry-content-single").first() val descElement = document.select("div.desc > .entry-content.entry-content-single").first()
val sepName = infoElement.select(".infox > .spe > span:nth-child(2)").last() val sepName = infoElement.select(".infox > .spe > span:nth-child(2)").last()
val manga = SManga.create() val manga = SManga.create()
// need authorCleaner to take "pengarang:" string to remove it from author // need authorCleaner to take "pengarang:" string to remove it from author
val authorCleaner = document.select(".infox .spe b:contains(Pengarang)").text() val authorCleaner = document.select(".infox .spe b:contains(Pengarang)").text()
manga.author = document.select(".infox .spe span:contains(Pengarang)").text().substringAfter(authorCleaner) manga.author = document.select(".infox .spe span:contains(Pengarang)").text().substringAfter(authorCleaner)
manga.artist = manga.author manga.artist = manga.author
val genres = mutableListOf<String>() val genres = mutableListOf<String>()
infoElement.select(".infox > .genre-info > a").forEach { element -> infoElement.select(".infox > .genre-info > a").forEach { element ->
val genre = element.text() val genre = element.text()
genres.add(genre) genres.add(genre)
} }
manga.genre = genres.joinToString(", ") manga.genre = genres.joinToString(", ")
manga.status = parseStatus(infoElement.select(".infox > .spe > span:nth-child(1)").text()) manga.status = parseStatus(infoElement.select(".infox > .spe > span:nth-child(1)").text())
manga.description = descElement.select("p").text() manga.description = descElement.select("p").text()
manga.thumbnail_url = document.select(".thumb > img:nth-child(1)").attr("src") manga.thumbnail_url = document.select(".thumb > img:nth-child(1)").attr("src")
return manga return manga
} }
private fun parseStatus(element: String): Int = when { private fun parseStatus(element: String): Int = when {
element.toLowerCase().contains("berjalan") -> SManga.ONGOING element.contains("berjalan", true) -> SManga.ONGOING
element.toLowerCase().contains("tamat") -> SManga.COMPLETED element.contains("tamat", true) -> SManga.COMPLETED
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
override fun chapterListSelector() = "#chapter_list li" override fun chapterListSelector() = "#chapter_list li"
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select(".lchx a").first() val urlElement = element.select(".lchx a").first()
val chapter = SChapter.create() val chapter = SChapter.create()
chapter.setUrlWithoutDomain(urlElement.attr("href")) chapter.setUrlWithoutDomain(urlElement.attr("href"))
chapter.name = urlElement.text() chapter.name = urlElement.text()
chapter.date_upload = element.select(".dt a").first()?.text()?.let { parseChapterDate(it) } ?: 0 chapter.date_upload = element.select(".dt a").first()?.text()?.let { parseChapterDate(it) } ?: 0
return chapter return chapter
} }
fun parseChapterDate(date: String): Long { fun parseChapterDate(date: String): Long {
return if (date.contains("lalu")) { return if (date.contains("lalu")) {
val value = date.split(' ')[0].toInt() val value = date.split(' ')[0].toInt()
when { when {
"detik" in date -> Calendar.getInstance().apply { "detik" in date -> Calendar.getInstance().apply {
add(Calendar.SECOND, value * -1) add(Calendar.SECOND, value * -1)
}.timeInMillis }.timeInMillis
"menit" in date -> Calendar.getInstance().apply { "menit" in date -> Calendar.getInstance().apply {
add(Calendar.MINUTE, value * -1) add(Calendar.MINUTE, value * -1)
}.timeInMillis }.timeInMillis
"jam" in date -> Calendar.getInstance().apply { "jam" in date -> Calendar.getInstance().apply {
add(Calendar.HOUR_OF_DAY, value * -1) add(Calendar.HOUR_OF_DAY, value * -1)
}.timeInMillis }.timeInMillis
"hari" in date -> Calendar.getInstance().apply { "hari" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * -1) add(Calendar.DATE, value * -1)
}.timeInMillis }.timeInMillis
"minggu" in date -> Calendar.getInstance().apply { "minggu" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * 7 * -1) add(Calendar.DATE, value * 7 * -1)
}.timeInMillis }.timeInMillis
"bulan" in date -> Calendar.getInstance().apply { "bulan" in date -> Calendar.getInstance().apply {
add(Calendar.MONTH, value * -1) add(Calendar.MONTH, value * -1)
}.timeInMillis }.timeInMillis
"tahun" in date -> Calendar.getInstance().apply { "tahun" in date -> Calendar.getInstance().apply {
add(Calendar.YEAR, value * -1) add(Calendar.YEAR, value * -1)
}.timeInMillis }.timeInMillis
else -> { else -> {
0L 0L
} }
} }
} else { } else {
try { try {
dateFormat.parse(date)?.time ?: 0 dateFormat.parse(date)?.time ?: 0
} catch (_: Exception) { } catch (_: Exception) {
0L 0L
} }
} }
} }
override fun prepareNewChapter(chapter: SChapter, manga: SManga) { override fun prepareNewChapter(chapter: SChapter, manga: SManga) {
val basic = Regex("""Chapter\s([0-9]+)""") val basic = Regex("""Chapter\s([0-9]+)""")
when { when {
basic.containsMatchIn(chapter.name) -> { basic.containsMatchIn(chapter.name) -> {
basic.find(chapter.name)?.let { basic.find(chapter.name)?.let {
chapter.chapter_number = it.groups[1]?.value!!.toFloat() chapter.chapter_number = it.groups[1]?.value!!.toFloat()
} }
} }
} }
} }
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>() val pages = mutableListOf<Page>()
var i = 0 var i = 0
document.select("div.imgch img").forEach { element -> document.select("div.imgch img").forEach { element ->
val url = element.attr("src") val url = element.attr("src")
i++ i++
if (url.isNotEmpty()) { if (url.isNotEmpty()) {
pages.add(Page(i, "", url)) pages.add(Page(i, "", url))
} }
} }
return pages return pages
} }
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not Used") override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not Used")
private class AuthorFilter : Filter.Text("Author") private class AuthorFilter : Filter.Text("Author")
private class YearFilter : Filter.Text("Year") private class YearFilter : Filter.Text("Year")
private class TypeFilter : UriPartFilter( private class TypeFilter : UriPartFilter(
"Type", "Type",
arrayOf( arrayOf(
Pair("Default", ""), Pair("Default", ""),
Pair("Manga", "Manga"), Pair("Manga", "Manga"),
Pair("Manhwa", "Manhwa"), Pair("Manhwa", "Manhwa"),
Pair("Manhua", "Manhua"), Pair("Manhua", "Manhua"),
Pair("Comic", "Comic") Pair("Comic", "Comic")
) )
) )
private class SortByFilter : UriPartFilter( private class SortByFilter : UriPartFilter(
"Sort By", "Sort By",
arrayOf( arrayOf(
Pair("Default", ""), Pair("Default", ""),
Pair("A-Z", "title"), Pair("A-Z", "title"),
Pair("Z-A", "titlereverse"), Pair("Z-A", "titlereverse"),
Pair("Latest Update", "update"), Pair("Latest Update", "update"),
Pair("Latest Added", "latest"), Pair("Latest Added", "latest"),
Pair("Popular", "popular") Pair("Popular", "popular")
) )
) )
private class StatusFilter : UriPartFilter( private class StatusFilter : UriPartFilter(
"Status", "Status",
arrayOf( arrayOf(
Pair("All", ""), Pair("All", ""),
Pair("Ongoing", "ongoing"), Pair("Ongoing", "ongoing"),
Pair("Completed", "completed") Pair("Completed", "completed")
) )
) )
private class Genre(name: String, val id: String = name) : Filter.TriState(name) private class Genre(name: String, val id: String = name) : Filter.TriState(name)
private class GenreListFilter(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres) private class GenreListFilter(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
Filter.Header("NOTE: Ignored if using text search!"), Filter.Header("NOTE: Ignored if using text search!"),
Filter.Separator(), Filter.Separator(),
AuthorFilter(), AuthorFilter(),
YearFilter(), YearFilter(),
StatusFilter(), StatusFilter(),
TypeFilter(), TypeFilter(),
SortByFilter(), SortByFilter(),
GenreListFilter(getGenreList()) GenreListFilter(getGenreList())
) )
private fun getGenreList() = listOf( private fun getGenreList() = listOf(
Genre("Action", "action"), Genre("Action", "action"),
Genre("Adventure", "adventure"), Genre("Adventure", "adventure"),
Genre("Comedy", "comedy"), Genre("Comedy", "comedy"),
Genre("Crime", "crime"), Genre("Crime", "crime"),
Genre("Drama", "drama"), Genre("Drama", "drama"),
Genre("Fantasy", "fantasy"), Genre("Fantasy", "fantasy"),
Genre("Girls Love", "girls-love"), Genre("Girls Love", "girls-love"),
Genre("Harem", "harem"), Genre("Harem", "harem"),
Genre("Historical", "historical"), Genre("Historical", "historical"),
Genre("Horror", "horror"), Genre("Horror", "horror"),
Genre("Isekai", "isekai"), Genre("Isekai", "isekai"),
Genre("Magical Girls", "magical-girls"), Genre("Magical Girls", "magical-girls"),
Genre("Mecha", "mecha"), Genre("Mecha", "mecha"),
Genre("Medical", "medical"), Genre("Medical", "medical"),
Genre("Philosophical", "philosophical"), Genre("Philosophical", "philosophical"),
Genre("Psychological", "psychological"), Genre("Psychological", "psychological"),
Genre("Romance", "romance"), Genre("Romance", "romance"),
Genre("Sci-Fi", "sci-fi"), Genre("Sci-Fi", "sci-fi"),
Genre("Shoujo Ai", "shoujo-ai"), Genre("Shoujo Ai", "shoujo-ai"),
Genre("Shounen Ai", "shounen-ai"), Genre("Shounen Ai", "shounen-ai"),
Genre("Slice of Life", "slice-of-life"), Genre("Slice of Life", "slice-of-life"),
Genre("Sports", "sports"), Genre("Sports", "sports"),
Genre("Superhero", "superhero"), Genre("Superhero", "superhero"),
Genre("Thriller", "thriller"), Genre("Thriller", "thriller"),
Genre("Tragedy", "tragedy"), Genre("Tragedy", "tragedy"),
Genre("Wuxia", "wuxia"), Genre("Wuxia", "wuxia"),
Genre("Yuri", "yuri") Genre("Yuri", "yuri")
) )
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second
} }
} }