diff --git a/src/zh/dmzj/build.gradle b/src/zh/dmzj/build.gradle index 48c299857..11b9ba490 100644 --- a/src/zh/dmzj/build.gradle +++ b/src/zh/dmzj/build.gradle @@ -6,7 +6,7 @@ ext { extName = 'DMZJ' pkgNameSuffix = 'zh.dmzj' extClass = '.Dmzj' - extVersionCode = 36 + extVersionCode = 37 } apply from: "$rootDir/common.gradle" diff --git a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/ApiV3.kt b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/ApiV3.kt index ba3dc993e..9d728c799 100644 --- a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/ApiV3.kt +++ b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/ApiV3.kt @@ -11,7 +11,7 @@ import okhttp3.Response object ApiV3 { private const val v3apiUrl = "https://v3api.idmzj.com" - private const val apiUrl = "https://api.dmzj.com" + private const val apiUrl = "https://api.idmzj.com" fun popularMangaUrl(page: Int) = "$v3apiUrl/classify/0/0/${page - 1}.json" @@ -44,6 +44,11 @@ object ApiV3 { } } + fun chapterImagesUrlV1(path: String) = "https://m.idmzj.com/chapinfo/$path.html" + + fun parseChapterImagesV1(response: Response) = + response.parseAs().toPageList() + fun chapterCommentsUrl(path: String) = "$v3apiUrl/viewPoint/0/$path.json" fun parseChapterComments(response: Response): List { @@ -90,6 +95,15 @@ object ApiV3 { } } + @Serializable + class ChapterImagesDto( + private val id: Int, + private val comic_id: Int, + private val page_url: List, + ) { + fun toPageList() = parsePageList(comic_id, id, page_url, emptyList()) + } + @Serializable class ChapterCommentDto( private val content: String, diff --git a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/ApiV4.kt b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/ApiV4.kt index fda8a7b8c..c10974f5d 100644 --- a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/ApiV4.kt +++ b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/ApiV4.kt @@ -10,16 +10,13 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.protobuf.ProtoNumber import kotlinx.serialization.serializer -import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Response -import kotlin.math.max import kotlin.reflect.KType import kotlin.reflect.typeOf object ApiV4 { private const val v4apiUrl = "https://nnv4api.idmzj.com" - private const val imageSmallCDNUrl = "https://imgsmall.idmzj.com" fun mangaInfoUrl(id: String) = "$v4apiUrl/comic/detail/$id?uid=2665531" @@ -136,21 +133,7 @@ object ApiV4 { @ProtoNumber(6) private val lowResImages: List, @ProtoNumber(8) private val images: List, ) { - // page count can be messy, see manga ID 55847 chapters 107-109 - fun toPageList(): ArrayList { - val pageCount = max(images.size, lowResImages.size) - val list = ArrayList(pageCount + 1) // for comments page - for (i in 0 until pageCount) { - val imageUrl = images.getOrNull(i)?.fixFilename()?.toHttps() - val lowResUrl = lowResImages.getOrElse(i) { - // this is sometimes different in low-res URLs and might fail, see manga ID 56649 - val initial = imageUrl!!.decodePath().toHttpUrl().pathSegments[0] - "$imageSmallCDNUrl/$initial/$mangaId/$id/$i.jpg" - }.toHttps() - list.add(Page(i, url = lowResUrl, imageUrl = imageUrl ?: lowResUrl)) - } - return list - } + fun toPageList() = parsePageList(mangaId, id, images, lowResImages) } // same as ApiV3.MangaDto diff --git a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Common.kt b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Common.kt index e75643648..553fac686 100644 --- a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Common.kt +++ b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Common.kt @@ -1,11 +1,14 @@ package eu.kanade.tachiyomi.extension.zh.dmzj +import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.SManga import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json +import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Response import uy.kohesive.injekt.injectLazy import java.net.URLDecoder +import kotlin.math.max const val PREFIX_ID_SEARCH = "id:" @@ -39,6 +42,29 @@ fun String.formatChapterName(): String { return "第$number$type" } +private const val imageSmallUrl = "https://imgsmall.idmzj.com" + +fun parsePageList( + mangaId: Int, + chapterId: Int, + images: List, + lowResImages: List, +): ArrayList { + // page count can be messy, see manga ID 55847 chapters 107-109 + val pageCount = max(images.size, lowResImages.size) + val list = ArrayList(pageCount + 1) // for comments page + for (i in 0 until pageCount) { + val imageUrl = images.getOrNull(i)?.fixFilename()?.toHttps() + val lowResUrl = lowResImages.getOrElse(i) { + // this is sometimes different in low-res URLs and might fail, see manga ID 56649 + val initial = imageUrl!!.decodePath().toHttpUrl().pathSegments[0] + "$imageSmallUrl/$initial/$mangaId/$chapterId/$i.jpg" + }.toHttps() + list.add(Page(i, url = lowResUrl, imageUrl = imageUrl ?: lowResUrl)) + } + return list +} + fun String.toHttps() = "https:" + substringAfter(':') // see https://github.com/tachiyomiorg/tachiyomi-extensions/issues/3457 diff --git a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt index 18d4804ca..50853e7e1 100644 --- a/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt +++ b/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt @@ -142,6 +142,7 @@ class Dmzj : ConfigurableSource, HttpSource() { if (id !in preferences.hiddenList) { fetchMangaInfoV4(id)?.run { return toSManga() } } + throw Exception("目前无法获取特殊漫画类型 (2) 的详情 (ID: $id)") val response = client.newCall(GET(ApiV3.mangaInfoUrlV1(id), headers)).execute() return ApiV3.parseMangaDetailsV1(response) } @@ -170,6 +171,7 @@ class Dmzj : ConfigurableSource, HttpSource() { return@fromCallable result.parseChapterList() } } + throw Exception("目前无法获取特殊漫画的章节目录 (ID: $id)") val response = client.newCall(GET(ApiV3.mangaInfoUrlV1(id), headers)).execute() ApiV3.parseChapterListV1(response) } @@ -185,7 +187,12 @@ class Dmzj : ConfigurableSource, HttpSource() { val path = chapter.url return Observable.fromCallable { val response = retryClient.newCall(GET(ApiV4.chapterImagesUrl(path), headers)).execute() - val result = ApiV4.parseChapterImages(response) + val result = try { + ApiV4.parseChapterImages(response) + } catch (_: Throwable) { + client.newCall(GET(ApiV3.chapterImagesUrlV1(path), headers)).execute() + .let(ApiV3::parseChapterImagesV1) + } if (preferences.showChapterComments) { result.add(Page(result.size, COMMENTS_FLAG, ApiV3.chapterCommentsUrl(path))) }