diff --git a/src/en/animeflix/AndroidManifest.xml b/src/en/animeflix/AndroidManifest.xml
new file mode 100644
index 000000000..acb4de356
--- /dev/null
+++ b/src/en/animeflix/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/en/animeflix/build.gradle b/src/en/animeflix/build.gradle
new file mode 100644
index 000000000..da94770c1
--- /dev/null
+++ b/src/en/animeflix/build.gradle
@@ -0,0 +1,17 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlinx-serialization'
+
+ext {
+ extName = 'AnimeFlix'
+ pkgNameSuffix = 'en.animeflix'
+ extClass = '.AnimeFlix'
+ extVersionCode = 1
+ libVersion = '13'
+}
+
+dependencies {
+ compileOnly libs.bundles.coroutines
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/en/animeflix/res/mipmap-hdpi/ic_launcher.png b/src/en/animeflix/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..6f64faa77
Binary files /dev/null and b/src/en/animeflix/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/en/animeflix/res/mipmap-mdpi/ic_launcher.png b/src/en/animeflix/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..f7ca2d46f
Binary files /dev/null and b/src/en/animeflix/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/en/animeflix/res/mipmap-xhdpi/ic_launcher.png b/src/en/animeflix/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..d76b68a64
Binary files /dev/null and b/src/en/animeflix/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/en/animeflix/res/mipmap-xxhdpi/ic_launcher.png b/src/en/animeflix/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..600b9bb28
Binary files /dev/null and b/src/en/animeflix/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/en/animeflix/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/animeflix/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..b7784bc44
Binary files /dev/null and b/src/en/animeflix/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/en/animeflix/res/web_hi_res_512.png b/src/en/animeflix/res/web_hi_res_512.png
new file mode 100644
index 000000000..f6d7fcfb1
Binary files /dev/null and b/src/en/animeflix/res/web_hi_res_512.png differ
diff --git a/src/en/animeflix/src/eu/kanade/tachiyomi/animeextension/en/animeflix/AnimeFlix.kt b/src/en/animeflix/src/eu/kanade/tachiyomi/animeextension/en/animeflix/AnimeFlix.kt
new file mode 100644
index 000000000..e7a877a3c
--- /dev/null
+++ b/src/en/animeflix/src/eu/kanade/tachiyomi/animeextension/en/animeflix/AnimeFlix.kt
@@ -0,0 +1,407 @@
+package eu.kanade.tachiyomi.animeextension.en.animeflix
+
+import android.app.Application
+import android.content.SharedPreferences
+import android.util.Base64
+import androidx.preference.ListPreference
+import androidx.preference.PreferenceScreen
+import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
+import eu.kanade.tachiyomi.animesource.model.AnimeFilter
+import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
+import eu.kanade.tachiyomi.animesource.model.AnimesPage
+import eu.kanade.tachiyomi.animesource.model.SAnime
+import eu.kanade.tachiyomi.animesource.model.SEpisode
+import eu.kanade.tachiyomi.animesource.model.Video
+import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
+import eu.kanade.tachiyomi.network.GET
+import eu.kanade.tachiyomi.network.asObservableSuccess
+import eu.kanade.tachiyomi.util.asJsoup
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.runBlocking
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
+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 rx.Observable
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
+import uy.kohesive.injekt.injectLazy
+
+class AnimeFlix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
+
+ override val name = "AnimeFlix"
+
+ override val baseUrl = "https://animeflix.org.in"
+
+ override val lang = "en"
+
+ override val supportsLatest = true
+
+ override val client: OkHttpClient = network.cloudflareClient
+
+ private val json: Json by injectLazy()
+
+ private val preferences: SharedPreferences by lazy {
+ Injekt.get().getSharedPreferences("source_$id", 0x0000)
+ }
+
+ // ============================== Popular ===============================
+
+ override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/page/$page/")
+
+ override fun popularAnimeSelector(): String = "div#page > div#content_box > article"
+
+ override fun popularAnimeNextPageSelector(): String = "div.nav-links > span.current ~ a"
+
+ override fun popularAnimeFromElement(element: Element): SAnime {
+ return SAnime.create().apply {
+ setUrlWithoutDomain(element.selectFirst("a").attr("href").toHttpUrl().encodedPath)
+ thumbnail_url = element.selectFirst("img").attr("src")
+ title = element.selectFirst("header").text()
+ }
+ }
+
+ // =============================== Latest ===============================
+
+ override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/latest-release/page/$page/")
+
+ override fun latestUpdatesSelector(): String = popularAnimeSelector()
+
+ override fun latestUpdatesNextPageSelector(): String = popularAnimeNextPageSelector()
+
+ override fun latestUpdatesFromElement(element: Element): SAnime = popularAnimeFromElement(element)
+
+ // =============================== Search ===============================
+
+ // https://animeflix.org.in/download-demon-slayer-movie-infinity-train-movie-2020-japanese-with-esubs-hevc-720p-1080p/
+
+ override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
+
+ override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = throw Exception("Not used")
+
+ override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable {
+ val (request, isExact) = searchAnimeRequestExact(page, query, filters)
+ return client.newCall(request)
+ .asObservableSuccess()
+ .map { response ->
+ searchAnimeParse(response, isExact)
+ }
+ }
+
+ private fun searchAnimeParse(response: Response, isExact: Boolean): AnimesPage {
+ val document = response.asJsoup()
+
+ if (isExact) {
+ val anime = SAnime.create()
+ anime.title = document.selectFirst("div.single_post > header > h1").text()
+ anime.thumbnail_url = document.selectFirst("div.imdbwp img").attr("src")
+ anime.setUrlWithoutDomain(response.request.url.encodedPath)
+ return AnimesPage(listOf(anime), false)
+ }
+
+ val animes = document.select(searchAnimeSelector()).map { element ->
+ searchAnimeFromElement(element)
+ }
+
+ val hasNextPage = searchAnimeNextPageSelector()?.let { selector ->
+ document.select(selector).first()
+ } != null
+
+ return AnimesPage(animes, hasNextPage)
+ }
+
+ private fun searchAnimeRequestExact(page: Int, query: String, filters: AnimeFilterList): Pair {
+ val cleanQuery = query.replace(" ", "+").lowercase()
+
+ val filterList = if (filters.isEmpty()) getFilterList() else filters
+ val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
+ val subpageFilter = filterList.find { it is SubPageFilter } as SubPageFilter
+ val urlFilter = filterList.find { it is URLFilter } as URLFilter
+
+ return when {
+ query.isNotBlank() -> Pair(GET("$baseUrl/page/$page/?s=$cleanQuery", headers = headers), false)
+ genreFilter.state != 0 -> Pair(GET("$baseUrl/genre/${genreFilter.toUriPart()}/page/$page/", headers = headers), false)
+ subpageFilter.state != 0 -> Pair(GET("$baseUrl/${subpageFilter.toUriPart()}/page/$page/", headers = headers), false)
+ urlFilter.state.isNotEmpty() -> Pair(GET(urlFilter.state, headers = headers), true)
+ else -> Pair(popularAnimeRequest(page), false)
+ }
+ }
+
+ override fun searchAnimeSelector(): String = popularAnimeSelector()
+
+ override fun searchAnimeNextPageSelector(): String = popularAnimeNextPageSelector()
+
+ override fun searchAnimeFromElement(element: Element): SAnime = popularAnimeFromElement(element)
+
+ // ============================== FILTERS ===============================
+
+ override fun getFilterList(): AnimeFilterList = AnimeFilterList(
+ AnimeFilter.Header("Text search ignores filters"),
+ GenreFilter(),
+ SubPageFilter(),
+ AnimeFilter.Separator(),
+ AnimeFilter.Header("Get item url from webview"),
+ URLFilter(),
+ )
+
+ private class GenreFilter : UriPartFilter(
+ "Genres",
+ arrayOf(
+ Pair("