diff --git a/src/en/zinchanmanga/AndroidManifest.xml b/src/en/zinchanmanga/AndroidManifest.xml
new file mode 100644
index 000000000..30deb7f79
--- /dev/null
+++ b/src/en/zinchanmanga/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/en/zinchanmanga/build.gradle b/src/en/zinchanmanga/build.gradle
new file mode 100644
index 000000000..2e30473f2
--- /dev/null
+++ b/src/en/zinchanmanga/build.gradle
@@ -0,0 +1,17 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlinx-serialization'
+
+ext {
+ extName = 'ZinChanManga'
+ pkgNameSuffix = 'en.zinchanmanga'
+ extClass = '.ZinChanManga'
+ extVersionCode = 1
+ isNsfw = true
+}
+
+dependencies {
+ implementation project(':lib-ratelimit')
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/en/zinchanmanga/res/mipmap-hdpi/ic_launcher.png b/src/en/zinchanmanga/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..98863e81b
Binary files /dev/null and b/src/en/zinchanmanga/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/en/zinchanmanga/res/mipmap-mdpi/ic_launcher.png b/src/en/zinchanmanga/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..a17a6e171
Binary files /dev/null and b/src/en/zinchanmanga/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/en/zinchanmanga/res/mipmap-xhdpi/ic_launcher.png b/src/en/zinchanmanga/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..8aed81fd2
Binary files /dev/null and b/src/en/zinchanmanga/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/en/zinchanmanga/res/mipmap-xxhdpi/ic_launcher.png b/src/en/zinchanmanga/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..2c0771c26
Binary files /dev/null and b/src/en/zinchanmanga/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/en/zinchanmanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/zinchanmanga/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..ee9bcac78
Binary files /dev/null and b/src/en/zinchanmanga/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/en/zinchanmanga/res/web_hi_res_512.png b/src/en/zinchanmanga/res/web_hi_res_512.png
new file mode 100644
index 000000000..17f70e1d2
Binary files /dev/null and b/src/en/zinchanmanga/res/web_hi_res_512.png differ
diff --git a/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanAPI.kt b/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanAPI.kt
new file mode 100644
index 000000000..b83ddadda
--- /dev/null
+++ b/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanAPI.kt
@@ -0,0 +1,102 @@
+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(
+ private val data: List,
+ private val err_message: String
+) : List by data {
+ init { require(err_message == "Success") { err_message } }
+}
+
+@Serializable
+data class SeriesList(
+ private val data: Pagination,
+ private val err_message: String
+) : List 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
+) : List 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
+) {
+ val url by lazy {
+ "$slug_story?id=$id_story"
+ }
+
+ val description by lazy {
+ Jsoup.parse(content_story).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
+) : List by data_chapter
diff --git a/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanCert.kt b/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanCert.kt
new file mode 100644
index 000000000..cc2254f22
--- /dev/null
+++ b/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanCert.kt
@@ -0,0 +1,78 @@
+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-----"""
+}
diff --git a/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanGenre.kt b/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanGenre.kt
new file mode 100644
index 000000000..c69f09a1b
--- /dev/null
+++ b/src/en/zinchanmanga/src/eu/kanade/tachiyomi/extension/en/zinchanmanga/ZinChanGenre.kt
@@ -0,0 +1,27 @@
+package eu.kanade.tachiyomi.extension.en.zinchanmanga
+
+import eu.kanade.tachiyomi.source.model.Filter
+
+class ZinChanGenre(values: Array) : Filter.Select("Genres", values) {
+ override fun toString() = (state + 27).toString()
+
+ companion object {
+ object Note : Filter.Header("NOTE: can't combine with text search!")
+
+ val genres: Array
+ get() = arrayOf(
+ "