diff --git a/src/en/mangaowl/AndroidManifest.xml b/src/en/mangaowl/AndroidManifest.xml
deleted file mode 100644
index 30deb7f79..000000000
--- a/src/en/mangaowl/AndroidManifest.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/src/en/mangaowl/build.gradle b/src/en/mangaowl/build.gradle
deleted file mode 100644
index b3fc8f4fa..000000000
--- a/src/en/mangaowl/build.gradle
+++ /dev/null
@@ -1,11 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-
-ext {
- extName = 'MangaOwl'
- pkgNameSuffix = 'en.mangaowl'
- extClass = '.MangaOwl'
- extVersionCode = 25
-}
-
-apply from: "$rootDir/common.gradle"
diff --git a/src/en/mangaowl/res/mipmap-hdpi/ic_launcher.png b/src/en/mangaowl/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 2d63f0ab2..000000000
Binary files a/src/en/mangaowl/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/mangaowl/res/mipmap-mdpi/ic_launcher.png b/src/en/mangaowl/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 13b650f39..000000000
Binary files a/src/en/mangaowl/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/mangaowl/res/mipmap-xhdpi/ic_launcher.png b/src/en/mangaowl/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index e412e079f..000000000
Binary files a/src/en/mangaowl/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/mangaowl/res/mipmap-xxhdpi/ic_launcher.png b/src/en/mangaowl/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 644ee754b..000000000
Binary files a/src/en/mangaowl/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/mangaowl/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/mangaowl/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 3ad68eaa0..000000000
Binary files a/src/en/mangaowl/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/mangaowl/res/web_hi_res_512.png b/src/en/mangaowl/res/web_hi_res_512.png
deleted file mode 100644
index 1e8a6282b..000000000
Binary files a/src/en/mangaowl/res/web_hi_res_512.png and /dev/null differ
diff --git a/src/en/mangaowl/src/eu/kanade/tachiyomi/extension/en/mangaowl/MangaOwl.kt b/src/en/mangaowl/src/eu/kanade/tachiyomi/extension/en/mangaowl/MangaOwl.kt
deleted file mode 100644
index e14bbe15b..000000000
--- a/src/en/mangaowl/src/eu/kanade/tachiyomi/extension/en/mangaowl/MangaOwl.kt
+++ /dev/null
@@ -1,383 +0,0 @@
-package eu.kanade.tachiyomi.extension.en.mangaowl
-
-import android.util.Base64
-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.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.ParsedHttpSource
-import eu.kanade.tachiyomi.util.asJsoup
-import okhttp3.HttpUrl.Companion.toHttpUrl
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.Response
-import org.jsoup.nodes.Document
-import org.jsoup.nodes.Element
-import java.net.URLDecoder
-import java.text.ParseException
-import java.text.SimpleDateFormat
-import java.util.Locale
-import java.util.concurrent.TimeUnit
-
-class MangaOwl : ParsedHttpSource() {
-
- override val name = "MangaOwl"
-
- override val baseUrl = "https://mangaowls.com"
-
- override val lang = "en"
-
- override val supportsLatest = true
-
- override val client: OkHttpClient = network.cloudflareClient.newBuilder()
- .connectTimeout(1, TimeUnit.MINUTES)
- .readTimeout(1, TimeUnit.MINUTES)
- .writeTimeout(1, TimeUnit.MINUTES)
- .build()
-
- private val trPattern = "window\\['tr'] = '([^']*)';".toRegex(RegexOption.IGNORE_CASE)
-
- private fun getTr(document: Document): String {
- val trElement = document.getElementsByTag("script").find { trPattern.find(it.data()) != null } ?: error("tr not found")
- val tr = trPattern.find(trElement.data())!!.groups[1]!!.value
- return URLDecoder.decode(tr, "utf-8")
- }
-
- // Popular
-
- override fun popularMangaRequest(page: Int): Request {
- return GET("$baseUrl/popular/$page", headers)
- }
-
- override fun popularMangaSelector() = "div.col-md-2"
-
- override fun popularMangaFromElement(element: Element): SManga {
- val manga = SManga.create()
- element.select("h6 a").let {
- manga.setUrlWithoutDomain(it.attr("href"))
- manga.title = it.text()
- }
- manga.thumbnail_url = element.select("div.img-responsive").attr("abs:data-background-image")
-
- return manga
- }
-
- override fun popularMangaNextPageSelector() = "div.blog-pagenat-wthree li a:contains(>>)"
-
- // Latest
-
- override fun latestUpdatesRequest(page: Int): Request {
- return GET("$baseUrl/lastest/$page", headers)
- }
-
- override fun latestUpdatesSelector() = popularMangaSelector()
-
- override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
-
- override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
-
- // Search
-
- // This is necessary because the HTML response does not contain pagination links
- override fun searchMangaParse(response: Response): MangasPage {
- val document = response.asJsoup()
-
- val mangas = document.select(searchMangaSelector()).map { element ->
- searchMangaFromElement(element)
- }
- // Max manga in 1 page is 36
- val hasNextPage = document.select(searchMangaSelector()).size == 36
-
- return MangasPage(mangas, hasNextPage)
- }
-
- override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
- val url = "$baseUrl/search/$page".toHttpUrl().newBuilder()
- url.addQueryParameter("search", query)
-
- filters.forEach { filter ->
- when (filter) {
- is SearchFieldFilter -> {
- val fields = filter.state
- .filter { it.state }
- .joinToString("") { it.uriPart }
- url.addQueryParameter("search_field", fields)
- }
- is SortFilter -> url.addQueryParameter("sort", filter.toUriPart())
- is StatusFilter -> url.addQueryParameter("completed", filter.toUriPart())
- is GenreFilter -> {
- val genres = filter.state
- .filter { it.state }
- .joinToString(",") { it.uriPart }
- url.addQueryParameter("genres", genres)
- }
- is MinChapterFilter -> url.addQueryParameter("chapter_from", filter.state)
- is MaxChapterFilter -> url.addQueryParameter("chapter_to", filter.state)
- }
- }
- return GET(url.toString(), headers)
- }
-
- override fun searchMangaSelector() = popularMangaSelector()
-
- override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
-
- override fun searchMangaNextPageSelector() = throw UnsupportedOperationException("Not used")
-
- // Manga summary page
-
- override fun mangaDetailsParse(document: Document): SManga {
- val infoElement = document.select("div.single_detail").first()
-
- return SManga.create().apply {
- title = infoElement.select("h2").first().ownText()
- author = infoElement.select("p.fexi_header_para a.author_link").text()
- artist = author
- status = parseStatus(infoElement.select("p.fexi_header_para:contains(status)").first().ownText())
- genre = infoElement.select("div.col-xs-12.col-md-8.single-right-grid-right > p > a[href*=genres]").joinToString { it.text() }
- description = infoElement.select(".description").first().ownText()
- thumbnail_url = infoElement.select("img").first()?.let { img ->
- if (img.hasAttr("data-src")) img.attr("abs:data-src") else img.attr("abs:src")
- }
- }
- }
-
- private fun parseStatus(status: String?) = when {
- status == null -> SManga.UNKNOWN
- status.contains("Ongoing") -> SManga.ONGOING
- status.contains("Completed") -> SManga.COMPLETED
- else -> SManga.UNKNOWN
- }
-
- // Chapters
-
- // Only selects chapter elements with links, since sometimes chapter lists have unlinked chapters
- override fun chapterListSelector() = "div.table-chapter-list ul li:has(a)"
-
- override fun chapterListParse(response: Response): List {
- val document = response.asJsoup()
- TR = getTr(document)
- val s = Base64.encodeToString(baseUrl.toByteArray(), Base64.NO_PADDING)
- return document.select(chapterListSelector()).map { element ->
- SChapter.create().apply {
- element.select("a").let {
- url = it.attr("data-href")
- .toHttpUrl().newBuilder()
- .addQueryParameter("tr", TR)
- .addQueryParameter("s", s)
- .toString()
- name = it.select("label").first().text()
- }
- date_upload = parseChapterDate(element.select("small:last-of-type").text())
- }
- }
- }
-
- override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException("Not used")
-
- companion object {
- val dateFormat by lazy {
- SimpleDateFormat("MM/dd/yyyy", Locale.US)
- }
- var TR: String? = null
- }
-
- private fun parseChapterDate(string: String): Long {
- return try {
- dateFormat.parse(string)?.time ?: 0
- } catch (_: ParseException) {
- 0
- }
- }
-
- // Pages
- override fun pageListRequest(chapter: SChapter): Request {
- if (TR == null) {
- val document = client.newCall(GET(baseUrl)).execute().asJsoup()
- TR = getTr(document)
- }
-
- val url = chapter.url.toHttpUrl().newBuilder()
- .removeAllQueryParameters("tr")
- .addQueryParameter("tr", TR)
-
- return GET(url.toString(), headers)
- }
-
- override fun pageListParse(document: Document): List {
- return document.select("div.item img.owl-lazy").mapIndexed { i, img ->
- Page(i, "", img.attr("abs:data-src"))
- }.ifEmpty {
- TR = null
- listOf()
- }
- }
-
- override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
-
- // Filters
-
- override fun getFilterList() = FilterList(
- SearchFieldFilter(getSearchFields()),
- SortFilter(),
- StatusFilter(),
- GenreFilter(getGenreList()),
- Filter.Separator(),
- Filter.Header("Only works with text search"),
- MinChapterFilter(),
- MaxChapterFilter()
- )
-
- private open class UriPartFilter(displayName: String, val vals: Array>) :
- Filter.Select(displayName, vals.map { it.first }.toTypedArray()) {
- fun toUriPart() = vals[state].second
- }
-
- private class SortFilter : UriPartFilter(
- "Sort by",
- arrayOf(
- Pair("Matched", "4"),
- Pair("Viewed", "0"),
- Pair("Popularity", "1"),
- Pair("Create Date", "2"),
- Pair("Upload Date", "3")
- )
- )
-
- private class StatusFilter : UriPartFilter(
- "Status",
- arrayOf(
- Pair("Any", "2"),
- Pair("Completed", "1"),
- Pair("Ongoing", "0")
- )
- )
-
- private class Genre(name: String, val uriPart: String) : Filter.CheckBox(name)
- private class GenreFilter(genres: List) : Filter.Group("Genres", genres)
-
- private fun getGenreList() = listOf(
- Genre("4-koma", "89"),
- Genre("Action", "1"),
- Genre("Adaptation", "72"),
- Genre("Adventure", "2"),
- Genre("Aliens", "112"),
- Genre("All Ages", "122"),
- Genre("Animals", "90"),
- Genre("Anthology", "101"),
- Genre("Award winning", "91"),
- Genre("Bara", "116"),
- Genre("Cars", "49"),
- Genre("Comedy", "15"),
- Genre("Comic", "130"),
- Genre("Cooking", "63"),
- Genre("Crime", "81"),
- Genre("Crossdressing", "105"),
- Genre("Delinquents", "73"),
- Genre("Dementia", "48"),
- Genre("Demons", "3"),
- Genre("Doujinshi", "55"),
- Genre("Drama", "4"),
- Genre("Ecchi", "27"),
- Genre("Fan colored", "92"),
- Genre("Fantasy", "7"),
- Genre("Full Color", "82"),
- Genre("Game", "33"),
- Genre("Gender Bender", "39"),
- Genre("Ghosts", "97"),
- Genre("Gore", "107"),
- Genre("Gossip", "123"),
- Genre("Gyaru", "104"),
- Genre("Harem", "38"),
- Genre("Historical", "12"),
- Genre("Horror", "5"),
- Genre("Incest", "98"),
- Genre("Isekai", "69"),
- Genre("Japanese", "129"),
- Genre("Josei", "35"),
- Genre("Kids", "42"),
- Genre("Korean", "128"),
- Genre("Long Strip", "76"),
- Genre("Mafia", "82"),
- Genre("Magic", "34"),
- Genre("Magical Girls", "88"),
- Genre("Manga", "127"),
- Genre("Manhua", "62"),
- Genre("Manhwa", "61"),
- Genre("Martial Arts", "37"),
- Genre("Mature", "60"),
- Genre("Mecha", "36"),
- Genre("Medical", "66"),
- Genre("Military", "8"),
- Genre("Monster girls", "95"),
- Genre("Monsters", "84"),
- Genre("Music", "32"),
- Genre("Mystery", "11"),
- Genre("Ninja", "93"),
- Genre("Novel", "56"),
- Genre("NTR", "121"),
- Genre("Office", "126"),
- Genre("Office Workers", "99"),
- Genre("Official colored", "78"),
- Genre("One shot", "67"),
- Genre("Parody", "30"),
- Genre("Philosophical", "100"),
- Genre("Police", "46"),
- Genre("Post apocalyptic", "94"),
- Genre("Psychological", "9"),
- Genre("Reincarnation", "74"),
- Genre("Reverse harem", "79"),
- Genre("Romance", "25"),
- Genre("Samurai", "18"),
- Genre("School life", "59"),
- Genre("Sci-fi", "70"),
- Genre("Seinen", "10"),
- Genre("Sexual violence", "117"),
- Genre("Shoujo", "28"),
- Genre("Shoujo Ai", "40"),
- Genre("Shounen", "13"),
- Genre("Shounen Ai", "44"),
- Genre("Slice of Life", "19"),
- Genre("Smut", "65"),
- Genre("Space", "29"),
- Genre("Sports", "22"),
- Genre("Super Power", "17"),
- Genre("Superhero", "109"),
- Genre("Supernatural", "6"),
- Genre("Survival", "85"),
- Genre("Thriller", "31"),
- Genre("Time travel", "80"),
- Genre("Toomics", "120"),
- Genre("Traditional games", "113"),
- Genre("Tragedy", "68"),
- Genre("Uncategorized", "50"),
- Genre("Uncensored", "124"),
- Genre("User created", "102"),
- Genre("Vampires", "103"),
- Genre("Vanilla", "125"),
- Genre("Video games", "75"),
- Genre("Villainess", "119"),
- Genre("Virtual reality", "110"),
- Genre("Web comic", "77"),
- Genre("Webtoon", "71"),
- Genre("Wuxia", "106"),
- Genre("Yaoi", "51"),
- Genre("Yuri", "54"),
- Genre("Zombies", "108")
- )
-
- private class SearchField(name: String, state: Boolean, val uriPart: String) : Filter.CheckBox(name, state)
- private class SearchFieldFilter(fields: List) : Filter.Group("Search in", fields)
-
- private fun getSearchFields() = listOf(
- SearchField("Manga title", true, "1"),
- SearchField("Authors", true, "2"),
- SearchField("Description", false, "3")
- )
-
- private class MinChapterFilter : Filter.Text("Minimum Chapters")
- private class MaxChapterFilter : Filter.Text("Maximum Chapters")
-}