From 2b26d7b3a62718177eec1da2d58e83384dc28b6d Mon Sep 17 00:00:00 2001 From: minhngoc25a <33834488+minhngoc25a@users.noreply.github.com> Date: Wed, 7 May 2025 22:26:00 +0700 Subject: [PATCH] NettruyenCO (unoriginal): update domain and use ajax to fetch chapters (#8709) * Changes domain of NettruyenCO and update chapter parsing logic (using AJAX) * GET with headers Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> * * Used `kotlinx.serialization` instead of `org.json.JSONObject` * Used HttpUrl.Builder to encode * Used `keiyoushi.utils.tryParse` * * Replaced jsonPrimitive with better logic * Remove data keyword * Passed chapter date into constructor * Update NetTruyenCO.kt --------- Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> --- src/vi/nettruyenco/build.gradle | 4 +- .../extension/vi/nettruyenco/NetTruyenCO.kt | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/vi/nettruyenco/build.gradle b/src/vi/nettruyenco/build.gradle index 60f6fafb5..04468df96 100644 --- a/src/vi/nettruyenco/build.gradle +++ b/src/vi/nettruyenco/build.gradle @@ -2,8 +2,8 @@ ext { extName = 'NetTruyenCO (unoriginal)' extClass = '.NetTruyenCO' themePkg = 'wpcomics' - baseUrl = 'https://nettruyenrr.com' - overrideVersionCode = 4 + baseUrl = 'https://nettruyener.com' + overrideVersionCode = 5 isNsfw = false } diff --git a/src/vi/nettruyenco/src/eu/kanade/tachiyomi/extension/vi/nettruyenco/NetTruyenCO.kt b/src/vi/nettruyenco/src/eu/kanade/tachiyomi/extension/vi/nettruyenco/NetTruyenCO.kt index 27c71037e..ee47c0e2f 100644 --- a/src/vi/nettruyenco/src/eu/kanade/tachiyomi/extension/vi/nettruyenco/NetTruyenCO.kt +++ b/src/vi/nettruyenco/src/eu/kanade/tachiyomi/extension/vi/nettruyenco/NetTruyenCO.kt @@ -1,20 +1,78 @@ package eu.kanade.tachiyomi.extension.vi.nettruyenco import eu.kanade.tachiyomi.multisrc.wpcomics.WPComics +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga +import keiyoushi.utils.parseAs +import keiyoushi.utils.tryParse +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Request +import okhttp3.Response import org.jsoup.nodes.Document import java.text.SimpleDateFormat import java.util.Locale class NetTruyenCO : WPComics( "NetTruyenCO (unoriginal)", - "https://nettruyenrr.com", + "https://nettruyener.com", "vi", - dateFormat = SimpleDateFormat("dd/MM/yy", Locale.getDefault()), + dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US), gmtOffset = null, ) { override val popularPath = "truyen-tranh-hot" + // Override chapters + + // Data class mapping for a single chapter entry from the JSON endpoint + @Serializable + private class ChapterDto( + @SerialName("chapter_id") val chapterId: Int, + @SerialName("chapter_name") val chapterName: String, + @SerialName("chapter_slug") val chapterSlug: String, + @SerialName("updated_at") val updatedAt: String, + @SerialName("chapter_num") val chapterNum: Float, + ) + + // Wrapper for the JSON response, containing a list of chapters + @Serializable + private class ChaptersData( + val data: List, + ) + + // Build and return the request to fetch all chapters in JSON form + override fun chapterListRequest(manga: SManga): Request { + val slugAndId = manga.url.substringAfterLast("/") // e.g. "slug-12345" + val comicId = slugAndId.substringAfterLast("-").toInt() // 12345 + val slug = slugAndId.substringBeforeLast("-") // "slug" + val url = baseUrl.toHttpUrl() + .newBuilder() + .addPathSegments("Comic/Services/ComicService.asmx/ChapterList") + .addQueryParameter("slug", slug) + .addQueryParameter("comicId", comicId.toString()) + .build() + return GET(url, headers) + } + + // Parse the JSON response into a list of SChapter objects + override fun chapterListParse(response: Response): List { + val chaptersDto = response.parseAs().data + val slug = response.request.url.queryParameter("slug")!! + + return chaptersDto.map { dto -> + SChapter.create().apply { + name = dto.chapterName + setUrlWithoutDomain("/truyen-tranh/$slug/${dto.chapterSlug}/${dto.chapterId}") + date_upload = dateFormat.tryParse(dto.updatedAt) + chapter_number = dto.chapterNum + } + } + } + + override fun chapterListSelector(): String = throw UnsupportedOperationException() + // Details override fun mangaDetailsParse(document: Document): SManga { return SManga.create().apply {