diff --git a/src/zh/manhuagui/build.gradle b/src/zh/manhuagui/build.gradle new file mode 100644 index 000000000..315ee6695 --- /dev/null +++ b/src/zh/manhuagui/build.gradle @@ -0,0 +1,17 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + appName = 'Tachiyomi: ManHuaGui' + pkgNameSuffix = 'zh.manhuagui' + extClass = '.Manhuagui' + extVersionCode = 1 + libVersion = '1.2' +} + +dependencies { + compileOnly project(':duktape-stub') + compileOnly 'com.google.code.gson:gson:2.8.5' +} + +apply from: "$rootDir/common.gradle" diff --git a/src/zh/manhuagui/res/mipmap-hdpi/ic_launcher.png b/src/zh/manhuagui/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..1e92dbb1c Binary files /dev/null and b/src/zh/manhuagui/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/zh/manhuagui/res/mipmap-ldpi/ic_launcher.png b/src/zh/manhuagui/res/mipmap-ldpi/ic_launcher.png new file mode 100644 index 000000000..d982a3585 Binary files /dev/null and b/src/zh/manhuagui/res/mipmap-ldpi/ic_launcher.png differ diff --git a/src/zh/manhuagui/res/mipmap-mdpi/ic_launcher.png b/src/zh/manhuagui/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..c4ea7a4c8 Binary files /dev/null and b/src/zh/manhuagui/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/zh/manhuagui/res/mipmap-xhdpi/ic_launcher.png b/src/zh/manhuagui/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..2766f693c Binary files /dev/null and b/src/zh/manhuagui/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/zh/manhuagui/res/mipmap-xxhdpi/ic_launcher.png b/src/zh/manhuagui/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..f35e8e137 Binary files /dev/null and b/src/zh/manhuagui/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/zh/manhuagui/res/mipmap-xxxhdpi/ic_launcher.png b/src/zh/manhuagui/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..a8e06fe93 Binary files /dev/null and b/src/zh/manhuagui/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/zh/manhuagui/res/web_hi_res_512.png b/src/zh/manhuagui/res/web_hi_res_512.png new file mode 100644 index 000000000..589afa8ab Binary files /dev/null and b/src/zh/manhuagui/res/web_hi_res_512.png differ diff --git a/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Comic.kt b/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Comic.kt new file mode 100644 index 000000000..44073173e --- /dev/null +++ b/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Comic.kt @@ -0,0 +1,18 @@ +package eu.kanade.tachiyomi.extension.zh.manhuagui + +data class Comic( + val bid: Int? = 0, + val block_cc: String? = "", + val bname: String? = "", + val bpic: String? = "", + val cid: Int? = 0, + val cname: String? = "", + val files: List? = listOf(), + val finished: Boolean? = false, + val len: Int? = 0, + val nextId: Int? = 0, + val path: String? = "", + val prevId: Int? = 0, + val sl: Sl? = Sl(), + val status: Int? = 0 +) \ No newline at end of file diff --git a/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Manhuagui.kt b/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Manhuagui.kt new file mode 100644 index 000000000..f49535738 --- /dev/null +++ b/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Manhuagui.kt @@ -0,0 +1,109 @@ +package eu.kanade.tachiyomi.extension.zh.manhuagui + +import android.util.Log +import com.google.gson.Gson +import com.squareup.duktape.Duktape +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import okhttp3.HttpUrl +import okhttp3.Request +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element + + +class Manhuagui : ParsedHttpSource() { + + override val name = "漫画柜" + override val baseUrl = "https://www.manhuagui.com" + override val lang = "zh" + override val supportsLatest = true + val imageServer = arrayOf("https://i.hamreus.com") + + private val gson = Gson() + + override fun popularMangaRequest(page: Int) = GET("$baseUrl/list/view_p$page.html", headers) + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/list/update_p$page.html", headers) + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request + = GET("$baseUrl/s/${query}_p$page.html", headers) + + override fun mangaDetailsRequest(manga: SManga) = GET(baseUrl + manga.url, headers) + override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga) + override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url, headers) + + override fun popularMangaSelector() = "ul#contList > li" + override fun latestUpdatesSelector() = popularMangaSelector() + override fun searchMangaSelector() = "div.book-result > ul > li" + override fun chapterListSelector() = "ul > li > a.status0" + + override fun searchMangaNextPageSelector() = "a.prev" + override fun popularMangaNextPageSelector() = searchMangaNextPageSelector() + override fun latestUpdatesNextPageSelector() = searchMangaNextPageSelector() + + override fun headersBuilder() = super.headersBuilder() + .add("Referer", baseUrl) + + override fun popularMangaFromElement(element: Element) = mangaFromElement(element) + override fun latestUpdatesFromElement(element: Element) = mangaFromElement(element) + private fun mangaFromElement(element: Element): SManga { + val manga = SManga.create() + element.select("a.bcover").first().let { + manga.url = it.attr("href") + manga.title = it.attr("title").trim() + manga.thumbnail_url = it.select("img").first().attr("src") + } + return manga + } + + override fun searchMangaFromElement(element: Element): SManga { + val manga = SManga.create() + + element.select("div.book-cover > a.bcover > img").first().attr("src") + + element.select("div.book-detail").first().let { + manga.url = it.select("dl > dt > a").first().attr("href") + manga.title = it.select("dl > dt > a").first().attr("title").trim() + } + + return manga + } + + override fun chapterFromElement(element: Element): SChapter { + val chapter = SChapter.create() + chapter.url = element.attr("href") + chapter.name = element.attr("title").trim() + return chapter + } + + override fun mangaDetailsParse(document: Document): SManga { + val manga = SManga.create() + manga.description = document.select("div#intro-all").text().trim() + return manga + } + + private val jsDecodeFunc = """ + var LZString=(function(){var f=String.fromCharCode;var keyStrBase64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var baseReverseDic={};function getBaseValue(alphabet,character){if(!baseReverseDic[alphabet]){baseReverseDic[alphabet]={};for(var i=0;i>=1;if(data.position==0){data.position=resetValue;data.val=getNextValue(data.index++)}bits|=(resb>0?1:0)*power;power<<=1}switch(next=bits){case 0:bits=0;maxpower=Math.pow(2,8);power=1;while(power!=maxpower){resb=data.val&data.position;data.position>>=1;if(data.position==0){data.position=resetValue;data.val=getNextValue(data.index++)}bits|=(resb>0?1:0)*power;power<<=1}c=f(bits);break;case 1:bits=0;maxpower=Math.pow(2,16);power=1;while(power!=maxpower){resb=data.val&data.position;data.position>>=1;if(data.position==0){data.position=resetValue;data.val=getNextValue(data.index++)}bits|=(resb>0?1:0)*power;power<<=1}c=f(bits);break;case 2:return""}dictionary[3]=c;w=c;result.push(c);while(true){if(data.index>length){return""}bits=0;maxpower=Math.pow(2,numBits);power=1;while(power!=maxpower){resb=data.val&data.position;data.position>>=1;if(data.position==0){data.position=resetValue;data.val=getNextValue(data.index++)}bits|=(resb>0?1:0)*power;power<<=1}switch(c=bits){case 0:bits=0;maxpower=Math.pow(2,8);power=1;while(power!=maxpower){resb=data.val&data.position;data.position>>=1;if(data.position==0){data.position=resetValue;data.val=getNextValue(data.index++)}bits|=(resb>0?1:0)*power;power<<=1}dictionary[dictSize++]=f(bits);c=dictSize-1;enlargeIn--;break;case 1:bits=0;maxpower=Math.pow(2,16);power=1;while(power!=maxpower){resb=data.val&data.position;data.position>>=1;if(data.position==0){data.position=resetValue;data.val=getNextValue(data.index++)}bits|=(resb>0?1:0)*power;power<<=1}dictionary[dictSize++]=f(bits);c=dictSize-1;enlargeIn--;break;case 2:return result.join('')}if(enlargeIn==0){enlargeIn=Math.pow(2,numBits);numBits++}if(dictionary[c]){entry=dictionary[c]}else{if(c===dictSize){entry=w+w.charAt(0)}else{return null}}result.push(entry);dictionary[dictSize++]=w+entry.charAt(0);enlargeIn--;w=entry;if(enlargeIn==0){enlargeIn=Math.pow(2,numBits);numBits++}}}};return LZString})();String.prototype.splic=function(f){return LZString.decompressFromBase64(this).split(f)}; + """ + + override fun pageListParse(document: Document): List { + val html = document.html() + val re = Regex("""window\[".*?"\](\(.*\)\s*\{[\s\S]+\}\s*\(.*\))""") + val imgCode = re.find(html)?.groups?.get(1)?.value + val imgDecode = Duktape.create().use { + it.evaluate(jsDecodeFunc + imgCode) as String + } + Log.i("jsonresult", imgDecode) + + val re2 = Regex("""\{.*\}""") + val imgJsonStr = re2.find(imgDecode)?.groups?.get(0)?.value + val imageJson: Comic = gson.fromJson(imgJsonStr, Comic::class.java) + + return imageJson.files!!.mapIndexed { i, imgStr -> + val imgurl = "${imageServer[0]}${imageJson.path}$imgStr?cid=${imageJson.cid}&md5=${imageJson.sl?.md5}" + Log.i("image", imgurl) + Page(i, "", imgurl) + } + } + + override fun imageUrlParse(document: Document) = "" +} diff --git a/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Sl.kt b/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Sl.kt new file mode 100644 index 000000000..3e01cdd9d --- /dev/null +++ b/src/zh/manhuagui/src/eu/kanade/tachiyomi/extension/zh/manhuagui/Sl.kt @@ -0,0 +1,5 @@ +package eu.kanade.tachiyomi.extension.zh.manhuagui + +data class Sl( + val md5: String? = "" +) \ No newline at end of file