diff --git a/src/zh/zerobyw/AndroidManifest.xml b/src/zh/zerobyw/AndroidManifest.xml
new file mode 100644
index 000000000..30deb7f79
--- /dev/null
+++ b/src/zh/zerobyw/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/zh/zerobyw/build.gradle b/src/zh/zerobyw/build.gradle
new file mode 100644
index 000000000..9c001f03d
--- /dev/null
+++ b/src/zh/zerobyw/build.gradle
@@ -0,0 +1,13 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+ext {
+ extName = 'Zerobyw'
+ pkgNameSuffix = 'zh.zerobyw'
+ extClass = '.Zerobyw'
+ extVersionCode = 1
+ libVersion = '1.2'
+}
+
+apply from: "$rootDir/common.gradle"
+
diff --git a/src/zh/zerobyw/res/mipmap-hdpi/ic_launcher.png b/src/zh/zerobyw/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..45dfa22df
Binary files /dev/null and b/src/zh/zerobyw/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/zh/zerobyw/res/mipmap-mdpi/ic_launcher.png b/src/zh/zerobyw/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..b55b8982f
Binary files /dev/null and b/src/zh/zerobyw/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/zh/zerobyw/res/mipmap-xhdpi/ic_launcher.png b/src/zh/zerobyw/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..2366796cc
Binary files /dev/null and b/src/zh/zerobyw/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/zh/zerobyw/res/mipmap-xxhdpi/ic_launcher.png b/src/zh/zerobyw/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..c05684064
Binary files /dev/null and b/src/zh/zerobyw/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/zh/zerobyw/res/mipmap-xxxhdpi/ic_launcher.png b/src/zh/zerobyw/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..6fc862d06
Binary files /dev/null and b/src/zh/zerobyw/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/zh/zerobyw/res/web_hi_res_512.png b/src/zh/zerobyw/res/web_hi_res_512.png
new file mode 100644
index 000000000..969c296c5
Binary files /dev/null and b/src/zh/zerobyw/res/web_hi_res_512.png differ
diff --git a/src/zh/zerobyw/src/eu/kanade/tachiyomi/extension/zh/zerobyw/Zerobyw.kt b/src/zh/zerobyw/src/eu/kanade/tachiyomi/extension/zh/zerobyw/Zerobyw.kt
new file mode 100644
index 000000000..029b508d7
--- /dev/null
+++ b/src/zh/zerobyw/src/eu/kanade/tachiyomi/extension/zh/zerobyw/Zerobyw.kt
@@ -0,0 +1,195 @@
+package eu.kanade.tachiyomi.extension.zh.zerobyw
+
+import android.net.Uri
+import eu.kanade.tachiyomi.network.GET
+import eu.kanade.tachiyomi.source.model.Filter
+import eu.kanade.tachiyomi.source.model.FilterList
+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.ParsedHttpSource
+import okhttp3.Request
+import okhttp3.Response
+import org.jsoup.nodes.Document
+import org.jsoup.nodes.Element
+
+class Zerobyw : ParsedHttpSource() {
+ override val name: String = "zero搬运网"
+ override val lang: String = "zh"
+ override val supportsLatest: Boolean = false
+ override val baseUrl: String = "https://www.zerobywzio.com"
+
+ // Popular
+ // Website does not provide popular manga, this is actually latest manga
+
+ override fun popularMangaRequest(page: Int) = GET("$baseUrl/plugin.php?id=jameson_manhua&c=index&a=ku&&page=$page", headers)
+ override fun popularMangaNextPageSelector(): String? = "div.pg > a.nxt"
+ override fun popularMangaSelector(): String = "div.uk-card"
+ override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
+ title = getTitle(element.select("p.mt5 > a").text())
+ setUrlWithoutDomain(element.select("p.mt5 > a").attr("abs:href"))
+ thumbnail_url = element.select("img").attr("src")
+ }
+
+ // Latest
+
+ override fun latestUpdatesRequest(page: Int) = throw Exception("Not used")
+ override fun latestUpdatesNextPageSelector() = throw Exception("Not used")
+ override fun latestUpdatesSelector() = throw Exception("Not used")
+ override fun latestUpdatesFromElement(element: Element) = throw Exception("Not used")
+
+ // Search
+
+ override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
+ val uri = Uri.parse(baseUrl).buildUpon()
+ if (query.isNotBlank()) {
+ uri.appendPath("plugin.php")
+ .appendQueryParameter("id", "jameson_manhua")
+ .appendQueryParameter("a", "search")
+ .appendQueryParameter("c", "index")
+ .appendQueryParameter("keyword", query)
+ .appendQueryParameter("page", page.toString())
+ } else {
+ uri.appendPath("plugin.php")
+ .appendQueryParameter("id", "jameson_manhua")
+ .appendQueryParameter("c", "index")
+ .appendQueryParameter("a", "ku")
+ filters.forEach {
+ if (it is UriSelectFilterPath && it.toUri().second.isNotEmpty())
+ uri.appendQueryParameter(it.toUri().first, it.toUri().second)
+ }
+ uri.appendQueryParameter("page", page.toString())
+ }
+ return GET(uri.toString(), headers)
+ }
+
+ override fun searchMangaNextPageSelector(): String? = "div.pg > a.nxt"
+ override fun searchMangaSelector(): String = "a.uk-card, div.uk-card"
+ override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
+ title = getTitle(element.select("p.mt5").text())
+ setUrlWithoutDomain(element.select("a").attr("abs:href"))
+ thumbnail_url = element.select("img").attr("src")
+ }
+
+ // Details
+
+ override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
+ title = getTitle(document.select("li.uk-active > h3.uk-heading-line").text())
+ thumbnail_url = document.select("div.uk-width-medium > img").attr("abs:src")
+ author = document.selectFirst("div.cl > a.uk-label").text().substring(3)
+ artist = author
+ genre = document.select("div.cl > a.uk-label, div.cl > span.uk-label").eachText().joinToString(", ")
+ description = document.select("li > div.uk-alert").html().replace("
", "")
+ status = when (document.select("div.cl > span.uk-label").last().text()) {
+ "连载中" -> SManga.ONGOING
+ "已完结" -> SManga.COMPLETED
+ else -> SManga.UNKNOWN
+ }
+ }
+
+ // Chapters
+
+ override fun chapterListSelector(): String = "div.uk-grid-collapse > div.muludiv"
+ override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
+ setUrlWithoutDomain(element.select("a.uk-button-default").attr("abs:href"))
+ name = element.select("a.uk-button-default").text()
+ }
+ override fun chapterListParse(response: Response): List {
+ return super.chapterListParse(response).reversed()
+ }
+
+ // Pages
+
+ override fun pageListParse(document: Document): List = mutableListOf().apply {
+ val images = document.select("div.uk-text-center > img")
+ if (images.size == 0) {
+ var message = document.select("div#messagetext > p")
+ if (message.size == 0) {
+ message = document.select("div.uk-alert > p")
+ }
+ if (message.size != 0) {
+ throw Exception(message.text())
+ }
+ }
+ images.forEach {
+ add(Page(size, "", it.attr("src")))
+ }
+ }
+
+ override fun imageUrlParse(document: Document): String = throw Exception("Not Used")
+
+ // Filters
+
+ override fun getFilterList() = FilterList(
+ Filter.Header("如果使用文本搜索"),
+ Filter.Header("过滤器将被忽略"),
+ CategoryFilter(),
+ StatusFilter(),
+ AttributeFilter()
+ )
+
+ private class CategoryFilter : UriSelectFilterPath(
+ "category_id",
+ "分类",
+ arrayOf(
+ Pair("", "全部"),
+ Pair("1", "卖肉"),
+ Pair("15", "战斗"),
+ Pair("32", "日常"),
+ Pair("6", "后宫"),
+ Pair("13", "搞笑"),
+ Pair("28", "日常"),
+ Pair("31", "爱情"),
+ Pair("22", "冒险"),
+ Pair("23", "奇幻"),
+ Pair("26", "战斗"),
+ Pair("29", "体育"),
+ Pair("34", "机战"),
+ Pair("35", "职业"),
+ Pair("36", "汉化组跟上,不再更新")
+ )
+ )
+
+ private class StatusFilter : UriSelectFilterPath(
+ "jindu",
+ "进度",
+ arrayOf(
+ Pair("", "全部"),
+ Pair("0", "连载中"),
+ Pair("1", "已完结")
+ )
+ )
+
+ private class AttributeFilter : UriSelectFilterPath(
+ "shuxing",
+ "性质",
+ arrayOf(
+ Pair("", "全部"),
+ Pair("一半中文一半生肉", "一半中文一半生肉"),
+ Pair("全生肉", "全生肉"),
+ Pair("全中文", "全中文")
+ )
+ )
+
+ /**
+ * Class that creates a select filter. Each entry in the dropdown has a name and a display name.
+ * If an entry is selected it is appended as a query parameter onto the end of the URI.
+ */
+ // vals:
+ private open class UriSelectFilterPath(
+ val key: String,
+ displayName: String,
+ val vals: Array>
+ ) : Filter.Select(displayName, vals.map { it.second }.toTypedArray()) {
+ fun toUri() = Pair(key, vals[state].first)
+ }
+
+ private fun getTitle(title: String): String {
+ val result = Regex("【\\d+").find(title)
+ return if (result != null) {
+ title.substringBefore(result.value)
+ } else {
+ title.substringBefore("【")
+ }
+ }
+}