diff --git a/src/en/seez/AndroidManifest.xml b/src/en/seez/AndroidManifest.xml
new file mode 100644
index 000000000..568741e54
--- /dev/null
+++ b/src/en/seez/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/en/seez/build.gradle b/src/en/seez/build.gradle
new file mode 100644
index 000000000..fd896a58a
--- /dev/null
+++ b/src/en/seez/build.gradle
@@ -0,0 +1,22 @@
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.serialization)
+}
+
+ext {
+ extName = 'Seez'
+ pkgNameSuffix = 'en.seez'
+ extClass = '.Seez'
+ extVersionCode = 1
+ libVersion = '13'
+}
+
+dependencies {
+ implementation(project(':lib-filemoon-extractor'))
+ implementation(project(':lib-streamtape-extractor'))
+ implementation(project(':lib-playlist-utils'))
+}
+
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/en/seez/res/mipmap-hdpi/ic_launcher.png b/src/en/seez/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..41ef17c34
Binary files /dev/null and b/src/en/seez/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/en/seez/res/mipmap-mdpi/ic_launcher.png b/src/en/seez/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..402737887
Binary files /dev/null and b/src/en/seez/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/en/seez/res/mipmap-xhdpi/ic_launcher.png b/src/en/seez/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..6bf2ef21e
Binary files /dev/null and b/src/en/seez/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/en/seez/res/mipmap-xxhdpi/ic_launcher.png b/src/en/seez/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..272e5ed38
Binary files /dev/null and b/src/en/seez/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/en/seez/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/seez/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..8f181f6b6
Binary files /dev/null and b/src/en/seez/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/en/seez/res/web_hi_res_512.png b/src/en/seez/res/web_hi_res_512.png
new file mode 100644
index 000000000..548973187
Binary files /dev/null and b/src/en/seez/res/web_hi_res_512.png differ
diff --git a/src/en/seez/src/eu/kanade/tachiyomi/animeextension/en/seez/Seez.kt b/src/en/seez/src/eu/kanade/tachiyomi/animeextension/en/seez/Seez.kt
new file mode 100644
index 000000000..f1b34dde7
--- /dev/null
+++ b/src/en/seez/src/eu/kanade/tachiyomi/animeextension/en/seez/Seez.kt
@@ -0,0 +1,415 @@
+package eu.kanade.tachiyomi.animeextension.en.seez
+
+import android.app.Application
+import android.content.SharedPreferences
+import androidx.preference.ListPreference
+import androidx.preference.PreferenceScreen
+import eu.kanade.tachiyomi.animeextension.en.seez.extractors.VidsrcExtractor
+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.AnimeHttpSource
+import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
+import eu.kanade.tachiyomi.network.GET
+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.encodeToString
+import kotlinx.serialization.json.Json
+import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrl
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
+import uy.kohesive.injekt.injectLazy
+import java.text.SimpleDateFormat
+import java.util.Locale
+
+class Seez : ConfigurableAnimeSource, AnimeHttpSource() {
+
+ override val name = "Seez"
+
+ override val baseUrl = "https://seez.su"
+
+ private val embedUrl = "https://vidsrc.to"
+
+ override val lang = "en"
+
+ override val supportsLatest = false
+
+ 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 vrfHelper by lazy { VrfHelper(client, headers) }
+
+ private val apiKey by lazy {
+ val jsUrl = client.newCall(GET(baseUrl, headers)).execute().asJsoup()
+ .select("script[defer][src]")[1].attr("abs:src")
+
+ val jsBody = client.newCall(GET(jsUrl, headers)).execute().use { it.body.string() }
+ Regex("""f="(\w{20,})"""").find(jsBody)!!.groupValues[1]
+ }
+
+ private val apiHeaders = headers.newBuilder().apply {
+ add("Accept", "application/json, text/javascript, */*; q=0.01")
+ add("Host", "api.themoviedb.org")
+ add("Origin", baseUrl)
+ add("Referer", "$baseUrl/")
+ }.build()
+
+ // ============================== Popular ===============================
+
+ override fun popularAnimeRequest(page: Int): Request {
+ val url = TMDB_URL.newBuilder().apply {
+ addPathSegment("movie")
+ addPathSegment("popular")
+ addQueryParameter("language", "en-US")
+ addQueryParameter("page", page.toString())
+ }.buildAPIUrl()
+
+ return GET(url, headers = apiHeaders)
+ }
+
+ override fun popularAnimeParse(response: Response): AnimesPage {
+ val data = response.parseAs()
+
+ val animeList = data.results.map { ani ->
+ val name = ani.title ?: ani.name ?: "Title N/A"
+
+ SAnime.create().apply {
+ title = name
+ url = LinkData(ani.id, "movie").toJsonString()
+ thumbnail_url = ani.poster_path?.let { IMG_URL + it } ?: FALLBACK_IMG
+ }
+ }
+
+ return AnimesPage(animeList, data.page < data.total_pages)
+ }
+
+ // =============================== Latest ===============================
+
+ override fun latestUpdatesRequest(page: Int): Request = throw Exception("Not used")
+
+ override fun latestUpdatesParse(response: Response): AnimesPage = throw Exception("Not used")
+
+ // =============================== Search ===============================
+
+ override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
+ val filterList = if (filters.isEmpty()) getFilterList() else filters
+ val typeFilter = filterList.find { it is TypeFilter } as TypeFilter
+ val collectionFilter = filterList.find { it is CollectionFilter } as CollectionFilter
+ val orderFilter = filterList.find { it is OrderFilter } as OrderFilter
+
+ val url = if (query.isNotBlank()) {
+ TMDB_URL.newBuilder().apply {
+ addPathSegment("search")
+ addPathSegment("multi")
+ addQueryParameter("query", query)
+ addQueryParameter("page", page.toString())
+ }.buildAPIUrl()
+ } else {
+ TMDB_URL.newBuilder().apply {
+ addPathSegment(typeFilter.toUriPart())
+ addPathSegment(orderFilter.toUriPart())
+ if (collectionFilter.state != 0) {
+ addQueryParameter("with_networks", collectionFilter.toUriPart())
+ }
+ addQueryParameter("language", "en-US")
+ addQueryParameter("page", page.toString())
+ }.buildAPIUrl()
+ }
+
+ return GET(url, headers = apiHeaders)
+ }
+
+ override fun searchAnimeParse(response: Response): AnimesPage {
+ val data = response.parseAs()
+
+ val animeList = data.results.map { ani ->
+ val name = ani.title ?: ani.name ?: "Title N/A"
+
+ SAnime.create().apply {
+ title = name
+ url = LinkData(ani.id, ani.media_type).toJsonString()
+ thumbnail_url = ani.poster_path?.let { IMG_URL + it } ?: FALLBACK_IMG
+ }
+ }
+
+ return AnimesPage(animeList, data.page < data.total_pages)
+ }
+
+ // ============================== Filters ===============================
+
+ override fun getFilterList(): AnimeFilterList = AnimeFilterList(
+ AnimeFilter.Header("NOTE: Filters are going to be ignored if using search text"),
+ TypeFilter(),
+ CollectionFilter(),
+ OrderFilter(),
+ )
+
+ private class TypeFilter : UriPartFilter(
+ "Type",
+ arrayOf(
+ Pair("Movies", "movie"),
+ Pair("TV-shows", "tv"),
+ ),
+ )
+
+ private class CollectionFilter : UriPartFilter(
+ "Collection",
+ arrayOf(
+ Pair("