diff --git a/src/en/manmanga/build.gradle b/src/en/manmanga/build.gradle new file mode 100644 index 000000000..21e67b7a3 --- /dev/null +++ b/src/en/manmanga/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + appName = 'Tachiyomi: Man Manga' + pkgNameSuffix = 'en.manmanga' + extClass = '.ManManga' + extVersionCode = 1 + libVersion = '1.2' +} + +apply from: "$rootDir/common.gradle" diff --git a/src/en/manmanga/res/mipmap-hdpi/ic_launcher.png b/src/en/manmanga/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..173efd8c0 Binary files /dev/null and b/src/en/manmanga/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/en/manmanga/res/mipmap-mdpi/ic_launcher.png b/src/en/manmanga/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..5046fdd98 Binary files /dev/null and b/src/en/manmanga/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/en/manmanga/res/mipmap-xhdpi/ic_launcher.png b/src/en/manmanga/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..9e4af5bfa Binary files /dev/null and b/src/en/manmanga/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/en/manmanga/res/mipmap-xxhdpi/ic_launcher.png b/src/en/manmanga/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..163506098 Binary files /dev/null and b/src/en/manmanga/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/en/manmanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/manmanga/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..e31710844 Binary files /dev/null and b/src/en/manmanga/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/en/manmanga/res/web_hi_res_512.png b/src/en/manmanga/res/web_hi_res_512.png new file mode 100644 index 000000000..2dafcbbfb Binary files /dev/null and b/src/en/manmanga/res/web_hi_res_512.png differ diff --git a/src/en/manmanga/src/eu/kanade/tachiyomi/extension/en/manmanga/ManManga.kt b/src/en/manmanga/src/eu/kanade/tachiyomi/extension/en/manmanga/ManManga.kt new file mode 100644 index 000000000..42c8244d8 --- /dev/null +++ b/src/en/manmanga/src/eu/kanade/tachiyomi/extension/en/manmanga/ManManga.kt @@ -0,0 +1,140 @@ +package eu.kanade.tachiyomi.extension.en.manmanga + +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import eu.kanade.tachiyomi.util.asJsoup +import eu.kanade.tachiyomi.network.asObservableSuccess +import okhttp3.OkHttpClient +import rx.Observable +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import java.text.ParseException +import java.text.SimpleDateFormat + +class ManManga : ParsedHttpSource() { + override val name = "Man Manga" + + override val baseUrl = "https://m.manmanga.com" + + override val lang = "en" + + override val supportsLatest = true + + override val client: OkHttpClient = network.cloudflareClient + + companion object { + val dateFormat by lazy { + SimpleDateFormat("MMM dd, yyyy") + } + } + + + override fun popularMangaSelector() = "#scrollBox > #scrollContent > li > a" + + override fun latestUpdatesSelector() = popularMangaSelector() + + override fun searchMangaSelector() = popularMangaSelector() + + override fun popularMangaRequest(page: Int) + = GET("$baseUrl/category?sort=hot&page=$page", headers) + + override fun latestUpdatesRequest(page: Int) + = GET("$baseUrl/category?sort=new&page=$page", headers) + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList) + = GET("$baseUrl/search?keyword=$query&page=$page", headers) + + override fun popularMangaFromElement(element: Element) = SManga.create().apply { + setUrlWithoutDomain(element.attr("href")) + title = element.select("div.text > h4").text().trim() + } + + override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element) + + override fun searchMangaFromElement(element: Element) = SManga.create().apply { + setUrlWithoutDomain(element.attr("href")) + title = element.select("div.text > div.name > h4").text().trim() + } + + override fun popularMangaNextPageSelector() = "script:containsData(next_page_url):not(:containsData(false))" + + override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() + + override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() + + override fun searchMangaParse(response: Response): MangasPage { + val document = response.asJsoup() + + val mangas = document.select(searchMangaSelector()).map { element -> + searchMangaFromElement(element) + } + + val hasNextPage = searchMangaNextPageSelector()?.let { selector -> + document.select(selector).first() + } != null + + return MangasPage(mangas, hasNextPage) + } + + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return client.newCall(searchMangaRequest(page, query, filters)) + .asObservableSuccess() + .map { response -> + searchMangaParse(response) + } + } + + override fun mangaDetailsParse(document: Document) = SManga.create().apply{ + val getThumbnailUrl = document.select(".bg-box .bg").attr("style") + + author = document.select(".author").text().replace("Author:","").trim() + genre = document.select(".tags span").map { + it.text().trim() + }.joinToString(", ") + status = document.select(".type").text().replace("Status:","").trim().let { + parseStatus(it) + } + description = document.select(".inner-text").text().trim() + thumbnail_url = getThumbnailUrl.substring( getThumbnailUrl.indexOf("https://"), getThumbnailUrl.indexOf("')") ) + } + + private fun parseStatus(status: String) = when { + status.contains("Ongoing") -> SManga.ONGOING + status.contains("Completed") -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + + override fun chapterListParse(response: Response): List { + return super.chapterListParse(response).reversed() + } + + override fun chapterListSelector() = "dl.chapter-list > dd > ul > li > a" + + override fun chapterFromElement(element: Element) = SChapter.create().apply { + setUrlWithoutDomain(element.attr("href")) + name = element.attr("alt").trim() + } + + override fun pageListParse(document: Document): List { + val pages = mutableListOf() + + if(document.select("ul.img-list > li.unloaded > img").toString().isNotEmpty()) { + document.select("ul.img-list > li.unloaded > img").forEach { + val imgUrl = it.attr("data-src") + pages.add(Page(pages.size, "", "$imgUrl")) + } + } else { + document.select("ul.img-list > li.loaded > img").forEach { + val imgUrl = it.attr("data-src") + pages.add(Page(pages.size, "", "$imgUrl")) + } + } + return pages + } + + override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used") + + override fun getFilterList() = FilterList() +}