ZinChanManga: remove extension (#15565)
This commit is contained in:
parent
907cb38a55
commit
2a7edfd738
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
@ -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 |
|
@ -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
|
|
@ -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-----"""
|
||||
}
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue