From b0bfe86ca220f34ca28c5bbc7b3246579a838045 Mon Sep 17 00:00:00 2001 From: tanaka-shizuku3 Date: Sat, 11 Oct 2025 15:32:50 +0800 Subject: [PATCH] Add Creative Comic Collection (#10739) * Add Creative Comic * Add login * Make getToken() non null * Use String.parseAs --- src/zh/creativecomic/build.gradle | 11 + .../res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 4471 bytes .../res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2602 bytes .../res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5669 bytes .../res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 9955 bytes .../res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 13130 bytes .../zh/creativecomic/Creativecomic.kt | 244 ++++++++++++++++++ .../zh/creativecomic/CreativecomicDto.kt | 108 ++++++++ 8 files changed, 363 insertions(+) create mode 100644 src/zh/creativecomic/build.gradle create mode 100644 src/zh/creativecomic/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/zh/creativecomic/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/zh/creativecomic/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/zh/creativecomic/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/zh/creativecomic/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/zh/creativecomic/src/eu/kanade/tachiyomi/extension/zh/creativecomic/Creativecomic.kt create mode 100644 src/zh/creativecomic/src/eu/kanade/tachiyomi/extension/zh/creativecomic/CreativecomicDto.kt diff --git a/src/zh/creativecomic/build.gradle b/src/zh/creativecomic/build.gradle new file mode 100644 index 000000000..0c161e9c0 --- /dev/null +++ b/src/zh/creativecomic/build.gradle @@ -0,0 +1,11 @@ +ext { + extName = 'Creative Comic Collection' + extClass = '.Creativecomic' + extVersionCode = 1 +} + +apply from: "$rootDir/common.gradle" + +dependencies { + implementation(project(':lib:cryptoaes')) +} diff --git a/src/zh/creativecomic/res/mipmap-hdpi/ic_launcher.png b/src/zh/creativecomic/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..df85f88646fdaf72acba0483c15e408b4d5905e1 GIT binary patch literal 4471 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 literal 0 HcmV?d00001 diff --git a/src/zh/creativecomic/res/mipmap-xhdpi/ic_launcher.png b/src/zh/creativecomic/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..82af3e33bf8150480f614d0b1634e9efb7d7c489 GIT binary patch literal 5669 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 z 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 literal 0 HcmV?d00001 diff --git a/src/zh/creativecomic/src/eu/kanade/tachiyomi/extension/zh/creativecomic/Creativecomic.kt b/src/zh/creativecomic/src/eu/kanade/tachiyomi/extension/zh/creativecomic/Creativecomic.kt new file mode 100644 index 000000000..8593540e9 --- /dev/null +++ b/src/zh/creativecomic/src/eu/kanade/tachiyomi/extension/zh/creativecomic/Creativecomic.kt @@ -0,0 +1,244 @@ +package eu.kanade.tachiyomi.extension.zh.creativecomic + +import android.annotation.SuppressLint +import android.app.Application +import android.os.Handler +import android.os.Looper +import android.util.Base64 +import android.webkit.WebView +import android.webkit.WebViewClient +import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.MangasPage +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.online.HttpSource +import keiyoushi.utils.parseAs +import okhttp3.Headers +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Interceptor +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.ResponseBody.Companion.toResponseBody +import uy.kohesive.injekt.injectLazy +import java.security.MessageDigest +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import javax.crypto.Cipher +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec + +class Creativecomic : HttpSource() { + override val name: String = "CCC追漫台" + override val lang: String = "zh-Hant" + override val supportsLatest: Boolean = true + override val baseUrl: String = "https://www.creative-comic.tw" + private val apiUrl = "https://api.creative-comic.tw" + private var _pageKey: ByteArray? = null + private var _pageIv: ByteArray? = null + private var _token: String? = null + private val context: Application by injectLazy() + private val handler by lazy { Handler(Looper.getMainLooper()) } + + @SuppressLint("SetJavaScriptEnabled") + fun getToken(): String { + _token?.also { return it } + val latch = CountDownLatch(1) + handler.post { + val webview = WebView(context) + with(webview.settings) { + javaScriptEnabled = true + domStorageEnabled = true + databaseEnabled = true + blockNetworkImage = true + } + webview.webViewClient = object : WebViewClient() { + override fun onPageFinished(view: WebView?, url: String?) { + view!!.evaluateJavascript("window.localStorage.getItem('accessToken')") { token -> + webview.stopLoading() + webview.destroy() + _token = token.removeSurrounding("\"") + latch.countDown() + } + } + } + webview.loadDataWithBaseURL("$baseUrl/", " ", "text/html", null, null) + } + latch.await(10, TimeUnit.SECONDS) + return _token!! + } + + private fun getApiHeaders(): Headers { + val token = getToken() + if (token == "null") { + return headersBuilder() + .add("device: web_desktop") + .add("uuid: null") + .build() + } + + // Check token expiration + val claims = token.substringAfter(".").substringBefore(".") + val decoded = Base64.decode(claims, Base64.DEFAULT).decodeToString() + val expiration = decoded.parseAs().exp + val now = System.currentTimeMillis() / 1000 + if (now > expiration) throw Exception("token过期,请到WebView重新登录") + + return headersBuilder() + .add("device: web_desktop") + .add("Authorization: Bearer $token") + .build() + } + + private fun getPageKeyIv(): Pair { + _pageIv?.also { return Pair(_pageKey!!, _pageIv!!) } + val token = (getToken().takeUnless { it == "null" } ?: "freeforccc2020reading").toByteArray() + val md = MessageDigest.getInstance("SHA-512") + val digest = md.digest(token) + _pageKey = digest.sliceArray(0..31) + _pageIv = _pageKey!!.sliceArray(15..30) + return Pair(_pageKey!!, _pageIv!!) + } + + override val client: OkHttpClient = network.cloudflareClient.newBuilder() + .addInterceptor(::authIntercept) + .build() + + private fun authIntercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val response = chain.proceed(request) + val url = request.url.toString() + if (!url.startsWith("https://storage.googleapis.com/ccc-www/fs/chapter_content/encrypt/")) { + return response + } + + val (key, iv) = request.url.fragment!!.split(":") + val keyBytes = key.hexStringToByteArray() + val ivBytes = iv.hexStringToByteArray() + val cipherBytes = response.body.bytes() + val cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING") + val keySpec = SecretKeySpec(keyBytes, "AES") + cipher.init(Cipher.DECRYPT_MODE, keySpec, IvParameterSpec(ivBytes)) + val data = cipher.doFinal(cipherBytes).toString(Charsets.UTF_8) + + val image = Base64.decode(data.substringAfter("base64,"), Base64.DEFAULT) + val mediaType = data.substringAfter("data:").substringBefore(";").toMediaType() + val body = image.toResponseBody(mediaType) + return response.newBuilder().body(body).build() + } + + // Popular + + override fun popularMangaRequest(page: Int): Request { + return GET("$apiUrl/book?page=$page&rows_per_page=24&sort_by=like_count&class=2", getApiHeaders()) + } + + override fun popularMangaParse(response: Response): MangasPage { + val data = response.parseAs().data + val total = data.total + val page = response.request.url.queryParameter("page")!!.toInt() + val rowsPerPage = response.request.url.queryParameter("rows_per_page")!!.toInt() + val hasNextPage = total > page * rowsPerPage + val mangas = data.data.map { + it.toSManga() + } + return MangasPage(mangas, hasNextPage) + } + + // Latest + + override fun latestUpdatesRequest(page: Int): Request { + return GET("$apiUrl/book?page=$page&rows_per_page=24&sort_by=updated_at&class=2", getApiHeaders()) + } + + override fun latestUpdatesParse(response: Response): MangasPage = popularMangaParse(response) + + // Search + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = apiUrl.toHttpUrl().newBuilder().apply { + encodedPath("/book") + addQueryParameter("page", page.toString()) + addQueryParameter("rows_per_page", "12") + addQueryParameter("keyword", query) + addQueryParameter("category", "all") + addQueryParameter("sort_by", "updated_at") + addQueryParameter("class", "2") + }.build() + return GET(url, getApiHeaders()) + } + + override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response) + + // Details + + override fun mangaDetailsRequest(manga: SManga): Request { + return GET("$apiUrl/book/${manga.url}/info", getApiHeaders()) + } + + override fun mangaDetailsParse(response: Response): SManga { + return response.parseAs().data.toSManga() + } + + // Chapters + + override fun chapterListRequest(manga: SManga): Request { + return GET("$apiUrl/book/${manga.url}/chapter", getApiHeaders()) + } + + override fun chapterListParse(response: Response): List { + return response.parseAs().data.chapters.map { + it.toSChapter() + }.reversed() + } + + // Pages + + override fun pageListRequest(chapter: SChapter): Request { + return GET("$apiUrl/book/chapter/${chapter.url}", getApiHeaders()) + } + + override fun pageListParse(response: Response): List { + return response.parseAs().data.chapter.proportion.mapIndexed { index, it -> + Page(index, it.id.toString()) + } + } + + override fun imageUrlRequest(page: Page): Request { + return GET("$apiUrl/book/chapter/image/${page.url}", getApiHeaders()) + } + + override fun imageUrlParse(response: Response): String { + val encryptedKey = response.parseAs().data.key + val (pageKey, pageIv) = getPageKeyIv() + val decryptedKey = CryptoAES.decrypt(encryptedKey, pageKey, pageIv) + val id = response.request.url.encodedPathSegments.last() + return "https://storage.googleapis.com/ccc-www/fs/chapter_content/encrypt/$id/2#$decryptedKey" + } + + override fun getMangaUrl(manga: SManga): String { + return "$baseUrl/zh/book/${manga.url}/content" + } + + override fun getChapterUrl(chapter: SChapter): String { + return "$baseUrl/zh/reader_comic/${chapter.url}" + } + + private fun String.hexStringToByteArray(): ByteArray { + val len = length + val data = ByteArray(len / 2) + var i = 0 + while (i < len) { + data[i / 2] = ( + (Character.digit(this[i], 16) shl 4) + + Character.digit(this[i + 1], 16) + ).toByte() + i += 2 + } + return data + } +} diff --git a/src/zh/creativecomic/src/eu/kanade/tachiyomi/extension/zh/creativecomic/CreativecomicDto.kt b/src/zh/creativecomic/src/eu/kanade/tachiyomi/extension/zh/creativecomic/CreativecomicDto.kt new file mode 100644 index 000000000..e20f4eb2f --- /dev/null +++ b/src/zh/creativecomic/src/eu/kanade/tachiyomi/extension/zh/creativecomic/CreativecomicDto.kt @@ -0,0 +1,108 @@ +package eu.kanade.tachiyomi.extension.zh.creativecomic + +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import keiyoushi.utils.tryParse +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import java.text.SimpleDateFormat +import java.util.Locale + +@Serializable +class PopularResponseDto(val data: PopularDto) + +@Serializable +class PopularDto(val total: Int, val data: List) + +@Serializable +class MangaDto( + private val id: Int, + private val name: String, + private val image1: String, +) { + fun toSManga() = SManga.create().apply { + url = id.toString() + title = name + thumbnail_url = image1 + } +} + +@Serializable +class DetailsResponseDto(val data: DetailsDto) + +@Serializable +class DetailsDto( + private val name: String, + private val description: String, + private val image1: String, + private val author: List, + private val type: GenreDto, + private val tags: List, + private val completed: Int, +) { + fun toSManga() = SManga.create().apply { + title = name + thumbnail_url = image1 + author = this@DetailsDto.author.joinToString { it.name } + description = this@DetailsDto.description + genre = "${type.name}, ${tags.joinToString{ it.name }}" + status = if (completed == 1) SManga.COMPLETED else SManga.ONGOING + } +} + +@Serializable +class GenreDto(val name: String) + +@Serializable +class AuthorDto(val name: String) + +@Serializable +class ChapterListResponseDto(val data: ChapterListDataDto) + +@Serializable +class ChapterListDataDto(val chapters: List) + +@Serializable +class ChapterDto( + private val id: Int, + private val name: String, + @SerialName("vol_name") private val volName: String, + @SerialName("is_free") private val isFree: Int, + @SerialName("is_buy") private val isBuy: Int, + @SerialName("is_rent") private val isRent: Int, + @SerialName("sales_plan") private val salesPlan: Int, + @SerialName("online_at") private val onlineAt: String, +) { + fun toSChapter() = SChapter.create().apply { + url = id.toString() + // Prepend lock emoji to name if locked + val isReadable = isFree == 1 || isBuy == 1 || isRent == 1 || salesPlan == 0 + name = (if (isReadable) "" else "\uD83D\uDD12") + "$volName ${this@ChapterDto.name}" + date_upload = dateFormat.tryParse(onlineAt) + } +} + +@Serializable +class PageListResponseDto(val data: PageListDataDto) + +@Serializable +class PageListDataDto(val chapter: PageListChapterDto) + +@Serializable +class PageListChapterDto(val proportion: List) + +@Serializable +class PageDto(val id: Int) + +@Serializable +class ImageUrlResponseDto(val data: ImageUrlDto) + +@Serializable +class ImageUrlDto(val key: String) + +private val dateFormat by lazy { + SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.ENGLISH) +} + +@Serializable +class JWTClaims(val exp: Int)