diff --git a/src/es/legionanime/AndroidManifest.xml b/src/es/legionanime/AndroidManifest.xml
new file mode 100644
index 000000000..acb4de356
--- /dev/null
+++ b/src/es/legionanime/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/es/legionanime/build.gradle b/src/es/legionanime/build.gradle
new file mode 100644
index 000000000..53a95c1c5
--- /dev/null
+++ b/src/es/legionanime/build.gradle
@@ -0,0 +1,20 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+ext {
+ extName = 'LegionAnime'
+ pkgNameSuffix = 'es.legionanime'
+ extClass = '.LegionAnime'
+ extVersionCode = 1
+ libVersion = '13'
+}
+
+dependencies {
+ implementation(project(':lib-fembed-extractor'))
+ implementation(project(':lib-streamtape-extractor'))
+ implementation(project(':lib-okru-extractor'))
+ implementation(project(':lib-streamsb-extractor'))
+ implementation(project(':lib-dood-extractor'))
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/es/legionanime/res/mipmap-hdpi/ic_launcher.png b/src/es/legionanime/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..b9458eaf5
Binary files /dev/null and b/src/es/legionanime/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/es/legionanime/res/mipmap-mdpi/ic_launcher.png b/src/es/legionanime/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..237013518
Binary files /dev/null and b/src/es/legionanime/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/es/legionanime/res/mipmap-xhdpi/ic_launcher.png b/src/es/legionanime/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..770f8025e
Binary files /dev/null and b/src/es/legionanime/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/es/legionanime/res/mipmap-xxhdpi/ic_launcher.png b/src/es/legionanime/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..d5bac2468
Binary files /dev/null and b/src/es/legionanime/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/es/legionanime/res/mipmap-xxxhdpi/ic_launcher.png b/src/es/legionanime/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..1259ab2d2
Binary files /dev/null and b/src/es/legionanime/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/es/legionanime/src/eu/kanade/tachiyomi/animeextension/es/legionanime/LegionAnime.kt b/src/es/legionanime/src/eu/kanade/tachiyomi/animeextension/es/legionanime/LegionAnime.kt
new file mode 100644
index 000000000..5400d8d40
--- /dev/null
+++ b/src/es/legionanime/src/eu/kanade/tachiyomi/animeextension/es/legionanime/LegionAnime.kt
@@ -0,0 +1,293 @@
+package eu.kanade.tachiyomi.animeextension.es.legionanime
+
+import android.app.Application
+import android.content.SharedPreferences
+import androidx.preference.PreferenceScreen
+import eu.kanade.tachiyomi.animeextension.es.legionanime.extractors.JkanimeExtractor
+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.lib.fembedextractor.FembedExtractor
+import eu.kanade.tachiyomi.lib.streamsbextractor.StreamSBExtractor
+import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
+import eu.kanade.tachiyomi.network.GET
+import eu.kanade.tachiyomi.network.POST
+import eu.kanade.tachiyomi.util.asJsoup
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonObject
+import kotlinx.serialization.json.jsonArray
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.json.jsonPrimitive
+import okhttp3.FormBody
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import org.jsoup.nodes.Document
+import org.jsoup.nodes.Element
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
+import uy.kohesive.injekt.injectLazy
+
+class LegionAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
+
+ override val name = "LegionAnime"
+
+ override val baseUrl = "https://legionanime.club/api"
+
+ override val lang = "es"
+
+ 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)
+ }
+
+ private val headers1 = headersBuilder().add("json", jsonString).add("User-Agent", "android l3gi0n4N1mE %E6%9C%AC%E7%89%A9").build()
+
+ override fun animeDetailsParse(document: Document): SAnime {
+ val jsonResponse = json.decodeFromString(document.body().text())["response"]!!.jsonObject
+ val anime = jsonResponse["anime"]!!.jsonObject
+ val studioId = anime["studios"]!!
+ val studio = studiosMap.filter { it.value == studioId.jsonPrimitive.content.toInt() }.keys.firstOrNull()
+ return SAnime.create().apply {
+ title = anime["name"]!!.jsonPrimitive.content
+ description = anime["synopsis"]!!.jsonPrimitive.content
+ genre = anime["genres"]!!.jsonPrimitive.content
+ author = studio
+ status = when (anime["status"]!!.jsonPrimitive.content) {
+ "En emisión" -> SAnime.ONGOING
+ "Finalizado" -> SAnime.COMPLETED
+ else -> SAnime.UNKNOWN
+ }
+ }
+ }
+
+ override fun animeDetailsRequest(anime: SAnime): Request = episodeListRequest(anime)
+
+ override fun episodeListParse(response: Response): List {
+ val jsonResponse = json.decodeFromString(response.asJsoup().body().text())
+ val episodes = jsonResponse["response"]!!.jsonObject["episodes"]!!.jsonArray
+
+ return episodes.map {
+ SEpisode.create().apply {
+ name = it.jsonObject["name"]!!.jsonPrimitive.content
+ url = "$baseUrl/v2/episode_links/${it.jsonObject["id"]!!.jsonPrimitive.content}"
+ }
+ }
+ }
+
+ override fun episodeListRequest(anime: SAnime): Request = GET(anime.url, headers1)
+
+ override fun latestUpdatesRequest(page: Int): Request {
+ val body = FormBody.Builder().add("apyki", apyki).build()
+ return POST(
+ "$baseUrl/v2/directories?studio=0¬_genre=&year=&orderBy=2&language=&type=&duration=&search=&letter=0&limit=24&genre=&season=&page=${(page - 1) * 24}&status=",
+ headers = headers1, body = body
+ )
+ }
+
+ override fun latestUpdatesParse(response: Response): AnimesPage = popularAnimeParse(response)
+
+ override fun popularAnimeRequest(page: Int): Request {
+ val body = FormBody.Builder().add("apyki", apyki).build()
+ return POST(
+ "$baseUrl/v2/directories?studio=0¬_genre=&year=&orderBy=4&language=&type=&duration=&search=&letter=0&limit=24&genre=&season=&page=${(page - 1) * 24}&status=",
+ headers = headers1, body = body
+ )
+ }
+
+ override fun popularAnimeParse(response: Response): AnimesPage {
+ val responseJson = json.decodeFromString(response.asJsoup().body().text())
+ try {
+ val animeArray = responseJson["response"]!!.jsonArray
+ return AnimesPage(
+ animeArray.map {
+ val animeDetail = it.jsonObject
+ val animeId = animeDetail["id"]!!.jsonPrimitive.content
+ SAnime.create().apply {
+ title = animeDetail["nombre"]!!.jsonPrimitive.content
+ url = "$baseUrl/v1/episodes/$animeId"
+ thumbnail_url = aip.random() + animeDetail["img_url"]!!.jsonPrimitive.content
+ }
+ },
+ true
+ )
+ } catch (e: Exception) {
+ return AnimesPage(emptyList(), false)
+ }
+ }
+
+ override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
+ val body = FormBody.Builder().add("apyki", apyki).build()
+ val genreFilter = (filters.find { it is TagFilter } as TagFilter).state
+ val excludeGenreFilter = (filters.find { it is ExcludeTagFilter } as ExcludeTagFilter).state
+ val studioFilter = (filters.find { it is StudioFilter } as StudioFilter).state
+ val stateFilter = (filters.find { it is StateFilter } as StateFilter)
+
+ val genre = if (genreFilter.isNotEmpty()) {
+ genreFilter.filter { it.state }.map { genres[it.name] }.joinToString("%2C") { it.toString() }
+ } else {
+ ""
+ }
+ val excludeGenre = if (genreFilter.isNotEmpty()) {
+ excludeGenreFilter.filter { it.state }.map { genres[it.name] }.joinToString("%2C") { it.toString() }
+ } else {
+ ""
+ }
+ val studio = if (studioFilter.isNotEmpty()) {
+ studioFilter.filter { it.state }.map { studiosMap[it.name] }.joinToString("%2C") { it.toString() }
+ } else {
+ "0"
+ }
+ val status = if (stateFilter.state != 0) {
+ stateFilter.toUriPart()
+ } else {
+ ""
+ }
+
+ val url = "$baseUrl/v2/directories?studio=$studio¬_genre=$excludeGenre&year=&orderBy=4&language=&type=&duration=&search=$query&letter=0&limit=24&genre=$genre&season=&page=${(page - 1) * 24}&status=$status"
+
+ return POST(
+ url,
+ headers = headers1, body = body
+ )
+ }
+
+ override fun searchAnimeParse(response: Response): AnimesPage = popularAnimeParse(response)
+
+ override fun videoListParse(response: Response): List