Fix warnings (refactor)

master
Koitharu 9 months ago
parent 4eeb879451
commit 9d35f26252
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -230,7 +230,7 @@ internal class ComickFunParser(context: MangaLoaderContext) :
url = jo.getString("hid"), url = jo.getString("hid"),
scanlator = jo.optJSONArray("group_name")?.asTypedList<String>()?.joinToString() scanlator = jo.optJSONArray("group_name")?.asTypedList<String>()?.joinToString()
?.takeUnless { it.isBlank() }, ?.takeUnless { it.isBlank() },
uploadDate = dateFormat.tryParse(jo.getString("created_at").substringBefore('T')), uploadDate = dateFormat.parseSafe(jo.getString("created_at").substringBefore('T')),
branch = branch, branch = branch,
source = source, source = source,
) )

@ -202,7 +202,7 @@ internal class ExHentaiParser(
val uploadDate = gd3 val uploadDate = gd3
?.selectFirst("tr:contains(Posted)") ?.selectFirst("tr:contains(Posted)")
?.selectFirst(".gdt2")?.ownTextOrNull() ?.selectFirst(".gdt2")?.ownTextOrNull()
.let { SimpleDateFormat("yyyy-MM-dd HH:mm", sourceLocale).tryParse(it) } .let { SimpleDateFormat("yyyy-MM-dd HH:mm", sourceLocale).parseSafe(it) }
val uploader = gd3 val uploader = gd3
?.getElementsByAttributeValueContaining("href", "/uploader/") ?.getElementsByAttributeValueContaining("href", "/uploader/")
?.firstOrNull() ?.firstOrNull()

@ -590,7 +590,7 @@ internal class HitomiLaParser(context: MangaLoaderContext) : AbstractMangaParser
volume = 0, volume = 0,
branch = json.getString("language_localname"), branch = json.getString("language_localname"),
source = source, source = source,
uploadDate = dateFormat.tryParse(json.getString("date").substringBeforeLast("-")), uploadDate = dateFormat.parseSafe(json.getString("date").substringBeforeLast("-")),
), ),
), ),
) )

@ -5,11 +5,10 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.core.PagedMangaParser import org.koitharu.kotatsu.parsers.core.PagedMangaParser
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.model.search.*
import org.koitharu.kotatsu.parsers.util.generateUid import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.parseHtml import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.tryParse import org.koitharu.kotatsu.parsers.util.parseSafe
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -99,7 +98,7 @@ internal class HoloEarthParser(context: MangaLoaderContext) :
val url = li.selectFirstOrThrow(".manga-detail__list-link").attr("href") val url = li.selectFirstOrThrow(".manga-detail__list-link").attr("href")
val title = li.selectFirstOrThrow(".manga-detail__list-title").text() val title = li.selectFirstOrThrow(".manga-detail__list-title").text()
val dateStr = li.selectFirstOrThrow(".manga-detail__list-date").text() val dateStr = li.selectFirstOrThrow(".manga-detail__list-date").text()
val uploadDate = dateFormat.tryParse(dateStr) ?: 0L val uploadDate = dateFormat.parseSafe(dateStr) ?: 0L
val scanlator = root.selectFirst(".manga-detail__person")?.text() val scanlator = root.selectFirst(".manga-detail__person")?.text()
MangaChapter( MangaChapter(

@ -489,7 +489,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : FlexibleMangaParser
volume = volume, volume = volume,
url = id, url = id,
scanlator = team, scanlator = team,
uploadDate = dateFormat.tryParse(attrs.getString("publishAt")), uploadDate = dateFormat.parseSafe(attrs.getString("publishAt")),
branch = branch, branch = branch,
source = source, source = source,
) )

@ -295,7 +295,7 @@ internal abstract class MangaFireParser(
}, },
url = "${branch.type}/${it.attr("data-id")}", url = "${branch.type}/${it.attr("data-id")}",
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(it.attr("upload-date")), uploadDate = dateFormat.parseSafe(it.attr("upload-date")),
branch = "${branch.langTitle} ${branch.type.toTitleCase()}", branch = "${branch.langTitle} ${branch.type.toTitleCase()}",
source = source, source = source,
) )

@ -252,7 +252,7 @@ internal class MangaPark(context: MangaLoaderContext) :
}.timeInMillis }.timeInMillis
} }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -233,7 +233,7 @@ internal abstract class NineMangaParser(
if (dateWords.size == 3) { if (dateWords.size == 3) {
if (dateWords[1].contains(",")) { if (dateWords[1].contains(",")) {
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).tryParse(date) SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parseSafe(date)
} else { } else {
val timeAgo = Integer.parseInt(dateWords[0]) val timeAgo = Integer.parseInt(dateWords[0])
return Calendar.getInstance().apply { return Calendar.getInstance().apply {

@ -128,7 +128,7 @@ internal class PapScan(context: MangaLoaderContext) :
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = href, url = href,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
source = source, source = source,
scanlator = null, scanlator = null,
branch = null, branch = null,

@ -202,7 +202,7 @@ internal class FlixScans(context: MangaLoaderContext) :
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
branch = null, branch = null,
uploadDate = dateFormat.tryParse(date), uploadDate = dateFormat.parseSafe(date),
scanlator = null, scanlator = null,
source = source, source = source,
) )

@ -200,7 +200,7 @@ internal class TeamXNovel(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(li.selectFirstOrThrow(".epl-date").text()), uploadDate = dateFormat.parseSafe(li.selectFirstOrThrow(".epl-date").text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -185,7 +185,7 @@ internal class AsuraScansParser(context: MangaLoaderContext) :
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = SimpleDateFormat("MMMM d yyyy", Locale.US) uploadDate = SimpleDateFormat("MMMM d yyyy", Locale.US)
.tryParse(cleanDate), .parseSafe(cleanDate),
branch = null, branch = null,
source = source, source = source,
) )

@ -1,7 +1,6 @@
package org.koitharu.kotatsu.parsers.site.en package org.koitharu.kotatsu.parsers.site.en
import org.json.JSONObject import org.json.JSONObject
import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
@ -130,7 +129,7 @@ internal class BatCave(context: MangaLoaderContext) :
url = "/reader/$newsId/$chapterId", url = "/reader/$newsId/$chapterId",
number = chapter.getFloatOrDefault("posi", 0f), number = chapter.getFloatOrDefault("posi", 0f),
title = chapter.getStringOrNull("title"), title = chapter.getStringOrNull("title"),
uploadDate = dateFormat.tryParse(chapter.getStringOrNull("date")), uploadDate = dateFormat.parseSafe(chapter.getStringOrNull("date")),
source = source, source = source,
scanlator = null, scanlator = null,
branch = null, branch = null,

@ -125,7 +125,7 @@ internal class BeeToon(context: MangaLoaderContext) :
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = SimpleDateFormat("MM/dd/yyyy HH:mm:ss", Locale.ENGLISH) uploadDate = SimpleDateFormat("MM/dd/yyyy HH:mm:ss", Locale.ENGLISH)
.tryParse(a.selectFirst(".chapter-date")?.attr("title") ?: "0"), .parseSafe(a.selectFirst(".chapter-date")?.attr("title") ?: "0"),
branch = null, branch = null,
source = source, source = source,
) )

@ -173,7 +173,7 @@ internal class DemonicScans(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(date), uploadDate = dateFormat.parseSafe(date),
branch = null, branch = null,
source = source source = source
) )

@ -183,7 +183,7 @@ internal class DynastyScans(context: MangaLoaderContext) :
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = href, url = href,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
source = source, source = source,
scanlator = null, scanlator = null,
branch = null, branch = null,

@ -186,7 +186,7 @@ internal class FlixScansOrg(context: MangaLoaderContext) :
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
branch = null, branch = null,
uploadDate = dateFormat.tryParse(date), uploadDate = dateFormat.parseSafe(date),
scanlator = null, scanlator = null,
source = source, source = source,
) )

@ -233,7 +233,7 @@ internal class Hentalk(context: MangaLoaderContext) :
} }
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
val parseTime = dateFormat.tryParse(createdAt) val parseTime = dateFormat.parseSafe(createdAt)
val chapter = MangaChapter( val chapter = MangaChapter(
id = generateUid("/g/$mangaId/read/1"), id = generateUid("/g/$mangaId/read/1"),
url = "/g/$mangaId/read/1/__data.json?x-sveltekit-invalidated=011", url = "/g/$mangaId/read/1/__data.json?x-sveltekit-invalidated=011",

@ -149,7 +149,7 @@ internal class MangaGeko(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
branch = null, branch = null,
source = source, source = source,
) )

@ -249,7 +249,7 @@ internal class MangaTownParser(context: MangaLoaderContext) :
date.isNullOrEmpty() -> 0L date.isNullOrEmpty() -> 0L
date.contains("Today") -> Calendar.getInstance().timeInMillis date.contains("Today") -> Calendar.getInstance().timeInMillis
date.contains("Yesterday") -> Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -1) }.timeInMillis date.contains("Yesterday") -> Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -1) }.timeInMillis
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -170,7 +170,7 @@ internal class Mangaowl(context: MangaLoaderContext) :
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = url, url = url,
uploadDate = dateFormat.tryParse(date), uploadDate = dateFormat.parseSafe(date),
source = source, source = source,
scanlator = null, scanlator = null,
branch = null, branch = null,

@ -149,7 +149,7 @@ internal class ManhwasMen(context: MangaLoaderContext) :
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
d.endsWith(" ago") -> parseRelativeDate(date) d.endsWith(" ago") -> parseRelativeDate(date)
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -84,7 +84,7 @@ internal class Po2Scans(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(div.select(".detail span").last()?.text()), uploadDate = dateFormat.parseSafe(div.select(".detail span").last()?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -17,7 +17,7 @@ import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.parseHtml import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.urlEncoded import org.koitharu.kotatsu.parsers.util.urlEncoded
import org.koitharu.kotatsu.parsers.util.tryParse import org.koitharu.kotatsu.parsers.util.parseSafe
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -199,7 +199,7 @@ internal class VioletScans(context: MangaLoaderContext) :
} }
val dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH) val dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
val date = dateFormat.tryParse(dateString) ?: 0L val date = dateFormat.parseSafe(dateString) ?: 0L
val chaptersList = root.selectFirstOrThrow("#chapterlist ul") val chaptersList = root.selectFirstOrThrow("#chapterlist ul")
val chapters = chaptersList.select("li") val chapters = chaptersList.select("li")

@ -172,7 +172,7 @@ internal class VyManga(context: MangaLoaderContext) :
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
d.endsWith(" ago") -> parseRelativeDate(date) d.endsWith(" ago") -> parseRelativeDate(date)
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -318,7 +318,7 @@ internal class WeebCentral(context: MangaLoaderContext) : AbstractMangaParser(co
"#d8b4fe" -> "Official" "#d8b4fe" -> "Official"
else -> null else -> null
}, },
uploadDate = dateFormat.tryParse( uploadDate = dateFormat.parseSafe(
element.selectFirst("time[datetime]")?.attr("datetime"), element.selectFirst("time[datetime]")?.attr("datetime"),
), ),
branch = null, branch = null,

@ -104,7 +104,7 @@ internal class TempleScanEsp(context: MangaLoaderContext) :
parseRelativeDate(d) parseRelativeDate(d)
} }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -216,7 +216,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars
url = href, url = href,
scanlator = element.select("div.col-md-6.text-truncate").text(), scanlator = element.select("div.col-md-6.text-truncate").text(),
branch = null, branch = null,
uploadDate = chapterDateFormat.tryParse(element.select("span.badge.badge-primary.p-2").first()?.text()), uploadDate = chapterDateFormat.parseSafe(element.select("span.badge.badge-primary.p-2").first()?.text()),
source = source, source = source,
) )
} }
@ -233,7 +233,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars
url = href, url = href,
scanlator = element.select("div.col-md-6.text-truncate").text(), scanlator = element.select("div.col-md-6.text-truncate").text(),
branch = null, branch = null,
uploadDate = chapterDateFormat.tryParse(element.select("span.badge.badge-primary.p-2").first()?.text()), uploadDate = chapterDateFormat.parseSafe(element.select("span.badge.badge-primary.p-2").first()?.text()),
source = source, source = source,
) )
} }

@ -272,9 +272,9 @@ internal abstract class FmreaderParser(
} else { } else {
it it
} }
}.let { dateFormat.tryParse(it.joinToString(" ")) } }.let { dateFormat.parseSafe(it.joinToString(" ")) }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -148,7 +148,7 @@ internal abstract class FoolSlideParser(
volume = 0, volume = 0,
url = href, url = href,
uploadDate = if (div.selectFirst(selectDate)?.text()?.contains(", ") == true) { uploadDate = if (div.selectFirst(selectDate)?.text()?.contains(", ") == true) {
dateFormat.tryParse(dateText) dateFormat.parseSafe(dateText)
} else { } else {
0 0
}, },

@ -148,7 +148,7 @@ internal class FuryoSociety(context: MangaLoaderContext) :
parseRelativeDate(d) parseRelativeDate(d)
} }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -196,7 +196,7 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
branch = null, branch = null,
source = source, source = source,
) )

@ -121,7 +121,7 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context,
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
branch = null, branch = null,
source = source, source = source,
) )

@ -184,7 +184,7 @@ internal class LugnicaScans(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(date), uploadDate = dateFormat.parseSafe(date),
branch = null, branch = null,
source = source, source = source,
) )

@ -298,7 +298,7 @@ internal class MangaMana(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
branch = null, branch = null,
source = source, source = source,
) )

@ -221,9 +221,9 @@ internal class PhenixscansParser(context: MangaLoaderContext) :
} else { } else {
it it
} }
}.let { dateFormat.tryParse(it.joinToString(" ")) } }.let { dateFormat.parseSafe(it.joinToString(" ")) }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -160,7 +160,7 @@ internal class ScantradUnion(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(date), uploadDate = dateFormat.parseSafe(date),
branch = null, branch = null,
source = source, source = source,
) )

@ -297,7 +297,7 @@ internal abstract class FuzzyDoodleParser(
parseRelativeDate(d) parseRelativeDate(d)
} }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -96,7 +96,7 @@ internal abstract class GalleryParser(
volume = 0, volume = 0,
url = relUrl, url = relUrl,
scanlator = null, scanlator = null,
uploadDate = df.tryParse(time), uploadDate = df.parseSafe(time),
branch = null, branch = null,
source = source, source = source,
) )

@ -25,7 +25,7 @@ import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.src import org.koitharu.kotatsu.parsers.util.src
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.tryParse import org.koitharu.kotatsu.parsers.util.parseSafe
import org.koitharu.kotatsu.parsers.util.urlDecode import org.koitharu.kotatsu.parsers.util.urlDecode
import org.koitharu.kotatsu.parsers.util.urlEncoded import org.koitharu.kotatsu.parsers.util.urlEncoded
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -177,7 +177,7 @@ internal class HentaiNexus(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = manga.url, url = manga.url,
scanlator = doc.select(selectPublisher).text().replace(Regex(" \\([\\d,]+\\)")) { "" }, scanlator = doc.select(selectPublisher).text().replace(Regex(" \\([\\d,]+\\)")) { "" },
uploadDate = format.tryParse(doc.select(selectPublishedDate).text()), uploadDate = format.parseSafe(doc.select(selectPublishedDate).text()),
branch = "English", branch = "English",
source = source, source = source,
), ),

@ -30,7 +30,7 @@ import org.koitharu.kotatsu.parsers.util.parseJson
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.src import org.koitharu.kotatsu.parsers.util.src
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.tryParse import org.koitharu.kotatsu.parsers.util.parseSafe
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -250,7 +250,7 @@ internal class HentaiRead(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = manga.url, url = manga.url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(uploadDateString), uploadDate = dateFormat.parseSafe(uploadDateString),
branch = "English", branch = "English",
source = source, source = source,
) )

@ -164,7 +164,7 @@ internal abstract class HeanCms(
volume = 0, volume = 0,
url = chapterUrl, url = chapterUrl,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(it.getString("created_at").substringBefore("T")), uploadDate = dateFormat.parseSafe(it.getString("created_at").substringBefore("T")),
branch = null, branch = null,
source = source, source = source,
) )

@ -133,7 +133,7 @@ internal abstract class HeanCmsAlt(
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
d.startsWith("hace ") || d.endsWith(" antes") -> parseRelativeDate(date) d.startsWith("hace ") || d.endsWith(" antes") -> parseRelativeDate(date)
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -155,7 +155,7 @@ internal abstract class HotComicsParser(
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(li.selectFirst("time")?.attr("datetime")), uploadDate = dateFormat.parseSafe(li.selectFirst("time")?.attr("datetime")),
branch = null, branch = null,
source = source, source = source,
) )

@ -20,7 +20,7 @@ internal class DayComics(context: MangaLoaderContext) :
val url = element.attr("onclick").substringAfter("popupLogin('").substringBefore("'") val url = element.attr("onclick").substringAfter("popupLogin('").substringBefore("'")
val name = element.selectFirst(".cell-num")?.text() ?: "Unknown" val name = element.selectFirst(".cell-num")?.text() ?: "Unknown"
val dateFormat = SimpleDateFormat(datePattern, sourceLocale) val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val dateUpload = dateFormat.tryParse(element.selectFirst(".cell-time")?.text()) val dateUpload = dateFormat.parseSafe(element.selectFirst(".cell-time")?.text())
val chapterNum = element.selectFirst(".num")?.text()?.toFloat() ?: (i + 1f) val chapterNum = element.selectFirst(".num")?.text()?.toFloat() ?: (i + 1f)
MangaChapter( MangaChapter(
id = generateUid(url), id = generateUid(url),

@ -20,7 +20,7 @@ internal class HotComics(context: MangaLoaderContext) :
val url = element.attr("onclick").substringAfter("popupLogin('").substringBefore("'") val url = element.attr("onclick").substringAfter("popupLogin('").substringBefore("'")
val name = element.selectFirst(".cell-num")?.text() ?: "Unknown" val name = element.selectFirst(".cell-num")?.text() ?: "Unknown"
val dateFormat = SimpleDateFormat(datePattern, sourceLocale) val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val dateUpload = dateFormat.tryParse(element.selectFirst(".cell-time")?.text()) val dateUpload = dateFormat.parseSafe(element.selectFirst(".cell-time")?.text())
val chapterNum = element.selectFirst(".num")?.text()?.toFloat() ?: (i + 1f) val chapterNum = element.selectFirst(".num")?.text()?.toFloat() ?: (i + 1f)
MangaChapter( MangaChapter(
id = generateUid(url), id = generateUid(url),
@ -40,4 +40,4 @@ internal class HotComics(context: MangaLoaderContext) :
chapters = chapters, chapters = chapters,
) )
} }
} }

@ -166,7 +166,7 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = chapterDateFormat.tryParse(element.select(".epsleft > .date").text()), uploadDate = chapterDateFormat.parseSafe(element.select(".epsleft > .date").text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -151,7 +151,7 @@ internal class Kumapage(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = row.select("td:nth-child(4) a").attr("href"), url = row.select("td:nth-child(4) a").attr("href"),
scanlator = null, scanlator = null,
uploadDate = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").tryParse(row.select("td:nth-child(3)").text()), uploadDate = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parseSafe(row.select("td:nth-child(3)").text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -5,7 +5,6 @@ import org.json.JSONObject
import org.json.JSONArray import org.json.JSONArray
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.core.PagedMangaParser import org.koitharu.kotatsu.parsers.core.PagedMangaParser
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
@ -156,7 +155,7 @@ internal abstract class IkenParser(
volume = 0, volume = 0,
url = chapterUrl, url = chapterUrl,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(it.getString("createdAt").substringBefore("T")), uploadDate = dateFormat.parseSafe(it.getString("createdAt").substringBefore("T")),
branch = null, branch = null,
source = source, source = source,
) )

@ -283,9 +283,9 @@ internal abstract class KeyoappParser(
} else { } else {
it it
} }
}.let { dateFormat.tryParse(it.joinToString(" ")) } }.let { dateFormat.parseSafe(it.joinToString(" ")) }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -292,7 +292,7 @@ internal abstract class LikeMangaParser(
set(Calendar.MILLISECOND, 0) set(Calendar.MILLISECOND, 0)
}.timeInMillis }.timeInMillis
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }
} }

@ -805,9 +805,9 @@ internal abstract class MadaraParser(
} else { } else {
it it
} }
}.let { dateFormat.tryParse(it.joinToString(" ")) } }.let { dateFormat.parseSafe(it.joinToString(" ")) }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -288,9 +288,9 @@ internal abstract class MadthemeParser(
} else { } else {
it it
} }
}.let { dateFormat.tryParse(it.joinToString(" ")) } }.let { dateFormat.parseSafe(it.joinToString(" ")) }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -191,7 +191,7 @@ internal abstract class Manga18Parser(
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = href, url = href,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
source = source, source = source,
scanlator = null, scanlator = null,
branch = null, branch = null,

@ -322,9 +322,9 @@ internal abstract class MangaboxParser(
} else { } else {
it it
} }
}.let { dateFormat.tryParse(it.joinToString(" ")) } }.let { dateFormat.parseSafe(it.joinToString(" ")) }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -186,7 +186,7 @@ internal abstract class MangaReaderParser(
number = index + 1f, number = index + 1f,
volume = 0, volume = 0,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(element.selectFirst(".chapterdate")?.text()), uploadDate = dateFormat.parseSafe(element.selectFirst(".chapterdate")?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -86,7 +86,7 @@ internal class Normoyun(context: MangaLoaderContext) :
number = index + 1f, number = index + 1f,
volume = 0, volume = 0,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(element.selectFirst(".chapter-date")?.text()), uploadDate = dateFormat.parseSafe(element.selectFirst(".chapter-date")?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -55,7 +55,7 @@ internal class VexManga(context: MangaLoaderContext) :
set(Calendar.MILLISECOND, 0) set(Calendar.MILLISECOND, 0)
}.timeInMillis }.timeInMillis
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -86,7 +86,7 @@ internal class HentaiReader(context: MangaLoaderContext) :
number = index + 1f, number = index + 1f,
volume = 0, volume = 0,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(docs.selectFirst("time")?.text()), uploadDate = dateFormat.parseSafe(docs.selectFirst("time")?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -85,7 +85,7 @@ internal class LectorHentai(context: MangaLoaderContext) :
number = index + 1f, number = index + 1f,
volume = 0, volume = 0,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(docs.selectFirst("time")?.text()), uploadDate = dateFormat.parseSafe(docs.selectFirst("time")?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -137,7 +137,7 @@ internal class TuManhwas(context: MangaLoaderContext) :
return when { return when {
d.startsWith("hace") -> parseRelativeDate(date) d.startsWith("hace") -> parseRelativeDate(date)
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -123,7 +123,7 @@ internal class RevolutionScantrad(context: MangaLoaderContext) :
number = index + 1f, number = index + 1f,
volume = 0, volume = 0,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(element.selectFirst(".chapterdate")?.text()), uploadDate = dateFormat.parseSafe(element.selectFirst(".chapterdate")?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -117,7 +117,7 @@ internal class XxxRevolutionScantrad(context: MangaLoaderContext) :
number = index + 1f, number = index + 1f,
volume = 0, volume = 0,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(element.selectFirst(".chapterdate")?.text()), uploadDate = dateFormat.parseSafe(element.selectFirst(".chapterdate")?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -197,7 +197,7 @@ internal class Komikcast(context: MangaLoaderContext) :
parseRelativeDate(date) parseRelativeDate(date)
} }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -204,7 +204,7 @@ internal abstract class MangaWorldParser(
url = "$url?style=list", url = "$url?style=list",
scanlator = null, scanlator = null,
uploadDate = uploadDate =
SimpleDateFormat("dd MMMM yyyy", Locale.ITALIAN).tryParse( SimpleDateFormat("dd MMMM yyyy", Locale.ITALIAN).parseSafe(
a.selectFirst(".chap-date")?.text(), a.selectFirst(".chap-date")?.text(),
), ),
branch = null, branch = null,

@ -228,7 +228,7 @@ internal abstract class MmrcmsParser(
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = href, url = href,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
source = source, source = source,
scanlator = null, scanlator = null,
branch = null, branch = null,

@ -236,7 +236,7 @@ internal abstract class NepnepParser(
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(date), uploadDate = dateFormat.parseSafe(date),
branch = null, branch = null,
source = source, source = source,
) )

@ -251,7 +251,7 @@ internal abstract class OtakuSanctuaryParser(
parseRelativeDate(d) parseRelativeDate(d)
} }
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -234,7 +234,7 @@ internal abstract class PizzaReaderParser(
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(date), uploadDate = dateFormat.parseSafe(date),
branch = null, branch = null,
source = source, source = source,
) )

@ -144,7 +144,7 @@ internal class LerManga(context: MangaLoaderContext) : PagedMangaParser(context,
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(div.selectFirstOrThrow("small small").text()), uploadDate = dateFormat.parseSafe(div.selectFirstOrThrow("small small").text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -124,7 +124,7 @@ internal class LerMangaOnline(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
branch = null, branch = null,
source = source, source = source,
) )

@ -106,7 +106,7 @@ internal class LuratoonScansParser(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(span.nextElementSibling()?.text()), uploadDate = dateFormat.parseSafe(span.nextElementSibling()?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -117,7 +117,7 @@ internal class MangaOnline(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(dateText), uploadDate = dateFormat.parseSafe(dateText),
branch = null, branch = null,
source = source, source = source,
) )

@ -141,7 +141,7 @@ internal class YugenMangas(context: MangaLoaderContext) :
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
d.endsWith(" atrás") -> parseRelativeDate(date) d.endsWith(" atrás") -> parseRelativeDate(date)
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -1,7 +1,6 @@
package org.koitharu.kotatsu.parsers.site.en package org.koitharu.kotatsu.parsers.site.en
import org.json.JSONObject import org.json.JSONObject
import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
@ -141,7 +140,7 @@ internal class ComXParser(context: MangaLoaderContext) :
url = "/reader/$newsId/$chapterId", url = "/reader/$newsId/$chapterId",
number = chapter.getFloatOrDefault("posi", 0f), number = chapter.getFloatOrDefault("posi", 0f),
title = decodeText(chapter.getStringOrNull("title")), title = decodeText(chapter.getStringOrNull("title")),
uploadDate = dateFormat.tryParse(chapter.getStringOrNull("date")), uploadDate = dateFormat.parseSafe(chapter.getStringOrNull("date")),
source = source, source = source,
scanlator = null, scanlator = null,
branch = null, branch = null,

@ -214,7 +214,7 @@ internal class MangaWtfParser(
volume = volume, volume = volume,
url = jo.getString("id"), url = jo.getString("id"),
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(jo.getString("createdAt")), uploadDate = dateFormat.parseSafe(jo.getString("createdAt")),
branch = branches.getOrPut(branchId) { getBranchName(branchId) }, branch = branches.getOrPut(branchId) { getBranchName(branchId) },
source = source, source = source,
) )

@ -143,7 +143,7 @@ internal class NudeMoonParser(
title = manga.title, title = manga.title,
scanlator = root.getElementsByAttributeValueContaining("href", "/perevod/").firstOrNull() scanlator = root.getElementsByAttributeValueContaining("href", "/perevod/").firstOrNull()
?.textOrNull(), ?.textOrNull(),
uploadDate = dateFormat.tryParse( uploadDate = dateFormat.parseSafe(
root.getElementsByAttributeValueEnding("src", "ico/time.png").firstOrNull() root.getElementsByAttributeValueEnding("src", "ico/time.png").firstOrNull()
?.nextElementSibling()?.text(), ?.nextElementSibling()?.text(),
), ),

@ -176,7 +176,7 @@ internal class RemangaParser(
number = jo.getIntOrDefault("index", chapters.size - i).toFloat(), number = jo.getIntOrDefault("index", chapters.size - i).toFloat(),
volume = 0, volume = 0,
title = name.nullIfEmpty(), title = name.nullIfEmpty(),
uploadDate = dateFormat.tryParse(jo.getString("upload_date")), uploadDate = dateFormat.parseSafe(jo.getString("upload_date")),
scanlator = publishers?.optJSONObject(0)?.getStringOrNull("name"), scanlator = publishers?.optJSONObject(0)?.getStringOrNull("name"),
source = MangaParserSource.REMANGA, source = MangaParserSource.REMANGA,
branch = null, branch = null,
@ -192,7 +192,7 @@ internal class RemangaParser(
val pages = content.optJSONArray("pages") val pages = content.optJSONArray("pages")
if (pages == null) { if (pages == null) {
val pubDate = content.getStringOrNull("pub_date")?.let { val pubDate = content.getStringOrNull("pub_date")?.let {
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US).tryParse(it) SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US).parseSafe(it)
} }
if (pubDate != null && pubDate > System.currentTimeMillis()) { if (pubDate != null && pubDate > System.currentTimeMillis()) {
val at = SimpleDateFormat.getDateInstance(DateFormat.LONG).format(Date(pubDate)) val at = SimpleDateFormat.getDateInstance(DateFormat.LONG).format(Date(pubDate))

@ -94,7 +94,7 @@ internal class WaMangaParser(
volume = it.getIntOrDefault("volume", 0), volume = it.getIntOrDefault("volume", 0),
title = it.getStringOrNull("full_title"), title = it.getStringOrNull("full_title"),
scanlator = it.getJSONArray("teams").getJSONObject(0)?.getStringOrNull("name"), scanlator = it.getJSONArray("teams").getJSONObject(0)?.getStringOrNull("name"),
uploadDate = dateFormat.tryParse(it.getStringOrNull("published_on")), uploadDate = dateFormat.parseSafe(it.getStringOrNull("published_on")),
branch = null, branch = null,
) )
}, },

@ -179,7 +179,7 @@ internal abstract class GroupleParser(
number = number, number = number,
volume = volume, volume = volume,
url = href.withQueryParam("d", userHash), url = href.withQueryParam("d", userHash),
uploadDate = dateFormat.tryParse(tr.selectFirst("td.date")?.text()), uploadDate = dateFormat.parseSafe(tr.selectFirst("td.date")?.text()),
scanlator = translators, scanlator = translators,
source = newSource, source = newSource,
branch = null, branch = null,
@ -196,7 +196,7 @@ internal abstract class GroupleParser(
number = number, number = number,
volume = volume, volume = volume,
url = link.withQueryParam("d", userHash), url = link.withQueryParam("d", userHash),
uploadDate = dateFormat.tryParse(jo.getStringOrNull("dateCreated")), uploadDate = dateFormat.parseSafe(jo.getStringOrNull("dateCreated")),
scanlator = null, scanlator = null,
source = newSource, source = newSource,
branch = translations[personId], branch = translations[personId],

@ -99,7 +99,7 @@ internal abstract class ChanParser(
url = href, url = href,
scanlator = null, scanlator = null,
branch = null, branch = null,
uploadDate = dateFormat.tryParse(tr.selectFirst("div.date")?.text()), uploadDate = dateFormat.parseSafe(tr.selectFirst("div.date")?.text()),
source = source, source = source,
) )
}, },

@ -320,7 +320,7 @@ internal abstract class LibSocialParser(
} }
}, },
scanlator = team, scanlator = team,
uploadDate = dateFormat.tryParse(bjo.getStringOrNull("created_at")), uploadDate = dateFormat.parseSafe(bjo.getStringOrNull("created_at")),
branch = if (useBranching) team else null, branch = if (useBranching) team else null,
source = source, source = source,
) )

@ -97,7 +97,7 @@ internal abstract class ScanParser(
id = generateUid(href), id = generateUid(href),
url = href, url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain), publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.attr("data-src")?.replace("\t", "").orEmpty(), coverUrl = div.selectFirst("img")?.attr("data-src")?.replace("\t", ""),
title = div.selectFirst(".link-series h3, .item-title")?.text().orEmpty(), title = div.selectFirst(".link-series h3, .item-title")?.text().orEmpty(),
altTitles = emptySet(), altTitles = emptySet(),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
@ -116,10 +116,10 @@ internal abstract class ScanParser(
protected suspend fun getOrCreateTagMap(): Map<String, MangaTag> = mutex.withLock { protected suspend fun getOrCreateTagMap(): Map<String, MangaTag> = mutex.withLock {
tagCache?.let { return@withLock it } tagCache?.let { return@withLock it }
val tagMap = ArrayMap<String, MangaTag>()
val tagElements = webClient.httpGet("https://$domain$listUrl").parseHtml() val tagElements = webClient.httpGet("https://$domain$listUrl").parseHtml()
.requireElementById("filter-wrapper") .requireElementById("filter-wrapper")
.select(".form-filters div.form-check, .form-filters div.custom-control") .select(".form-filters div.form-check, .form-filters div.custom-control")
val tagMap = ArrayMap<String, MangaTag>(tagElements.size)
for (el in tagElements) { for (el in tagElements) {
val name = el.selectFirstOrThrow("label").text() val name = el.selectFirstOrThrow("label").text()
if (name.isEmpty()) continue if (name.isEmpty()) continue
@ -130,7 +130,7 @@ internal abstract class ScanParser(
) )
} }
tagCache = tagMap tagCache = tagMap
return@withLock tagMap tagMap
} }
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
@ -162,7 +162,7 @@ internal abstract class ScanParser(
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(doc.selectFirst("h5 div")?.text()), uploadDate = dateFormat.parseSafe(doc.selectFirst("h5 div")?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -40,7 +40,7 @@ internal class MangaFr(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(doc.selectFirstOrThrow("h5 div").text()), uploadDate = dateFormat.parseSafe(doc.selectFirstOrThrow("h5 div").text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -50,7 +50,7 @@ internal class ScanIta(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(doc.selectFirstOrThrow("h5 div").text()), uploadDate = dateFormat.parseSafe(doc.selectFirstOrThrow("h5 div").text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -174,7 +174,7 @@ internal abstract class SinmhParser(
val href = a.attrAsRelativeUrl("href") val href = a.attrAsRelativeUrl("href")
MangaChapter( MangaChapter(
id = generateUid(href), id = generateUid(href),
title = a.text(), title = a.textOrNull(),
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = href, url = href,

@ -159,7 +159,7 @@ internal class ElderManga(context: MangaLoaderContext):
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = el.selectFirst("span")?.text()?.let { dateFormat.tryParse(it) } ?: 0L, uploadDate = el.selectFirst("span")?.text()?.let { dateFormat.parseSafe(it) } ?: 0L,
branch = null, branch = null,
source = source, source = source,
) )

@ -65,7 +65,7 @@ internal class EleceedTurkiye(context: MangaLoaderContext) :
title = title, title = title,
number = title?.let { Regex("\\d+").find(it)?.value?.toFloatOrNull() } ?: 0f, number = title?.let { Regex("\\d+").find(it)?.value?.toFloatOrNull() } ?: 0f,
url = href, url = href,
uploadDate = dateFormat.tryParse(div.selectFirst("span.chapterdate")?.text()), uploadDate = dateFormat.parseSafe(div.selectFirst("span.chapterdate")?.text()),
scanlator = null, scanlator = null,
branch = null, branch = null,
source = source, source = source,

@ -90,14 +90,14 @@ internal class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context,
url = href, url = href,
publicUrl = a.attrAsAbsoluteUrl("href"), publicUrl = a.attrAsAbsoluteUrl("href"),
title = div.selectLast(".item-name")?.text().orEmpty(), title = div.selectLast(".item-name")?.text().orEmpty(),
coverUrl = div.selectFirst("img")?.src().orEmpty(), coverUrl = div.selectFirst("img")?.src(),
altTitles = emptySet(), altTitles = emptySet(),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
tags = emptySet(), tags = emptySet(),
description = null, description = null,
state = null, state = null,
authors = emptySet(), authors = emptySet(),
contentRating = if (isNsfwSource) ContentRating.ADULT else null, contentRating = sourceContentRating,
source = source, source = source,
) )
} }
@ -119,7 +119,7 @@ internal class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context,
description = null, description = null,
state = null, state = null,
authors = emptySet(), authors = emptySet(),
contentRating = if (isNsfwSource) ContentRating.ADULT else null, contentRating = sourceContentRating,
source = source, source = source,
) )
} }
@ -152,7 +152,8 @@ internal class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context,
val tags = doc.select("P.card-text .bg-success").mapNotNullToSet { tagMap[it.text()] } val tags = doc.select("P.card-text .bg-success").mapNotNullToSet { tagMap[it.text()] }
return manga.copy( return manga.copy(
description = doc.selectFirst("p.card-text")?.html()?.substringAfterLast("<br>"), description = doc.selectFirst("p.card-text")?.html()?.substringAfterLast("<br>"),
coverUrl = doc.selectFirst("div.align-items-center div.align-items-center img")?.src().orEmpty(), coverUrl = doc.selectFirst("div.align-items-center div.align-items-center img")?.src()
?: manga.coverUrl,
tags = tags, tags = tags,
chapters = doc.requireElementById("sonyuklemeler").select("tbody tr") chapters = doc.requireElementById("sonyuklemeler").select("tbody tr")
.mapChapters(reversed = true) { i, tr -> .mapChapters(reversed = true) { i, tr ->
@ -165,7 +166,7 @@ internal class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context,
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(tr.selectFirstOrThrow("time").attr("datetime")), uploadDate = dateFormat.parseSafe(tr.selectFirstOrThrow("time").attr("datetime")),
branch = null, branch = null,
source = source, source = source,
) )

@ -80,12 +80,12 @@ internal class SadScans(context: MangaLoaderContext) :
val url = "/" + a.attrAsRelativeUrl("href") val url = "/" + a.attrAsRelativeUrl("href")
MangaChapter( MangaChapter(
id = generateUid(url), id = generateUid(url),
title = a.text(), title = a.textOrNull(),
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = url, url = url,
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(div.select(".detail span").last()?.text()), uploadDate = dateFormat.parseSafe(div.select(".detail span").last()?.text()),
branch = null, branch = null,
source = source, source = source,
) )

@ -7,198 +7,199 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.core.PagedMangaParser import org.koitharu.kotatsu.parsers.core.PagedMangaParser
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.* import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@MangaSourceParser("TENSHIMANGA", "Tenshi Manga", "tr") @MangaSourceParser("TENSHIMANGA", "Tenshi Manga", "tr")
internal class TenshiManga(context: MangaLoaderContext): internal class TenshiManga(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.TENSHIMANGA, 25) { PagedMangaParser(context, MangaParserSource.TENSHIMANGA, 25) {
override val configKeyDomain = ConfigKey.Domain("tenshimanga.com") override val configKeyDomain = ConfigKey.Domain("tenshimanga.com")
private val cdnSuffix = "cdn1.$domain" private val cdnSuffix = "cdn1.$domain"
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.ALPHABETICAL_DESC, SortOrder.ALPHABETICAL_DESC,
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.UPDATED, SortOrder.UPDATED,
) )
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isSearchSupported = true, isSearchSupported = true,
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isSearchWithFiltersSupported = true, isSearchWithFiltersSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchTags(), availableTags = fetchTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED, MangaState.PAUSED), availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED, MangaState.PAUSED),
availableContentTypes = EnumSet.of( availableContentTypes = EnumSet.of(
ContentType.MANGA, ContentType.MANGA,
ContentType.MANHWA, ContentType.MANHWA,
ContentType.MANHUA, ContentType.MANHUA,
ContentType.COMICS, ContentType.COMICS,
), ),
) )
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
append("/search") append("/search")
append("?page=") append("?page=")
append(page.toString()) append(page.toString())
if (!filter.query.isNullOrEmpty()) { if (!filter.query.isNullOrEmpty()) {
append("&search=") append("&search=")
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
} }
if (filter.tags.isNotEmpty()) { if (filter.tags.isNotEmpty()) {
append("&categories=") append("&categories=")
filter.tags.joinTo(this, ",") { it.key } filter.tags.joinTo(this, ",") { it.key }
} }
if (filter.states.isNotEmpty()) { if (filter.states.isNotEmpty()) {
append("&publicStatus=") append("&publicStatus=")
filter.states.oneOrThrowIfMany()?.let { filter.states.oneOrThrowIfMany()?.let {
append( append(
when (it) { when (it) {
MangaState.ONGOING -> "1" MangaState.ONGOING -> "1"
MangaState.FINISHED -> "2" MangaState.FINISHED -> "2"
MangaState.ABANDONED -> "3" MangaState.ABANDONED -> "3"
MangaState.PAUSED -> "4" MangaState.PAUSED -> "4"
else -> "" else -> ""
}, },
) )
} }
} }
if (filter.types.isNotEmpty()) { if (filter.types.isNotEmpty()) {
append("&country=") append("&country=")
filter.types.oneOrThrowIfMany()?.let { filter.types.oneOrThrowIfMany()?.let {
append( append(
when (it) { when (it) {
ContentType.MANHUA -> "1" ContentType.MANHUA -> "1"
ContentType.MANHWA -> "2" ContentType.MANHWA -> "2"
ContentType.MANGA -> "3" ContentType.MANGA -> "3"
ContentType.COMICS -> "4" ContentType.COMICS -> "4"
else -> "" else -> ""
}, },
) )
} }
} }
append("&order=") append("&order=")
append( append(
when (order) { when (order) {
SortOrder.ALPHABETICAL -> "1" SortOrder.ALPHABETICAL -> "1"
SortOrder.ALPHABETICAL_DESC -> "2" SortOrder.ALPHABETICAL_DESC -> "2"
SortOrder.NEWEST -> "3" SortOrder.NEWEST -> "3"
SortOrder.POPULARITY -> "4" SortOrder.POPULARITY -> "4"
SortOrder.UPDATED, -> "5" SortOrder.UPDATED -> "5"
else -> "1" else -> "1"
} },
) )
} }
val doc = webClient.httpGet(url).parseHtml() val doc = webClient.httpGet(url).parseHtml()
return doc.select("section[aria-label='series area'] .card").map { card -> return doc.select("section[aria-label='series area'] .card").map { card ->
val href = card.selectFirstOrThrow("a").attrAsRelativeUrl("href") val href = card.selectFirstOrThrow("a").attrAsRelativeUrl("href")
Manga( Manga(
id = generateUid(href), id = generateUid(href),
title = card.selectFirst("h2")?.text().orEmpty(), title = card.selectFirst("h2")?.text().orEmpty(),
altTitles = emptySet(), altTitles = emptySet(),
url = href, url = href,
publicUrl = href.toAbsoluteUrl(domain), publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
contentRating = null, contentRating = null,
coverUrl = card.selectFirst("img")?.attrAsAbsoluteUrlOrNull("src"), coverUrl = card.selectFirst("img")?.attrAsAbsoluteUrlOrNull("src"),
tags = emptySet(), tags = emptySet(),
state = null, state = null,
authors = emptySet(), authors = emptySet(),
source = source, source = source,
) )
} }
} }
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val statusText = doc.selectFirst("span:contains(Durum) + span")?.text().orEmpty() val statusText = doc.selectFirst("span:contains(Durum) + span")?.text().orEmpty()
return manga.copy( return manga.copy(
tags = doc.select("a[href^='search?categories']").mapToSet { tags = doc.select("a[href^='search?categories']").mapToSet {
val key = it.attr("href").substringAfter("?categories=") val key = it.attr("href").substringAfter("?categories=")
MangaTag( MangaTag(
key = key, key = key,
title = it.text(), title = it.text(),
source = source, source = source,
) )
}, },
description = doc.selectFirst("div.grid h2 + p")?.text(), description = doc.selectFirst("div.grid h2 + p")?.text(),
state = when (statusText) { state = when (statusText) {
"Devam Ediyor" -> MangaState.ONGOING "Devam Ediyor" -> MangaState.ONGOING
"Birakildi" -> MangaState.ONGOING "Birakildi" -> MangaState.ONGOING
"Tamamlandi" -> MangaState.FINISHED "Tamamlandi" -> MangaState.FINISHED
else -> null else -> null
}, },
chapters = doc.select("div.list-episode a").mapChapters(reversed = true) { i, el -> chapters = doc.select("div.list-episode a").mapChapters(reversed = true) { i, el ->
val href = el.attrAsRelativeUrl("href") val href = el.attrAsRelativeUrl("href")
val dateFormat = SimpleDateFormat("MMM d ,yyyy", Locale("tr")) val dateFormat = SimpleDateFormat("MMM d ,yyyy", Locale("tr"))
MangaChapter( MangaChapter(
id = generateUid(href), id = generateUid(href),
title = el.selectFirstOrThrow("h3").text(), title = el.selectFirst("h3")?.textOrNull(),
number = (i + 1).toFloat(), number = (i + 1).toFloat(),
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = el.selectFirst("span")?.text()?.let { dateFormat.tryParse(it) } ?: 0L, uploadDate = dateFormat.parseSafe(el.selectFirst("span")?.text()),
branch = null, branch = null,
source = source, source = source,
) )
}, },
) )
} }
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml()
val pageRegex = Regex("\\\\\"path\\\\\":\\\\\"([^\"]+)\\\\\"") val pageRegex = Regex("\\\\\"path\\\\\":\\\\\"([^\"]+)\\\\\"")
val script = doc.select("script").find { it.html().contains(pageRegex) }?.html() ?: return emptyList() val script = doc.select("script").find { it.html().contains(pageRegex) }?.html() ?: return emptyList()
return pageRegex.findAll(script).mapNotNull { result -> return pageRegex.findAll(script).mapNotNull { result ->
result.groups[1]?.value?.let { url -> result.groups[1]?.value?.let { url ->
MangaPage( MangaPage(
id = generateUid(url), id = generateUid(url),
url = "https://$cdnSuffix/upload/series/$url", url = "https://$cdnSuffix/upload/series/$url",
preview = null, preview = null,
source = source, source = source,
) )
} }
}.toList() }.toList()
} }
private suspend fun fetchTags(): Set<MangaTag> { private suspend fun fetchTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/search").parseHtml() val doc = webClient.httpGet("https://$domain/search").parseHtml()
val script = doc.select("script").find { it.html().contains("self.__next_f.push([1,\"10:[\\\"\\$,\\\"section") }?.html() val script =
?: return emptySet() doc.select("script").find { it.html().contains("self.__next_f.push([1,\"10:[\\\"\\$,\\\"section") }?.html()
?: return emptySet()
val jsonStr = script.substringAfter("\"category\":[")
.substringBefore("],\"searchParams\":{}") val jsonStr = script.substringAfter("\"category\":[")
.replace("\\", "") .substringBefore("],\"searchParams\":{}")
.replace("\\", "")
val jsonArray = JSONArray("[$jsonStr]")
return jsonArray.mapJSONToSet { jo -> val jsonArray = JSONArray("[$jsonStr]")
MangaTag( return jsonArray.mapJSONToSet { jo ->
key = jo.getString("id"), MangaTag(
title = jo.getString("name"), key = jo.getString("id"),
source = source title = jo.getString("name"),
) source = source,
} )
} }
}
} }

@ -104,7 +104,7 @@ internal class TrWebtoon(context: MangaLoaderContext) :
id = generateUid(href), id = generateUid(href),
url = href, url = href,
publicUrl = href.toAbsoluteUrl(domain), publicUrl = href.toAbsoluteUrl(domain),
coverUrl = li.selectFirst("img")?.src().orEmpty(), coverUrl = li.selectFirst("img")?.src(),
title = li.selectFirst(".table-responsive a")?.text().orEmpty(), title = li.selectFirst(".table-responsive a")?.text().orEmpty(),
altTitles = emptySet(), altTitles = emptySet(),
rating = li.selectFirst(".row .col-xl-4 .mt-2 .my-1 .text-muted")?.text()?.substringBefore("/") rating = li.selectFirst(".row .col-xl-4 .mt-2 .my-1 .text-muted")?.text()?.substringBefore("/")
@ -117,7 +117,7 @@ internal class TrWebtoon(context: MangaLoaderContext) :
else -> null else -> null
}, },
source = source, source = source,
contentRating = if (isNsfwSource) ContentRating.ADULT else null, contentRating = sourceContentRating,
) )
} }
} }
@ -129,7 +129,7 @@ internal class TrWebtoon(context: MangaLoaderContext) :
id = generateUid(href), id = generateUid(href),
url = href, url = href,
publicUrl = href.toAbsoluteUrl(domain), publicUrl = href.toAbsoluteUrl(domain),
coverUrl = li.selectFirst(".figure img")?.src().orEmpty(), coverUrl = li.selectFirst(".figure img")?.src(),
title = li.selectFirst(".title")?.text().orEmpty(), title = li.selectFirst(".title")?.text().orEmpty(),
altTitles = emptySet(), altTitles = emptySet(),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
@ -207,7 +207,7 @@ internal class TrWebtoon(context: MangaLoaderContext) :
d.endsWith(" önce") -> parseRelativeDate(date) d.endsWith(" önce") -> parseRelativeDate(date)
else -> dateFormat.tryParse(date) else -> dateFormat.parseSafe(date)
} }
} }

@ -7,83 +7,83 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.core.PagedMangaParser import org.koitharu.kotatsu.parsers.core.PagedMangaParser
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.* import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@MangaSourceParser("UZAYMANGA", "Uzay Manga", "tr") @MangaSourceParser("UZAYMANGA", "Uzay Manga", "tr")
internal class UzayManga(context: MangaLoaderContext): internal class UzayManga(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.UZAYMANGA, 25) { PagedMangaParser(context, MangaParserSource.UZAYMANGA, 25) {
override val configKeyDomain = ConfigKey.Domain("uzaymanga.com") override val configKeyDomain = ConfigKey.Domain("uzaymanga.com")
private val cdnSuffix = "cdn1.$domain" private val cdnSuffix = "cdn1.$domain"
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.ALPHABETICAL_DESC, SortOrder.ALPHABETICAL_DESC,
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.UPDATED, SortOrder.UPDATED,
) )
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isSearchSupported = true, isSearchSupported = true,
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isSearchWithFiltersSupported = true, isSearchWithFiltersSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchTags(), availableTags = fetchTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED, MangaState.PAUSED), availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED, MangaState.PAUSED),
availableContentTypes = EnumSet.of( availableContentTypes = EnumSet.of(
ContentType.MANGA, ContentType.MANGA,
ContentType.MANHWA, ContentType.MANHWA,
ContentType.MANHUA, ContentType.MANHUA,
ContentType.COMICS, ContentType.COMICS,
), ),
) )
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
append("/search") append("/search")
append("?page=") append("?page=")
append(page.toString()) append(page.toString())
if (!filter.query.isNullOrEmpty()) { if (!filter.query.isNullOrEmpty()) {
append("&search=") append("&search=")
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
} }
if (filter.tags.isNotEmpty()) { if (filter.tags.isNotEmpty()) {
append("&categories=") append("&categories=")
filter.tags.joinTo(this, ",") { it.key } filter.tags.joinTo(this, ",") { it.key }
} }
if (filter.states.isNotEmpty()) { if (filter.states.isNotEmpty()) {
append("&publicStatus=") append("&publicStatus=")
filter.states.oneOrThrowIfMany()?.let { filter.states.oneOrThrowIfMany()?.let {
append( append(
when (it) { when (it) {
MangaState.ONGOING -> "1" MangaState.ONGOING -> "1"
MangaState.FINISHED -> "2" MangaState.FINISHED -> "2"
MangaState.ABANDONED -> "3" MangaState.ABANDONED -> "3"
MangaState.PAUSED -> "4" MangaState.PAUSED -> "4"
else -> "" else -> ""
}, },
) )
} }
} }
if (filter.types.isNotEmpty()) { if (filter.types.isNotEmpty()) {
append("&country=") append("&country=")
filter.types.oneOrThrowIfMany()?.let { filter.types.oneOrThrowIfMany()?.let {
append( append(
when (it) { when (it) {
@ -97,108 +97,109 @@ internal class UzayManga(context: MangaLoaderContext):
} }
} }
append("&order=") append("&order=")
append( append(
when (order) { when (order) {
SortOrder.ALPHABETICAL -> "1" SortOrder.ALPHABETICAL -> "1"
SortOrder.ALPHABETICAL_DESC -> "2" SortOrder.ALPHABETICAL_DESC -> "2"
SortOrder.NEWEST -> "3" SortOrder.NEWEST -> "3"
SortOrder.POPULARITY -> "4" SortOrder.POPULARITY -> "4"
SortOrder.UPDATED -> "5" SortOrder.UPDATED -> "5"
else -> "1" else -> "1"
} },
) )
} }
val doc = webClient.httpGet(url).parseHtml() val doc = webClient.httpGet(url).parseHtml()
return doc.select("section[aria-label='series area'] .card").map { card -> return doc.select("section[aria-label='series area'] .card").map { card ->
val href = card.selectFirstOrThrow("a").attrAsRelativeUrl("href") val href = card.selectFirstOrThrow("a").attrAsRelativeUrl("href")
Manga( Manga(
id = generateUid(href), id = generateUid(href),
title = card.selectFirst("h2")?.text().orEmpty(), title = card.selectFirst("h2")?.text().orEmpty(),
altTitles = emptySet(), altTitles = emptySet(),
url = href, url = href,
publicUrl = href.toAbsoluteUrl(domain), publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
contentRating = null, contentRating = null,
coverUrl = card.selectFirst("img")?.attrAsAbsoluteUrlOrNull("src"), coverUrl = card.selectFirst("img")?.attrAsAbsoluteUrlOrNull("src"),
tags = emptySet(), tags = emptySet(),
state = null, state = null,
authors = emptySet(), authors = emptySet(),
source = source, source = source,
) )
} }
} }
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val statusText = doc.selectFirst("span:contains(Durum) + span")?.text().orEmpty() val statusText = doc.selectFirst("span:contains(Durum) + span")?.text().orEmpty()
return manga.copy( return manga.copy(
tags = doc.select("a[href^='search?categories']").mapToSet { tags = doc.select("a[href^='search?categories']").mapToSet {
val key = it.attr("href").substringAfter("?categories=") val key = it.attr("href").substringAfter("?categories=")
MangaTag( MangaTag(
key = key, key = key,
title = it.text(), title = it.text(),
source = source, source = source,
) )
}, },
description = doc.selectFirst("div.grid h2 + p")?.text(), description = doc.selectFirst("div.grid h2 + p")?.text(),
state = when (statusText) { state = when (statusText) {
"Devam Ediyor" -> MangaState.ONGOING "Devam Ediyor" -> MangaState.ONGOING
"Birakildi" -> MangaState.ONGOING "Birakildi" -> MangaState.ONGOING
"Tamamlandi" -> MangaState.FINISHED "Tamamlandi" -> MangaState.FINISHED
else -> null else -> null
}, },
chapters = doc.select("div.list-episode a").mapChapters(reversed = true) { i, el -> chapters = doc.select("div.list-episode a").mapChapters(reversed = true) { i, el ->
val href = el.attrAsRelativeUrl("href") val href = el.attrAsRelativeUrl("href")
val dateFormat = SimpleDateFormat("MMM d ,yyyy", Locale("tr")) val dateFormat = SimpleDateFormat("MMM d ,yyyy", Locale("tr"))
MangaChapter( MangaChapter(
id = generateUid(href), id = generateUid(href),
title = el.selectFirstOrThrow("h3").text(), title = el.selectFirst("h3")?.textOrNull(),
number = (i + 1).toFloat(), number = (i + 1).toFloat(),
volume = 0, volume = 0,
url = href, url = href,
scanlator = null, scanlator = null,
uploadDate = el.selectFirst("span")?.text()?.let { dateFormat.tryParse(it) } ?: 0L, uploadDate = dateFormat.parseSafe(el.selectFirst("span")?.text()),
branch = null, branch = null,
source = source, source = source,
) )
}, },
) )
} }
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml()
val pageRegex = Regex("\\\\\"path\\\\\":\\\\\"([^\"]+)\\\\\"") val pageRegex = Regex("\\\\\"path\\\\\":\\\\\"([^\"]+)\\\\\"")
val script = doc.select("script").find { it.html().contains(pageRegex) }?.html() ?: return emptyList() val script = doc.select("script").find { it.html().contains(pageRegex) }?.html() ?: return emptyList()
return pageRegex.findAll(script).mapNotNull { result -> return pageRegex.findAll(script).mapNotNull { result ->
result.groups[1]?.value?.let { url -> result.groups[1]?.value?.let { url ->
MangaPage( MangaPage(
id = generateUid(url), id = generateUid(url),
url = "https://$cdnSuffix/upload/series/$url", url = "https://$cdnSuffix/upload/series/$url",
preview = null, preview = null,
source = source, source = source,
) )
} }
}.toList() }.toList()
} }
private suspend fun fetchTags(): Set<MangaTag> { private suspend fun fetchTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/search").parseHtml() val doc = webClient.httpGet("https://$domain/search").parseHtml()
val script = doc.select("script").find { it.html().contains("self.__next_f.push([1,\"10:[\\\"\\$,\\\"section") }?.html() val script =
?: return emptySet() doc.select("script").find { it.html().contains("self.__next_f.push([1,\"10:[\\\"\\$,\\\"section") }?.html()
?: return emptySet()
val jsonStr = script.substringAfter("\"category\":[")
.substringBefore("],\"searchParams\":{}") val jsonStr = script.substringAfter("\"category\":[")
.replace("\\", "") .substringBefore("],\"searchParams\":{}")
.replace("\\", "")
val jsonArray = JSONArray("[$jsonStr]")
return jsonArray.mapJSONToSet { jo -> val jsonArray = JSONArray("[$jsonStr]")
MangaTag( return jsonArray.mapJSONToSet { jo ->
key = jo.getString("id"), MangaTag(
title = jo.getString("name"), key = jo.getString("id"),
source = source title = jo.getString("name"),
) source = source,
} )
} }
}
} }

@ -78,7 +78,7 @@ internal class HentaiUkrParser(context: MangaLoaderContext) : AbstractMangaParse
volume = 0, volume = 0,
url = manga.url, url = manga.url,
scanlator = null, scanlator = null,
uploadDate = date.tryParse(jsonDeferred.await().getString("add_date")), uploadDate = date.parseSafe(jsonDeferred.await().getString("add_date")),
branch = null, branch = null,
source = source, source = source,
), ),

@ -80,7 +80,7 @@ internal class HoneyMangaParser(context: MangaLoaderContext) :
volume = volume, volume = volume,
url = jo.optString("chapterResourcesId"), url = jo.optString("chapterResourcesId"),
scanlator = null, scanlator = null,
uploadDate = dateFormat.tryParse(jo.getString("lastUpdated")), uploadDate = dateFormat.parseSafe(jo.getString("lastUpdated")),
branch = null, branch = null,
source = source, source = source,
) )

@ -145,7 +145,7 @@ internal class MangaInUaParser(context: MangaLoaderContext) : PagedMangaParser(
} else { } else {
DEF_BRANCH_NAME DEF_BRANCH_NAME
}, },
uploadDate = dateFormat.tryParse(item.selectFirst("div.ltcright")?.text()), uploadDate = dateFormat.parseSafe(item.selectFirst("div.ltcright")?.text()),
source = source, source = source,
) )
}, },

@ -150,7 +150,7 @@ internal class BlogTruyenParser(context: MangaLoaderContext) :
val name = titleElement.text() val name = titleElement.text()
val relativeUrl = titleElement.attrAsRelativeUrl("href") val relativeUrl = titleElement.attrAsRelativeUrl("href")
val id = relativeUrl.substringAfter('/').substringBefore('/') val id = relativeUrl.substringAfter('/').substringBefore('/')
val uploadDate = dateFormat.tryParse(element.select("span.publishedDate").text()) val uploadDate = dateFormat.parseSafe(element.select("span.publishedDate").text())
MangaChapter( MangaChapter(
id = generateUid(id), id = generateUid(id),
title = name, title = name,

@ -202,7 +202,7 @@ internal class BlogTruyenVN(context: MangaLoaderContext) :
val name = titleElement.text() val name = titleElement.text()
val relativeUrl = titleElement.attrAsRelativeUrl("href") val relativeUrl = titleElement.attrAsRelativeUrl("href")
val id = relativeUrl.substringAfter('/').substringBefore('/') val id = relativeUrl.substringAfter('/').substringBefore('/')
val uploadDate = dateFormat.tryParse(element.select("span.publishedDate").text()) val uploadDate = dateFormat.parseSafe(element.select("span.publishedDate").text())
MangaChapter( MangaChapter(
id = generateUid(id), id = generateUid(id),
title = name, title = name,

@ -94,7 +94,7 @@ internal class CMangaParser(context: MangaLoaderContext) :
number = chapterNumber, number = chapterNumber,
volume = 0, volume = 0,
url = "/album/$slug/chapter-$mangaId-$chapterId", url = "/album/$slug/chapter-$mangaId-$chapterId",
uploadDate = df.tryParse(info.getString("last_update")), uploadDate = df.parseSafe(info.getString("last_update")),
branch = null, branch = null,
scanlator = null, scanlator = null,
source = source, source = source,

@ -197,7 +197,7 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
volume = 0, volume = 0,
url = "/api/v2/chapters/$chapterId", url = "/api/v2/chapters/$chapterId",
scanlator = team, scanlator = team,
uploadDate = chapterDateFormat.tryParse(jo.getStringOrNull("created_at")), uploadDate = chapterDateFormat.parseSafe(jo.getStringOrNull("created_at")),
branch = null, branch = null,
source = source, source = source,
) )

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save