()
61 | val doc = app.get("$mainUrl/page/1/?s=$query").document
62 | val paginationElement = doc.select("ul[aria-label=\"pagination\"]")
63 | doc.select("section article a").map {
64 | val postUrl = it.attr("href")
65 | if(it.select("li[aria-label=\"episode\"]").isNotEmpty()) return@map
66 | if(postUrl.contains("$mainUrl/expired-download/|$mainUrl/افلام-اون-لاين/".toRegex())) return@map
67 | result.add(it.toSearchResponse()!!)
68 | }
69 | if(paginationElement.isNotEmpty()) {
70 | val max = paginationElement.select("li").not("li.active").last()?.text()?.toIntOrNull()
71 | if (max != null) {
72 | if(max > 5) return result.distinct().sortedBy { it.name }
73 | (2..max!!).toList().apmap {
74 | app.get("$mainUrl/page/$it/?s=$query\"").document.select("section article a").map { element ->
75 | val postUrl = element.attr("href")
76 | if(element.select("li[aria-label=\"episode\"]").isNotEmpty()) return@map
77 | if(postUrl.contains("$mainUrl/expired-download/|$mainUrl/افلام-اون-لاين/".toRegex())) return@map
78 | result.add(element.toSearchResponse()!!)
79 | }
80 | }
81 | }
82 | }
83 | return result.distinct().sortedBy { it.name }
84 | }
85 |
86 | override suspend fun load(url: String): LoadResponse {
87 | val doc = app.get(url).document
88 | val posterUrl = doc.select("body > script:nth-child(3)").html().replace(".*,\"image\":\"|\".*".toRegex(),"").ifEmpty { doc.select("meta[property=\"og:image\"]").attr("content") }
89 | val year = doc.select("article ul:nth-child(1) li a").last()?.text()?.toIntOrNull()
90 | val title = doc.select("title").text().split(" | ")[0]
91 | val isMovie = title.contains("فيلم|حفلات|مسرحية".toRegex())
92 | val youtubeTrailer = doc.select("iframe")?.attr("src")
93 |
94 | val synopsis = doc.select("ul#details li:contains(لمحة) p").text()
95 |
96 | val tags = doc.select("article ul").first()?.select("li")?.map { it.text() }
97 |
98 | val recommendations = doc.select("ul#related li").map { element ->
99 | MovieSearchResponse(
100 | apiName = this@CimaNow.name,
101 | url = element.select("a").attr("href"),
102 | name = element.select("img:nth-child(2)").attr("alt"),
103 | posterUrl = element.select("img:nth-child(2)").attr("src")
104 | )
105 | }
106 |
107 | return if (isMovie) {
108 | newMovieLoadResponse(
109 | title,
110 | url,
111 | TvType.Movie,
112 | "$url/watching"
113 | ) {
114 | this.posterUrl = posterUrl
115 | this.year = year
116 | this.recommendations = recommendations
117 | this.plot = synopsis
118 | this.tags = tags
119 | addTrailer(youtubeTrailer)
120 | }
121 | } else {
122 | val episodes = doc.select("ul#eps li").map { episode ->
123 | Episode(
124 | episode.select("a").attr("href")+"/watching",
125 | episode.select("a img:nth-child(2)").attr("alt"),
126 | doc.select("span[aria-label=\"season-title\"]").html().replace(".*|\n".toRegex(), "").getIntFromText(),
127 | episode.select("a em").text().toIntOrNull(),
128 | episode.select("a img:nth-child(2)").attr("src")
129 | )
130 | }
131 | newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
132 | this.posterUrl = posterUrl
133 | this.tags = tags
134 | this.year = year
135 | this.plot = synopsis
136 | this.recommendations = recommendations
137 | addTrailer(youtubeTrailer)
138 | }
139 | }
140 | }
141 |
142 | override suspend fun loadLinks(
143 | data: String,
144 | isCasting: Boolean,
145 | subtitleCallback: (SubtitleFile) -> Unit,
146 | callback: (ExtractorLink) -> Unit
147 | ): Boolean {
148 | app.get(data).document.select("ul#download [aria-label=\"quality\"]").forEach {
149 | val name = if(it.select("span").text().contains("فائق السرعة")) "Fast Servers" else "Servers"
150 | it.select("a").forEach { media ->
151 | callback.invoke(
152 | ExtractorLink(
153 | source = this.name,
154 | name = name,
155 | url = media.attr("href"),
156 | referer = this.mainUrl,
157 | quality = media.text().getIntFromText() ?: Qualities.Unknown.value
158 | )
159 | )
160 | }
161 | }
162 | return true
163 | }
164 | }
--------------------------------------------------------------------------------
/EgyBestProvider/build.gradle.kts:
--------------------------------------------------------------------------------
1 | version = 7
2 |
3 | cloudstream {
4 | description = "Egybest is broken"
5 | authors = listOf( "ImZaw" )
6 |
7 | language = "ar"
8 |
9 | status = 0
10 |
11 | tvTypes = listOf( "TvSeries" , "Movie" , "Anime" )
12 |
13 | iconUrl = "https://www.google.com/s2/favicons?domain=www.egy.best&sz=%size%"
14 | }
15 |
--------------------------------------------------------------------------------
/EgyBestProvider/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/EgyBestProvider/src/main/kotlin/com/egybest/EgyBestPlugin.kt:
--------------------------------------------------------------------------------
1 | package com.egybest
2 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
3 | import com.lagradost.cloudstream3.plugins.Plugin
4 | import android.content.Context
5 |
6 | @CloudstreamPlugin
7 | class EgyBestPlugin: Plugin() {
8 | override fun load(context: Context) {
9 | registerMainAPI(EgyBest())
10 | }
11 | }
--------------------------------------------------------------------------------
/EgyBestProvider/src/main/kotlin/com/egybest/EgyBestProvider.kt:
--------------------------------------------------------------------------------
1 | package com.egybest
2 |
3 |
4 | import android.annotation.TargetApi
5 | import android.os.Build
6 | import com.lagradost.cloudstream3.*
7 | import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
8 | import com.lagradost.cloudstream3.utils.ExtractorLink
9 | import com.lagradost.cloudstream3.utils.M3u8Helper
10 | import com.lagradost.nicehttp.Requests
11 | import com.lagradost.nicehttp.Session
12 | import okhttp3.HttpUrl.Companion.toHttpUrl
13 | import org.jsoup.nodes.Element
14 | import java.util.Base64
15 | import org.mozilla.javascript.Context
16 | import org.mozilla.javascript.Scriptable
17 |
18 | fun String.runJS(variableName: String): String {
19 | val rhino = Context.enter()
20 | rhino.initSafeStandardObjects()
21 | rhino.optimizationLevel = -1
22 | val scope: Scriptable = rhino.initSafeStandardObjects()
23 | val script = this
24 | val result: String
25 | try {
26 | var js = ""
27 | for (i in script.indices) {
28 | js += script[i]
29 | }
30 | rhino.evaluateString(scope, js, "JavaScript", 1, null)
31 | result = Context.toString(scope.get(variableName, scope))
32 | } finally {
33 | Context.exit()
34 | }
35 | return result
36 | }
37 |
38 | class EgyBest : MainAPI() {
39 | override var lang = "ar"
40 | override var mainUrl = "https://egybest.org"
41 | override var name = "EgyBest"
42 | var pssid = ""
43 | override val usesWebView = false
44 | override val hasMainPage = true
45 | override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime)
46 |
47 | private fun String.getIntFromText(): Int? {
48 | return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
49 | }
50 |
51 | private fun Element.toSearchResponse(): SearchResponse? {
52 | val url = this.attr("href") ?: return null
53 | val posterUrl = select("img")?.attr("src")
54 | var title = select("span.title").text()
55 | val year = title.getYearFromTitle()
56 | val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
57 | val tvType = if (isMovie) TvType.Movie else TvType.TvSeries
58 | title = if (year !== null) title else title.split(" (")[0].trim()
59 | val quality = select("span.ribbon span").text().replace("-", "")
60 | // If you need to differentiate use the url.
61 | return MovieSearchResponse(
62 | title,
63 | mainUrl + url,
64 | this@EgyBest.name,
65 | tvType,
66 | posterUrl,
67 | year,
68 | null,
69 | quality = getQualityFromString(quality)
70 | )
71 | }
72 |
73 | override val mainPage = mainPageOf(
74 | "$mainUrl/trending/?page=" to "الأفلام الأكثر مشاهدة",
75 | "$mainUrl/movies/?page=" to "أفلام جديدة",
76 | "$mainUrl/tv/?page=" to "مسلسلات جديدة ",
77 | "$mainUrl/tv/korean?page=" to "الدراما الكورية ",
78 | "$mainUrl/animes/popular?page=" to "مسلسلات الانمي",
79 | "$mainUrl/wwe/?page=" to "عروض المصارعة ",
80 | "$mainUrl/movies/latest-bluray-2020-2019?page=" to "أفلام جديدة BluRay",
81 | "$mainUrl/masrahiyat/?page=" to "مسرحيات ",
82 | "$mainUrl/movies/latest?page=" to "أحدث الاضافات",
83 | "$mainUrl/movies/comedy?page=" to "أفلام كوميدية",
84 | "$mainUrl/explore/?q=superhero/" to "أفلام سوبر هيرو",
85 | "$mainUrl/movies/animation?page=" to "أفلام انمي و كرتون",
86 | "$mainUrl/movies/romance?page=" to "أفلام رومانسية",
87 | "$mainUrl/movies/drama?page=" to "أفلام دراما",
88 | "$mainUrl/movies/horror?page=" to "أفلام رعب",
89 | "$mainUrl/movies/documentary?page=" to "أفلام وثائقية",
90 | "$mainUrl/World-War-Movies/?page=" to "أفلام عن الحرب العالمية ☢",
91 | "$mainUrl/End-Of-The-World-Movies/?page=" to "أفلام عن نهاية العالم",
92 | "$mainUrl/movies/arab?page=" to "أفلام عربية ",
93 | )
94 |
95 | override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
96 | val doc = app.get(request.data + page).document
97 | val list = doc.select(".movie")
98 | .mapNotNull { element ->
99 | element.toSearchResponse()
100 | }
101 | return newHomePageResponse(request.name, list)
102 | }
103 |
104 | override suspend fun search(query: String): List {
105 | val result = arrayListOf()
106 | listOf("$mainUrl/explore/?q=$query").apmap { url ->
107 | val d = app.get(url).document
108 | d.select("div.movies a").not("a.auto.load.btn.b").mapNotNull {
109 | it.toSearchResponse()?.let { it1 -> result.add(it1) }
110 | }
111 | }
112 | return result.distinct().sortedBy { it.name }
113 | }
114 |
115 | private fun String.getYearFromTitle(): Int? {
116 | return Regex("""\(\d{4}\)""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
117 | }
118 |
119 | override suspend fun load(url: String): LoadResponse {
120 | val doc = app.get(url).document
121 | val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
122 | val posterUrl = doc.select("div.movie_img a img")?.attr("src")
123 | val year = doc.select("div.movie_title h1 a")?.text()?.toIntOrNull()
124 | val title = doc.select("div.movie_title h1 span").text()
125 | val youtubeTrailer = doc.select("div.play")?.attr("url")
126 |
127 | val synopsis = doc.select("div.mbox").firstOrNull {
128 | it.text().contains("القصة")
129 | }?.text()?.replace("القصة ", "")
130 |
131 | val tags = doc.select("table.movieTable tbody tr").firstOrNull {
132 | it.text().contains("النوع")
133 | }?.select("a")?.map { it.text() }
134 |
135 | val actors = doc.select("div.cast_list .cast_item").mapNotNull {
136 | val name = it.selectFirst("div > a > img")?.attr("alt") ?: return@mapNotNull null
137 | val image = it.selectFirst("div > a > img")?.attr("src") ?: return@mapNotNull null
138 | val roleString = it.selectFirst("div > span")!!.text()
139 | val mainActor = Actor(name, image)
140 | ActorData(actor = mainActor, roleString = roleString)
141 | }
142 |
143 | return if (isMovie) {
144 | val recommendations = doc.select(".movies_small .movie").mapNotNull { element ->
145 | element.toSearchResponse()
146 | }
147 |
148 | newMovieLoadResponse(
149 | title,
150 | url,
151 | TvType.Movie,
152 | url
153 | ) {
154 | this.posterUrl = posterUrl
155 | this.year = year
156 | this.recommendations = recommendations
157 | this.plot = synopsis
158 | this.tags = tags
159 | this.actors = actors
160 | addTrailer(youtubeTrailer)
161 | }
162 | } else {
163 | val episodes = ArrayList()
164 | doc.select("#mainLoad > div:nth-child(2) > div.h_scroll > div a").map {
165 | it.attr("href")
166 | }.apmap {
167 | val d = app.get(it).document
168 | val season = Regex("season-(.....)").find(it)?.groupValues?.getOrNull(1)?.getIntFromText()
169 | if(d.select("tr.published").isNotEmpty()) {
170 | d.select("tr.published").map { element ->
171 | val ep = Regex("ep-(.....)").find(element.select(".ep_title a").attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
172 | episodes.add(
173 | Episode(
174 | mainUrl + element.select(".ep_title a").attr("href"),
175 | name = element.select("td.ep_title").html().replace(".*|".toRegex(), ""),
176 | season,
177 | ep,
178 | rating = element.select("td.tam:not(.date, .ep_len)").text().getIntFromText()
179 | )
180 | )
181 | }
182 | } else {
183 | d.select("#mainLoad > div:nth-child(3) > div.movies_small a").map { eit ->
184 | val ep = Regex("ep-(.....)").find(eit.attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
185 | episodes.add(
186 | Episode(
187 | mainUrl + eit.attr("href"),
188 | eit.select("span.title").text(),
189 | season,
190 | ep,
191 | )
192 | )
193 | }
194 | }
195 | }
196 | newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
197 | this.posterUrl = posterUrl
198 | this.tags = tags
199 | this.year = year
200 | this.plot = synopsis
201 | this.actors = actors
202 | addTrailer(youtubeTrailer)
203 | }
204 | }
205 | }
206 |
207 | @TargetApi(Build.VERSION_CODES.O)
208 | override suspend fun loadLinks(
209 | data: String,
210 | isCasting: Boolean,
211 | subtitleCallback: (SubtitleFile) -> Unit,
212 | callback: (ExtractorLink) -> Unit
213 | ): Boolean {
214 | val baseURL = data.split("/")[0] + "//" + data.split("/")[2]
215 | val client = Requests().baseClient
216 | val session = Session(client)
217 | println(baseURL)
218 | println(data)
219 | val doc = session.get(data).document
220 |
221 | val vidstreamURL = baseURL + doc.select("iframe.auto-size").attr("src")
222 |
223 | val videoSoup = session.get(vidstreamURL, cookies = mapOf(
224 | "PSSID" to this@EgyBest.pssid,
225 | )).document
226 | videoSoup.select("source").firstOrNull { it.hasAttr("src") }?.attr("src")?.let {
227 | M3u8Helper.generateM3u8(
228 | this.name,
229 | it,
230 | referer = mainUrl,
231 | headers = mapOf("range" to "bytes=0-")
232 | ).forEach(callback)
233 | } ?: run {
234 | var jsCode = videoSoup.select("script")[1].html()
235 | val function = videoSoup.select("script")[2].attr("onload")
236 | val verificationToken = Regex("\\{'[0-9a-zA-Z_]*':'ok'\\}").findAll(jsCode).first().value.replace("\\{'|':.*".toRegex(), "")
237 | val encodedAdLinkVar = Regex("\\([0-9a-zA-Z_]{2,12}\\[Math").findAll(jsCode).first().value.replace("\\(|\\[M.*".toRegex(),"")
238 | val encodingArraysRegEx = Regex(",[0-9a-zA-Z_]{2,12}=\\[]").findAll(jsCode).toList()
239 | val firstEncodingArray = encodingArraysRegEx[1].value.replace(",|=.*".toRegex(),"")
240 | val secondEncodingArray = encodingArraysRegEx[2].value.replace(",|=.*".toRegex(),"")
241 |
242 | jsCode = jsCode.replace("^