diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt index 177c106f..7706b51f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt @@ -176,7 +176,7 @@ internal abstract class GalleryAdultsParser( override suspend fun getPages(chapter: MangaChapter): List { val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml() val totalPages = doc.selectFirstOrThrow(selectTotalPage).text().toInt() - val rawUrl = chapter.url.replace("/1/", "/") + val rawUrl = chapter.url.removeSuffix("/").substringBeforeLast("/") + "/" return (1..totalPages).map { val url = "$rawUrl$it/" MangaPage( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/Hentai3.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/Hentai3.kt new file mode 100644 index 00000000..28ff59d8 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/Hentai3.kt @@ -0,0 +1,72 @@ +package org.koitharu.kotatsu.parsers.site.galleryadults.all + +import org.koitharu.kotatsu.parsers.MangaLoaderContext +import org.koitharu.kotatsu.parsers.MangaSourceParser +import org.koitharu.kotatsu.parsers.model.* +import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser +import org.koitharu.kotatsu.parsers.util.* + +@MangaSourceParser("HENTAI3", "3Hentai", type = ContentType.HENTAI) +internal class Hentai3(context: MangaLoaderContext) : + GalleryAdultsParser(context, MangaSource.HENTAI3, "3hentai.net") { + + override val selectGallery = ".doujin " + override val selectGalleryLink = "a" + override val selectGalleryTitle = ".title" + override val pathTagUrl = "/tags-popular/" + override val selectTags = "span.filter-elem" + override val selectTag = "div.tag-container:contains(Tags :) .filter-elem" + override val selectAuthor = "div.tag-container:contains(Artistes :) .filter-elem" + override val selectLanguageChapter = "div.tag-container:contains(Langues :) .filter-elem" + override val selectUrlChapter = "#main-cover a" + override val idImg = ".js-main-img" + override val listLanguage = arrayOf( + "/english", + "/spanish", + "/french", + "/italian", + "/portuguese", + "/russian", + "/japanese", + ) + + override suspend fun getListPage( + page: Int, + query: String?, + tags: Set?, + sortOrder: SortOrder, + ): List { + val tag = tags.oneOrThrowIfMany() + val url = buildString { + append("https://") + append(domain) + if (!tags.isNullOrEmpty()) { + if (tag?.key == "languageKey") { + append("/language") + append(tag.title) + append("/") + append(page) + } else { + append("/tags/") + append(tag?.key.orEmpty()) + append("/") + append(page) + } + } else if (!query.isNullOrEmpty()) { + append("/search/?q=") + append(query.urlEncoded()) + append("&page=") + append(page) + } else { + append("/") + append(page) + } + } + return parseMangaList(webClient.httpGet(url).parseHtml()) + } + + override suspend fun getPageUrl(page: MangaPage): String { + val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml() + return doc.selectFirstOrThrow(idImg).src() ?: doc.parseFailed("Image src not found") + } +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/DarkScan.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/DarkScan.kt new file mode 100644 index 00000000..bb952008 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/DarkScan.kt @@ -0,0 +1,10 @@ +package org.koitharu.kotatsu.parsers.site.madara.en + +import org.koitharu.kotatsu.parsers.MangaLoaderContext +import org.koitharu.kotatsu.parsers.MangaSourceParser +import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.parsers.site.madara.MadaraParser + +@MangaSourceParser("DARKSCAN", "Dark-Scan", "en") +internal class DarkScan(context: MangaLoaderContext) : + MadaraParser(context, MangaSource.DARKSCAN, "dark-scan.com") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/fr/FrScan.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/fr/FrScan.kt index cd305497..09a09a3c 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/fr/FrScan.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/fr/FrScan.kt @@ -7,6 +7,4 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser @MangaSourceParser("FRSCAN", "Fr-Scan", "fr") internal class FrScan(context: MangaLoaderContext) : - MadaraParser(context, MangaSource.FRSCAN, "fr-scan.com") { - override val withoutAjax = true -} + MadaraParser(context, MangaSource.FRSCAN, "fr-scan.com") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/es/MiauScan.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/es/MiauScan.kt index 9231664c..6270faa5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/es/MiauScan.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/es/MiauScan.kt @@ -7,4 +7,4 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser @MangaSourceParser("MIAUSCAN", "MiauScan", "es") internal class MiauScan(context: MangaLoaderContext) : - MangaReaderParser(context, MangaSource.MIAUSCAN, "miauscans.com", pageSize = 20, searchPageSize = 20) + MangaReaderParser(context, MangaSource.MIAUSCAN, "miaucomics.org", pageSize = 20, searchPageSize = 10) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/TrWebtoon.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/TrWebtoon.kt index 525322b3..c79392b9 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/TrWebtoon.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/TrWebtoon.kt @@ -17,7 +17,7 @@ class TrWebtoon(context: MangaLoaderContext) : override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("trwebtoon.com") override val sortOrders: Set - get() = EnumSet.of(SortOrder.POPULARITY, SortOrder.ALPHABETICAL) + get() = EnumSet.of(SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.UPDATED) override suspend fun getListPage( page: Int, @@ -26,53 +26,90 @@ class TrWebtoon(context: MangaLoaderContext) : sortOrder: SortOrder, ): List { val tag = tags.oneOrThrowIfMany() - val url = buildString { - append("https://") - append(domain) - append("/webtoon-listesi") - append("?page=") - append(page) - when { - !query.isNullOrEmpty() -> { - append("&q=") - append(query.urlEncoded()) - } + val url = if (sortOrder == SortOrder.UPDATED && query.isNullOrEmpty() && tags.isNullOrEmpty()) { + buildString { + append("https://") + append(domain) + append("/son-eklenenler") + append("?page=") + append(page) + } + } else { + buildString { + append("https://") + append(domain) + append("/webtoon-listesi") + append("?page=") + append(page) + when { + !query.isNullOrEmpty() -> { + append("&q=") + append(query.urlEncoded()) + } - !tags.isNullOrEmpty() -> { - append("&genre=") - append(tag?.key.orEmpty()) + !tags.isNullOrEmpty() -> { + append("&genre=") + append(tag?.key.orEmpty()) + } + } + append("&sort=") + when (sortOrder) { + SortOrder.POPULARITY -> append("views&short_type=DESC") + SortOrder.ALPHABETICAL -> append("name&short_type=ASC") + else -> append("views&short_type=DESC") } - } - append("&sort=") - when (sortOrder) { - SortOrder.POPULARITY -> append("views&short_type=DESC") - SortOrder.ALPHABETICAL -> append("name&short_type=ASC") - else -> append("views&short_type=DESC") } } + val doc = webClient.httpGet(url).parseHtml() - return doc.select(".row .col-xl-4 .card-body").map { li -> - val href = li.selectFirstOrThrow("a").attrAsRelativeUrl("href") - Manga( - id = generateUid(href), - url = href, - publicUrl = href.toAbsoluteUrl(domain), - coverUrl = li.selectFirst("img")?.src().orEmpty(), - title = li.selectFirst(".table-responsive a")?.text().orEmpty(), - altTitle = null, - rating = li.selectFirst(".row .col-xl-4 .mt-2 .my-1 .text-muted")?.text()?.substringBefore("/") - ?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, - tags = emptySet(), - author = null, - state = when (doc.selectLast(".row .col-xl-4 .mt-2 .rounded-pill")?.text()) { - "Devam Ediyor", "Güncel" -> MangaState.ONGOING - "Tamamlandı" -> MangaState.FINISHED - else -> null - }, - source = source, - isNsfw = isNsfwSource, - ) + val mangas = if (sortOrder == SortOrder.UPDATED && query.isNullOrEmpty() && tags.isNullOrEmpty()) { + doc.select(".page-content div.bslist_item").map { li -> + val href = li.selectFirstOrThrow("a").attrAsRelativeUrl("href") + Manga( + id = generateUid(href), + url = href, + publicUrl = href.toAbsoluteUrl(domain), + coverUrl = li.selectFirst(".figure img")?.src().orEmpty(), + title = li.selectFirst(".title")?.text().orEmpty(), + altTitle = null, + rating = RATING_UNKNOWN, + tags = emptySet(), + author = null, + state = when (doc.selectFirst("d-inline .badge")?.text()) { + "Devam Ediyor", "Güncel" -> MangaState.ONGOING + "Tamamlandı" -> MangaState.FINISHED + else -> null + }, + source = source, + isNsfw = isNsfwSource, + ) + } + } else { + doc.select(".row .col-xl-4 .card-body").map { li -> + val href = li.selectFirstOrThrow("a").attrAsRelativeUrl("href") + Manga( + id = generateUid(href), + url = href, + publicUrl = href.toAbsoluteUrl(domain), + coverUrl = li.selectFirst("img")?.src().orEmpty(), + title = li.selectFirst(".table-responsive a")?.text().orEmpty(), + altTitle = null, + rating = li.selectFirst(".row .col-xl-4 .mt-2 .my-1 .text-muted")?.text()?.substringBefore("/") + ?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, + tags = emptySet(), + author = null, + state = when (doc.selectLast(".row .col-xl-4 .mt-2 .rounded-pill")?.text()) { + "Devam Ediyor", "Güncel" -> MangaState.ONGOING + "Tamamlandı" -> MangaState.FINISHED + else -> null + }, + source = source, + isNsfw = isNsfwSource, + ) + } } + + return mangas } override suspend fun getTags(): Set {