diff --git a/src/en/catmanga/AndroidManifest.xml b/src/en/catmanga/AndroidManifest.xml
deleted file mode 100644
index 70b11d5a3..000000000
--- a/src/en/catmanga/AndroidManifest.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/en/catmanga/build.gradle b/src/en/catmanga/build.gradle
deleted file mode 100644
index 9297a89ce..000000000
--- a/src/en/catmanga/build.gradle
+++ /dev/null
@@ -1,12 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlinx-serialization'
-
-ext {
- extName = 'CatManga'
- pkgNameSuffix = "en.catmanga"
- extClass = '.CatManga'
- extVersionCode = 7
-}
-
-apply from: "$rootDir/common.gradle"
diff --git a/src/en/catmanga/res/mipmap-hdpi/ic_launcher.png b/src/en/catmanga/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 4db917a88..000000000
Binary files a/src/en/catmanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/catmanga/res/mipmap-mdpi/ic_launcher.png b/src/en/catmanga/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 8637c4583..000000000
Binary files a/src/en/catmanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/catmanga/res/mipmap-xhdpi/ic_launcher.png b/src/en/catmanga/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 423723cf7..000000000
Binary files a/src/en/catmanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/catmanga/res/mipmap-xxhdpi/ic_launcher.png b/src/en/catmanga/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index f5cf760a0..000000000
Binary files a/src/en/catmanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/catmanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/catmanga/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 1e7256b0d..000000000
Binary files a/src/en/catmanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/en/catmanga/res/web_hi_res_512.png b/src/en/catmanga/res/web_hi_res_512.png
deleted file mode 100644
index 6e46ab8b8..000000000
Binary files a/src/en/catmanga/res/web_hi_res_512.png and /dev/null differ
diff --git a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatData.kt b/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatData.kt
deleted file mode 100644
index 2d6015bd7..000000000
--- a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatData.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package eu.kanade.tachiyomi.extension.en.catmanga
-
-import eu.kanade.tachiyomi.source.model.SManga
-import kotlinx.serialization.Serializable
-
-@Serializable
-data class CatSeries(
- val alt_titles: List,
- val authors: List,
- val genres: List,
- val chapters: List? = null,
- val title: String,
- val series_id: String,
- val description: String,
- val status: String,
- val cover_art: CatSeriesCover,
- val all_covers: List? = null
-) {
- fun toSManga() = this.let { series ->
- SManga.create().apply {
- url = "/series/${series.series_id}"
- title = series.title
- thumbnail_url = series.cover_art.source
- author = series.authors.joinToString(", ")
- description = series.description
- genre = series.genres.joinToString(", ")
- status = when (series.status) {
- "ongoing" -> SManga.ONGOING
- "completed" -> SManga.COMPLETED
- else -> SManga.UNKNOWN
- }
-
- if (alt_titles.isNotEmpty()) {
- description += "\n\nAlternative titles:\n"
- alt_titles.forEach {
- description += "• $it\n"
- }
- }
- }
- }
-}
-
-@Serializable
-data class CatSeriesChapter(
- val title: String? = null,
- val groups: List,
- val number: Float,
- val display_number: String? = null,
- val volume: Int? = null
-)
-
-@Serializable
-data class CatSeriesCover(
- val source: String,
- val width: Int,
- val height: Int
-)
diff --git a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatManga.kt b/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatManga.kt
deleted file mode 100644
index abae4e7c4..000000000
--- a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatManga.kt
+++ /dev/null
@@ -1,179 +0,0 @@
-package eu.kanade.tachiyomi.extension.en.catmanga
-
-import android.app.Application
-import eu.kanade.tachiyomi.network.GET
-import eu.kanade.tachiyomi.network.asObservableSuccess
-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 eu.kanade.tachiyomi.util.asJsoup
-import kotlinx.serialization.ExperimentalSerializationApi
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.boolean
-import kotlinx.serialization.json.decodeFromJsonElement
-import kotlinx.serialization.json.jsonObject
-import kotlinx.serialization.json.jsonPrimitive
-import okhttp3.Request
-import okhttp3.Response
-import org.jsoup.nodes.Document
-import rx.Observable
-import uy.kohesive.injekt.injectLazy
-
-@ExperimentalSerializationApi
-class CatManga : HttpSource() {
-
- private val application: Application by injectLazy()
-
- override val name = "CatManga"
- override val baseUrl = "https://catmanga.org"
- override val supportsLatest = false
- override val lang = "en"
- private val json: Json by injectLazy()
-
- private val allSeriesRequest = GET("$baseUrl/api/series/allSeries")
-
- override fun popularMangaRequest(page: Int) = allSeriesRequest
-
- override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = allSeriesRequest
-
- override fun chapterListRequest(manga: SManga): Request {
- val seriesId = manga.url.substringAfter("/series/")
- return GET("$baseUrl/api/series/$seriesId")
- }
-
- override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable {
- return client.newCall(searchMangaRequest(page, query, filters))
- .asObservableSuccess()
- .map { response ->
- val manga = json.decodeFromString>(response.body!!.string())
- .filter {
- if (query.startsWith(SERIES_ID_SEARCH_PREFIX)) {
- return@filter it.series_id.contains(query.removePrefix(SERIES_ID_SEARCH_PREFIX), true)
- }
- sequence { yieldAll(it.alt_titles); yield(it.title) }
- .any { title -> title.contains(query, true) }
- }
- .map { it.toSManga() }
- .toList()
- MangasPage(manga, false)
- }
- }
-
- override fun fetchMangaDetails(manga: SManga): Observable {
- val seriesId = manga.url.substringAfter("/series/")
- return client.newCall(allSeriesRequest)
- .asObservableSuccess()
- .map { response ->
- json.decodeFromString>(response.body!!.string())
- .find { it.series_id == seriesId }
- ?.toSManga() ?: manga
- }
- }
-
- override fun chapterListParse(response: Response): List {
- val series = json.decodeFromString(response.body!!.string())
- val seriesPrefs = application.getSharedPreferences("source_${id}_time_found:${series.series_id}", 0)
- val seriesPrefsEditor = seriesPrefs.edit()
- val chapters = series.chapters!!
- .asReversed()
- .map { chapter ->
- val title = chapter.title ?: ""
- val groups = chapter.groups.joinToString(", ")
- val numberUrl = chapter.number.chapterNumberToUrlPath()
- val displayNumber = chapter.display_number ?: numberUrl
- SChapter.create().apply {
- url = "/series/${series.series_id}/$numberUrl"
- chapter_number = chapter.number
- scanlator = groups
-
- name = if (chapter.volume != null) {
- "Vol.${chapter.volume} "
- } else {
- ""
- }
- name += "Ch.$displayNumber"
- if (title.isNotBlank()) {
- name += " - $title"
- }
-
- // Save current time when a chapter is found for the first time, and reuse it on future
- // checks to prevent manga entry without any new chapter bumped to the top of
- // "Latest chapter" list when the library is updated.
- val currentTimeMillis = System.currentTimeMillis()
- if (!seriesPrefs.contains(numberUrl)) {
- seriesPrefsEditor.putLong(numberUrl, currentTimeMillis)
- }
- date_upload = seriesPrefs.getLong(numberUrl, currentTimeMillis)
- }
- }
- seriesPrefsEditor.apply()
- return chapters
- }
-
- override fun popularMangaParse(response: Response): MangasPage {
- val mangas = json.decodeFromString>(response.body!!.string()).map { it.toSManga() }
- return MangasPage(mangas, false)
- }
-
- override fun fetchPageList(chapter: SChapter): Observable> {
- return client.newCall(pageListRequest(chapter))
- .asObservableSuccess()
- .map {
- val doc = it.asJsoup().getDataJsonObject()
- val pages = if (doc["isFallback"]!!.jsonPrimitive.boolean) {
- val buildId = doc["buildId"]!!.jsonPrimitive.content
- val directRequest = GET("$baseUrl/_next/data/$buildId/${chapter.url}.json")
- val directResponse = client.newCall(directRequest).execute()
- json.parseToJsonElement(directResponse.body!!.string())
- } else {
- doc["props"]!!
- }.jsonObject["pageProps"]!!.jsonObject["pages"]!!
- json.decodeFromJsonElement>(pages)
- .mapIndexed { index, s -> Page(index, "", s) }
- }
- }
-
- /**
- * Returns json object of site data
- */
- private fun Document.getDataJsonObject() = json.parseToJsonElement(getElementById("__NEXT_DATA__").html()).jsonObject
-
- /**
- * Returns string without decimal when it is not relevant
- */
- private fun Float.chapterNumberToUrlPath(): String {
- return if (toInt().toFloat() == this) toInt().toString() else toString()
- }
-
- override fun pageListParse(response: Response): List {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun latestUpdatesRequest(page: Int): Request {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun latestUpdatesParse(response: Response): MangasPage {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun mangaDetailsParse(response: Response): SManga {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun searchMangaParse(response: Response): MangasPage {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun imageUrlParse(response: Response): String {
- throw UnsupportedOperationException("Not used.")
- }
-
- companion object {
- const val SERIES_ID_SEARCH_PREFIX = "series_id:"
- }
-}
diff --git a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatMangaUrlActivity.kt b/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatMangaUrlActivity.kt
deleted file mode 100644
index fc2a09fe1..000000000
--- a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatMangaUrlActivity.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package eu.kanade.tachiyomi.extension.en.catmanga
-
-import android.app.Activity
-import android.content.ActivityNotFoundException
-import android.content.Intent
-import android.os.Bundle
-import android.util.Log
-import kotlin.system.exitProcess
-
-/**
- * Springboard that accepts https://catmanga.org/series/xxxxxx intents and redirects them to
- * the main Tachiyomi process.
- */
-class CatMangaUrlActivity : Activity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val pathSegments = intent?.data?.pathSegments
- if (pathSegments != null && pathSegments.size > 1) {
- val id = pathSegments[1]
- val mainIntent = Intent().apply {
- action = "eu.kanade.tachiyomi.SEARCH"
- putExtra("query", "${CatManga.SERIES_ID_SEARCH_PREFIX}$id")
- putExtra("filter", packageName)
- }
-
- try {
- startActivity(mainIntent)
- } catch (e: ActivityNotFoundException) {
- Log.e("CatMangaUrlActivity", e.toString())
- }
- } else {
- Log.e("CatMangaUrlActivity", "could not parse uri from intent $intent")
- }
-
- finish()
- exitProcess(0)
- }
-}