ZinChanManga: remove extension (#15565)

This commit is contained in:
ObserverOfTime 2023-03-05 23:44:43 +02:00 committed by GitHub
parent 907cb38a55
commit 2a7edfd738
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 0 additions and 370 deletions

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.extension" />

View File

@ -1,13 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'ZinChanManga'
pkgNameSuffix = 'en.zinchanmanga'
extClass = '.ZinChanManga'
extVersionCode = 5
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1,103 +0,0 @@
package eu.kanade.tachiyomi.extension.en.zinchanmanga
import kotlinx.serialization.Serializable
import org.jsoup.Jsoup
import java.text.SimpleDateFormat
import java.util.Locale
import kotlinx.serialization.SerialName as N
@Serializable
data class Data<T>(
private val data: List<T>,
private val err_message: String,
) : List<T> by data {
init { require(err_message == "Success") { err_message } }
}
@Serializable
data class SeriesList(
private val data: Pagination,
private val err_message: String,
) : List<Series> by data {
init { require(err_message == "Success") { err_message } }
val pages by lazy { data.pages }
}
@Serializable
data class Pagination(
@N("total_page") val pages: Int,
private val data: List<Series>,
) : List<Series> by data
@Serializable
data class Series(
private val id_story: Int,
@N("name_story") val title: String,
private val slug_story: String,
@N("status_story") val status: String? = null,
private val name_genre: String,
private val name_author: String,
@N("thumbnail_story") val cover: String,
private val content_story: String? = null,
) {
val url by lazy {
"$slug_story?id=$id_story"
}
val description by lazy {
content_story?.let(Jsoup::parse)?.text()
?.takeIf { "Updating" !in it }
}
val genres by lazy {
name_genre.trim('|').replace("|", ", ")
}
val authors by lazy {
name_author.replace(",|", "|").trim('|').takeIf {
it != "Updating" && it != "Đang Cập Nhật"
}?.replace("Author: ", "")?.replace(" ", ", ")
}
}
@Serializable
data class Chapter(
private val id_chapter: Int,
private val name_chapter: String,
private val latest_update_chapter: String,
private val name_extend: String,
) {
val params by lazy {
"?id_chapter=$id_chapter&type_story=manga"
}
val title by lazy {
buildString {
append(name_chapter)
if (name_extend != "") {
append(" - ")
append(name_extend)
}
}
}
val number by lazy {
name_chapter.substringAfter(' ').toFloatOrNull() ?: -1f
}
val timestamp by lazy {
dateFormat.parse(latest_update_chapter)?.time ?: 0L
}
companion object {
private val dateFormat by lazy {
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT)
}
}
}
@Serializable
data class PageList(
private val data_chapter: List<String>,
) : List<String> by data_chapter

View File

@ -1,78 +0,0 @@
package eu.kanade.tachiyomi.extension.en.zinchanmanga
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
object ZinChanCert {
private val keystore by lazy {
KeyStore.getInstance(KeyStore.getDefaultType()).apply {
load(null, null)
setCertificateEntry("zin-chan-cert", certificate)
}
}
private val certificate by lazy {
CertificateFactory.getInstance("X.509").run {
PEM.byteInputStream().use(::generateCertificate)
}
}
private val managers by lazy {
TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm(),
).apply { init(keystore) }.trustManagers
}
val factory by lazy {
SSLContext.getInstance("TLS").apply {
init(null, managers, SecureRandom())
}.socketFactory!!
}
val manager: X509TrustManager
get() = managers[0] as X509TrustManager
private const val PEM = """-----BEGIN CERTIFICATE-----
MIIG1TCCBL2gAwIBAgIQbFWr29AHksedBwzYEZ7WvzANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw
MTMwMDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBLMQswCQYDVQQGEwJBVDEQMA4GA1UE
ChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBSU0EgRG9tYWluIFNlY3VyZSBT
aXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAhmlzfqO1Mdgj
4W3dpBPTVBX1AuvcAyG1fl0dUnw/MeueCWzRWTheZ35LVo91kLI3DDVaZKW+TBAs
JBjEbYmMwcWSTWYCg5334SF0+ctDAsFxsX+rTDh9kSrG/4mp6OShubLaEIUJiZo4
t873TuSd0Wj5DWt3DtpAG8T35l/v+xrN8ub8PSSoX5Vkgw+jWf4KQtNvUFLDq8mF
WhUnPL6jHAADXpvs4lTNYwOtx9yQtbpxwSt7QJY1+ICrmRJB6BuKRt/jfDJF9Jsc
RQVlHIxQdKAJl7oaVnXgDkqtk2qddd3kCDXd74gv813G91z7CjsGyJ93oJIlNS3U
gFbD6V54JMgZ3rSmotYbz98oZxX7MKbtCm1aJ/q+hTv2YK1yMxrnfcieKmOYBbFD
hnW5O6RMA703dBK92j6XRN2EttLkQuujZgy+jXRKtaWMIlkNkWJmOiHmErQngHvt
iNkIcjJumq1ddFX4iaTI40a6zgvIBtxFeDs2RfcaH73er7ctNUUqgQT5rFgJhMmF
x76rQgB5OZUkodb5k2ex7P+Gu4J86bS15094UuYcV09hVeknmTh5Ex9CBKipLS2W
2wKBakf+aVYnNCU6S0nASqt2xrZpGC1v7v6DhuepyyJtn3qSV2PoBiU5Sql+aARp
wUibQMGm44gjyNDqDlVp+ShLQlUH9x8CAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaA
FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTI2XhootkZaNU9ct5fCj7c
tYaGpjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQIC
TjAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1
c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYG
CCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3Qu
Y29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAVDwoIzQDV
ercT0eYqZjBNJ8VNWwVFlQOtZERqn5iWnEVaLZZdzxlbvz2Fx0ExUNuUEgYkIVM4
YocKkCQ7hO5noicoq/DrEYH5IuNcuW1I8JJZ9DLuB1fYvIHlZ2JG46iNbVKA3ygA
Ez86RvDQlt2C494qqPVItRjrz9YlJEGT0DrttyApq0YLFDzf+Z1pkMhh7c+7fXeJ
qmIhfJpduKc8HEQkYQQShen426S3H0JrIAbKcBCiyYFuOhfyvuwVCFDfFvrjADjd
4jX1uQXd161IyFRbm89s2Oj5oU1wDYz5sx+hoCuh6lSs+/uPuWomIq3y1GDFNafW
+LsHBU16lQo5Q2yh25laQsKRgyPmMpHJ98edm6y2sHUabASmRHxvGiuwwE25aDU0
2SAeepyImJ2CzB80YG7WxlynHqNhpE7xfC7PzQlLgmfEHdU+tHFeQazRQnrFkW2W
kqRGIq7cKRnyypvjPMkjeiV9lRdAM9fSJvsB3svUuu1coIG1xxI1yegoGM4r5QP4
RGIVvYaiI76C0djoSbQ/dkIUUXQuB8AL5jyH34g3BZaaXyvpmnV4ilppMXVAnAYG
ON51WhJ6W0xNdNJwzYASZYH+tmCWI+N60Gv2NNMGHwMZ7e9bXgzUCZH5FaBFDGR5
S9VWqHB73Q+OyIVvIbKYcSc2w/aSuFKGSA==
-----END CERTIFICATE-----"""
}

View File

@ -1,27 +0,0 @@
package eu.kanade.tachiyomi.extension.en.zinchanmanga
import eu.kanade.tachiyomi.source.model.Filter
class ZinChanGenre(values: Array<String>) : Filter.Select<String>("Genres", values) {
override fun toString() = (state + 27).toString()
companion object {
object Note : Filter.Header("NOTE: can't combine with text search!")
val genres: Array<String>
get() = arrayOf(
"<select>",
"BL",
"Manhwa",
"Smut",
"Comedy",
"Romance",
"Cooking",
"Korean",
"Japanese",
"Manga",
"Manhua",
"Webtoon",
)
}
}

View File

@ -1,147 +0,0 @@
package eu.kanade.tachiyomi.extension.en.zinchanmanga
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimit
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 kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Response
import uy.kohesive.injekt.injectLazy
class ZinChanManga : HttpSource() {
override val lang = "en"
override val name = "ZinChanManga"
override val baseUrl = "https://zinchanmanga.net"
override val supportsLatest = true
private val json by injectLazy<Json>()
private val apiClient by lazy {
network.client.newBuilder()
.sslSocketFactory(ZinChanCert.factory, ZinChanCert.manager)
.rateLimit(5, 50)
.build()
}
private val apiHeaders by lazy {
headers.newBuilder().add("Origin", baseUrl).build()
}
override fun latestUpdatesRequest(page: Int) =
GET("$API_URL/latest-manga-updates?page=$page&total=10", apiHeaders)
override fun popularMangaRequest(page: Int) =
GET("$API_URL/all?page=$page&total=10", apiHeaders)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
filters.find { it is ZinChanGenre }?.takeIf { it.state != 0 }?.let {
GET("$API_URL/category?id_cate=$it&page=$page&total=10", apiHeaders)
} ?: GET("$API_URL/search?keyword=$query&page=$page&total=10", apiHeaders)
// Request the frontend URL for the webview
override fun mangaDetailsRequest(manga: SManga) =
GET("$baseUrl/manga/${manga.url}", headers)
override fun chapterListRequest(manga: SManga) =
GET("$API_URL/list-chapters?id_story=${manga.id}&id_user=-1", apiHeaders)
override fun pageListRequest(chapter: SChapter) =
GET("$API_URL/reading${chapter.url}", apiHeaders)
override fun fetchLatestUpdates(page: Int) =
fetchManga(latestUpdatesRequest(page), page)
override fun fetchPopularManga(page: Int) =
fetchManga(popularMangaRequest(page), page)
override fun fetchSearchManga(page: Int, query: String, filters: FilterList) =
fetchManga(searchMangaRequest(page, query, filters), page)
override fun fetchMangaDetails(manga: SManga) =
rx.Observable.just(manga.apply { initialized = true })!!
override fun fetchChapterList(manga: SManga) =
apiClient.newCall(chapterListRequest(manga)).asObservableSuccess().map { res ->
res.parse<Data<Chapter>>().map {
SChapter.create().apply {
name = it.title
chapter_number = it.number
date_upload = it.timestamp
url = "${it.params}&id_story=${manga.id}"
}
}
}!!
override fun fetchPageList(chapter: SChapter) =
apiClient.newCall(pageListRequest(chapter)).asObservableSuccess().map { res ->
res.parse<Data<PageList>>().single()
.mapIndexed { idx, img -> Page(idx, "", img) }
}!!
override fun getFilterList() = FilterList(
ZinChanGenre.Companion.Note,
ZinChanGenre(ZinChanGenre.genres),
)
private inline val SManga.id: String
get() = url.substringAfter("?id=")
private fun fetchManga(request: okhttp3.Request, page: Int) =
apiClient.newCall(request).asObservableSuccess().map { res ->
res.parse<SeriesList>().run {
val manga = map {
SManga.create().apply {
url = it.url
title = it.title
thumbnail_url = it.cover
description = it.description
genre = it.genres
author = it.authors
artist = author
status = when (it.status) {
"on-going" -> SManga.ONGOING
else -> SManga.UNKNOWN
}
}
}
MangasPage(manga, pages != page)
}
}!!
private inline fun <reified T> Response.parse() =
json.decodeFromString<T>(body.string())
override fun latestUpdatesParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun popularMangaParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun searchMangaParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun mangaDetailsParse(response: Response): SManga =
throw UnsupportedOperationException("Not used")
override fun chapterListParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun pageListParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun imageUrlParse(response: Response) =
throw UnsupportedOperationException("Not used")
companion object {
private const val API_URL = "https://api.zinchanmanga.net:5555/api/web/manga"
}
}