From 7c8f6924884a070101007b89d8ccf29b1cbd6409 Mon Sep 17 00:00:00 2001 From: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:18:40 +0500 Subject: [PATCH] add Blacktoon (#4617) * add BlackToon * newline --- src/ko/blacktoon/build.gradle | 8 + .../blacktoon/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3337 bytes .../blacktoon/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2228 bytes .../res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4642 bytes .../res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7680 bytes .../res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10812 bytes .../extension/ko/blacktoon/BlackToon.kt | 218 ++++++++++++++++++ .../tachiyomi/extension/ko/blacktoon/Data.kt | 57 +++++ .../tachiyomi/extension/ko/blacktoon/Dto.kt | 84 +++++++ .../extension/ko/blacktoon/Filters.kt | 122 ++++++++++ 10 files changed, 489 insertions(+) create mode 100644 src/ko/blacktoon/build.gradle create mode 100644 src/ko/blacktoon/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/ko/blacktoon/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/ko/blacktoon/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/ko/blacktoon/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/ko/blacktoon/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/BlackToon.kt create mode 100644 src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Data.kt create mode 100644 src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Dto.kt create mode 100644 src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Filters.kt diff --git a/src/ko/blacktoon/build.gradle b/src/ko/blacktoon/build.gradle new file mode 100644 index 000000000..dd87ca866 --- /dev/null +++ b/src/ko/blacktoon/build.gradle @@ -0,0 +1,8 @@ +ext { + extName = 'BlackToon' + extClass = '.BlackToon' + extVersionCode = 1 + isNsfw = true +} + +apply from: "$rootDir/common.gradle" diff --git a/src/ko/blacktoon/res/mipmap-hdpi/ic_launcher.png b/src/ko/blacktoon/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..e625e5a3596465c85caedea13f27c42bb7afa7a5 GIT binary patch literal 3337 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 YKNt--Gr6fGod5s;07*qoM6N<$f|PZyi2wiq literal 0 HcmV?d00001 diff --git a/src/ko/blacktoon/res/mipmap-xxhdpi/ic_launcher.png b/src/ko/blacktoon/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..9366697b47029129ab5453c2112df31548e5605a GIT binary patch literal 7680 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 + if (currentBaseUrlHost.isBlank()) { + noRedirectClient.newCall(GET(baseUrl, headers)).execute().use { + currentBaseUrlHost = it.headers["location"]?.toHttpUrlOrNull()?.host + ?: throw IOException("unable to get updated url") + } + } + + val request = chain.request().newBuilder().apply { + if (chain.request().url.toString().startsWith(baseUrl)) { + url( + chain.request().url.newBuilder() + .host(currentBaseUrlHost) + .build(), + ) + } + header("Referer", "https://$currentBaseUrlHost/") + header("Origin", "https://$currentBaseUrlHost") + }.build() + + return@addInterceptor chain.proceed(request) + }.build() + + private val noRedirectClient = network.cloudflareClient.newBuilder() + .followRedirects(false) + .build() + + private val json by injectLazy() + + private val db by lazy { + val doc = client.newCall(GET(baseUrl, headers)).execute().asJsoup() + doc.select("script[src*=data/webtoon]").flatMap { scriptEl -> + var listIdx: Int + client.newCall(GET(scriptEl.absUrl("src"), headers)) + .execute().body.string() + .also { + listIdx = it.substringBefore(" = ") + .substringAfter("data") + .toInt() + } + .substringAfter(" = ") + .removeSuffix(";") + .let { json.decodeFromString>(it) } + .onEach { it.listIndex = listIdx } + } + } + + private fun List.getPageChunk(page: Int): MangasPage { + return MangasPage( + mangas = subList((page - 1) * 24, min(page * 24, size)) + .map { it.toSManga(cdnUrl) }, + hasNextPage = (page + 1) * 24 <= size, + ) + } + + override fun fetchPopularManga(page: Int): Observable { + return Observable.just( + db.sortedByDescending { it.hot }.getPageChunk(page), + ) + } + + override fun fetchLatestUpdates(page: Int): Observable { + return Observable.just( + db.sortedByDescending { it.updatedAt }.getPageChunk(page), + ) + } + + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + var list = db + + if (query.isNotBlank()) { + val stdQuery = query.trim() + list = list.filter { + it.name.contains(stdQuery, true) || + it.author.contains(stdQuery, true) + } + } + + filters.filterIsInstance().forEach { + list = it.applyFilter(list) + } + + return Observable.just( + list.getPageChunk(page), + ) + } + + override fun getFilterList() = getFilters() + + override fun mangaDetailsRequest(manga: SManga): Request { + return GET("$baseUrl/webtoon/${manga.url}.html#${manga.status}", headers) + } + + override fun getMangaUrl(manga: SManga): String { + return buildString { + if (currentBaseUrlHost.isBlank()) { + append(baseUrl) + } else { + append("https://") + append(currentBaseUrlHost) + } + append("/webtoon/") + append(manga.url) + append(".html") + } + } + + override fun mangaDetailsParse(response: Response): SManga { + val doc = response.asJsoup() + return SManga.create().apply { + description = doc.select("p.mt-2").last()?.text() + thumbnail_url = doc.selectFirst("script:containsData(+img_domain+)")?.data()?.let { + cdnUrl + it.substringAfter("+'").substringBefore("'+") + } + status = response.request.url.fragment!!.toInt() + } + } + + override fun chapterListRequest(manga: SManga): Request { + val url = "$baseUrl/data/toonlist/${manga.url}.js?v=${"%.17f".format(Random.nextDouble())}" + + return GET(url, headers) + } + + override fun chapterListParse(response: Response): List { + val mangaId = response.request.url.pathSegments.last().removeSuffix(".js") + + val data = response.body.string() + .substringAfter(" = ") + .removeSuffix(";") + .let { json.decodeFromString>(it) } + + return data.map { it.toSChapter(mangaId) }.reversed() + } + + override fun getChapterUrl(chapter: SChapter): String { + return buildString { + if (currentBaseUrlHost.isBlank()) { + append(baseUrl) + } else { + append("https://") + append(currentBaseUrlHost) + } + append("/webtoons/") + append(chapter.url) + append(".html") + } + } + + override fun pageListRequest(chapter: SChapter): Request { + return GET("$baseUrl/webtoons/${chapter.url}.html", headers) + } + + override fun pageListParse(response: Response): List { + val document = response.asJsoup() + + return document.select("#toon_content_imgs img").map { + Page(0, imageUrl = cdnUrl + it.attr("o_src")) + } + } + + // unused + override fun popularMangaRequest(page: Int): Request { + throw UnsupportedOperationException() + } + override fun popularMangaParse(response: Response): MangasPage { + throw UnsupportedOperationException() + } + override fun latestUpdatesRequest(page: Int): Request { + throw UnsupportedOperationException() + } + override fun latestUpdatesParse(response: Response): MangasPage { + throw UnsupportedOperationException() + } + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + throw UnsupportedOperationException() + } + override fun searchMangaParse(response: Response): MangasPage { + throw UnsupportedOperationException() + } + override fun imageUrlParse(response: Response): String { + throw UnsupportedOperationException() + } +} diff --git a/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Data.kt b/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Data.kt new file mode 100644 index 000000000..56aac86a8 --- /dev/null +++ b/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Data.kt @@ -0,0 +1,57 @@ +package eu.kanade.tachiyomi.extension.ko.blacktoon + +val platformsMap = mapOf( + 1 to "네이버", + 2 to "다음", + 3 to "카카오", + 4 to "레진", + 5 to "투믹스", + 6 to "탑툰", + 7 to "코미카", + 8 to "배틀코믹", + 9 to "코믹GT", + 10 to "케이툰", + 11 to "애니툰", + 12 to "폭스툰", + 13 to "피너툰", + 14 to "봄툰", + 15 to "코미코", + 16 to "무툰", + 17 to "지존신마", + 99 to "기타", +) + +val tagsMap = mapOf( + 1 to "학원", + 2 to "액션", + 3 to "SF", + 4 to "스토리", + 5 to "판타지", + 6 to "BL/백합", + 7 to "개그/코미디", + 8 to "연애/순정", + 9 to "드라마", + 10 to "로맨스", + 11 to "시대극", + 12 to "스포츠", + 13 to "일상", + 14 to "추리/미스터리", + 15 to "공포/스릴러", + 16 to "성인", + 17 to "옴니버스", + 18 to "에피소드", + 19 to "무협", + 20 to "소년", + 99 to "기타", +) + +val publishDayMap = mapOf( + 1 to "월", + 2 to "화", + 3 to "수", + 4 to "목", + 5 to "금", + 6 to "토", + 7 to "일", + 10 to "열흘", +) diff --git a/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Dto.kt b/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Dto.kt new file mode 100644 index 000000000..15d03c0a7 --- /dev/null +++ b/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Dto.kt @@ -0,0 +1,84 @@ +package eu.kanade.tachiyomi.extension.ko.blacktoon + +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.Locale + +@Serializable +class SeriesItem( + @SerialName("x") + private val id: String, + @SerialName("t") + val name: String, + @SerialName("p") + private val poster: String = "", + @SerialName("au") + val author: String = "", + @SerialName("g") + val updatedAt: Long = 0, + @SerialName("tag") + private val tagIds: String = "", + @SerialName("c") + private val platformId: String = "-1", + @SerialName("d") + private val publishDayId: String = "-1", + @SerialName("h") + val hot: Int = 0, +) { + val tag get() = tagIds.split(",") + .filter(String::isNotBlank) + .map(String::toInt) + + val platform get() = platformId.toInt() + + val publishDay get() = publishDayId.toInt() + + var listIndex = -1 + + fun toSManga(cdnUrl: String) = SManga.create().apply { + url = id + title = name + thumbnail_url = poster.takeIf { it.isNotBlank() }?.let { + cdnUrl + it.replace("_x4", "").replace("_x3", "") + } + genre = buildList { + add(platformsMap[platform]) + add(publishDayMap[publishDay]) + tag.forEach { + add(tagsMap[it]) + } + }.filterNotNull().joinToString() + author = this@SeriesItem.author + status = when (listIndex) { + 0 -> SManga.COMPLETED + 1 -> SManga.ONGOING + else -> SManga.UNKNOWN + } + } +} + +@Serializable +class Chapter( + @SerialName("id") + val id: String, + @SerialName("t") + val title: String, + @SerialName("d") + val date: String = "", +) { + fun toSChapter(mangaId: String) = SChapter.create().apply { + url = "$mangaId/$id" + name = title + date_upload = try { + dateFormat.parse(date)!!.time + } catch (_: ParseException) { + 0L + } + } +} + +private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) diff --git a/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Filters.kt b/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Filters.kt new file mode 100644 index 000000000..85c61baec --- /dev/null +++ b/src/ko/blacktoon/src/eu/kanade/tachiyomi/extension/ko/blacktoon/Filters.kt @@ -0,0 +1,122 @@ +package eu.kanade.tachiyomi.extension.ko.blacktoon + +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList + +interface ListFilter { + fun applyFilter(list: List): List +} + +class TriFilter(name: String, val id: Int) : Filter.TriState(name) + +abstract class TriFilterGroup( + name: String, + values: Map, +) : Filter.Group(name, values.map { TriFilter(it.value, it.key) }), ListFilter { + private val included get() = state.filter { it.isIncluded() }.map { it.id } + private val excluded get() = state.filter { it.isExcluded() }.map { it.id } + + abstract fun SeriesItem.getAttribute(): List + override fun applyFilter(list: List): List { + return list.filter { series -> + included.all { + it in series.getAttribute() + } and excluded.all { + it !in series.getAttribute() + } + } + } +} + +abstract class SelectFilter( + name: String, + private val options: List>, +) : Filter.Select( + name, + options.map { it.second }.toTypedArray(), +) { + + val selected get() = options[state].first +} + +class TagFilter : TriFilterGroup("Tag", tagsMap) { + override fun SeriesItem.getAttribute(): List { + return tag + } +} + +class PlatformFilter : + SelectFilter( + "Platform", + buildList { + add(-1 to "") + platformsMap.forEach { + add(it.key to it.value) + } + }, + ), + ListFilter { + override fun applyFilter(list: List): List { + return list.filter { selected == -1 || it.platform == selected } + } +} + +class PublishDayFilter : + SelectFilter( + "Publishing Day", + buildList { + add(-1 to "") + publishDayMap.forEach { + add(it.key to it.value) + } + }, + ), + ListFilter { + override fun applyFilter(list: List): List { + return list.filter { selected == -1 || it.publishDay == state } + } +} + +class Status : + SelectFilter( + "Status", + listOf( + -1 to "All", + 1 to "연재", + 0 to "완결", + ), + ), + ListFilter { + override fun applyFilter(list: List): List { + return when (selected) { + 1, 0 -> list.filter { it.listIndex == selected } + else -> list + } + } +} + +class Order : + SelectFilter( + "Order by", + listOf( + 0 to "최신순", + 1 to "인기순", + ), + ), + ListFilter { + override fun applyFilter(list: List): List { + return when (selected) { + 0 -> list.sortedByDescending { it.updatedAt } + 1 -> list.sortedByDescending { it.hot } + else -> list + } + } +} + +fun getFilters() = FilterList( + Order(), + Status(), + PlatformFilter(), + PublishDayFilter(), + TagFilter(), +)