diff --git a/src/all/meituatop/AndroidManifest.xml b/src/all/meituatop/AndroidManifest.xml
new file mode 100644
index 000000000..30deb7f79
--- /dev/null
+++ b/src/all/meituatop/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/all/meituatop/build.gradle b/src/all/meituatop/build.gradle
new file mode 100644
index 000000000..dd7159295
--- /dev/null
+++ b/src/all/meituatop/build.gradle
@@ -0,0 +1,12 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+ext {
+ extName = 'Meitua.top'
+ pkgNameSuffix = 'all.meituatop'
+ extClass = '.MeituaTop'
+ extVersionCode = 1
+ isNsfw = true
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/all/meituatop/res/mipmap-hdpi/ic_launcher.png b/src/all/meituatop/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..ab954a480
Binary files /dev/null and b/src/all/meituatop/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/all/meituatop/res/mipmap-mdpi/ic_launcher.png b/src/all/meituatop/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..5842c008b
Binary files /dev/null and b/src/all/meituatop/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/all/meituatop/res/mipmap-xhdpi/ic_launcher.png b/src/all/meituatop/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..da15fb7ac
Binary files /dev/null and b/src/all/meituatop/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/all/meituatop/res/mipmap-xxhdpi/ic_launcher.png b/src/all/meituatop/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..169aa3c23
Binary files /dev/null and b/src/all/meituatop/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/all/meituatop/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/meituatop/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..a77d68b94
Binary files /dev/null and b/src/all/meituatop/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/all/meituatop/res/web_hi_res_512.png b/src/all/meituatop/res/web_hi_res_512.png
new file mode 100644
index 000000000..bfa3415d2
Binary files /dev/null and b/src/all/meituatop/res/web_hi_res_512.png differ
diff --git a/src/all/meituatop/src/eu/kanade/tachiyomi/extension/all/meituatop/MeituaTop.kt b/src/all/meituatop/src/eu/kanade/tachiyomi/extension/all/meituatop/MeituaTop.kt
new file mode 100644
index 000000000..51bdc73ad
--- /dev/null
+++ b/src/all/meituatop/src/eu/kanade/tachiyomi/extension/all/meituatop/MeituaTop.kt
@@ -0,0 +1,108 @@
+package eu.kanade.tachiyomi.extension.all.meituatop
+
+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.MangasPage
+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.HttpSource
+import eu.kanade.tachiyomi.util.asJsoup
+import okhttp3.HttpUrl.Companion.toHttpUrl
+import okhttp3.Request
+import okhttp3.Response
+import org.jsoup.select.Evaluator
+import rx.Observable
+import java.text.SimpleDateFormat
+import java.util.Locale
+
+// Uses MACCMS http://www.maccms.la/
+class MeituaTop : HttpSource() {
+ override val name = "Meitua.top"
+ override val lang = "all"
+ override val supportsLatest = false
+
+ override val baseUrl = "https://meitua.top"
+
+ override fun popularMangaRequest(page: Int) = GET("$baseUrl/arttype/0a-$page.html", headers)
+
+ override fun popularMangaParse(response: Response): MangasPage {
+ val document = response.asJsoup()
+ val mangas = document.selectFirst(Evaluator.Class("thumbnail-group")).children().map {
+ SManga.create().apply {
+ url = it.selectFirst(Evaluator.Tag("a")).attr("href")
+ val image = it.selectFirst(Evaluator.Tag("img"))
+ title = image.attr("alt")
+ thumbnail_url = image.attr("src")
+ val info = it.selectFirst(Evaluator.Tag("p")).ownText().split(" - ")
+ genre = info[0]
+ description = info[1]
+ status = SManga.COMPLETED
+ initialized = true
+ }
+ }
+ val lastPage = document.select(Evaluator.Class("page_link"))[3].attr("href")
+ val hasNextPage = document.location().pageNumber() != lastPage.pageNumber()
+ return MangasPage(mangas, hasNextPage)
+ }
+
+ override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException("Not used.")
+
+ override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException("Not used.")
+
+ override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
+ if (query.isNotEmpty()) {
+ val url = "$baseUrl/artsearch/-------.html".toHttpUrl().newBuilder()
+ .addQueryParameter("wd", query)
+ .addQueryParameter("page", page.toString())
+ .toString()
+ return GET(url, headers)
+ }
+
+ val filter = filters.firstOrNull() as? RegionFilter ?: return popularMangaRequest(page)
+ return GET("$baseUrl/arttype/${21 + filter.state}a-$page.html", headers)
+ }
+
+ override fun searchMangaParse(response: Response) = popularMangaParse(response)
+
+ override fun fetchMangaDetails(manga: SManga): Observable = Observable.just(manga)
+
+ override fun mangaDetailsParse(response: Response) = throw UnsupportedOperationException("Not used.")
+
+ override fun fetchChapterList(manga: SManga): Observable> {
+ val chapter = SChapter.create().apply {
+ url = manga.url
+ name = manga.title
+ date_upload = dateFormat.parse(manga.description!!)!!.time
+ chapter_number = -2f
+ }
+ return Observable.just(listOf(chapter))
+ }
+
+ override fun chapterListParse(response: Response) = throw UnsupportedOperationException("Not used.")
+
+ override fun pageListParse(response: Response): List {
+ val document = response.asJsoup()
+ val images = document.selectFirst(Evaluator.Class("ttnr")).select(Evaluator.Tag("img"))
+ .map { it.attr("src")!! }.distinct()
+ return images.mapIndexed { index, imageUrl -> Page(index, imageUrl = imageUrl) }
+ }
+
+ override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Not used.")
+
+ override fun getFilterList() = FilterList(
+ Filter.Header("Category (ignored for text search)"),
+ RegionFilter()
+ )
+
+ private class RegionFilter : Filter.Select(
+ "Region", arrayOf("All", "国产美女", "韩国美女", "台湾美女", "日本美女", "欧美美女", "泰国美女")
+ )
+
+ private fun String.pageNumber() = numberRegex.findAll(this).last().value.toInt()
+
+ private val numberRegex by lazy { Regex("""\d+""") }
+
+ private val dateFormat by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) }
+}