diff --git a/src/pt/animefire/AndroidManifest.xml b/src/pt/animefire/AndroidManifest.xml
new file mode 100644
index 000000000..94339ee7a
--- /dev/null
+++ b/src/pt/animefire/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/src/pt/animefire/build.gradle b/src/pt/animefire/build.gradle
new file mode 100644
index 000000000..1c3d5a31c
--- /dev/null
+++ b/src/pt/animefire/build.gradle
@@ -0,0 +1,14 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlinx-serialization'
+
+ext {
+ extName = 'Anime Fire'
+ pkgNameSuffix = 'pt.animefire'
+ extClass = '.AnimeFire'
+ extVersionCode = 1
+ libVersion = '12'
+}
+
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/pt/animefire/res/mipmap-hdpi/ic_launcher.png b/src/pt/animefire/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..23d1c683b
Binary files /dev/null and b/src/pt/animefire/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/pt/animefire/res/mipmap-mdpi/ic_launcher.png b/src/pt/animefire/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..b2bb7e8fe
Binary files /dev/null and b/src/pt/animefire/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/pt/animefire/res/mipmap-xhdpi/ic_launcher.png b/src/pt/animefire/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..99bcbba1d
Binary files /dev/null and b/src/pt/animefire/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/pt/animefire/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/animefire/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..aa15db9a3
Binary files /dev/null and b/src/pt/animefire/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/pt/animefire/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/animefire/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..ff5cc2f7e
Binary files /dev/null and b/src/pt/animefire/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/pt/animefire/src/eu/kanade/tachiyomi/animeextension/pt/animefire/AFFilters.kt b/src/pt/animefire/src/eu/kanade/tachiyomi/animeextension/pt/animefire/AFFilters.kt
new file mode 100644
index 000000000..ad39cecbe
--- /dev/null
+++ b/src/pt/animefire/src/eu/kanade/tachiyomi/animeextension/pt/animefire/AFFilters.kt
@@ -0,0 +1,95 @@
+package eu.kanade.tachiyomi.animeextension.pt.animefire
+
+import eu.kanade.tachiyomi.animesource.model.AnimeFilter
+import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
+
+object AFFilters {
+
+ open class QueryPartFilter(
+ displayName: String,
+ val vals: Array>
+ ) : AnimeFilter.Select(
+ displayName,
+ vals.map { it.first }.toTypedArray()
+ ) {
+ fun toQueryPart() = vals[state].second
+ }
+
+ private inline fun AnimeFilterList.asQueryPart(): String {
+ return this.filterIsInstance().joinToString("") {
+ (it as QueryPartFilter).toQueryPart()
+ }
+ }
+
+ class GenreFilter : QueryPartFilter("Gênero", AFFiltersData.genres)
+ class SeasonFilter : QueryPartFilter("Temporada", AFFiltersData.seasons)
+
+ val filterList = AnimeFilterList(
+ AnimeFilter.Header(AFFiltersData.IGNORE_SEARCH_MSG),
+ SeasonFilter(),
+ AnimeFilter.Header(AFFiltersData.IGNORE_SEASON_MSG),
+ GenreFilter()
+ )
+
+ data class FilterSearchParams(
+ val genre: String = "",
+ val season: String = ""
+ )
+
+ internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
+ return FilterSearchParams(
+ filters.asQueryPart(),
+ filters.asQueryPart()
+ )
+ }
+
+ private object AFFiltersData {
+
+ const val IGNORE_SEARCH_MSG = "NOTA: Os filtros abaixos são IGNORADOS durante a pesquisa."
+ const val IGNORE_SEASON_MSG = "NOTA: O filtro de gêneros IGNORA o de temporadas."
+ val every = Pair("Qualquer um", "")
+
+ val seasons = arrayOf(
+ every,
+ Pair("Outono", "outono"),
+ Pair("Inverno", "inverno"),
+ Pair("Primavera", "primavera"),
+ Pair("Verão", "verao")
+ )
+
+ val genres = arrayOf(
+ Pair("Ação", "acao"),
+ Pair("Artes Marciais", "artes-marciais"),
+ Pair("Aventura", "aventura"),
+ Pair("Comédia", "comedia"),
+ Pair("Demônios", "demonios"),
+ Pair("Drama", "drama"),
+ Pair("Ecchi", "ecchi"),
+ Pair("Espaço", "espaco"),
+ Pair("Esporte", "esporte"),
+ Pair("Fantasia", "fantasia"),
+ Pair("Ficção Científica", "ficcao-cientifica"),
+ Pair("Harém", "harem"),
+ Pair("Horror", "horror"),
+ Pair("Jogos", "jogos"),
+ Pair("Josei", "josei"),
+ Pair("Magia", "magia"),
+ Pair("Mecha", "mecha"),
+ Pair("Militar", "militar"),
+ Pair("Mistério", "misterio"),
+ Pair("Musical", "musical"),
+ Pair("Paródia", "parodia"),
+ Pair("Psicológico", "psicologico"),
+ Pair("Romance", "romance"),
+ Pair("Seinen", "seinen"),
+ Pair("Shoujo-ai", "shoujo-ai"),
+ Pair("Shounen", "shounen"),
+ Pair("Slice of Life", "slice-of-life"),
+ Pair("Sobrenatural", "sobrenatural"),
+ Pair("Superpoder", "superpoder"),
+ Pair("Suspense", "suspense"),
+ Pair("Vampiros", "vampiros"),
+ Pair("Vida Escolar", "vida-escolar")
+ )
+ }
+}
diff --git a/src/pt/animefire/src/eu/kanade/tachiyomi/animeextension/pt/animefire/AnimeFire.kt b/src/pt/animefire/src/eu/kanade/tachiyomi/animeextension/pt/animefire/AnimeFire.kt
new file mode 100644
index 000000000..51e61e10d
--- /dev/null
+++ b/src/pt/animefire/src/eu/kanade/tachiyomi/animeextension/pt/animefire/AnimeFire.kt
@@ -0,0 +1,220 @@
+package eu.kanade.tachiyomi.animeextension.pt.animefire
+
+import android.app.Application
+import android.content.SharedPreferences
+import androidx.preference.ListPreference
+import androidx.preference.PreferenceScreen
+import eu.kanade.tachiyomi.animeextension.pt.animefire.extractors.AnimeFireExtractor
+import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
+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.serialization.json.Json
+import okhttp3.Headers
+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 java.lang.Exception
+
+class AnimeFire : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
+
+ override val name = "Anime Fire"
+
+ override val baseUrl = "https://animefire.net"
+
+ override val lang = "pt-BR"
+
+ override val supportsLatest = true
+
+ override val client: OkHttpClient = network.cloudflareClient
+
+ private val json = Json {
+ ignoreUnknownKeys = true
+ }
+
+ private val preferences: SharedPreferences by lazy {
+ Injekt.get().getSharedPreferences("source_$id", 0x0000)
+ }
+
+ override fun headersBuilder(): Headers.Builder = Headers.Builder()
+ .add("Referer", baseUrl)
+ .add("Accept-Language", ACCEPT_LANGUAGE)
+
+ // ============================== Popular ===============================
+ override fun popularAnimeSelector() = latestUpdatesSelector()
+ override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/top-animes/$page")
+ override fun popularAnimeFromElement(element: Element) = latestUpdatesFromElement(element)
+ override fun popularAnimeNextPageSelector() = latestUpdatesNextPageSelector()
+
+ // ============================== Episodes ==============================
+ override fun episodeListSelector(): String = "div.div_video_list > a"
+ override fun episodeListParse(response: Response) = super.episodeListParse(response).reversed()
+
+ override fun episodeFromElement(element: Element): SEpisode {
+ val episode = SEpisode.create()
+ val url = element.attr("href")
+ episode.setUrlWithoutDomain(url)
+ episode.name = element.text()
+ episode.episode_number = try {
+ url.substringAfterLast("/").toFloat()
+ } catch (e: NumberFormatException) { 0F }
+ return episode
+ }
+
+ // ============================ Video Links =============================
+ override fun videoListParse(response: Response): List