Skip to content

Commit

Permalink
Happymh: Fix chapter list parsing (#6572)
Browse files Browse the repository at this point in the history
* Happymh: Fix chapter list parsing

* Update src/zh/happymh/src/eu/kanade/tachiyomi/extension/zh/happymh/Happymh.kt

Co-authored-by: AwkwardPeak7 <[email protected]>

---------

Co-authored-by: AwkwardPeak7 <[email protected]>
  • Loading branch information
AlphaBoom and AwkwardPeak7 authored Dec 12, 2024
1 parent ef02512 commit 26d291b
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/zh/happymh/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ext {
extName = 'Happymh'
extClass = '.Happymh'
extVersionCode = 14
extVersionCode = 15
}

apply from: "$rootDir/common.gradle"
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import android.app.Application
import android.widget.Toast
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.extension.zh.happymh.dto.ChapterListDto
import eu.kanade.tachiyomi.extension.zh.happymh.dto.ChapterByPageResponse
import eu.kanade.tachiyomi.extension.zh.happymh.dto.ChapterByPageResponseData
import eu.kanade.tachiyomi.extension.zh.happymh.dto.PageListResponseDto
import eu.kanade.tachiyomi.extension.zh.happymh.dto.PopularResponseDto
import eu.kanade.tachiyomi.network.GET
Expand All @@ -17,17 +18,18 @@ 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.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody.Companion.asResponseBody
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
Expand All @@ -38,6 +40,7 @@ class Happymh : HttpSource(), ConfigurableSource {
override val name: String = "嗨皮漫画"
override val lang: String = "zh"
override val supportsLatest: Boolean = true

override val baseUrl: String = "https://m.happymh.com"
private val json: Json by injectLazy()

Expand All @@ -54,7 +57,10 @@ class Happymh : HttpSource(), ConfigurableSource {

private val rewriteOctetStream: Interceptor = Interceptor { chain ->
val originalResponse: Response = chain.proceed(chain.request())
if (originalResponse.headers("Content-Type").contains("application/octet-stream") && originalResponse.request.url.toString().contains(".jpg")) {
if (originalResponse.headers("Content-Type")
.contains("application/octet-stream") && originalResponse.request.url.toString()
.contains(".jpg")
) {
val orgBody = originalResponse.body.source()
val newBody = orgBody.asResponseBody("image/jpeg".toMediaType())
originalResponse.newBuilder()
Expand Down Expand Up @@ -139,38 +145,75 @@ class Happymh : HttpSource(), ConfigurableSource {
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()
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)")!!.data()
return json.decodeFromString<ChapterListDto>(script).chapterList.map {
SChapter.create().apply {
val chapterId = it.id
url = "/reads/$comicId/$chapterId"
name = it.chapterName
private fun fetchChapterByPage(manga: SManga, page: Int): ChapterByPageResponseData {
val code = manga.url.substringAfterLast("/")
val url = "$baseUrl/v2.0/apis/manga/chapterByPage".toHttpUrl().newBuilder()
.addQueryParameter("code", code)
.addQueryParameter("lang", "cn")
.addQueryParameter("order", "asc")
.addQueryParameter("page", "$page")
.build()
return client.newCall(GET(url, headers)).execute().parseAs<ChapterByPageResponse>().data
}

private fun fetchChapterByPageObservable(
manga: SManga,
page: Int,
): Observable<ChapterByPageResponseData> {
return Observable.just(fetchChapterByPage(manga, page)).concatMap {
if (it.isEnd == 1 || it.items.isEmpty()) {
Observable.just(it)
} else {
Observable.just(it).concatWith(fetchChapterByPageObservable(manga, page + 1))
}
}
}

override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return Observable
.defer {
fetchChapterByPageObservable(manga, 1)
}
.map {
it.items.map {
SChapter.create().apply {
name = it.chapterName
url = "/mangaread/${it.codes}"
chapter_number = it.order.toFloat()
}
}
}
.toList()
.map { it.flatten().sortedByDescending { chapter -> chapter.chapter_number } }
.map {
// remove order mark
it.onEach { chapter ->
chapter.chapter_number = 0f
}
}
}

override fun chapterListParse(response: Response) = throw UnsupportedOperationException()

override fun getChapterUrl(chapter: SChapter): String {
return baseUrl + chapter.url
}

// Pages

override fun pageListRequest(chapter: SChapter): Request {
if (chapter.url.startsWith("/v2.0/apis/manga/read")) {
if (!chapter.url.contains("mangaread")) {
// Old format is detected
throw Exception("请刷新章节列表")
}
val comicId = chapter.url.substringAfter("/reads/").substringBefore("/")
val chapterId = chapter.url.substringAfterLast("/")
val url = "$baseUrl/v2.0/apis/manga/reading?code=$comicId&cid=$chapterId&v=v3.1613134"
val code = chapter.url.substringAfterLast("/")
val url = "$baseUrl/v2.0/apis/manga/reading?code=$code&v=v3.1818134"
// Some chapters return 403 without this header
val header = headersBuilder()
.add("X-Requested-With", "XMLHttpRequest")
Expand Down Expand Up @@ -210,7 +253,8 @@ class Happymh : HttpSource(), ConfigurableSource {
Headers.headersOf("User-Agent", newValue as String)
true
} catch (e: Throwable) {
Toast.makeText(context, "User Agent 无效:${e.message}", Toast.LENGTH_LONG).show()
Toast.makeText(context, "User Agent 无效:${e.message}", Toast.LENGTH_LONG)
.show()
false
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,22 @@ data class MangaDto(

// Chapters
@Serializable
data class ChapterListDto(val chapterList: List<ChapterDto>) {
@Serializable
data class ChapterDto(val id: String, val chapterName: String)
}
class ChapterByPageResponseDataItem(
val chapterName: String,
val order: Int,
val codes: String,
)

@Serializable
class ChapterByPageResponseData(
val items: List<ChapterByPageResponseDataItem>,
val isEnd: Int,
)

@Serializable
class ChapterByPageResponse(
val data: ChapterByPageResponseData,
)

// Pages
@Serializable
Expand Down

0 comments on commit 26d291b

Please sign in to comment.