diff --git a/src/es/animeid/AndroidManifest.xml b/src/es/animeid/AndroidManifest.xml
new file mode 100644
index 000000000..acb4de356
--- /dev/null
+++ b/src/es/animeid/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/es/animeid/build.gradle b/src/es/animeid/build.gradle
new file mode 100644
index 000000000..47159bbe5
--- /dev/null
+++ b/src/es/animeid/build.gradle
@@ -0,0 +1,12 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+ext {
+ extName = 'AnimeID'
+ pkgNameSuffix = 'es.animeid'
+ extClass = '.AnimeID'
+ extVersionCode = 1
+ libVersion = '12'
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/es/animeid/res/mipmap-hdpi/ic_launcher.png b/src/es/animeid/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..548cbfce5
Binary files /dev/null and b/src/es/animeid/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/es/animeid/res/mipmap-mdpi/ic_launcher.png b/src/es/animeid/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..bf5c2ea56
Binary files /dev/null and b/src/es/animeid/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/es/animeid/res/mipmap-xhdpi/ic_launcher.png b/src/es/animeid/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..df7d66270
Binary files /dev/null and b/src/es/animeid/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/es/animeid/res/mipmap-xxhdpi/ic_launcher.png b/src/es/animeid/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..24c533b5c
Binary files /dev/null and b/src/es/animeid/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/es/animeid/res/mipmap-xxxhdpi/ic_launcher.png b/src/es/animeid/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..736675f0b
Binary files /dev/null and b/src/es/animeid/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/es/animeid/src/eu/kanade/tachiyomi/animeextension/es/animeid/AnimeID.kt b/src/es/animeid/src/eu/kanade/tachiyomi/animeextension/es/animeid/AnimeID.kt
new file mode 100644
index 000000000..d9d84509c
--- /dev/null
+++ b/src/es/animeid/src/eu/kanade/tachiyomi/animeextension/es/animeid/AnimeID.kt
@@ -0,0 +1,400 @@
+package eu.kanade.tachiyomi.animeextension.es.animeid
+
+import android.app.Application
+import android.content.SharedPreferences
+import android.util.Log
+import androidx.preference.ListPreference
+import androidx.preference.PreferenceScreen
+import eu.kanade.tachiyomi.animeextension.es.animeid.extractors.StreamTapeExtractor
+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.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.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.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
+import java.net.URI
+import java.text.SimpleDateFormat
+
+class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
+
+ override val name = "AnimeID"
+
+ override val baseUrl = "https://www.animeid.tv/"
+
+ 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)
+ }
+
+ override fun popularAnimeSelector(): String = "#result article.item"
+
+ override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/series?sort=newest&pag=$page")
+
+ override fun popularAnimeFromElement(element: Element): SAnime {
+ val anime = SAnime.create()
+ anime.setUrlWithoutDomain(baseUrl + element.select("a").attr("href"))
+ anime.title = element.select("a header").text()
+ anime.thumbnail_url = element.select("a figure img").attr("src")
+ anime.description = element.select("p div").text().removeSurrounding("\"")
+ return anime
+ }
+
+ override fun popularAnimeNextPageSelector(): String = "#paginas ul li:nth-last-child(2) a"
+
+ // override fun episodeListSelector() = "ul.ListCaps li a"
+ override fun episodeListSelector() = throw Exception("not used")
+
+ override fun episodeListParse(response: Response): List {
+ val document = response.asJsoup()
+ var animeId = document.select("#ord").attr("data-id")
+ return episodeJsonParse(response.request.url.toString(), animeId)
+ }
+
+ private fun episodeJsonParse(url: String, animeId: String): MutableList {
+ val capList = mutableListOf()
+ var nextPage = 1
+ do {
+ val headers = headers.newBuilder()
+ .set("Referer", url)
+ .set("sec-fetch-site", "same-origin")
+ .set("x-requested-with", "XMLHttpRequest")
+ .set("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0")
+ .set("Accept-Language", "es-MX,es-419;q=0.9,es;q=0.8,en;q=0.7")
+ .build()
+
+ var responseString = client.newCall(GET("https://www.animeid.tv/ajax/caps?id=$animeId&ord=DESC&pag=$nextPage", headers))
+ .execute().asJsoup().body()!!.toString().substringAfter("").substringBefore("")
+ Log.i("bruh", responseString)
+ val jObject = json.decodeFromString(responseString)
+ var listCaps = jObject["list"]!!.jsonArray
+ Log.i("bruh list", jObject["list"]!!.toString())
+ listCaps!!.forEach { cap ->
+ var capParsed = cap.jsonObject
+ Log.i("bruh ep", capParsed.toString())
+ val epNum = capParsed["numero"]!!.jsonPrimitive.content!!.toFloat()
+ val format = SimpleDateFormat("dd MMM yyyy")
+ val episode = SEpisode.create()
+ episode.episode_number = epNum
+ episode.name = "Episodio $epNum"
+ episode.date_upload = format.parse(capParsed["date"]!!.jsonPrimitive.content!!.toString()).time
+ episode.setUrlWithoutDomain(baseUrl + capParsed["href"]!!.jsonPrimitive.content!!.toString())
+ capList.add(episode)
+ }
+
+ if (listCaps!!.any()) nextPage += 1 else nextPage = -1
+ } while (nextPage != -1)
+ return capList
+ }
+
+ override fun episodeFromElement(element: Element) = throw Exception("not used")
+
+ /*override fun episodeFromElement(element: Element): SEpisode {
+ val episode = SEpisode.create()
+ val epNum = getNumberFromEpsString(element.select("p").text())
+ episode.setUrlWithoutDomain(element.attr("href"))
+ episode.episode_number = when {
+ (epNum.isNotEmpty()) -> epNum.toFloat()
+ else -> 1F
+ }
+ episode.name = element.select("p").text()
+
+ return episode
+ }*/
+
+ override fun videoListParse(response: Response): List