diff --git a/src/ar/tuktukcinema/AndroidManifest.xml b/src/ar/tuktukcinema/AndroidManifest.xml
new file mode 100644
index 000000000..acb4de356
--- /dev/null
+++ b/src/ar/tuktukcinema/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/ar/tuktukcinema/build.gradle b/src/ar/tuktukcinema/build.gradle
new file mode 100644
index 000000000..21348af92
--- /dev/null
+++ b/src/ar/tuktukcinema/build.gradle
@@ -0,0 +1,16 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+ext {
+ extName = 'تك تك سينما'
+ pkgNameSuffix = 'ar.tuktukcinema'
+ extClass = '.Tuktukcinema'
+ extVersionCode = 1
+ libVersion = '13'
+}
+
+dependencies {
+ implementation(project(':lib-dood-extractor'))
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/ar/tuktukcinema/res/mipmap-hdpi/ic_launcher.png b/src/ar/tuktukcinema/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..db20dc7b0
Binary files /dev/null and b/src/ar/tuktukcinema/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/ar/tuktukcinema/res/mipmap-mdpi/ic_launcher.png b/src/ar/tuktukcinema/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..d29ea29a0
Binary files /dev/null and b/src/ar/tuktukcinema/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/ar/tuktukcinema/res/mipmap-xhdpi/ic_launcher.png b/src/ar/tuktukcinema/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..c1f34e21c
Binary files /dev/null and b/src/ar/tuktukcinema/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/ar/tuktukcinema/res/mipmap-xxhdpi/ic_launcher.png b/src/ar/tuktukcinema/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..f007b8ce3
Binary files /dev/null and b/src/ar/tuktukcinema/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/ar/tuktukcinema/res/mipmap-xxxhdpi/ic_launcher.png b/src/ar/tuktukcinema/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..707a055dc
Binary files /dev/null and b/src/ar/tuktukcinema/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/ar/tuktukcinema/res/web_hi_res_512.png b/src/ar/tuktukcinema/res/web_hi_res_512.png
new file mode 100644
index 000000000..55c57febc
Binary files /dev/null and b/src/ar/tuktukcinema/res/web_hi_res_512.png differ
diff --git a/src/ar/tuktukcinema/src/eu/kanade/tachiyomi/animeextension/ar/tuktukcinema/Tuktukcinema.kt b/src/ar/tuktukcinema/src/eu/kanade/tachiyomi/animeextension/ar/tuktukcinema/Tuktukcinema.kt
new file mode 100644
index 000000000..d238b2df9
--- /dev/null
+++ b/src/ar/tuktukcinema/src/eu/kanade/tachiyomi/animeextension/ar/tuktukcinema/Tuktukcinema.kt
@@ -0,0 +1,320 @@
+package eu.kanade.tachiyomi.animeextension.ar.tuktukcinema
+
+import android.app.Application
+import android.content.SharedPreferences
+import androidx.preference.ListPreference
+import androidx.preference.PreferenceScreen
+import eu.kanade.tachiyomi.animeextension.ar.tuktukcinema.extractors.MoshahdaExtractor
+import eu.kanade.tachiyomi.animeextension.ar.tuktukcinema.extractors.OkruExtractor
+import eu.kanade.tachiyomi.animeextension.ar.tuktukcinema.extractors.UQLoadExtractor
+import eu.kanade.tachiyomi.animeextension.ar.tuktukcinema.extractors.VidBomExtractor
+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.lib.doodextractor.DoodExtractor
+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 Tuktukcinema : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
+
+ override val name = "تك تك سينما"
+
+ override val baseUrl = "https://w.tuktukcinema.net"
+
+ 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.Block--Item, div.Small--Box"
+
+ override fun popularAnimeRequest(page: Int): Request = GET(baseUrl)
+
+ override fun popularAnimeFromElement(element: Element): SAnime {
+ val anime = SAnime.create()
+ anime.title = titleEdit(element.select("a").attr("title"), true).trim()
+ anime.thumbnail_url = element.select("img").attr("data-src")
+ anime.setUrlWithoutDomain(element.select("a").attr("href") + "watch/")
+ return anime
+ }
+
+ private fun titleEdit(title: String, details: Boolean = false): String {
+ return if (Regex("فيلم (.*?) مترجم").containsMatchIn(title))
+ Regex("فيلم (.*?) مترجم").find(title)!!.groupValues[1] + " (فيلم)" // افلام اجنبيه مترجمه
+ else if (Regex("فيلم (.*?) مدبلج").containsMatchIn(title))
+ Regex("فيلم (.*?) مدبلج").find(title)!!.groupValues[1] + " (مدبلج)(فيلم)" // افلام اجنبيه مدبلجه
+ else if (Regex("فيلم ([^a-zA-Z]+) ([0-9]+)").containsMatchIn(title)) // افلام عربى
+ Regex("فيلم ([^a-zA-Z]+) ([0-9]+)").find(title)!!.groupValues[1] + " (فيلم)"
+ else if (title.contains("مسلسل")) {
+ if (title.contains("الموسم") and details) {
+ val newTitle = Regex("مسلسل (.*?) الموسم (.*?) الحلقة ([0-9]+)").find(title)
+ return "${newTitle!!.groupValues[1]} (م.${newTitle.groupValues[2]})(${newTitle.groupValues[3]}ح)"
+ } else if (title.contains("الحلقة") and details) {
+ val newTitle = Regex("مسلسل (.*?) الحلقة ([0-9]+)").find(title)
+ return "${newTitle!!.groupValues[1]} (${newTitle.groupValues[2]}ح)"
+ } else Regex(if (title.contains("الموسم")) "مسلسل (.*?) الموسم" else "مسلسل (.*?) الحلقة").find(title)!!.groupValues[1] + " (مسلسل)"
+ } else if (title.contains("انمي"))
+ return 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.seasons--toggler ul li"
+
+ override fun episodeListParse(response: Response): List {
+ val episodes = mutableListOf()
+ fun addEpisodeNew(url: String, type: String, title: String = "") {
+ val episode = SEpisode.create()
+ episode.setUrlWithoutDomain(url)
+ if (type == "movie")
+ episode.name = "مشاهدة"
+ else
+ episode.name = title
+
+ episodes.add(episode)
+ }
+ fun addEpisodes(response: Response) {
+ val document = response.asJsoup()
+ val url = response.request.url.toString()
+ if (document.select("div.episodes--side--list").isNullOrEmpty()) {
+ // Movies
+ addEpisodeNew(url, "movie")
+ } else {
+ // Series
+ // look for what is wrong
+ document.select(seasonsNextPageSelector()).forEach { season ->
+ val seasonNum = season.text()
+ if (season.hasClass("active")) {
+ // get episodes from page
+ document.select("div.episodes--list--side a").forEach { ep ->
+ addEpisodeNew(
+ ep.attr("href"),
+ "series",
+ seasonNum + " " + ep.text()
+ )
+ }
+ } else {
+ // send request to get episodes
+ val seasonData = season.attr("data-season")
+ val postId = season.attr("data-id")
+ val refererHeaders = Headers.headersOf("referer", response.request.url.toString(), "x-requested-with", "XMLHttpRequest")
+ val requestBody = FormBody.Builder().add("season", seasonData).add("post_id", postId).build()
+ val getEpisodes = client.newCall(POST("$baseUrl/wp-content/themes/Elshaikh/Inc/Ajax/Single/Episodes.php", refererHeaders, requestBody)).execute().asJsoup()
+ getEpisodes.select("li a").forEach { ep ->
+ addEpisodeNew(
+ ep.attr("href"),
+ "series",
+ seasonNum + " " + ep.text()
+ )
+ }
+ }
+ }
+ }
+ }
+ addEpisodes(response)
+ return episodes
+ }
+
+ override fun episodeListSelector() = "link[rel=canonical]"
+
+ override fun episodeFromElement(element: Element): SEpisode = throw Exception("not used")
+
+ // ============================ video links ============================
+
+ override fun videoListSelector() = "div.watch--servers--list ul li.server--item"
+
+ override fun videoListParse(response: Response): List