diff --git a/src/zh/comicabc/AndroidManifest.xml b/src/zh/comicabc/AndroidManifest.xml new file mode 100644 index 000000000..30deb7f79 --- /dev/null +++ b/src/zh/comicabc/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/src/zh/comicabc/build.gradle b/src/zh/comicabc/build.gradle new file mode 100644 index 000000000..33d8c2850 --- /dev/null +++ b/src/zh/comicabc/build.gradle @@ -0,0 +1,11 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + extName = 'Comicabc' + pkgNameSuffix = 'zh.comicabc' + extClass = '.Comicabc' + extVersionCode = 1 +} + +apply from: "$rootDir/common.gradle" diff --git a/src/zh/comicabc/res/mipmap-hdpi/ic_launcher.png b/src/zh/comicabc/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..234b1b650 Binary files /dev/null and b/src/zh/comicabc/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/zh/comicabc/res/mipmap-mdpi/ic_launcher.png b/src/zh/comicabc/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..8fe10a815 Binary files /dev/null and b/src/zh/comicabc/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/zh/comicabc/res/mipmap-xhdpi/ic_launcher.png b/src/zh/comicabc/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..7118d4156 Binary files /dev/null and b/src/zh/comicabc/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/zh/comicabc/res/mipmap-xxhdpi/ic_launcher.png b/src/zh/comicabc/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..61ab38f69 Binary files /dev/null and b/src/zh/comicabc/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/zh/comicabc/res/mipmap-xxxhdpi/ic_launcher.png b/src/zh/comicabc/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..dd5f2182a Binary files /dev/null and b/src/zh/comicabc/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/zh/comicabc/res/web_hi_res_512.png b/src/zh/comicabc/res/web_hi_res_512.png new file mode 100644 index 000000000..4bda18751 Binary files /dev/null and b/src/zh/comicabc/res/web_hi_res_512.png differ diff --git a/src/zh/comicabc/src/eu/kanade/tachiyomi/extension/zh/comicabc/Comicabc.kt b/src/zh/comicabc/src/eu/kanade/tachiyomi/extension/zh/comicabc/Comicabc.kt new file mode 100644 index 000000000..386c06beb --- /dev/null +++ b/src/zh/comicabc/src/eu/kanade/tachiyomi/extension/zh/comicabc/Comicabc.kt @@ -0,0 +1,106 @@ +package eu.kanade.tachiyomi.extension.zh.comicabc + +import app.cash.quickjs.QuickJs +import eu.kanade.tachiyomi.network.GET +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.Request +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element + +class Comicabc : ParsedHttpSource() { + override val name: String = "無限動漫" + override val lang: String = "zh" + override val supportsLatest: Boolean = true + override val baseUrl: String = "https://www.comicabc.com" + + // Popular + + override fun popularMangaRequest(page: Int) = GET("$baseUrl/comic/h-$page.html", headers) + override fun popularMangaNextPageSelector(): String? = "div.pager a span.mdi-skip-next" + override fun popularMangaSelector(): String = "div.default_row_width > div.col-2" + override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { + title = element.selectFirst("li.cat2_list_name").text() + setUrlWithoutDomain(element.selectFirst("a").attr("abs:href")) + thumbnail_url = element.selectFirst("img").attr("abs:src") + } + + // Latest + + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/comic/u-$page.html", headers) + override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() + override fun latestUpdatesSelector() = popularMangaSelector() + override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element) + + // Search + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + return GET("$baseUrl/member/search.aspx?key=$query&page=$page", headers) + } + + override fun searchMangaNextPageSelector(): String? = popularMangaNextPageSelector() + override fun searchMangaSelector(): String = popularMangaSelector() + override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) + + // Details + + override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { + title = document.selectFirst("div.item-top-content h3.item_name").text() + thumbnail_url = document.selectFirst("div.item-topbar img.item_cover").attr("abs:src") + author = document.selectFirst("div.item-top-content > li:nth-of-type(3)").ownText() + artist = author + description = document.selectFirst("div.item-top-content > li.item_info_detail").text() + status = when { + document.selectFirst("div.item_comic_eps_div").text().contains("連載中") -> SManga.ONGOING + document.selectFirst("div.item_comic_eps_div").text().contains("已完結") -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + } + + // Chapters + + override fun chapterListSelector(): String = "div#div_li1 td > a" + override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { + val onclick = element.attr("onclick") + val comicId = onclick.substringAfter("cview('").substringBefore("-") + val chapterId = onclick.substringAfter("-").substringBefore(".html") + url = "/online/new-$comicId.html?ch=$chapterId" + name = element.text() + } + override fun chapterListParse(response: Response): List { + return super.chapterListParse(response).reversed() + } + + // Pages + + override fun pageListParse(response: Response): List = mutableListOf().apply { + val document = response.asJsoup() + val url = response.request.url.toString() + val script = document.selectFirst("script:containsData(function request)").data() + .replace("function ge(e){return document.getElementById(e);}", "") + .replace("ge\\(.*\\).src".toRegex(), "imageUrl") + .replace("spp()", "") + val quickJs = QuickJs.create() + val totalPage = quickJs.evaluate(nview + script.replace("document.location", "\"$url\"") + "ps") as Int + for (i in 1..totalPage) { + val imageUrl = quickJs.evaluate(nview + script.replace("document.location", "\"$url-$i\"") + "imageUrl") as String + add(Page(i - 1, "", "https:$imageUrl")) + } + quickJs.close() + } + + override fun pageListParse(document: Document): List = throw Exception("Not Used") + override fun imageUrlParse(document: Document): String = throw Exception("Not Used") + + companion object { + // Functions required by script in pageListParse() + // Taken from https://www.comicabc.com/js/nview.js?20180806 + const val nview = """function lc(l){if(l.length!=2 ) return l;var az="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";var a=l.substring(0,1);var b=l.substring(1,2);if(a=="Z") return 8000+az.indexOf(b);else return az.indexOf(a)*52+az.indexOf(b);} +function nn(n){return n<10?'00'+n:n<100?'0'+n:n;}function mm(p){return (parseInt((p-1)/10)%10)+(((p-1)%10)*3)};""" + } +}