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) } +}