From fadf8861e7f2cdfbc620d55e2265e7ca594bbbed Mon Sep 17 00:00:00 2001 From: devi Date: Sun, 14 Jul 2024 14:17:17 +0200 Subject: [PATCH] Rm BrMangas close #454 rm PowerManga close #462 Add MangaNinja close #897 Add Grimelek close #375 Add OpiaToon close#374 Add login on madara Fix ManhwaFreak --- .../parsers/site/foolslide/it/PowerManga.kt | 2 + .../parsers/site/madara/MadaraParser.kt | 30 ++- .../parsers/site/madara/pt/MangaNinja.kt | 12 + .../parsers/site/madara/tr/GloryManga.kt | 1 + .../parsers/site/madara/tr/Grimelek.kt | 14 ++ .../parsers/site/madara/tr/OpiaToon.kt | 13 ++ .../parsers/site/mangareader/en/FreakScans.kt | 2 + .../site/mangareader/en/ManhwaFreak.kt | 210 +----------------- .../parsers/site/mmrcms/es/MangaDoor.kt | 2 + .../kotatsu/parsers/site/pt/BrMangas.kt | 2 + 10 files changed, 78 insertions(+), 210 deletions(-) create mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/pt/MangaNinja.kt create mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/Grimelek.kt create mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/OpiaToon.kt diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/it/PowerManga.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/it/PowerManga.kt index 39f6844d..053179a8 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/it/PowerManga.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/it/PowerManga.kt @@ -1,10 +1,12 @@ package org.koitharu.kotatsu.parsers.site.foolslide.it +import org.koitharu.kotatsu.parsers.Broken 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.foolslide.FoolSlideParser +@Broken @MangaSourceParser("POWERMANGA", "PowerManga", "it") internal class PowerManga(context: MangaLoaderContext) : FoolSlideParser(context, MangaSource.POWERMANGA, "reader.powermanga.org") { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/MadaraParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/MadaraParser.kt index 5f43a3fc..ff5120fa 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/MadaraParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/MadaraParser.kt @@ -7,8 +7,11 @@ import org.json.JSONObject import org.jsoup.nodes.Document import org.jsoup.nodes.Element import org.koitharu.kotatsu.parsers.MangaLoaderContext +import org.koitharu.kotatsu.parsers.MangaParserAuthProvider import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey +import org.koitharu.kotatsu.parsers.exception.AuthRequiredException +import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* import java.text.DateFormat @@ -20,7 +23,7 @@ internal abstract class MadaraParser( source: MangaSource, domain: String, pageSize: Int = 12, -) : PagedMangaParser(context, source, pageSize) { +) : PagedMangaParser(context, source, pageSize), MangaParserAuthProvider { override val configKeyDomain = ConfigKey.Domain(domain) @@ -31,6 +34,28 @@ internal abstract class MadaraParser( keys.add(userAgentKey) } + override val authUrl: String + get() = "https://${domain}" + + override val isAuthorized: Boolean + get() { + return context.cookieJar.getCookies(domain).any { + it.name.contains("wordpress_logged_in") + } + } + + override suspend fun getUsername(): String { + val body = webClient.httpGet("https://${domain}/").parseHtml().body() + return body.selectFirst(".c-user_name")?.text() + ?: run { + throw if (body.selectFirst("#loginform") != null) { + AuthRequiredException(source) + } else { + body.parseFailed("Cannot find username") + } + } + } + override val isMultipleTagsSupported = false override val availableSortOrders: Set = EnumSet.of( @@ -557,7 +582,8 @@ internal abstract class MadaraParser( val doc = webClient.httpGet(fullUrl).parseHtml() val chapterProtector = doc.getElementById("chapter-protector-data") if (chapterProtector == null) { - val root = doc.body().selectFirstOrThrow(selectBodyPage) + val root = doc.body().selectFirst(selectBodyPage) + ?: throw ParseException("No image found, try to log in", fullUrl) return root.select(selectPage).map { div -> val img = div.selectFirstOrThrow("img") val url = img.src()?.toRelativeUrl(domain) ?: div.parseFailed("Image src not found") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/pt/MangaNinja.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/pt/MangaNinja.kt new file mode 100644 index 00000000..9cacca2e --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/pt/MangaNinja.kt @@ -0,0 +1,12 @@ +package org.koitharu.kotatsu.parsers.site.madara.pt + +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("MANGANINJA", "MangaNinja", "pt") +internal class MangaNinja(context: MangaLoaderContext) : + MadaraParser(context, MangaSource.MANGANINJA, "manganinja.com", 10) { + override val datePattern: String = "dd/MM/yyyy" +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/GloryManga.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/GloryManga.kt index f640d06e..0146d295 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/GloryManga.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/GloryManga.kt @@ -5,6 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.site.madara.MadaraParser +//This source requires an account. @MangaSourceParser("GLORYMANGA", "GloryManga", "tr") internal class GloryManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.GLORYMANGA, "glorymanga.com", 18) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/Grimelek.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/Grimelek.kt new file mode 100644 index 00000000..bd7a9fbb --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/Grimelek.kt @@ -0,0 +1,14 @@ +package org.koitharu.kotatsu.parsers.site.madara.tr + +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 + +//This source requires an account. +@MangaSourceParser("GRIMELEK", "Grimelek", "tr") +internal class Grimelek(context: MangaLoaderContext) : + MadaraParser(context, MangaSource.GRIMELEK, "glorymanga.com", 20) { + override val datePattern = "d MMMM yyyy" + override val listUrl = "seri/" +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/OpiaToon.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/OpiaToon.kt new file mode 100644 index 00000000..d6da03e9 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/OpiaToon.kt @@ -0,0 +1,13 @@ +package org.koitharu.kotatsu.parsers.site.madara.tr + +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 + +//This source requires an account. +@MangaSourceParser("OPIATOON", "OpiaToon", "tr") +internal class OpiaToon(context: MangaLoaderContext) : + MadaraParser(context, MangaSource.OPIATOON, "opiatoon.biz", 20) { + override val datePattern = "d MMMM" +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/FreakScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/FreakScans.kt index f02dffa3..9fe61058 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/FreakScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/FreakScans.kt @@ -1,10 +1,12 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en +import org.koitharu.kotatsu.parsers.Broken 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.mangareader.MangaReaderParser +@Broken @MangaSourceParser("FREAKSCANS", "FreakScans", "en") internal class FreakScans(context: MangaLoaderContext) : MangaReaderParser(context, MangaSource.FREAKSCANS, "freakscans.com", pageSize = 20, searchPageSize = 20) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/ManhwaFreak.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/ManhwaFreak.kt index aa37348e..cd00fa41 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/ManhwaFreak.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/ManhwaFreak.kt @@ -1,216 +1,10 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en -import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser -import org.koitharu.kotatsu.parsers.util.* -import java.text.DateFormat -import java.text.SimpleDateFormat -import java.util.Calendar - -@MangaSourceParser("MANHWA_FREAK", "Manhwa-Freak.com", "en") +@MangaSourceParser("MANHWA_FREAK", "ManhwaFreak", "en") internal class ManhwaFreak(context: MangaLoaderContext) : - MangaReaderParser(context, MangaSource.MANHWA_FREAK, "manhwa-freak.com", pageSize = 0, searchPageSize = 10) { - - override val selectMangaList = ".listupd .lastest-serie" - override val selectMangaListImg = "img" - override val availableStates: Set = emptySet() - override val isMultipleTagsSupported = false - override val isTagsExclusionSupported = false - - override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { - val url = buildString { - append("https://") - append(domain) - - when (filter) { - - is MangaListFilter.Search -> { - append("/page/") - append(page.toString()) - append("/?s=") - append(filter.query.urlEncoded()) - } - - is MangaListFilter.Advanced -> { - if (page > 1) { - return emptyList() - } - - if (filter.tags.isNotEmpty()) { - filter.tags.oneOrThrowIfMany()?.let { - append("/genres/?genre=") - append(it.key) - } - } else { - append(listUrl) - append("/?order=") - append( - when (filter.sortOrder) { - SortOrder.ALPHABETICAL -> "az" - SortOrder.NEWEST -> "new" - SortOrder.POPULARITY -> "views" - SortOrder.UPDATED -> "" - else -> "" - }, - ) - } - } - - null -> { - append(listUrl) - } - } - } - return parseMangaList(webClient.httpGet(url).parseHtml()) - } - - override suspend fun getAvailableTags(): Set { - val doc = webClient.httpGet("https://$domain/genres/").parseHtml() - return doc.select("ul.genre-list li a").mapNotNullToSet { a -> - val href = a.attr("href").substringAfterLast("=") - MangaTag( - key = href, - title = a.text(), - source = source, - ) - } - } - - override suspend fun getDetails(manga: Manga): Manga { - val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() - val dateFormat = SimpleDateFormat(datePattern, sourceLocale) - val chapters = docs.select("div.chapter-li a").mapChapters(reversed = true) { index, a -> - val url = a.attrAsRelativeUrl("href") - val dateText = a.selectFirst(".chapter-info p.new")?.text() ?: a.select(".chapter-info p")[1].text() - MangaChapter( - id = generateUid(url), - name = a.selectFirst(".chapter-info p:contains(Chapter)")?.text() ?: "Chapter ${index + 1}", - url = url, - number = index + 1f, - volume = 0, - scanlator = null, - uploadDate = if (dateText == "NEW") { - parseChapterDate( - dateFormat, - "today", - ) - } else { - parseChapterDate( - dateFormat, - dateText, - ) - }, - branch = null, - source = source, - ) - } - return parseInfo(docs, manga, chapters) - } - - override suspend fun parseInfo(docs: Document, manga: Manga, chapters: List): Manga { - val tagMap = getOrCreateTagMap() - val selectTag = docs.requireElementById("info").select("div:contains(Genre) > p:last-child").text().split(",") - val tags = selectTag.mapNotNullToSet { tagMap[it] } - val mangaState = docs.requireElementById("info").select("div:contains(Status) > p:last-child").text().let { - when (it) { - "Ongoing" -> MangaState.ONGOING - "Completed" -> MangaState.FINISHED - else -> null - } - } - val author = docs.requireElementById("info").select("div:contains(Author(s)) > p:last-child").text() - return manga.copy( - altTitle = docs.requireElementById("info").select("div:contains(Alternative) > p:last-child").text(), - description = docs.requireElementById("summary").html(), - state = mangaState, - author = author, - isNsfw = manga.isNsfw, - tags = tags, - chapters = chapters, - ) - } - - private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long { - // Clean date (e.g. 5th December 2019 to 5 December 2019) before parsing it - val d = date?.lowercase() ?: return 0 - return when { - d.endsWith(" ago") -> parseRelativeDate(date) - // Handle 'yesterday' and 'today', using midnight - d.startsWith("year") -> Calendar.getInstance().apply { - add(Calendar.DAY_OF_MONTH, -1) // yesterday - set(Calendar.HOUR_OF_DAY, 0) - set(Calendar.MINUTE, 0) - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - }.timeInMillis - - d.startsWith("today") -> Calendar.getInstance().apply { - set(Calendar.HOUR_OF_DAY, 0) - set(Calendar.MINUTE, 0) - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - }.timeInMillis - - date.contains(Regex("""\d(st|nd|rd|th)""")) -> date.split(" ").map { - if (it.contains(Regex("""\d\D\D"""))) { - it.replace(Regex("""\D"""), "") - } else { - it - } - }.let { dateFormat.tryParse(it.joinToString(" ")) } - - else -> dateFormat.tryParse(date) - } - } - - // Parses dates in this form: - // 21 hours ago - private fun parseRelativeDate(date: String): Long { - val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0 - val cal = Calendar.getInstance() - return when { - WordSet( - "day", - "days", - "d", - ).anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis - - WordSet( - "hour", - "hours", - "h", - ).anyWordIn(date) -> cal.apply { - add( - Calendar.HOUR, - -number, - ) - }.timeInMillis - - WordSet( - "minute", - "minutes", - "mins", - ).anyWordIn(date) -> cal.apply { - add( - Calendar.MINUTE, - -number, - ) - }.timeInMillis - - WordSet("second").anyWordIn(date) -> cal.apply { - add( - Calendar.SECOND, - -number, - ) - }.timeInMillis - - WordSet("month", "months").anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis - WordSet("year").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis - else -> 0 - } - } -} + MangaReaderParser(context, MangaSource.MANHWA_FREAK, "manhwafreak.site", pageSize = 20, searchPageSize = 10) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/es/MangaDoor.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/es/MangaDoor.kt index 727f748a..6139b0ba 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/es/MangaDoor.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/es/MangaDoor.kt @@ -1,11 +1,13 @@ package org.koitharu.kotatsu.parsers.site.mmrcms.es +import org.koitharu.kotatsu.parsers.Broken 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.mmrcms.MmrcmsParser import java.util.Locale +@Broken @MangaSourceParser("MANGADOOR", "MangaDoor", "es") internal class MangaDoor(context: MangaLoaderContext) : MmrcmsParser(context, MangaSource.MANGADOOR, "mangadoor.com") { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/BrMangas.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/BrMangas.kt index abf5bcfb..41cbc078 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/BrMangas.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/BrMangas.kt @@ -1,6 +1,7 @@ package org.koitharu.kotatsu.parsers.site.pt import okhttp3.Headers +import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.PagedMangaParser @@ -10,6 +11,7 @@ import org.koitharu.kotatsu.parsers.network.UserAgents import org.koitharu.kotatsu.parsers.util.* import java.util.* +@Broken @MangaSourceParser("BRMANGAS", "BrMangas", "pt") internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.BRMANGAS, 25) {