Add Happymh (#11680)
This commit is contained in:
parent
16eaf905e4
commit
64bda21dd9
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
@ -0,0 +1,11 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
extName = 'Happymh'
|
||||||
|
pkgNameSuffix = 'zh.happymh'
|
||||||
|
extClass = '.Happymh'
|
||||||
|
extVersionCode = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
|
@ -0,0 +1,117 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.zh.happymh
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
|
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 kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.boolean
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import okhttp3.FormBody
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class Happymh : HttpSource() {
|
||||||
|
override val name: String = "嗨皮漫画"
|
||||||
|
override val lang: String = "zh"
|
||||||
|
override val supportsLatest: Boolean = true
|
||||||
|
override val baseUrl: String = "https://m.happymh.com"
|
||||||
|
override val client: OkHttpClient = network.cloudflareClient
|
||||||
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
|
// Popular
|
||||||
|
|
||||||
|
// Requires login, otherwise result is the same as latest updates
|
||||||
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
val header = headersBuilder().add("referer", "$baseUrl/latest").build()
|
||||||
|
return GET("$baseUrl/apis/c/index?pn=$page&series_status=-1&order=views", header)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
|
val data = json.parseToJsonElement(response.body!!.string()).jsonObject["data"]!!.jsonObject
|
||||||
|
val items = data["items"]!!.jsonArray.map {
|
||||||
|
SManga.create().apply {
|
||||||
|
val obj = it.jsonObject
|
||||||
|
title = obj["name"]!!.jsonPrimitive.content
|
||||||
|
url = "/manga/${obj["manga_code"]!!.jsonPrimitive.content}"
|
||||||
|
thumbnail_url = obj["cover"]!!.jsonPrimitive.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val isEnd = data["isEnd"]!!.jsonPrimitive.boolean
|
||||||
|
return MangasPage(items, !isEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latest
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
|
val header = headersBuilder().add("referer", "$baseUrl/latest").build()
|
||||||
|
return GET("$baseUrl/apis/c/index?pn=$page&series_status=-1&order=last_date", header)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesParse(response: Response): MangasPage = popularMangaParse(response)
|
||||||
|
|
||||||
|
// Search
|
||||||
|
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
val body = FormBody.Builder().addEncoded("searchkey", query).build()
|
||||||
|
val header = headersBuilder().add("referer", "$baseUrl/ssearch").build()
|
||||||
|
return POST("$baseUrl/apis/m/ssearch?pn=$page", header, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchMangaParse(response: Response): MangasPage {
|
||||||
|
// I do not find a way to go to next page, so I always set hasNextPage to false
|
||||||
|
return MangasPage(popularMangaParse(response).mangas, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Details
|
||||||
|
|
||||||
|
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
title = document.selectFirst("div.mg-property > h2.mg-title").text()
|
||||||
|
thumbnail_url = document.selectFirst("div.mg-cover > mip-img").attr("abs:src")
|
||||||
|
author = document.selectFirst("div.mg-property > p.mg-sub-title:nth-of-type(2)").text()
|
||||||
|
artist = author
|
||||||
|
genre = document.select("div.mg-property > p.mg-cate > a").eachText().joinToString(", ")
|
||||||
|
description = document.selectFirst("div.manga-introduction > mip-showmore#showmore").text()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chapters
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
val comicId = response.request.url.pathSegments.last()
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val script = document.selectFirst("mip-data > script:containsData(chapterList)").html()
|
||||||
|
return json.parseToJsonElement(script).jsonObject["chapterList"]!!.jsonArray.map {
|
||||||
|
SChapter.create().apply {
|
||||||
|
val chapterId = it.jsonObject["id"]!!.jsonPrimitive.content
|
||||||
|
url = "/v2.0/apis/manga/read?code=$comicId&cid=$chapterId"
|
||||||
|
name = it.jsonObject["chapterName"]!!.jsonPrimitive.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pages
|
||||||
|
|
||||||
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
|
// Some chapters return 403 without this header
|
||||||
|
val header = headersBuilder().add("X-Requested-With", "XMLHttpRequest").build()
|
||||||
|
return GET(baseUrl + chapter.url, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response): List<Page> = mutableListOf<Page>().apply {
|
||||||
|
json.parseToJsonElement(response.body!!.string()).jsonObject["data"]!!.jsonObject["scans"]!!.jsonArray.mapIndexed() { index, it ->
|
||||||
|
add(Page(index, "", it.jsonObject["url"]!!.jsonPrimitive.content))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun imageUrlParse(response: Response): String = throw Exception("Not Used")
|
||||||
|
}
|
Loading…
Reference in New Issue