diff --git a/.github/summary.yaml b/.github/summary.yaml index 0d066e58..b504a883 100644 --- a/.github/summary.yaml +++ b/.github/summary.yaml @@ -1 +1 @@ -total: 1185 \ No newline at end of file +total: 1186 \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/liliana/vi/DocTruyen5s.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/liliana/vi/DocTruyen5s.kt index 343d42a0..cf6ed0b2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/liliana/vi/DocTruyen5s.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/liliana/vi/DocTruyen5s.kt @@ -12,7 +12,7 @@ import org.koitharu.kotatsu.parsers.util.json.getBooleanOrDefault @MangaSourceParser("DOCTRUYEN5S", "DocTruyen5s", "vi") internal class DocTruyen5s(context: MangaLoaderContext) : - LilianaParser(context, MangaParserSource.DOCTRUYEN5S, "manga.io.vn", pageSize = 42) { + LilianaParser(context, MangaParserSource.DOCTRUYEN5S, "manga.io.vn", 42) { override suspend fun getPages(chapter: MangaChapter): List { val fullUrl = chapter.url.toAbsoluteUrl(domain) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/HentaiCube.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/HentaiCube.kt index 794fc834..2a81af34 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/HentaiCube.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/HentaiCube.kt @@ -13,9 +13,9 @@ import org.koitharu.kotatsu.parsers.util.* @MangaSourceParser("HENTAICUBE", "CBHentai", "vi", ContentType.HENTAI) internal class HentaiCube(context: MangaLoaderContext) : - MadaraParser(context, MangaParserSource.HENTAICUBE, "hentaicb.art") { + MadaraParser(context, MangaParserSource.HENTAICUBE, "hentaicb.love") { - override val configKeyDomain = ConfigKey.Domain("hentaicb.art", "hentaicube.xyz") + override val configKeyDomain = ConfigKey.Domain("hentaicb.love", "hentaicube.xyz") override val datePattern = "dd/MM/yyyy" override val tagPrefix = "the-loai/" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/HentaiVnPlus.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/HentaiVnPlus.kt index 649e53f5..954202ff 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/HentaiVnPlus.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/HentaiVnPlus.kt @@ -8,7 +8,7 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser @MangaSourceParser("HENTAIVNPLUS", "HentaiVN.plus", "vi", ContentType.HENTAI) internal class HentaiVnPlus(context: MangaLoaderContext) : - MadaraParser(context, MangaParserSource.HENTAIVNPLUS, "hentaivn.tech", 24) { + MadaraParser(context, MangaParserSource.HENTAIVNPLUS, "hentaivn.men", 24) { override val listUrl = "truyen-hentai/" override val tagPrefix = "the-loai/" override val datePattern = "dd/MM/yyyy" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/TruyenVn.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/TruyenVn.kt index 1f63421b..a9cda99f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/TruyenVn.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/TruyenVn.kt @@ -8,7 +8,7 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser @MangaSourceParser("TRUYENVN", "TruyenVn", "vi", ContentType.HENTAI) internal class TruyenVn(context: MangaLoaderContext) : - MadaraParser(context, MangaParserSource.TRUYENVN, "truyenvn.li", 20) { + MadaraParser(context, MangaParserSource.TRUYENVN, "truyenvn.tech", 20) { override val listUrl = "truyen-tranh/" override val tagPrefix = "the-loai/" override val datePattern = "dd/MM/yyyy" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/DuaLeoTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/DuaLeoTruyen.kt index c7088179..7758ed43 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/DuaLeoTruyen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/DuaLeoTruyen.kt @@ -15,7 +15,7 @@ internal class DuaLeoTruyen(context: MangaLoaderContext) : PagedMangaParser(context, MangaParserSource.DUALEOTRUYEN, 60) { override val configKeyDomain: ConfigKey.Domain - get() = ConfigKey.Domain("dualeotruyenbeta.com") + get() = ConfigKey.Domain("dualeotruyenxxy.com") override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/VcomycsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/VcomycsParser.kt index 58e240ea..91fbc7f2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/VcomycsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/VcomycsParser.kt @@ -50,7 +50,7 @@ import javax.crypto.spec.SecretKeySpec internal class VcomycsParser(context: MangaLoaderContext) : PagedMangaParser(context, MangaParserSource.VCOMYCS, 36) { override val configKeyDomain: ConfigKey.Domain - get() = ConfigKey.Domain("vivicomi.store") + get() = ConfigKey.Domain("vivicomi.shop") override val availableSortOrders: Set get() = EnumSet.of(SortOrder.UPDATED) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/DocTruyen3Q.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/DocTruyen3Q.kt index 01be77da..8481172e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/DocTruyen3Q.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/DocTruyen3Q.kt @@ -12,17 +12,17 @@ import java.util.* @MangaSourceParser("DOCTRUYEN3Q", "DocTruyen3Q", "vi") internal class DocTruyen3Q(context: MangaLoaderContext) : - WpComicsParser(context, MangaParserSource.DOCTRUYEN3Q, "doctruyen3qui.com", 36) { + WpComicsParser(context, MangaParserSource.DOCTRUYEN3Q, "doctruyen3qui2.com", 36) { override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain( - "doctruyen3qui.com", // Main repo + "doctruyen3qui2.com", // Main domain "doctruyen3qll.net", "doctruyen3q3.net", "doctruyen3qw.com", "doctruyen3qk.pro", "doctruyen3qw.pro", "doctruyen3qvip.com", - "truyen3qvip.com", // Main repo + "truyen3qvip.com", // Backup domain ) override val datePattern = "dd/MM/yyyy" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyen.kt index 7c6dc372..a7dc4553 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyen.kt @@ -18,8 +18,10 @@ import java.text.SimpleDateFormat internal class NetTruyen(context: MangaLoaderContext) : WpComicsParser(context, MangaParserSource.NETTRUYEN, "nettruyenrr.com", 36) { - override val configKeyDomain: ConfigKey.Domain = - ConfigKey.Domain("nettruyenrr.com", "nettruyenww.com", "nettruyenx.com") + override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain( + "nettruyenrr.com", + "nettruyenx.com" + ) override suspend fun getDetails(manga: Manga): Manga = coroutineScope { val fullUrl = manga.url.toAbsoluteUrl(domain) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenFE.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenFE.kt index b02fb89b..e69dc0f8 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenFE.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenFE.kt @@ -16,7 +16,7 @@ import java.util.EnumSet @MangaSourceParser("NETTRUYENFE", "NetTruyenFE", "vi") internal class NetTruyenFE(context: MangaLoaderContext) : - WpComicsParser(context, MangaParserSource.NETTRUYENFE, "nettruyentet.com", 20) { + WpComicsParser(context, MangaParserSource.NETTRUYENFE, "nettruyenedu.com", 20) { override val listUrl = "/tim-kiem-nang-cao" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenLL.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenLL.kt index f38f3242..be077fbe 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenLL.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenLL.kt @@ -16,7 +16,7 @@ import java.util.EnumSet @MangaSourceParser("NETTRUYENLL", "NetTruyenLL", "vi") internal class NetTruyenLL(context: MangaLoaderContext) : - WpComicsParser(context, MangaParserSource.NETTRUYENLL, "nettruyentet.com", 20) { + WpComicsParser(context, MangaParserSource.NETTRUYENLL, "nettruyenedu.com", 20) { override val listUrl = "/tim-kiem-nang-cao" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenSSR.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenSSR.kt index bd9588f5..3ac9ab76 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenSSR.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenSSR.kt @@ -16,7 +16,7 @@ import java.util.EnumSet @MangaSourceParser("NETTRUYENSSR", "NetTruyenSSR", "vi") internal class NetTruyenSSR(context: MangaLoaderContext) : - WpComicsParser(context, MangaParserSource.NETTRUYENSSR, "nettruyentet.com", 20) { + WpComicsParser(context, MangaParserSource.NETTRUYENSSR, "nettruyenedu.com", 20) { override val listUrl = "/tim-kiem-nang-cao" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenUU.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenUU.kt index 8e1cc40f..1c8c2967 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenUU.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenUU.kt @@ -16,7 +16,7 @@ import java.util.* @MangaSourceParser("NETTRUYENUU", "NetTruyenUU", "vi") internal class NetTruyenUU(context: MangaLoaderContext) : - WpComicsParser(context, MangaParserSource.NETTRUYENUU, "nettruyentet.com", 20) { + WpComicsParser(context, MangaParserSource.NETTRUYENUU, "nettruyenedu.com", 20) { override val listUrl = "/tim-kiem-nang-cao" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NewTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NewTruyen.kt new file mode 100644 index 00000000..501f1ad7 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NewTruyen.kt @@ -0,0 +1,135 @@ +package org.koitharu.kotatsu.parsers.site.wpcomics.vi + +import androidx.collection.ArraySet +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import org.jsoup.nodes.Document +import org.koitharu.kotatsu.parsers.model.* +import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.MangaLoaderContext +import org.koitharu.kotatsu.parsers.MangaSourceParser +import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser +import org.koitharu.kotatsu.parsers.exception.ParseException +import java.text.SimpleDateFormat +import java.util.* + +@MangaSourceParser("NEWTRUYEN", "NewTruyen", "vi") +internal class NewTruyen(context: MangaLoaderContext) : + WpComicsParser(context, MangaParserSource.NEWTRUYEN, "newtruyen2.com", 36) { + + override suspend fun getFilterOptions() = MangaListFilterOptions( + availableTags = getAvailableTags(), + availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED), + ) + + override suspend fun getDetails(manga: Manga): Manga = coroutineScope { + val fullUrl = manga.url.toAbsoluteUrl(domain) + val doc = webClient.httpGet(fullUrl).parseHtml() + val storyID = doc.selectFirst("input#storyID")?.attr("value") + ?: throw ParseException("Story ID not found", fullUrl) + val chaptersDeferred = async { getChapterList(storyID) } + val tagsElement = doc.select("p.col-xs-12 a.tr-theloai") + val mangaTags = tagsElement.map { + MangaTag( + title = it.text(), + key = it.attr("href").substringAfterLast('/'), + source = source + ) + }.toSet() + + manga.copy( + description = doc.selectFirst(selectDesc)?.html(), + author = doc.body().select(selectAut).textOrNull(), + state = doc.selectFirst(selectState)?.let { + when (it.text()) { + in ongoing -> MangaState.ONGOING + in finished -> MangaState.FINISHED + else -> null + } + }, + tags = mangaTags, + chapters = chaptersDeferred.await(), + ) + } + + private suspend fun getChapterList(storyID: String): List { + val url = "/Story/ListChapterByStoryID?storyID=" + storyID + val fullUrl = url.toAbsoluteUrl(domain) + val doc = webClient.httpGet(fullUrl).parseHtml() + return doc.select("div.col-xs-5.chapter").mapChapters(reversed = true) { i, li -> + val a = li.selectFirstOrThrow("a") + val href = a.attrAsRelativeUrl("href") + val dateText = li.selectFirst("div.col-xs-4.text-center.small")?.text() // Broken, will fix it later + MangaChapter( + id = generateUid(href), + name = a.text(), + number = i + 1f, + volume = 0, + url = href, + uploadDate = parseChapterDate(dateText), // Broken, will fix it later + source = source, + scanlator = null, + branch = null, + ) + } + } + + private val relativeTimePattern = Regex("(\\d+)\\s*(phút|giờ|ngày|tháng) trước") + private val absoluteTimePattern = Regex("(\\d{2}-\\d{2}-\\d{4})") + + private fun parseChapterDate(dateText: String?): Long { // Broken, will fix it later + if (dateText == null) return 0 + + return when { + dateText.contains("phút trước") -> { + val match = relativeTimePattern.find(dateText) + val minutes = match?.groups?.get(1)?.value?.toIntOrNull() ?: 0 + System.currentTimeMillis() - minutes * 60 * 1000 + } + + dateText.contains("giờ trước") -> { + val match = relativeTimePattern.find(dateText) + val hours = match?.groups?.get(1)?.value?.toIntOrNull() ?: 0 + System.currentTimeMillis() - hours * 3600 * 1000 + } + + dateText.contains("ngày trước") -> { + val match = relativeTimePattern.find(dateText) + val days = match?.groups?.get(1)?.value?.toIntOrNull() ?: 0 + System.currentTimeMillis() - days * 86400 * 1000 + } + + dateText.contains("tháng trước") -> { + val match = relativeTimePattern.find(dateText) + val months = match?.groups?.get(1)?.value?.toIntOrNull() ?: 0 + System.currentTimeMillis() - months * 30 * 86400 * 1000 + } + + absoluteTimePattern.matches(dateText) -> { + val formatter = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()) + try { + val parsedDate = formatter.parse(dateText) + parsedDate?.time ?: 0L + } catch (e: Exception) { + 0L + } + } + + else -> 0L + } + } + + private suspend fun getAvailableTags(): Set { + val doc = webClient.httpGet("https://$domain/").parseHtml() + val tagItems = doc.select("ul.dropdown-menu.megamenu li a") + val tagSet = ArraySet(tagItems.size) + for (item in tagItems) { + val title = item.attr("title").toTitleCase(sourceLocale) + val key = item.attr("href").substringAfterLast('/').trim() + if (key.isNotEmpty() && title.isNotEmpty()) { + tagSet.add(MangaTag(title = title, key = key, source = source)) + } + } + return tagSet + } +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/TopTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/TopTruyen.kt index 34025804..02202ddb 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/TopTruyen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/TopTruyen.kt @@ -12,10 +12,10 @@ import java.util.* @MangaSourceParser("TOPTRUYEN", "TopTruyen", "vi") internal class TopTruyen(context: MangaLoaderContext) : - WpComicsParser(context, MangaParserSource.TOPTRUYEN, "www.toptruyentv.net", 36) { + WpComicsParser(context, MangaParserSource.TOPTRUYEN, "www.toptruyen369.net", 36) { override val configKeyDomain = ConfigKey.Domain( - "www.toptruyentv.net", // Main repo + "www.toptruyen369.net", // Main domain "www.toptruyen28.net", "www.toptruyento.pro", "www.toptruyenpro1.com",