diff --git a/src/ar/shahid4u/AndroidManifest.xml b/src/ar/shahid4u/AndroidManifest.xml
new file mode 100644
index 000000000..acb4de356
--- /dev/null
+++ b/src/ar/shahid4u/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/ar/shahid4u/build.gradle b/src/ar/shahid4u/build.gradle
new file mode 100644
index 000000000..7abbe5c17
--- /dev/null
+++ b/src/ar/shahid4u/build.gradle
@@ -0,0 +1,12 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+ext {
+ extName = 'شاهد فور يو'
+ pkgNameSuffix = 'ar.shahid4u'
+ extClass = '.Shahid4U'
+ extVersionCode = 1
+ libVersion = '13'
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/ar/shahid4u/res/mipmap-hdpi/ic_launcher.png b/src/ar/shahid4u/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..12cfa74d5
Binary files /dev/null and b/src/ar/shahid4u/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/ar/shahid4u/res/mipmap-mdpi/ic_launcher.png b/src/ar/shahid4u/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..cac0af0ca
Binary files /dev/null and b/src/ar/shahid4u/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/ar/shahid4u/res/mipmap-xhdpi/ic_launcher.png b/src/ar/shahid4u/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..e6472e8d4
Binary files /dev/null and b/src/ar/shahid4u/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/ar/shahid4u/res/mipmap-xxhdpi/ic_launcher.png b/src/ar/shahid4u/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..b8e3e4c5b
Binary files /dev/null and b/src/ar/shahid4u/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/ar/shahid4u/res/mipmap-xxxhdpi/ic_launcher.png b/src/ar/shahid4u/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..2a26fb744
Binary files /dev/null and b/src/ar/shahid4u/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/ar/shahid4u/res/web_hi_res_512.png b/src/ar/shahid4u/res/web_hi_res_512.png
new file mode 100644
index 000000000..5cec2a3e2
Binary files /dev/null and b/src/ar/shahid4u/res/web_hi_res_512.png differ
diff --git a/src/ar/shahid4u/src/eu/kanade/tachiyomi/animeextension/ar/shahid4u/Shahid4U.kt b/src/ar/shahid4u/src/eu/kanade/tachiyomi/animeextension/ar/shahid4u/Shahid4U.kt
new file mode 100644
index 000000000..01d67dde3
--- /dev/null
+++ b/src/ar/shahid4u/src/eu/kanade/tachiyomi/animeextension/ar/shahid4u/Shahid4U.kt
@@ -0,0 +1,320 @@
+package eu.kanade.tachiyomi.animeextension.ar.shahid4u
+
+import android.app.Application
+import android.content.SharedPreferences
+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.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.POST
+import eu.kanade.tachiyomi.util.asJsoup
+import okhttp3.FormBody
+import okhttp3.Headers
+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 java.lang.Exception
+
+class Shahid4U : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
+
+ override val name = "شاهد فور يو"
+
+ override val baseUrl = "https://shahed4u.mx/"
+
+ override val lang = "ar"
+
+ override val supportsLatest = true
+
+ override val client: OkHttpClient = network.cloudflareClient
+
+ private val preferences: SharedPreferences by lazy {
+ Injekt.get().getSharedPreferences("source_$id", 0x0000)
+ }
+
+ // Popular
+
+ override fun popularAnimeSelector(): String = "div.glide-slides div.media-block"
+
+ override fun popularAnimeRequest(page: Int): Request = GET(if (page == 1)" $baseUrl/home2/" else "$baseUrl")
+
+ override fun popularAnimeFromElement(element: Element): SAnime {
+ val anime = SAnime.create()
+ anime.title = titleEdit(element.select("h3").text()).trim()
+ anime.thumbnail_url = element.select("a.image img").attr("data-src")
+ anime.setUrlWithoutDomain(element.select("a.fullClick").attr("href") + "watch/")
+ return anime
+ }
+
+ private fun titleEdit(title: String): String {
+ return if (title.contains("فيلم"))
+ Regex("فيلم(.*?)مترجم").find(title)!!.groupValues[1] + "(فيلم)"
+ else if (title.contains("مسلسل"))
+ Regex(if (title.contains("الموسم"))"مسلسل(.*?)الموسم" else "مسلسل(.*?)الحلقة").find(title)!!.groupValues[1] + "(مسلسل)"
+ else if (title.contains("انمي"))
+ Regex(if (title.contains("الموسم"))"انمي(.*?)الموسم" else "انمي(.*?)الحلقة").find(title)!!.groupValues[1] + "(انمى)"
+ else if (title.contains("برنامج"))
+ Regex(if (title.contains("الموسم"))"برنامج(.*?)الموسم" else "برنامج(.*?)الحلقة").find(title)!!.groupValues[1] + "(برنامج)"
+ else
+ title
+ }
+
+ override fun popularAnimeNextPageSelector(): String = "div.paginate ul.page-numbers li.active + li a"
+
+ // episodes
+
+ private fun seasonsNextPageSelector() = "div.allseasonstab ul li"
+
+ override fun episodeListParse(response: Response): List {
+ val episodes = mutableListOf()
+ fun addEpisode(document: Document, season: String) {
+ document.select(episodeListSelector()).map { episodes.add(episodeFromElement(it, season)) }
+ }
+ fun addEpisodes(document: Document, url: String) {
+ if (url.contains("assemblies")) {
+ for (movie in document.select(popularAnimeSelector())) {
+ addEpisode(client.newCall(GET(movie.select("a.fullClick").attr("href") + "watch/", headers)).execute().asJsoup(), "assembly")
+ }
+ return
+ }
+ if (document.select("div.seasons--episodes").isNullOrEmpty()) {
+ // Movies
+ addEpisode(document, "0")
+ } else {
+ // Series
+ // look for what is wrong
+ for (season in document.select(seasonsNextPageSelector())) {
+ val seasonNum = season.text().replace("الموسم ", "")
+ if (season.attr("class").contains("active")) {
+ // get episodes from page
+ for (episode in document.select("ul.episodes-list li a")) {
+ addEpisode(client.newCall(GET(episode.attr("href"), headers)).execute().asJsoup(), seasonNum)
+ }
+ } else {
+ // send request to get episodes
+ val seasonData = season.attr("data-id")
+ val refererHeaders = Headers.headersOf("referer", response.request.url.toString(), "x-requested-with", "XMLHttpRequest")
+ val requestBody = FormBody.Builder().add("season", seasonData).build()
+ val getEpisodes = client.newCall(POST("$baseUrl/wp-content/themes/Shahid4u-WP_HOME/Ajaxat/Single/Episodes.php", refererHeaders, requestBody)).execute().asJsoup()
+ for (episode in getEpisodes.select("li a")) {
+ addEpisode(client.newCall(GET(episode.attr("href"), headers)).execute().asJsoup(), seasonNum)
+ }
+ }
+ }
+ }
+ }
+ addEpisodes(response.asJsoup(), response.request.url.toString())
+ return episodes
+ }
+
+ override fun episodeListSelector() = "link[rel=canonical]"
+
+ override fun episodeFromElement(element: Element): SEpisode = throw Exception("not used")
+
+ private fun episodeFromElement(element: Element, season: String): SEpisode {
+ val episode = SEpisode.create()
+ episode.setUrlWithoutDomain(element.attr("href"))
+ episode.name = element.ownerDocument().select("meta[property=og:title]").attr("content")
+ if (season != "assembly")
+ if (episode.name.contains("فيلم"))
+ episode.name = "watch"
+ else
+ episode.name = "S" + season + ".E" + episode.name.replace("[^0-9]".toRegex(), "").trim()
+ return episode
+ }
+ // Video links
+
+ override fun videoListParse(response: Response): List