add Manhuagui(zh-CN) (#1156)
* copy from pufei * add manhuagui * fix regex * fix search * add icon by http://bigjpg.com * remove comment * fix baseurl
|
@ -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"
|
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 197 KiB |
|
@ -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<String?>? = 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
|
||||
)
|
|
@ -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<alphabet.length;i++){baseReverseDic[alphabet][alphabet.charAt(i)]=i}}return baseReverseDic[alphabet][character]}var LZString={decompressFromBase64:function(input){if(input==null)return"";if(input=="")return null;return LZString._0(input.length,32,function(index){return getBaseValue(keyStrBase64,input.charAt(index))})},_0:function(length,resetValue,getNextValue){var dictionary=[],next,enlargeIn=4,dictSize=4,numBits=3,entry="",result=[],i,w,bits,resb,maxpower,power,c,data={val:getNextValue(0),position:resetValue,index:1};for(i=0;i<3;i+=1){dictionary[i]=i}bits=0;maxpower=Math.pow(2,2);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(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<Page> {
|
||||
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) = ""
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.zh.manhuagui
|
||||
|
||||
data class Sl(
|
||||
val md5: String? = ""
|
||||
)
|