diff --git a/src/zh/dmzj/build.gradle b/src/zh/dmzj/build.gradle new file mode 100644 index 000000000..ef3fac960 --- /dev/null +++ b/src/zh/dmzj/build.gradle @@ -0,0 +1,13 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + appName = 'Tachiyomi: Dmzj' + pkgNameSuffix = "zh.dmzj" + extClass = '.Dmzj' + extVersionCode = 1 + extVersionSuffix = 0 + libVersion = '1.0' +} + +apply from: "$rootDir/common.gradle" diff --git a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt new file mode 100644 index 000000000..ab596b15c --- /dev/null +++ b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt @@ -0,0 +1,260 @@ +package eu.kanade.tachiyomi.extension.zh.dmzj + +import android.net.Uri +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.HttpSource +import okhttp3.Request +import okhttp3.Response +import java.util.* +import kotlin.text.Regex + +import org.json.JSONArray; +import org.json.JSONObject; +/** + * Dmzj source + */ + +class Dmzj : HttpSource() { + override val lang = "zh" + private val TAG: String = "Dmzj" + override val supportsLatest = true + override val name = "动漫之家" + override val baseUrl = "http://v2.api.dmzj.com" + + private fun cleanUrl(url: String) = if (url.startsWith("//")) + "http:$url" + else url + + private fun mangaFromJSON1(json: String): MangasPage { + val arr = JSONArray(json) + val ret = ArrayList(arr.length()) + for (i in 0 until arr.length()) { + var obj = arr.getJSONObject(i) + var cid = obj.getString("id") + ret.add(SManga.create().apply { + title = obj.getString("name") + thumbnail_url = cleanUrl(obj.getString("cover")) + author = obj.optString("authors") + status = when(obj.getString("status_tag_id")) { + "2310" -> SManga.COMPLETED + "2309" -> SManga.ONGOING + else -> SManga.UNKNOWN + } + description = obj.getString("description") + url = "/comic/$cid.json" + }) + } + return MangasPage(ret, arr.length() != 0) + } + + private fun mangaFromJSON2(json: String): MangasPage { + val arr = JSONArray(json) + val ret = ArrayList(arr.length()) + for (i in 0 until arr.length()) { + var obj = arr.getJSONObject(i) + var cid = obj.getString("id") + ret.add(SManga.create().apply { + title = obj.getString("title") + thumbnail_url = obj.getString("cover") + author = obj.optString("authors") + status = when(obj.getString("status")) { + "已完结" -> SManga.COMPLETED + "连载中" -> SManga.ONGOING + else -> SManga.UNKNOWN + } + url = "/comic/$cid.json" + }) + } + return MangasPage(ret, arr.length() != 0) + } + + override fun popularMangaRequest(page: Int) = GET("http://v2.api.dmzj.com/classify/0/0/${page-1}.json") + + override fun popularMangaParse(response: Response) = searchMangaParse(response) + + override fun latestUpdatesRequest(page: Int) = GET("http://v2.api.dmzj.com/classify/0/1/${page-1}.json") + + override fun latestUpdatesParse(response: Response): MangasPage = searchMangaParse(response) + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + if (query != "") { + val uri = Uri.parse("http://s.acg.dmzj.com/comicsum/search.php").buildUpon() + uri.appendQueryParameter("s", query) + return GET(uri.toString()) + } else { + var params = filters.map { + if (it !is SortFilter && it is UriPartFilter) { + it.toUriPart() + } else "" + }.filter { it != "" }.joinToString("-") + if (params == "") { + params = "0" + } + + val order = filters.filter { it is SortFilter }.map { (it as UriPartFilter).toUriPart() }.joinToString("") + + return GET("http://v2.api.dmzj.com/classify/$params/$order/${page-1}.json") + } + } + + override fun searchMangaParse(response: Response): MangasPage { + val res = response.body()!!.string() + val r = Regex("g_search_data = (.*)") + val m = r.find(res) + if (m != null) { + return mangaFromJSON1(m.groupValues.get(1)) + } else { + return mangaFromJSON2(res) + } + } + + override fun mangaDetailsParse(response: Response) = SManga.create().apply { + val obj = JSONObject(response.body()!!.string()) + + title = obj.getString("title") + thumbnail_url = obj.getString("cover") + + var arr = obj.getJSONArray("authors") + var tmparr = ArrayList(arr.length()) + for (i in 0 until arr.length()) { + tmparr.add(arr.getJSONObject(i).getString("tag_name")) + } + author = tmparr.joinToString(", ") + + arr = obj.getJSONArray("types") + tmparr.clear() + for (i in 0 until arr.length()) { + tmparr.add(arr.getJSONObject(i).getString("tag_name")) + } + genre = tmparr.joinToString(", ") + + description = obj.getString("description") + } + + override fun chapterListParse(response: Response): List { + val obj = JSONObject(response.body()!!.string()) + val ret = ArrayList() + val cid = obj.getString("id") + val arr = obj.getJSONArray("chapters") + for (i in 0 until arr.length()) { + val obj2 = arr.getJSONObject(i) + val arr2 = obj2.getJSONArray("data") + val prefix = obj2.getString("title") + for (j in 0 until arr2.length()) { + val chapter = arr2.getJSONObject(j) + ret.add(SChapter.create().apply { + name = "$prefix: ${chapter.getString("chapter_title")}" + date_upload = chapter.getString("updatetime").toLong() + url = "/chapter/$cid/${chapter.getString("chapter_id")}.json" + }) + } + } + return ret + } + + override fun pageListParse(response: Response): List { + val obj = JSONObject(response.body()!!.string()) + val arr = obj.getJSONArray("page_url") + val ret = ArrayList(arr.length()) + for (i in 0 until arr.length()) { + ret.add(Page(i+1, "", arr.getString(i))) + } + return ret + } + + //Unused, we can get image urls directly from the chapter page + override fun imageUrlParse(response: Response) + = throw UnsupportedOperationException("This method should not be called!") + + override fun getFilterList() = FilterList( + SortFilter(), + GenreGroup(), + StatusFilter(), + TypeFilter(), + ReaderFilter() + ) + + private class GenreGroup : UriPartFilter("分类", arrayOf( + Pair("全部", ""), + Pair("冒险", "4"), + Pair("百合", "3243"), + Pair("生活", "3242"), + Pair("四格", "17"), + Pair("伪娘", "3244"), + Pair("悬疑", "3245"), + Pair("后宫", "3249"), + Pair("热血", "3248"), + Pair("耽美", "3246"), + Pair("其他", "16"), + Pair("恐怖", "14"), + Pair("科幻", "7"), + Pair("格斗", "6"), + Pair("欢乐向", "5"), + Pair("爱情", "8"), + Pair("侦探", "9"), + Pair("校园", "13"), + Pair("神鬼", "12"), + Pair("魔法", "11"), + Pair("竞技", "10"), + Pair("历史", "3250"), + Pair("战争", "3251"), + Pair("魔幻", "5806"), + Pair("扶她", "5345"), + Pair("东方", "5077"), + Pair("奇幻", "5848"), + Pair("轻小说", "6316"), + Pair("仙侠", "7900"), + Pair("搞笑", "7568"), + Pair("颜艺", "6437"), + Pair("性转换", "4518"), + Pair("高清单行", "4459"), + Pair("治愈", "3254"), + Pair("宅系", "3253"), + Pair("萌系", "3252"), + Pair("励志", "3255"), + Pair("节操", "6219"), + Pair("职场", "3328"), + Pair("西方魔幻", "3365"), + Pair("音乐舞蹈", "3326"), + Pair("机战", "3325") + )) + + private class StatusFilter : UriPartFilter("连载状态", arrayOf( + Pair("全部", ""), + Pair("连载", "2309"), + Pair("完结", "2310") + )) + + private class TypeFilter : UriPartFilter("地区", arrayOf( + Pair("全部", ""), + Pair("日本", "2304"), + Pair("韩国", "2305"), + Pair("欧美", "2306"), + Pair("港台", "2307"), + Pair("内地", "2308"), + Pair("其他", "8453") + )) + + private class SortFilter : UriPartFilter("排序", arrayOf( + Pair("更新", "1"), + Pair("人气", "0") + )) + + private class ReaderFilter : UriPartFilter("读者", arrayOf( + Pair("全部", ""), + Pair("少年", "3262"), + Pair("少女", "3263"), + Pair("青年", "3264") + )) + + //Headers + override fun headersBuilder() + = super.headersBuilder().add("Referer", "https://manhua.dmzj.com")!! + + private open class UriPartFilter(displayName: String, val vals: Array>, + defaultValue: Int = 0) : + Filter.Select(displayName, vals.map { it.first }.toTypedArray(), defaultValue) { + open fun toUriPart() = vals[state].second + } +}