BakaManga multisrc (#12005)

* add BakaManga multisrc

* add icons

* add run file
This commit is contained in:
Vetle Ledaal 2022-06-04 16:43:49 +00:00 committed by GitHub
parent 3ab69af58b
commit 589254ae23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 415 additions and 359 deletions

View File

@ -0,0 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="BakaMangaGenerator" type="JetRunConfigurationType" nameIsGenerated="true">
<module name="tachiyomi-extensions.multisrc" />
<option name="VM_PARAMETERS" value="" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" value="eu.kanade.tachiyomi.multisrc.bakamanga.BakaMangaGenerator" />
<option name="WORKING_DIRECTORY" value="" />
<method v="2">
<option name="Make" enabled="true" />
<option name="Gradle.BeforeRunTask" enabled="true" tasks="ktFormat" externalProjectPath="$PROJECT_DIR$/multisrc" vmOptions="" scriptParameters="" />
<option name="Gradle.BeforeRunTask" enabled="true" tasks="ktLint" externalProjectPath="$PROJECT_DIR$/multisrc" vmOptions="" scriptParameters="" />
</method>
</configuration>
</component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -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"),
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

View File

@ -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"),
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

View File

@ -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"),
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -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"),
)
}

View File

@ -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<SChapter> =
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<Page> {
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<Pair<String, String>>) : UriPartFilter("Category", vals)
abstract fun getGenreList(): Array<Pair<String, String>>
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>) :
Filter.Select<String>(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
}
}

View File

@ -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<String>) = BakaMangaGenerator().createAll()
}
}

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.extension" />

View File

@ -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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

View File

@ -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<SChapter> {
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<Page> = mutableListOf<Page>().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<Pair<String, String>>) : 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<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
}

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.extension" />

View File

@ -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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

View File

@ -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<SChapter> {
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<Page> {
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<Pair<String, String>>) : 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<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
}