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