diff --git a/.run/BakaMangaGenerator.run.xml b/.run/BakaMangaGenerator.run.xml new file mode 100644 index 000000000..b0cc06ee6 --- /dev/null +++ b/.run/BakaMangaGenerator.run.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..76c8c3f52 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..f424825d8 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..f9cbb9e40 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..0e573f61c Binary files /dev/null and b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..fcb0be641 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhuamanganet/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhuamanganet/res/web_hi_res_512.png b/multisrc/overrides/bakamanga/manhuamanganet/res/web_hi_res_512.png new file mode 100644 index 000000000..e55492a09 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhuamanganet/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/bakamanga/manhuamanganet/src/ManhuaMangaNet.kt b/multisrc/overrides/bakamanga/manhuamanganet/src/ManhuaMangaNet.kt new file mode 100644 index 000000000..3d484c802 --- /dev/null +++ b/multisrc/overrides/bakamanga/manhuamanganet/src/ManhuaMangaNet.kt @@ -0,0 +1,48 @@ +package eu.kanade.tachiyomi.extension.en.manhuamanganet + +import eu.kanade.tachiyomi.multisrc.bakamanga.BakaManga + +class ManhuaMangaNet : BakaManga( + "ManhuaManga.net", + "https://manhuamanga.net", + "en" +) { + override fun getGenreList() = arrayOf( + Pair("All", ""), + Pair("Action", "action"), + Pair("Adventure", "adventure"), + Pair("Based on a Novel", "based-on-a-novel"), + Pair("Comedy", "comedy"), + Pair("Comic", "comic"), + Pair("Cooking", "cooking"), + Pair("Drama", "drama"), + Pair("Ecchi", "ecchi"), + Pair("Fantasy", "fantasy"), + Pair("Harem", "harem"), + Pair("Historical", "historical"), + Pair("Horror", "horror"), + Pair("Isekai", "isekai"), + Pair("Josei", "josei"), + Pair("Magic", "magic"), + Pair("Manhua", "manhua"), + Pair("Manhwa", "manhwa"), + Pair("Martial Arts", "martial-arts"), + Pair("Mecha", "mecha"), + Pair("Medical", "medical"), + Pair("Mystery", "mystery"), + Pair("Psychological", "psychological"), + Pair("Reincarnation", "reincarnation"), + Pair("Romance", "romance"), + Pair("RPG", "rpg"), + Pair("School Life", "school-life"), + Pair("Sci-fi", "sci-fi"), + Pair("Seinen", "seinen"), + Pair("Shoujo", "shoujo"), + Pair("Shounen", "shounen"), + Pair("Slice of Life", "slice-of-life"), + Pair("Supernatural", "supernatural"), + Pair("Tragedy", "tragedy"), + Pair("Webtoon", "webtoon"), + Pair("Zombie", "zombie"), + ) +} diff --git a/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..7f9090fc4 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..35510c59a Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..227a32f02 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..fe01d68cd Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..e1944a0b5 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwamanganet/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwamanganet/res/web_hi_res_512.png b/multisrc/overrides/bakamanga/manhwamanganet/res/web_hi_res_512.png new file mode 100644 index 000000000..a2a5156da Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwamanganet/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/bakamanga/manhwamanganet/src/ManhwaMangaNet.kt b/multisrc/overrides/bakamanga/manhwamanganet/src/ManhwaMangaNet.kt new file mode 100644 index 000000000..1ab29561b --- /dev/null +++ b/multisrc/overrides/bakamanga/manhwamanganet/src/ManhwaMangaNet.kt @@ -0,0 +1,55 @@ +package eu.kanade.tachiyomi.extension.en.manhwamanganet + +import eu.kanade.tachiyomi.multisrc.bakamanga.BakaManga + +class ManhwaMangaNet : BakaManga( + "ManhwaManga.net", + "https://manhwamanga.net", + "en" +) { + override fun getGenreList() = arrayOf( + Pair("All", ""), + Pair("Action", "action"), + Pair("Adult", "adult"), + Pair("Adventure", "adventure"), + Pair("BL", "bl"), + Pair("Comedy", "comedy"), + Pair("Comics", "comics"), + Pair("Doujinshi", "doujinshi"), + Pair("Drama", "drama"), + Pair("Ecchi", "ecchi"), + Pair("Fantasy", "fantasy"), + Pair("Gender Bender", "gender-bender"), + Pair("GL", "gl"), + Pair("Harem", "harem"), + Pair("Hentai", "hentai"), + Pair("Historical", "historical"), + Pair("Horror", "horror"), + Pair("Isekai", "isekai"), + Pair("Josei", "josei"), + Pair("Manhwa", "manhwa"), + Pair("Martial Arts", "martial-arts"), + Pair("Mature", "mature"), + Pair("Mecha", "mecha"), + Pair("Mystery", "mystery"), + Pair("NTR", "ntr"), + Pair("Psychological", "psychological"), + Pair("Raw", "raw"), + Pair("Romance", "romance"), + Pair("School Life", "school-life"), + Pair("Sci-fi", "sci-fi"), + Pair("Seinen", "seinen"), + Pair("Shoujo", "shoujo"), + Pair("Shounen", "shounen"), + Pair("Slice of Life", "slice-of-life"), + Pair("Smut", "smut"), + Pair("Sports", "sports"), + Pair("Supernatural", "supernatural"), + Pair("Thriller", "thriller"), + Pair("Tragedy", "tragedy"), + Pair("Webtoon", "webtoon"), + Pair("Webtoons", "webtoons"), + Pair("Yaoi", "yaoi"), + Pair("Yuri", "yuri"), + ) +} diff --git a/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..32ea9d10c Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..a1e4fcd71 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..b6d29fc5b Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..3e545a58d Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..1c53e9207 Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwaxxl/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/manhwaxxl/res/web_hi_res_512.png b/multisrc/overrides/bakamanga/manhwaxxl/res/web_hi_res_512.png new file mode 100644 index 000000000..ba821393b Binary files /dev/null and b/multisrc/overrides/bakamanga/manhwaxxl/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/bakamanga/manhwaxxl/src/ManhwaXXL.kt b/multisrc/overrides/bakamanga/manhwaxxl/src/ManhwaXXL.kt new file mode 100644 index 000000000..07c2070ef --- /dev/null +++ b/multisrc/overrides/bakamanga/manhwaxxl/src/ManhwaXXL.kt @@ -0,0 +1,68 @@ +package eu.kanade.tachiyomi.extension.en.manhwaxxl + +import eu.kanade.tachiyomi.multisrc.bakamanga.BakaManga + +class ManhwaXXL : BakaManga( + "Manhwa XXL", + "https://manhwaxxl.com", + "en" +) { + override fun getGenreList() = arrayOf( + Pair("All", ""), + Pair("Action", "action"), + Pair("Adaptation", "adaptation"), + Pair("Adult", "adult"), + Pair("Adventure", "adventure"), + Pair("BL", "bl"), + Pair("Comedy", "comedy"), + Pair("Cooking", "cooking"), + Pair("Demons", "demons"), + Pair("Drama", "drama"), + Pair("Ecchi", "ecchi"), + Pair("Fantasy", "fantasy"), + Pair("Full color", "full-color"), + Pair("Game", "game"), + Pair("Gender Bender", "gender-bender"), + Pair("GL", "gl"), + Pair("Harem", "harem"), + Pair("Historical", "historical"), + Pair("Horror", "horror"), + Pair("Isekai", "isekai"), + Pair("Josei", "josei"), + Pair("Live action", "live-action"), + Pair("Love & Romance", "love-romance"), + Pair("Magic", "magic"), + Pair("Manga", "manga"), + Pair("Manhua", "manhua"), + Pair("Manhwa", "manhwa"), + Pair("Martial Arts", "martial-arts"), + Pair("Mature", "mature"), + Pair("Mecha", "mecha"), + Pair("Mystery", "mystery"), + Pair("Omegaverse", "omegaverse"), + Pair("Psychological", "psychological"), + Pair("Raw", "raw"), + Pair("Reincarnation", "reincarnation"), + Pair("Romance", "romance"), + Pair("RPG", "rpg"), + 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("Slice of Life", "slice-of-life"), + Pair("Smut", "smut"), + Pair("Sports", "sports"), + Pair("Supernatural", "supernatural"), + Pair("Thriller", "thriller"), + Pair("Tragedy", "tragedy"), + Pair("Vampire", "vampire"), + Pair("Vanilla", "vanilla"), + Pair("Webtoon", "webtoon"), + Pair("Webtoons", "webtoons"), + Pair("Yaoi", "yaoi"), + Pair("Yuri", "yuri"), + Pair("Zombie", "zombie"), + ) +} diff --git a/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..45ba914a3 Binary files /dev/null and b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..8dcf49908 Binary files /dev/null and b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..d2ee0b29a Binary files /dev/null and b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..979b03da4 Binary files /dev/null and b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..f97c41ccf Binary files /dev/null and b/multisrc/overrides/bakamanga/mwmanhwa/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/bakamanga/mwmanhwa/res/web_hi_res_512.png b/multisrc/overrides/bakamanga/mwmanhwa/res/web_hi_res_512.png new file mode 100644 index 000000000..0bedb66f0 Binary files /dev/null and b/multisrc/overrides/bakamanga/mwmanhwa/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/bakamanga/mwmanhwa/src/MWManhwa.kt b/multisrc/overrides/bakamanga/mwmanhwa/src/MWManhwa.kt new file mode 100644 index 000000000..0ec30735e --- /dev/null +++ b/multisrc/overrides/bakamanga/mwmanhwa/src/MWManhwa.kt @@ -0,0 +1,27 @@ +package eu.kanade.tachiyomi.extension.all.mwmanhwa + +import eu.kanade.tachiyomi.multisrc.bakamanga.BakaManga + +class MWManhwa : BakaManga( + "MWManhwa", + "https://mwmanhwa.net", + "all" +) { + override fun getGenreList() = arrayOf( + Pair("All", ""), + Pair("Action", "action"), + Pair("Comedy", "comedy"), + Pair("Drama", "drama"), + Pair("Ecchi", "ecchi"), + Pair("Fantasy", "fantasy"), + Pair("Gender Bender", "gender-bender"), + Pair("Harem", "harem"), + Pair("Mature", "mature"), + Pair("Psychological", "psychological"), + Pair("Raw", "adult"), + Pair("Romance", "romance"), + Pair("Seinen", "seinen"), + Pair("Slice of Life", "slice-of-life"), + Pair("Supernatural", "supernatural"), + ) +} diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakamanga/BakaManga.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakamanga/BakaManga.kt new file mode 100644 index 000000000..7c37e311c --- /dev/null +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakamanga/BakaManga.kt @@ -0,0 +1,176 @@ +package eu.kanade.tachiyomi.multisrc.bakamanga + +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import java.util.Calendar + +abstract class BakaManga( + override val name: String, + override val baseUrl: String, + override val lang: String +) : ParsedHttpSource() { + override val supportsLatest = true + + // Popular + override fun popularMangaRequest(page: Int): Request = + GET("$baseUrl/most-views/page/$page", headers) + + override fun popularMangaSelector(): String = + ".li_truyen" + + override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { + setUrlWithoutDomain(element.selectFirst("a").absUrl("href")) + title = element.selectFirst(".name").text() + thumbnail_url = element.selectFirst("img").absUrl("src") + } + + override fun popularMangaNextPageSelector(): String? = + ".page_redirect > a:last-child:not(.active)" + + // Search + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + return if (query.isNotEmpty()) { + val url = "$baseUrl/page/$page".toHttpUrl().newBuilder() + .addQueryParameter("s", query) + GET(url.toString(), headers) + } else { + val filterList = if (filters.isEmpty()) getFilterList() else filters + val genreFilter = filterList.find { it is GenreFilter } as GenreFilter + val url = "$baseUrl/category/${genreFilter.toUriPart()}/page/$page" + GET(url.toString(), headers) + } + } + + override fun searchMangaSelector(): String = + popularMangaSelector() + + override fun searchMangaFromElement(element: Element): SManga = + popularMangaFromElement(element) + + override fun searchMangaNextPageSelector(): String? = + popularMangaNextPageSelector() + + // Latest + override fun latestUpdatesRequest(page: Int): Request = + GET("$baseUrl/latest-updates/page/$page", headers) + + override fun latestUpdatesSelector(): String = + popularMangaSelector() + + override fun latestUpdatesFromElement(element: Element): SManga = + popularMangaFromElement(element) + + override fun latestUpdatesNextPageSelector(): String? = + popularMangaNextPageSelector() + + // Details + override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { + val info = document.selectFirst(".box_info") + title = info.selectFirst("h1").text() + artist = info.select(".info-item:contains(Artist:) > a").joinToString { it.text() } + + val descElements = info.select(".story-detail-info:matchText") + description = when { + descElements.size > 2 -> { + descElements.removeFirst() // "Summary:" + descElements.removeLast() // "-From example.com" + descElements.joinToString("\n") { it.text() } + } + else -> "" + } + + val altTitles = info.selectFirst(".info-item:contains(Alternate Title:)") + ?.text() + ?.removePrefix("Alternate Title:") + ?.trim() + + if (altTitles != null && altTitles.isNotEmpty()) { + description += "\n\nAlt title(s): $altTitles" + } + + genre = info.select(".post-categories > li > a").joinToString { it.text() } + status = info.selectFirst(".info-item:contains(Status:)").text() + .removePrefix("Status:") + .trim() + .toStatus() + + thumbnail_url = info.selectFirst(".box_info img").absUrl("src") + } + + // Chapters + override fun chapterListParse(response: Response): List = + super.chapterListParse(response).reversed() + + override fun chapterListSelector(): String = + ".list-chapters > .list-chapters > .box_list > .chapter-item" + + override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { + setUrlWithoutDomain(element.selectFirst("a").absUrl("href")) + name = element.selectFirst(".chap_name").text() + chapter_number = name + .substringAfter(' ') + .substringBefore(' ') + .toFloatOrNull() ?: -1f + + date_upload = parseRelativeDate(element.selectFirst(".chap_update").text()) + } + + private fun parseRelativeDate(date: String): Long { + val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0 + val cal = Calendar.getInstance() + + return when { + date.contains("year") -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis + date.contains("month") -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis + date.contains("week") -> cal.apply { add(Calendar.WEEK_OF_YEAR, -number) }.timeInMillis + date.contains("day") -> cal.apply { add(Calendar.DAY_OF_YEAR, -number) }.timeInMillis + date.contains("hour") -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis + date.contains("minute") -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis + date.contains("second") -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis + else -> 0 + } + } + + // Pages + override fun pageListParse(document: Document): List { + return document.select("noscript > img").mapIndexed { i, img -> + Page(i, document.location(), img.absUrl("src")) + } + } + + override fun imageUrlParse(document: Document): String = + "" + + // Filter + override fun getFilterList() = FilterList( + Filter.Header("NOTE: Ignored if using text search!"), + Filter.Separator(), + GenreFilter(getGenreList()) + ) + + class GenreFilter(vals: Array>) : UriPartFilter("Category", vals) + + abstract fun getGenreList(): Array> + + open class UriPartFilter(displayName: String, private val vals: Array>) : + Filter.Select(displayName, vals.map { it.first }.toTypedArray()) { + fun toUriPart() = vals[state].second + } + + // Other + private fun String.toStatus() = when (this) { + "Ongoing" -> SManga.ONGOING + "Completed" -> SManga.COMPLETED + else -> SManga.UNKNOWN + } +} diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakamanga/BakaMangaGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakamanga/BakaMangaGenerator.kt new file mode 100644 index 000000000..ff5325d52 --- /dev/null +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/bakamanga/BakaMangaGenerator.kt @@ -0,0 +1,24 @@ +package eu.kanade.tachiyomi.multisrc.bakamanga + +import generator.ThemeSourceData.SingleLang +import generator.ThemeSourceGenerator + +class BakaMangaGenerator : ThemeSourceGenerator { + override val themePkg = "bakamanga" + + override val themeClass = "BakaManga" + + override val baseVersionCode = 1 + + override val sources = listOf( + SingleLang("ManhuaManga.net", "https://manhuamanga.net", "en", className = "ManhuaMangaNet", overrideVersionCode = 2), + SingleLang("ManhwaManga.net", "https://manhwamanga.net", "en", isNsfw = true, className = "ManhwaMangaNet", overrideVersionCode = 7), + SingleLang("MWManhwa", "https://mwmanhwa.net", "all", isNsfw = true), + SingleLang("Manhwa XXL", "https://manhwaxxl.com", "en", isNsfw = true), + ) + + companion object { + @JvmStatic + fun main(args: Array) = BakaMangaGenerator().createAll() + } +} diff --git a/src/en/manhuamanga/AndroidManifest.xml b/src/en/manhuamanga/AndroidManifest.xml deleted file mode 100644 index 30deb7f79..000000000 --- a/src/en/manhuamanga/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/en/manhuamanga/build.gradle b/src/en/manhuamanga/build.gradle deleted file mode 100644 index 69f678745..000000000 --- a/src/en/manhuamanga/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -ext { - extName = 'ManhuaManga.net' - pkgNameSuffix = 'en.manhuamanga' - extClass = '.ManhuaManga' - extVersionCode = 2 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" diff --git a/src/en/manhuamanga/res/mipmap-hdpi/ic_launcher.png b/src/en/manhuamanga/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 580694e1b..000000000 Binary files a/src/en/manhuamanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhuamanga/res/mipmap-mdpi/ic_launcher.png b/src/en/manhuamanga/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 8efd2f57f..000000000 Binary files a/src/en/manhuamanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhuamanga/res/mipmap-xhdpi/ic_launcher.png b/src/en/manhuamanga/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index a600bdf93..000000000 Binary files a/src/en/manhuamanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhuamanga/res/mipmap-xxhdpi/ic_launcher.png b/src/en/manhuamanga/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index dd11d3f4e..000000000 Binary files a/src/en/manhuamanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhuamanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/manhuamanga/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index a24fb6f44..000000000 Binary files a/src/en/manhuamanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhuamanga/res/web_hi_res_512.png b/src/en/manhuamanga/res/web_hi_res_512.png deleted file mode 100644 index 2ef804be2..000000000 Binary files a/src/en/manhuamanga/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/manhuamanga/src/eu/kanade/tachiyomi/extension/en/manhuamanga/ManhuaManga.kt b/src/en/manhuamanga/src/eu/kanade/tachiyomi/extension/en/manhuamanga/ManhuaManga.kt deleted file mode 100644 index c5e279b02..000000000 --- a/src/en/manhuamanga/src/eu/kanade/tachiyomi/extension/en/manhuamanga/ManhuaManga.kt +++ /dev/null @@ -1,161 +0,0 @@ -package eu.kanade.tachiyomi.extension.en.manhuamanga - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.source.model.Filter -import eu.kanade.tachiyomi.source.model.FilterList -import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.model.SChapter -import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import eu.kanade.tachiyomi.util.asJsoup -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element - -class ManhuaManga : ParsedHttpSource() { - override val name = "ManhuaManga.net" - override val baseUrl = "https://manhuamanga.net" - override val lang = "en" - override val supportsLatest = true - - override fun popularMangaSelector() = ".home-truyendecu" - override fun latestUpdatesSelector() = popularMangaSelector() - override fun searchMangaSelector() = popularMangaSelector() - override fun chapterListSelector() = "#list-chapter > div.row > div > ul > li:nth-child(n)" - - override fun popularMangaNextPageSelector() = "li.active+li a[data-page]" - override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() - override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() - - override fun popularMangaRequest(page: Int): Request { - return GET("$baseUrl/most-views/page/$page", headers) - } - - override fun latestUpdatesRequest(page: Int): Request { - return GET("$baseUrl/latest-updates/page/$page", headers) - } - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - return if (query.isNotBlank()) { - GET("$baseUrl/?s=$query", headers) - } else { - val url = "$baseUrl/category/".toHttpUrlOrNull()!!.newBuilder() - filters.forEach { filter -> - when (filter) { - - is GenreFilter -> url.addPathSegment(filter.toUriPart()) - } - } - url.addPathSegment("page") - url.addPathSegment("$page") - GET(url.toString(), headers) - } - } - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.setUrlWithoutDomain(element.select("a").attr("href")) - manga.title = element.select("a").attr("title") - manga.thumbnail_url = element.select("a img").attr("src") - - return manga - } - override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element) - override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element) - - protected fun getXhrChapters(mangaId: String): Document { - val xhrHeaders = headersBuilder().add("Content-Type: application/x-www-form-urlencoded; charset=UTF-8") - .build() - val body = "action=tw_ajax&type=list_chap&id=$mangaId".toRequestBody(null) - return client.newCall(POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, body)).execute().asJsoup() - } - - override fun chapterListParse(response: Response): List { - val document = response.asJsoup() - val dataIdSelector = "input[id^=id_post]" - - return getXhrChapters(document.select(dataIdSelector).attr("value")).select("option").map { chapterFromElement(it) }.reversed() - } - - override fun chapterFromElement(element: Element): SChapter { - val chapter = SChapter.create() - element.let { urlElement -> - chapter.setUrlWithoutDomain(urlElement.attr("value")) - chapter.name = urlElement.text() - } - chapter.date_upload = 0 - - return chapter - } - - override fun mangaDetailsParse(document: Document) = SManga.create().apply { - title = document.select("h3.title").text() - description = document.select("div.desc-text > p").text() - thumbnail_url = document.select("div.books > div > img").attr("src") - author = document.select("div.info > div:nth-child(1) > a").attr("title") - genre = document.select("div.info > div:nth-child(2) > a").joinToString { it.text() } - status = document.select("div.info > div:nth-child(3) > span").text().let { - when { - it.contains("Ongoing") -> SManga.ONGOING - it.contains("Completed") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - } - } - - override fun pageListParse(document: Document): List = mutableListOf().apply { - document.select("p img").forEachIndexed { index, element -> - add(Page(index, "", element.attr("src"))) - } - } - - override fun imageUrlRequest(page: Page) = throw Exception("Not used") - override fun imageUrlParse(document: Document) = throw Exception("Not used") - - override fun getFilterList() = FilterList( - Filter.Header("NOTE: Ignored if using text search!"), - Filter.Separator(), - GenreFilter(getGenreList()) - ) - class GenreFilter(vals: Array>) : UriPartFilter("Category", vals) - - private fun getGenreList() = arrayOf( - Pair("All", ""), - Pair("Action", "action"), - Pair("Adventure", "adventure"), - Pair("Comedy", "comedy"), - Pair("Comic", "comic"), - Pair("Drama", "drama"), - Pair("Ecchi", "ecchi"), - Pair("Fantasy", "fantasy"), - Pair("Harem", "harem"), - Pair("Historical", "historical"), - Pair("Isekai", "isekai"), - Pair("Josei", "josei"), - Pair("Manhua", "manhua"), - Pair("Manhwa", "manhwa"), - Pair("Martial arts", "martial-arts"), - Pair("Moder", "moder"), - Pair("Mystery", "mystery"), - Pair("Psychological", "psychological"), - Pair("Romance", "romance"), - Pair("School Life", "school-life"), - Pair("Sci Fi", "sci-fi"), - Pair("Seinen", "seinen"), - Pair("Shoujo", "shoujo"), - Pair("Shounen", "shounen"), - Pair("Shounen ai", "shounen-ai"), - Pair("Slice of Life", "slice-of-life"), - Pair("Super power", "super-power"), - Pair("Tragedy", "tragedy"), - Pair("Webtoon", "webtoon"), - Pair("Webtoons", "webtoons"), - ) - open class UriPartFilter(displayName: String, private val vals: Array>) : - Filter.Select(displayName, vals.map { it.first }.toTypedArray()) { - fun toUriPart() = vals[state].second - } -} diff --git a/src/en/manhwamanga/AndroidManifest.xml b/src/en/manhwamanga/AndroidManifest.xml deleted file mode 100644 index 30deb7f79..000000000 --- a/src/en/manhwamanga/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/en/manhwamanga/build.gradle b/src/en/manhwamanga/build.gradle deleted file mode 100644 index 8b3d2738a..000000000 --- a/src/en/manhwamanga/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -ext { - extName = 'ManhwaManga.net' - pkgNameSuffix = 'en.manhwamanga' - extClass = '.ManhwaManga' - extVersionCode = 7 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" diff --git a/src/en/manhwamanga/res/mipmap-hdpi/ic_launcher.png b/src/en/manhwamanga/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index ef5e2ab53..000000000 Binary files a/src/en/manhwamanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhwamanga/res/mipmap-mdpi/ic_launcher.png b/src/en/manhwamanga/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 8cca76001..000000000 Binary files a/src/en/manhwamanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhwamanga/res/mipmap-xhdpi/ic_launcher.png b/src/en/manhwamanga/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index dfafe6efd..000000000 Binary files a/src/en/manhwamanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhwamanga/res/mipmap-xxhdpi/ic_launcher.png b/src/en/manhwamanga/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 4d91f8b3e..000000000 Binary files a/src/en/manhwamanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhwamanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/manhwamanga/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index a92c696a3..000000000 Binary files a/src/en/manhwamanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/manhwamanga/res/web_hi_res_512.png b/src/en/manhwamanga/res/web_hi_res_512.png deleted file mode 100644 index cda085eaf..000000000 Binary files a/src/en/manhwamanga/res/web_hi_res_512.png and /dev/null differ diff --git a/src/en/manhwamanga/src/eu/kanade/tachiyomi/extension/en/manhwamanga/ManhwaManga.kt b/src/en/manhwamanga/src/eu/kanade/tachiyomi/extension/en/manhwamanga/ManhwaManga.kt deleted file mode 100644 index 3e7c75672..000000000 --- a/src/en/manhwamanga/src/eu/kanade/tachiyomi/extension/en/manhwamanga/ManhwaManga.kt +++ /dev/null @@ -1,170 +0,0 @@ -package eu.kanade.tachiyomi.extension.en.manhwamanga - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.source.model.Filter -import eu.kanade.tachiyomi.source.model.FilterList -import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.model.SChapter -import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element - -class ManhwaManga : ParsedHttpSource() { - override val name = "ManhwaManga.net" - override val baseUrl = "https://mwmanhwa.net" - override val lang = "en" - override val supportsLatest = true - - override fun popularMangaSelector() = ".box_list .li_truyen" - override fun latestUpdatesSelector() = popularMangaSelector() - override fun searchMangaSelector() = popularMangaSelector() - override fun chapterListSelector() = "div.content_view div.list-chapters div.list-chapters div.box_list div.chapter-item.row" - - override fun popularMangaNextPageSelector() = "div.page_redirect a.active+ a[data-page]" - override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() - override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() - - override fun popularMangaRequest(page: Int): Request { - return GET("$baseUrl/most-views/page/$page", headers) - } - - override fun latestUpdatesRequest(page: Int): Request { - return GET("$baseUrl/latest-updates/page/$page", headers) - } - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - return if (query.isNotBlank()) { - GET("$baseUrl/?s=$query", headers) - } else { - val url = "$baseUrl/category/".toHttpUrlOrNull()!!.newBuilder() - filters.forEach { filter -> - when (filter) { - - is GenreFilter -> url.addPathSegment(filter.toUriPart()) - } - } - url.addPathSegment("page") - url.addPathSegment("$page") - GET(url.toString(), headers) - } - } - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.setUrlWithoutDomain(element.select("a").attr("href")) - manga.title = element.select("a").attr("title") - manga.thumbnail_url = element.select("a img").attr("src") - - return manga - } - override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element) - override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element) - - override fun chapterListParse(response: Response): List { - return super.chapterListParse(response).reversed() - } - - override fun chapterFromElement(element: Element): SChapter { - val chapter = SChapter.create() - - element.select("a").let { - chapter.setUrlWithoutDomain(it.attr("href")) - chapter.name = it.text() - } - chapter.date_upload = 0 - return chapter - } - - override fun mangaDetailsParse(document: Document) = SManga.create().apply { - title = document.select("h1").text() - description = document.select("div.story-detail-info").text() - thumbnail_url = document.select("div.box_info div.box_info_left div.img img").attr("src") - author = document.select(".box_info_right .info-item:nth-child(2)").text() - // genre = document.select("div.info > div:nth-child(2) > a").joinToString { it.text() } - status = document.select(".box_info_right .info-item:nth-child(4) span").text().let { - when { - it.contains("Ongoing") -> SManga.ONGOING - it.contains("Completed") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - } - } - - override fun pageListParse(document: Document): List { - return document.select("div.content_view_chap > p > img") - .mapIndexed { i, el -> Page(i, "", el.attr("data-lazy-src")) } - } - - override fun imageUrlRequest(page: Page) = throw Exception("Not used") - override fun imageUrlParse(document: Document) = throw Exception("Not used") - - override fun getFilterList() = FilterList( - Filter.Header("NOTE: Ignored if using text search!"), - Filter.Separator(), - GenreFilter(getGenreList()) - ) - class GenreFilter(vals: Array>) : UriPartFilter("Category", vals) - - private fun getGenreList() = arrayOf( - Pair("All", ""), - Pair("Action", "action"), - Pair("Adult", "adult"), - Pair("Adventure", "adventure"), - Pair("BL", "bl"), - Pair("Comedy", "comedy"), - Pair("Comic", "comic"), - Pair("Crime", "crime"), - Pair("Detective", "detective"), - Pair("Drama", "drama"), - Pair("Ecchi", "ecchi"), - Pair("Fantasy", "fantasy"), - Pair("Gender bender", "gender-bender"), - Pair("GL", "gl"), - Pair("Gossip", "gossip"), - Pair("Harem", "harem"), - Pair("HentaiVN.Net", "hentaivn"), - Pair("Historical", "historical"), - Pair("HoiHentai.Com", "hoihentai-com"), - Pair("Horror", "horror"), - Pair("Incest", "incest"), - Pair("Isekai", "isekai"), - Pair("Manhua", "manhua"), - Pair("Martial arts", "martial-arts"), - Pair("Mature", "mature"), - Pair("Mecha", "mecha"), - Pair("Medical", "medical"), - Pair("Monster/Tentacle", "monster-tentacle"), - Pair("Mystery", "mystery"), - Pair("Novel", "novel"), - Pair("Office Life", "office-life"), - Pair("One shot", "one-shot"), - Pair("Psychological", "psychological"), - Pair("Revenge", "revenge"), - Pair("Romance", "romance"), - Pair("School Life", "school-life"), - Pair("Sci Fi", "sci-fi"), - Pair("Seinen", "seinen"), - Pair("Shoujo", "shoujo"), - Pair("Shounen", "shounen"), - Pair("Slice of Life", "slice-of-life"), - Pair("Smut", "smut"), - Pair("Sports", "sports"), - Pair("Supernatural", "supernatural"), - Pair("Teenager", "teenager"), - Pair("Thriller", "thriller"), - Pair("Time Travel", "time-travel"), - Pair("Tragedy", "tragedy"), - Pair("Uncensored", "uncensored"), - Pair("Vampire", "vampire"), - Pair("Webtoon", "webtoon"), - Pair("Yaoi", "yaoi"), - Pair("Yuri", "yuri") - ) - open class UriPartFilter(displayName: String, private val vals: Array>) : - Filter.Select(displayName, vals.map { it.first }.toTypedArray()) { - fun toUriPart() = vals[state].second - } -}