DMZJ: update to reflect API changes (#15859)

* DMZJ: update to reflect API changes

* camel case
This commit is contained in:
stevenyomi 2023-03-28 21:33:45 +08:00 committed by GitHub
parent 347507052a
commit aa9ac35a98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 21 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'DMZJ' extName = 'DMZJ'
pkgNameSuffix = 'zh.dmzj' pkgNameSuffix = 'zh.dmzj'
extClass = '.Dmzj' extClass = '.Dmzj'
extVersionCode = 36 extVersionCode = 37
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -11,7 +11,7 @@ import okhttp3.Response
object ApiV3 { object ApiV3 {
private const val v3apiUrl = "https://v3api.idmzj.com" 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" 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<ChapterImagesDto>().toPageList()
fun chapterCommentsUrl(path: String) = "$v3apiUrl/viewPoint/0/$path.json" fun chapterCommentsUrl(path: String) = "$v3apiUrl/viewPoint/0/$path.json"
fun parseChapterComments(response: Response): List<String> { fun parseChapterComments(response: Response): List<String> {
@ -90,6 +95,15 @@ object ApiV3 {
} }
} }
@Serializable
class ChapterImagesDto(
private val id: Int,
private val comic_id: Int,
private val page_url: List<String>,
) {
fun toPageList() = parsePageList(comic_id, id, page_url, emptyList())
}
@Serializable @Serializable
class ChapterCommentDto( class ChapterCommentDto(
private val content: String, private val content: String,

View File

@ -10,16 +10,13 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.protobuf.ProtoBuf
import kotlinx.serialization.protobuf.ProtoNumber import kotlinx.serialization.protobuf.ProtoNumber
import kotlinx.serialization.serializer import kotlinx.serialization.serializer
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Response import okhttp3.Response
import kotlin.math.max
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
object ApiV4 { object ApiV4 {
private const val v4apiUrl = "https://nnv4api.idmzj.com" 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" fun mangaInfoUrl(id: String) = "$v4apiUrl/comic/detail/$id?uid=2665531"
@ -136,21 +133,7 @@ object ApiV4 {
@ProtoNumber(6) private val lowResImages: List<String>, @ProtoNumber(6) private val lowResImages: List<String>,
@ProtoNumber(8) private val images: List<String>, @ProtoNumber(8) private val images: List<String>,
) { ) {
// page count can be messy, see manga ID 55847 chapters 107-109 fun toPageList() = parsePageList(mangaId, id, images, lowResImages)
fun toPageList(): ArrayList<Page> {
val pageCount = max(images.size, lowResImages.size)
val list = ArrayList<Page>(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
}
} }
// same as ApiV3.MangaDto // same as ApiV3.MangaDto

View File

@ -1,11 +1,14 @@
package eu.kanade.tachiyomi.extension.zh.dmzj package eu.kanade.tachiyomi.extension.zh.dmzj
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Response import okhttp3.Response
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.net.URLDecoder import java.net.URLDecoder
import kotlin.math.max
const val PREFIX_ID_SEARCH = "id:" const val PREFIX_ID_SEARCH = "id:"
@ -39,6 +42,29 @@ fun String.formatChapterName(): String {
return "$number$type" return "$number$type"
} }
private const val imageSmallUrl = "https://imgsmall.idmzj.com"
fun parsePageList(
mangaId: Int,
chapterId: Int,
images: List<String>,
lowResImages: List<String>,
): ArrayList<Page> {
// page count can be messy, see manga ID 55847 chapters 107-109
val pageCount = max(images.size, lowResImages.size)
val list = ArrayList<Page>(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(':') fun String.toHttps() = "https:" + substringAfter(':')
// see https://github.com/tachiyomiorg/tachiyomi-extensions/issues/3457 // see https://github.com/tachiyomiorg/tachiyomi-extensions/issues/3457

View File

@ -142,6 +142,7 @@ class Dmzj : ConfigurableSource, HttpSource() {
if (id !in preferences.hiddenList) { if (id !in preferences.hiddenList) {
fetchMangaInfoV4(id)?.run { return toSManga() } fetchMangaInfoV4(id)?.run { return toSManga() }
} }
throw Exception("目前无法获取特殊漫画类型 (2) 的详情 (ID: $id)")
val response = client.newCall(GET(ApiV3.mangaInfoUrlV1(id), headers)).execute() val response = client.newCall(GET(ApiV3.mangaInfoUrlV1(id), headers)).execute()
return ApiV3.parseMangaDetailsV1(response) return ApiV3.parseMangaDetailsV1(response)
} }
@ -170,6 +171,7 @@ class Dmzj : ConfigurableSource, HttpSource() {
return@fromCallable result.parseChapterList() return@fromCallable result.parseChapterList()
} }
} }
throw Exception("目前无法获取特殊漫画的章节目录 (ID: $id)")
val response = client.newCall(GET(ApiV3.mangaInfoUrlV1(id), headers)).execute() val response = client.newCall(GET(ApiV3.mangaInfoUrlV1(id), headers)).execute()
ApiV3.parseChapterListV1(response) ApiV3.parseChapterListV1(response)
} }
@ -185,7 +187,12 @@ class Dmzj : ConfigurableSource, HttpSource() {
val path = chapter.url val path = chapter.url
return Observable.fromCallable { return Observable.fromCallable {
val response = retryClient.newCall(GET(ApiV4.chapterImagesUrl(path), headers)).execute() 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) { if (preferences.showChapterComments) {
result.add(Page(result.size, COMMENTS_FLAG, ApiV3.chapterCommentsUrl(path))) result.add(Page(result.size, COMMENTS_FLAG, ApiV3.chapterCommentsUrl(path)))
} }