Added Providers
This commit is contained in:
		
							parent
							
								
									46cd183528
								
							
						
					
					
						commit
						dd683a98d2
					
				
					 54 changed files with 2704 additions and 0 deletions
				
			
		
							
								
								
									
										12
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
*.iml
 | 
			
		||||
.gradle
 | 
			
		||||
/local.properties
 | 
			
		||||
/.idea
 | 
			
		||||
.DS_Store
 | 
			
		||||
/build
 | 
			
		||||
**/build
 | 
			
		||||
/captures
 | 
			
		||||
.externalNativeBuild
 | 
			
		||||
.cxx
 | 
			
		||||
local.properties
 | 
			
		||||
.vscode
 | 
			
		||||
							
								
								
									
										12
									
								
								AkwamProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								AkwamProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "TvSeries" , "Movie" , "Anime" , "Cartoon" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=akwam.to&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								AkwamProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								AkwamProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.akwam"/>
 | 
			
		||||
							
								
								
									
										11
									
								
								AkwamProvider/src/main/kotlin/com/akwam/AkwamPlugin.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								AkwamProvider/src/main/kotlin/com/akwam/AkwamPlugin.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.akwam
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class AkwamPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(Akwam())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										221
									
								
								AkwamProvider/src/main/kotlin/com/akwam/AkwamProvider.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								AkwamProvider/src/main/kotlin/com/akwam/AkwamProvider.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,221 @@
 | 
			
		|||
package com.akwam
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class Akwam : MainAPI() {
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://akwam.to"
 | 
			
		||||
    override var name = "Akwam"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime, TvType.Cartoon)
 | 
			
		||||
 | 
			
		||||
    private fun Element.toSearchResponse(): SearchResponse? {
 | 
			
		||||
        val url = select("a.box").attr("href") ?: return null
 | 
			
		||||
        if (url.contains("/games/") || url.contains("/programs/")) return null
 | 
			
		||||
        val poster = select("picture > img")
 | 
			
		||||
        val title = poster.attr("alt")
 | 
			
		||||
        val posterUrl = poster.attr("data-src")
 | 
			
		||||
        val year = select(".badge-secondary").text().toIntOrNull()
 | 
			
		||||
 | 
			
		||||
        // If you need to differentiate use the url.
 | 
			
		||||
        return MovieSearchResponse(
 | 
			
		||||
            title,
 | 
			
		||||
            url,
 | 
			
		||||
            this@Akwam.name,
 | 
			
		||||
            TvType.TvSeries,
 | 
			
		||||
            posterUrl,
 | 
			
		||||
            year,
 | 
			
		||||
            null,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    override val mainPage = mainPageOf(
 | 
			
		||||
            "$mainUrl/movies?page=" to "Movies",
 | 
			
		||||
            "$mainUrl/series?page=" to "Series",
 | 
			
		||||
            "$mainUrl/shows?page=" to "Shows"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
 | 
			
		||||
        val doc = app.get(request.data + page).document
 | 
			
		||||
        val list = doc.select("div.col-lg-auto.col-md-4.col-6.mb-12").mapNotNull { element ->
 | 
			
		||||
            element.toSearchResponse()
 | 
			
		||||
        }
 | 
			
		||||
        return newHomePageResponse(request.name, list)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val url = "$mainUrl/search?q=$query"
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
        return doc.select("div.col-lg-auto").mapNotNull {
 | 
			
		||||
            it.toSearchResponse()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun String.getIntFromText(): Int? {
 | 
			
		||||
        return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun Element.toEpisode(): Episode {
 | 
			
		||||
        val a = select("a.text-white")
 | 
			
		||||
        val url = a.attr("href")
 | 
			
		||||
        val title = a.text()
 | 
			
		||||
        val thumbUrl = select("picture > img").attr("src")
 | 
			
		||||
        val date = select("p.entry-date").text()
 | 
			
		||||
        return newEpisode(url) {
 | 
			
		||||
            name = title
 | 
			
		||||
            episode = title.getIntFromText()
 | 
			
		||||
            posterUrl = thumbUrl
 | 
			
		||||
            addDate(date)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
        val isMovie = url.contains("/movie/")
 | 
			
		||||
        val title = doc.select("h1.entry-title").text()
 | 
			
		||||
        val posterUrl = doc.select("picture > img").attr("src")
 | 
			
		||||
 | 
			
		||||
        val year =
 | 
			
		||||
            doc.select("div.font-size-16.text-white.mt-2").firstOrNull {
 | 
			
		||||
                it.text().contains("السنة")
 | 
			
		||||
            }?.text()?.getIntFromText()
 | 
			
		||||
 | 
			
		||||
        // A bit iffy to parse twice like this, but it'll do.
 | 
			
		||||
        val duration =
 | 
			
		||||
            doc.select("div.font-size-16.text-white.mt-2").firstOrNull {
 | 
			
		||||
                it.text().contains("مدة الفيلم")
 | 
			
		||||
            }?.text()?.getIntFromText()
 | 
			
		||||
 | 
			
		||||
        val synopsis = doc.select("div.widget-body p:first-child").text()
 | 
			
		||||
 | 
			
		||||
        val rating = doc.select("span.mx-2").text().split("/").lastOrNull()?.toRatingInt()
 | 
			
		||||
 | 
			
		||||
        val tags = doc.select("div.font-size-16.d-flex.align-items-center.mt-3 > a").map {
 | 
			
		||||
            it.text()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val actors = doc.select("div.widget-body > div > div.entry-box > a").mapNotNull {
 | 
			
		||||
            val name = it?.selectFirst("div > .entry-title")?.text() ?: return@mapNotNull null
 | 
			
		||||
            val image = it.selectFirst("div > img")?.attr("src") ?: return@mapNotNull null
 | 
			
		||||
            Actor(name, image)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val recommendations =
 | 
			
		||||
            doc.select("div > div.widget-body > div.row > div > div.entry-box").mapNotNull {
 | 
			
		||||
                val recTitle = it?.selectFirst("div.entry-body > .entry-title > .text-white")
 | 
			
		||||
                    ?: return@mapNotNull null
 | 
			
		||||
                val href = recTitle.attr("href") ?: return@mapNotNull null
 | 
			
		||||
                val name = recTitle.text() ?: return@mapNotNull null
 | 
			
		||||
                val poster = it.selectFirst(".entry-image > a > picture > img")?.attr("data-src")
 | 
			
		||||
                    ?: return@mapNotNull null
 | 
			
		||||
                MovieSearchResponse(name, href, this.name, TvType.Movie, fixUrl(poster))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        return if (isMovie) {
 | 
			
		||||
            newMovieLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.Movie,
 | 
			
		||||
                url
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.rating = rating
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.duration = duration
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                addActors(actors)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            val episodes = doc.select("div.bg-primary2.p-4.col-lg-4.col-md-6.col-12").map {
 | 
			
		||||
                it.toEpisode()
 | 
			
		||||
            }.let {
 | 
			
		||||
                val isReversed = (it.lastOrNull()?.episode ?: 1) < (it.firstOrNull()?.episode ?: 0)
 | 
			
		||||
                if (isReversed)
 | 
			
		||||
                    it.reversed()
 | 
			
		||||
                else it
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
 | 
			
		||||
                this.duration = duration
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.tags = tags.filterNotNull()
 | 
			
		||||
                this.rating = rating
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                addActors(actors)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//    // Maybe possible to not use the url shortener but cba investigating that.
 | 
			
		||||
//    private suspend fun skipUrlShortener(url: String): AppResponse {
 | 
			
		||||
//        return app.get(app.get(url).document.select("a.download-link").attr("href"))
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    private fun getQualityFromId(id: Int?): Qualities {
 | 
			
		||||
        return when (id) {
 | 
			
		||||
            2 -> Qualities.P360 // Extrapolated
 | 
			
		||||
            3 -> Qualities.P480
 | 
			
		||||
            4 -> Qualities.P720
 | 
			
		||||
            5 -> Qualities.P1080
 | 
			
		||||
            else -> Qualities.Unknown
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        val doc = app.get(data).document
 | 
			
		||||
 | 
			
		||||
        val links = doc.select("div.tab-content.quality").map { element ->
 | 
			
		||||
            val quality = getQualityFromId(element.attr("id").getIntFromText())
 | 
			
		||||
            element.select(".col-lg-6 > a:contains(تحميل)").map { linkElement ->
 | 
			
		||||
                if (linkElement.attr("href").contains("/download/")) {
 | 
			
		||||
                    Pair(
 | 
			
		||||
                        linkElement.attr("href"),
 | 
			
		||||
                        quality,
 | 
			
		||||
                    )
 | 
			
		||||
                } else {
 | 
			
		||||
                    val url = "$mainUrl/download${
 | 
			
		||||
                        linkElement.attr("href").split("/link")[1]
 | 
			
		||||
                    }${data.split("/movie|/episode|/show/episode".toRegex())[1]}"
 | 
			
		||||
                    Pair(
 | 
			
		||||
                        url,
 | 
			
		||||
                        quality,
 | 
			
		||||
                    )
 | 
			
		||||
                    // just in case if they add the shorts urls again
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }.flatten()
 | 
			
		||||
 | 
			
		||||
        links.map {
 | 
			
		||||
            val linkDoc = app.get(it.first).document
 | 
			
		||||
            val button = linkDoc.select("div.btn-loader > a")
 | 
			
		||||
            val url = button.attr("href")
 | 
			
		||||
 | 
			
		||||
            callback.invoke(
 | 
			
		||||
                ExtractorLink(
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    url,
 | 
			
		||||
                    this.mainUrl,
 | 
			
		||||
                    it.second.value
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								AnimeBlkomProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								AnimeBlkomProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "Anime" , "AnimeMovie" , "OVA" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=animeblkom.net&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								AnimeBlkomProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								AnimeBlkomProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.animeblkom"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.animeblkom
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class AnimeBlkomPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(AnimeBlkom())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,127 @@
 | 
			
		|||
package com.animeblkom
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class AnimeBlkom : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://animeblkom.net"
 | 
			
		||||
    override var name = "AnimeBlkom"
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
        TvType.Anime,
 | 
			
		||||
        TvType.AnimeMovie,
 | 
			
		||||
        TvType.OVA,
 | 
			
		||||
    )
 | 
			
		||||
	
 | 
			
		||||
    private fun Element.toSearchResponse(): SearchResponse {
 | 
			
		||||
        val url = select("div.poster a").attr("href")
 | 
			
		||||
        val name = select("div.name a").text()
 | 
			
		||||
        val poster = mainUrl + select("div.poster img").attr("data-original")
 | 
			
		||||
        val year = select("div[title=\"سنة الانتاج\"]").text().toIntOrNull()
 | 
			
		||||
        val episodesNumber = select("div[title=\"عدد الحلقات\"]").text().toIntOrNull()
 | 
			
		||||
        val tvType = select("div[title=\"النوع\"]").text().let { if(it.contains("فيلم|خاصة".toRegex())) TvType.AnimeMovie else if(it.contains("أوفا|أونا".toRegex())) TvType.OVA else TvType.Anime }
 | 
			
		||||
        return newAnimeSearchResponse(
 | 
			
		||||
            name,
 | 
			
		||||
            url,
 | 
			
		||||
            tvType,
 | 
			
		||||
        ) {
 | 
			
		||||
            addDubStatus(false, episodesNumber)
 | 
			
		||||
            this.year = year
 | 
			
		||||
            this.posterUrl = poster
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    override val mainPage = mainPageOf(
 | 
			
		||||
        "$mainUrl/anime-list?sort_by=rate&page=" to "Most rated",
 | 
			
		||||
        "$mainUrl/anime-list?sort_by=created_at&page=" to "Recently added",
 | 
			
		||||
        "$mainUrl/anime-list?states=finished&page=" to "Completed"
 | 
			
		||||
    )
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
 | 
			
		||||
        val doc = app.get(request.data + page).document
 | 
			
		||||
        val list = doc.select("div.content-inner")
 | 
			
		||||
            .mapNotNull { element ->
 | 
			
		||||
                element.toSearchResponse()
 | 
			
		||||
            }
 | 
			
		||||
        return newHomePageResponse(request.name, list)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val q = query.replace(" ","+")
 | 
			
		||||
        return app.get("$mainUrl/search?query=$q").document.select("div.content.ratable").map {
 | 
			
		||||
            it.toSearchResponse()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
 | 
			
		||||
        val title = doc.select("span h1").text().replace("\\(.*".toRegex(),"")
 | 
			
		||||
        val poster = mainUrl + doc.select("div.poster img").attr("data-original")
 | 
			
		||||
        val description = doc.select(".story p").text()
 | 
			
		||||
        val genre = doc.select("p.genres a").map {
 | 
			
		||||
            it.text()
 | 
			
		||||
        }
 | 
			
		||||
        val year = doc.select(".info-table div:contains(تاريخ الانتاج) span.info").text().split("-")[0].toIntOrNull()
 | 
			
		||||
        val status = doc.select(".info-table div:contains(حالة الأنمي) span.info").text().let { if(it.contains("مستمر")) ShowStatus.Ongoing else ShowStatus.Completed }
 | 
			
		||||
        val nativeName = doc.select("span[title=\"الاسم باليابانية\"]").text().replace(".*:".toRegex(),"")
 | 
			
		||||
        val type = doc.select("h1 small").text().let {
 | 
			
		||||
            if (it.contains("movie")) TvType.AnimeMovie
 | 
			
		||||
            if (it.contains("ova|ona".toRegex())) TvType.OVA
 | 
			
		||||
            else TvType.Anime
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val malId = doc.select("a.blue.cta:contains(المزيد من المعلومات)").attr("href").replace(".*e\\/|\\/.*".toRegex(),"").toInt()
 | 
			
		||||
        val episodes = arrayListOf<Episode>()
 | 
			
		||||
        val episodeElements = doc.select(".episode-link")
 | 
			
		||||
        if(episodeElements.isEmpty()) {
 | 
			
		||||
            episodes.add(Episode(
 | 
			
		||||
                url,
 | 
			
		||||
                "Watch",
 | 
			
		||||
            ))
 | 
			
		||||
        } else {
 | 
			
		||||
            episodeElements.map {
 | 
			
		||||
                val a = it.select("a")
 | 
			
		||||
                episodes.add(Episode(
 | 
			
		||||
                    mainUrl + a.attr("href"),
 | 
			
		||||
                    a.text().replace(":"," "),
 | 
			
		||||
                    episode = a.select("span").not(".pull-left").last()?.text()?.toIntOrNull()
 | 
			
		||||
                ))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return newAnimeLoadResponse(title, url, type) {
 | 
			
		||||
            addMalId(malId)
 | 
			
		||||
            japName = nativeName
 | 
			
		||||
            engName = title
 | 
			
		||||
            posterUrl = poster
 | 
			
		||||
            this.year = year
 | 
			
		||||
            addEpisodes(DubStatus.Subbed, episodes) // TODO CHECK
 | 
			
		||||
            plot = description
 | 
			
		||||
            tags = genre
 | 
			
		||||
 | 
			
		||||
            showStatus = status
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        val doc = app.get(data).document
 | 
			
		||||
        doc.select(".panel .panel-body a").forEach {
 | 
			
		||||
            callback.invoke(
 | 
			
		||||
                ExtractorLink(
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    it.attr("title") + " " + it.select("small").text(),
 | 
			
		||||
                    it.attr("href"),
 | 
			
		||||
                    this.mainUrl,
 | 
			
		||||
                    it.text().replace("p.*| ".toRegex(),"").toInt(),
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								CimaNowProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								CimaNowProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "TvSeries" , "Movie" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=cimanow.cc&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								CimaNowProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								CimaNowProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.cimanow"/>
 | 
			
		||||
							
								
								
									
										11
									
								
								CimaNowProvider/src/main/kotlin/com/cimanow/CimaNowPlugin.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								CimaNowProvider/src/main/kotlin/com/cimanow/CimaNowPlugin.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.cimanow
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class CimaNowPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(CimaNow())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										164
									
								
								CimaNowProvider/src/main/kotlin/com/cimanow/CimaNowProvider.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								CimaNowProvider/src/main/kotlin/com/cimanow/CimaNowProvider.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,164 @@
 | 
			
		|||
package com.cimanow
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class CimaNow : MainAPI() {
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://cimanow.cc"
 | 
			
		||||
    override var name = "CimaNow"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)
 | 
			
		||||
 | 
			
		||||
    private fun String.getIntFromText(): Int? {
 | 
			
		||||
        return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun Element.toSearchResponse(): SearchResponse? {
 | 
			
		||||
        val url = this.attr("href")
 | 
			
		||||
        val posterUrl = select("img")?.attr("data-src")
 | 
			
		||||
        var title = select("li[aria-label=\"title\"]").html().replace(" <em>.*|\\\\n".toRegex(), "").replace(" ", "")
 | 
			
		||||
        val year = select("li[aria-label=\"year\"]").text().toIntOrNull()
 | 
			
		||||
        val tvType = if (url.contains("فيلم|مسرحية|حفلات".toRegex())) TvType.Movie else TvType.TvSeries
 | 
			
		||||
        val quality = select("li[aria-label=\"ribbon\"]").first()?.text()?.replace(" |-|1080|720".toRegex(), "")
 | 
			
		||||
        val dubEl = select("li[aria-label=\"ribbon\"]:nth-child(2)").isNotEmpty()
 | 
			
		||||
        val dubStatus = if(dubEl) select("li[aria-label=\"ribbon\"]:nth-child(2)").text().contains("مدبلج")
 | 
			
		||||
        else select("li[aria-label=\"ribbon\"]:nth-child(1)").text().contains("مدبلج")
 | 
			
		||||
        if(dubStatus) title = "$title (مدبلج)"
 | 
			
		||||
        return MovieSearchResponse(
 | 
			
		||||
            "$title ${select("li[aria-label=\"ribbon\"]:contains(الموسم)").text()}",
 | 
			
		||||
            url,
 | 
			
		||||
            this@CimaNow.name,
 | 
			
		||||
            tvType,
 | 
			
		||||
            posterUrl,
 | 
			
		||||
            year,
 | 
			
		||||
            null,
 | 
			
		||||
            quality = getQualityFromString(quality)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
 | 
			
		||||
 | 
			
		||||
        val doc = app.get("$mainUrl/home", headers = mapOf("user-agent" to "MONKE")).document
 | 
			
		||||
        val pages = doc.select("section").not("section:contains(أختر وجهتك المفضلة)").not("section:contains(تم اضافته حديثاً)").apmap {
 | 
			
		||||
            val name = it.select("span").html().replace("<em>.*| <i c.*".toRegex(), "")
 | 
			
		||||
            val list = it.select("a").mapNotNull {
 | 
			
		||||
                if(it.attr("href").contains("$mainUrl/category/|$mainUrl/الاكثر-مشاهدة/".toRegex())) return@mapNotNull null
 | 
			
		||||
                it.toSearchResponse()
 | 
			
		||||
            }
 | 
			
		||||
            HomePageList(name, list)
 | 
			
		||||
        }
 | 
			
		||||
        return HomePageResponse(pages)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val result = arrayListOf<SearchResponse>()
 | 
			
		||||
        val doc = app.get("$mainUrl/page/1/?s=$query").document
 | 
			
		||||
        val paginationElement = doc.select("ul[aria-label=\"pagination\"]")
 | 
			
		||||
        doc.select("section article a").map {
 | 
			
		||||
            val postUrl = it.attr("href")
 | 
			
		||||
            if(it.select("li[aria-label=\"episode\"]").isNotEmpty()) return@map
 | 
			
		||||
            if(postUrl.contains("$mainUrl/expired-download/|$mainUrl/افلام-اون-لاين/".toRegex())) return@map
 | 
			
		||||
            result.add(it.toSearchResponse()!!)
 | 
			
		||||
        }
 | 
			
		||||
        if(paginationElement.isNotEmpty()) {
 | 
			
		||||
            val max = paginationElement.select("li").not("li.active").last()?.text()?.toIntOrNull()
 | 
			
		||||
            if (max != null) {
 | 
			
		||||
                if(max > 5) return result.distinct().sortedBy { it.name }
 | 
			
		||||
                (2..max!!).toList().apmap {
 | 
			
		||||
                    app.get("$mainUrl/page/$it/?s=$query\"").document.select("section article a").map { element ->
 | 
			
		||||
                        val postUrl = element.attr("href")
 | 
			
		||||
                        if(element.select("li[aria-label=\"episode\"]").isNotEmpty()) return@map
 | 
			
		||||
                        if(postUrl.contains("$mainUrl/expired-download/|$mainUrl/افلام-اون-لاين/".toRegex())) return@map
 | 
			
		||||
                        result.add(element.toSearchResponse()!!)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result.distinct().sortedBy { it.name }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
        val posterUrl = doc.select("body > script:nth-child(3)").html().replace(".*,\"image\":\"|\".*".toRegex(),"").ifEmpty { doc.select("meta[property=\"og:image\"]").attr("content") }
 | 
			
		||||
        val year = doc.select("article ul:nth-child(1) li a").last()?.text()?.toIntOrNull()
 | 
			
		||||
        val title = doc.select("title").text().split(" | ")[0]
 | 
			
		||||
        val isMovie = title.contains("فيلم|حفلات|مسرحية".toRegex())
 | 
			
		||||
        val youtubeTrailer = doc.select("iframe")?.attr("src")
 | 
			
		||||
 | 
			
		||||
        val synopsis = doc.select("ul#details li:contains(لمحة) p").text()
 | 
			
		||||
 | 
			
		||||
        val tags = doc.select("article ul").first()?.select("li")?.map { it.text() }
 | 
			
		||||
 | 
			
		||||
        val recommendations = doc.select("ul#related li").map { element ->
 | 
			
		||||
            MovieSearchResponse(
 | 
			
		||||
                apiName = this@CimaNow.name,
 | 
			
		||||
                url = element.select("a").attr("href"),
 | 
			
		||||
                name = element.select("img:nth-child(2)").attr("alt"),
 | 
			
		||||
                posterUrl = element.select("img:nth-child(2)").attr("src")
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return if (isMovie) {
 | 
			
		||||
            newMovieLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.Movie,
 | 
			
		||||
                "$url/watching"
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                addTrailer(youtubeTrailer)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            val episodes = doc.select("ul#eps li").map { episode ->
 | 
			
		||||
                Episode(
 | 
			
		||||
                    episode.select("a").attr("href")+"/watching",
 | 
			
		||||
                    episode.select("a img:nth-child(2)").attr("alt"),
 | 
			
		||||
                    doc.select("span[aria-label=\"season-title\"]").html().replace("<p>.*|\n".toRegex(), "").getIntFromText(),
 | 
			
		||||
                    episode.select("a em").text().toIntOrNull(),
 | 
			
		||||
                    episode.select("a img:nth-child(2)").attr("src")
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                addTrailer(youtubeTrailer)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        app.get("$data").document.select("ul#download [aria-label=\"quality\"]").forEach {
 | 
			
		||||
            val name = if(it.select("span").text().contains("فائق السرعة")) "Fast Servers" else "Servers"
 | 
			
		||||
            it.select("a").forEach { media ->
 | 
			
		||||
                callback.invoke(
 | 
			
		||||
                    ExtractorLink(
 | 
			
		||||
                        source = this.name,
 | 
			
		||||
                        name = name,
 | 
			
		||||
                        url = media.attr("href"),
 | 
			
		||||
                        referer = this.mainUrl,
 | 
			
		||||
                        quality = media.text().getIntFromText() ?: Qualities.Unknown.value
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								EgyBestProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								EgyBestProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "TvSeries" , "Movie" , "Anime" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=www.egy.best&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								EgyBestProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								EgyBestProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.egybest"/>
 | 
			
		||||
							
								
								
									
										11
									
								
								EgyBestProvider/src/main/kotlin/com/egybest/EgyBestPlugin.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								EgyBestProvider/src/main/kotlin/com/egybest/EgyBestPlugin.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.egybest
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class EgyBestPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(EgyBest())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										262
									
								
								EgyBestProvider/src/main/kotlin/com/egybest/EgyBestProvider.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								EgyBestProvider/src/main/kotlin/com/egybest/EgyBestProvider.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,262 @@
 | 
			
		|||
package com.egybest
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
import com.lagradost.nicehttp.Requests
 | 
			
		||||
 | 
			
		||||
class EgyBest : MainAPI() {
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://www.egy.best"
 | 
			
		||||
    override var name = "EgyBest"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime)
 | 
			
		||||
 | 
			
		||||
    private fun String.getIntFromText(): Int? {
 | 
			
		||||
        return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun Element.toSearchResponse(): SearchResponse? {
 | 
			
		||||
        val url = this.attr("href") ?: return null
 | 
			
		||||
        val posterUrl = select("img")?.attr("src")
 | 
			
		||||
        var title = select("span.title").text()
 | 
			
		||||
        val year = title.getYearFromTitle()
 | 
			
		||||
        val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
 | 
			
		||||
        val tvType = if (isMovie) TvType.Movie else TvType.TvSeries
 | 
			
		||||
        title = if (year !== null) title else title.split(" (")[0].trim()
 | 
			
		||||
        val quality = select("span.ribbon span").text().replace("-", "")
 | 
			
		||||
        // If you need to differentiate use the url.
 | 
			
		||||
        return MovieSearchResponse(
 | 
			
		||||
            title,
 | 
			
		||||
            url,
 | 
			
		||||
            this@EgyBest.name,
 | 
			
		||||
            tvType,
 | 
			
		||||
            posterUrl,
 | 
			
		||||
            year,
 | 
			
		||||
            null,
 | 
			
		||||
            quality = getQualityFromString(quality)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
 | 
			
		||||
        // url, title
 | 
			
		||||
        val doc = app.get(mainUrl).document
 | 
			
		||||
        val pages = arrayListOf<HomePageList>()
 | 
			
		||||
        doc.select("#mainLoad div.mbox").apmap {
 | 
			
		||||
            val name = it.select(".bdb.pda > strong").text()
 | 
			
		||||
            if (it.select(".movie").first()?.attr("href")?.contains("season-(.....)|ep-(.....)".toRegex()) == true) return@apmap
 | 
			
		||||
            val list = arrayListOf<SearchResponse>()
 | 
			
		||||
            it.select(".movie").map { element ->
 | 
			
		||||
                list.add(element.toSearchResponse()!!)
 | 
			
		||||
            }
 | 
			
		||||
            pages.add(HomePageList(name, list))
 | 
			
		||||
        }
 | 
			
		||||
        return HomePageResponse(pages)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val q = query.replace(" ","%20")
 | 
			
		||||
        val result = arrayListOf<SearchResponse>()
 | 
			
		||||
        listOf("$mainUrl/explore/?q=$q").apmap { url ->
 | 
			
		||||
            val d = app.get(url).document
 | 
			
		||||
            d.select("div.movies a").not("a.auto.load.btn.b").mapNotNull {
 | 
			
		||||
                it.toSearchResponse()?.let { it1 -> result.add(it1) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result.distinct().sortedBy { it.name }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun String.getYearFromTitle(): Int? {
 | 
			
		||||
        return Regex("""\(\d{4}\)""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
        val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
 | 
			
		||||
        val posterUrl = doc.select("div.movie_img a img")?.attr("src")
 | 
			
		||||
        val year = doc.select("div.movie_title h1 a")?.text()?.toIntOrNull()
 | 
			
		||||
        val title = doc.select("div.movie_title h1 span").text()
 | 
			
		||||
        val youtubeTrailer = doc.select("div.play")?.attr("url")
 | 
			
		||||
 | 
			
		||||
        val synopsis = doc.select("div.mbox").firstOrNull {
 | 
			
		||||
            it.text().contains("القصة")
 | 
			
		||||
        }?.text()?.replace("القصة ", "")
 | 
			
		||||
 | 
			
		||||
        val tags = doc.select("table.movieTable tbody tr").firstOrNull {
 | 
			
		||||
            it.text().contains("النوع")
 | 
			
		||||
        }?.select("a")?.map { it.text() }
 | 
			
		||||
 | 
			
		||||
        val actors = doc.select("div.cast_list .cast_item").mapNotNull {
 | 
			
		||||
            val name = it.selectFirst("div > a > img")?.attr("alt") ?: return@mapNotNull null
 | 
			
		||||
            val image = it.selectFirst("div > a > img")?.attr("src") ?: return@mapNotNull null
 | 
			
		||||
            val roleString = it.selectFirst("div > span")!!.text()
 | 
			
		||||
            val mainActor = Actor(name, image)
 | 
			
		||||
            ActorData(actor = mainActor, roleString = roleString)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return if (isMovie) {
 | 
			
		||||
            val recommendations = doc.select(".movies_small .movie").mapNotNull { element ->
 | 
			
		||||
                element.toSearchResponse()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            newMovieLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.Movie,
 | 
			
		||||
                url
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.actors = actors
 | 
			
		||||
                addTrailer(youtubeTrailer)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            val episodes = ArrayList<Episode>()
 | 
			
		||||
            doc.select("#mainLoad > div:nth-child(2) > div.h_scroll > div a").map {
 | 
			
		||||
                it.attr("href")
 | 
			
		||||
            }.apmap {
 | 
			
		||||
                val d = app.get(it).document
 | 
			
		||||
                val season = Regex("season-(.....)").find(it)?.groupValues?.getOrNull(1)?.getIntFromText()
 | 
			
		||||
                if(d.select("tr.published").isNotEmpty()) {
 | 
			
		||||
                    d.select("tr.published").map { element ->
 | 
			
		||||
                        val ep = Regex("ep-(.....)").find(element.select(".ep_title a").attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
 | 
			
		||||
                        episodes.add(
 | 
			
		||||
                            Episode(
 | 
			
		||||
                                element.select(".ep_title a").attr("href"),
 | 
			
		||||
                                name = element.select("td.ep_title").html().replace(".*</span>|</a>".toRegex(), ""),
 | 
			
		||||
                                season,
 | 
			
		||||
                                ep,
 | 
			
		||||
                                rating = element.select("td.tam:not(.date, .ep_len)").text().getIntFromText()
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    d.select("#mainLoad > div:nth-child(3) > div.movies_small a").map { eit ->
 | 
			
		||||
                        val ep = Regex("ep-(.....)").find(eit.attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
 | 
			
		||||
                        episodes.add(
 | 
			
		||||
                            Episode(
 | 
			
		||||
                                eit.attr("href"),
 | 
			
		||||
                                eit.select("span.title").text(),
 | 
			
		||||
                                season,
 | 
			
		||||
                                ep,
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.actors = actors
 | 
			
		||||
                addTrailer(youtubeTrailer)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    data class Sources (
 | 
			
		||||
        @JsonProperty("quality") val quality: Int?,
 | 
			
		||||
        @JsonProperty("link") val link: String
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    private fun String.ExtractLinks(): Boolean? {
 | 
			
		||||
        val list = Regex("#EXT.*\\n.*").findAll(this).toList()
 | 
			
		||||
        println(list)
 | 
			
		||||
        list.map {
 | 
			
		||||
            val url = Regex(".*stream\\.m3u8").find(it.value)?.value.toString()
 | 
			
		||||
            val quality = Regex("[0-9]{3,4}x[0-9]{3,4}").find(it.value)?.value?.replace(".*x".toRegex(),"")?.toInt()
 | 
			
		||||
                ExtractorLink(
 | 
			
		||||
                    this@EgyBest.name,
 | 
			
		||||
                    this@EgyBest.name,
 | 
			
		||||
                    url,
 | 
			
		||||
                    this@EgyBest.mainUrl,
 | 
			
		||||
                    quality ?: Qualities.Unknown.value,
 | 
			
		||||
                    true
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        /*val baseURL = data.split("/")[0] + "//" + data.split("/")[2]
 | 
			
		||||
 | 
			
		||||
        val session = Requests()
 | 
			
		||||
        val episodeSoup = session.get(data).document
 | 
			
		||||
 | 
			
		||||
        val vidstreamURL = fixUrlNull(episodeSoup.selectFirst("iframe.auto-size")?.attr("src") ) ?: throw ErrorLoadingException("No iframe")
 | 
			
		||||
 | 
			
		||||
        val videoSoup = app.get(vidstreamURL).document
 | 
			
		||||
        fixUrlNull( videoSoup.select("source").firstOrNull { it.hasAttr("src") }?.attr("src"))?.let {
 | 
			
		||||
            app.get(it).text.replace("#EXTM3U\n","").ExtractLinks()
 | 
			
		||||
        } ?: run {
 | 
			
		||||
            var jsCode = videoSoup.select("script")[1].data()
 | 
			
		||||
            println(jsCode)
 | 
			
		||||
            val verificationToken = Regex("\\{'[0-9a-zA-Z_]*':'ok'\\}").findAll(jsCode).first().value.replace("\\{'|':.*".toRegex(), "")
 | 
			
		||||
            val encodedAdLinkVar = Regex("\\([0-9a-zA-Z_]{2,12}\\[Math").findAll(jsCode).first().value.replace("\\(|\\[M.*".toRegex(),"")
 | 
			
		||||
            val encodingArraysRegEx = Regex(",[0-9a-zA-Z_]{2,12}=\\[\\]").findAll(jsCode).toList()
 | 
			
		||||
 | 
			
		||||
            val firstEncodingArray = encodingArraysRegEx[1].value.replace(",|=.*".toRegex(),"")
 | 
			
		||||
            val secondEncodingArray = encodingArraysRegEx[2].value.replace(",|=.*".toRegex(),"")
 | 
			
		||||
 | 
			
		||||
            jsCode = jsCode.replace("^<script type=\"text/javascript\">".toRegex(),"")
 | 
			
		||||
            jsCode = jsCode.replace("[;,]\\\$\\('\\*'\\)(.*)\$".toRegex(),";")
 | 
			
		||||
            jsCode = jsCode.replace(",ismob=(.*)\\(navigator\\[(.*)\\]\\)[,;]".toRegex(),";")
 | 
			
		||||
            jsCode = jsCode.replace("var a0b=function\\(\\)(.*)a0a\\(\\);".toRegex(),"")
 | 
			
		||||
            jsCode += "var link = ''; for (var i = 0; i <= $secondEncodingArray['length']; i++) { link += $firstEncodingArray[$secondEncodingArray[i]] || ''; } return [link, $encodedAdLinkVar[0]] }"
 | 
			
		||||
 | 
			
		||||
            // till here everything should be fine
 | 
			
		||||
            val jsCodeReturn = js(jsCode)()
 | 
			
		||||
            val verificationPath = jsCodeReturn[0]
 | 
			
		||||
            val encodedAdPath = jsCodeReturn[1]
 | 
			
		||||
 | 
			
		||||
            val adLink = baseURL + "/" + str(decode(encodedAdPath + "=" * (-len(encodedAdPath) % 4)), "utf-8")
 | 
			
		||||
            val session.get(adLink)
 | 
			
		||||
 | 
			
		||||
            val verificationLink = baseURL + "/tvc.php?verify=" + verificationPath
 | 
			
		||||
            val session.post(verificationLink, data={verificationToken: "ok"})
 | 
			
		||||
 | 
			
		||||
            val vidstreamResponseText = session.get(vidstreamURL).text
 | 
			
		||||
            val videoSoup = BeautifulSoup(vidstreamResponseText, features="html.parser")
 | 
			
		||||
 | 
			
		||||
            val qualityLinksFileURL = baseURL + videoSoup.body.find("source").get("src")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return true*/
 | 
			
		||||
 | 
			
		||||
        val requestJSON = app.get("https://api.zr5.repl.co/egybest?url=$data").text
 | 
			
		||||
        // To solve this you need to send a verify request which is pretty hidden, see
 | 
			
		||||
        // https://vear.egybest.deals/tvc.php?verify=.......
 | 
			
		||||
        val jsonArray = parseJson<List<Sources>>(requestJSON)
 | 
			
		||||
        for (i in jsonArray) {
 | 
			
		||||
            val quality = i.quality
 | 
			
		||||
            val link = i.link
 | 
			
		||||
            callback.invoke(
 | 
			
		||||
                ExtractorLink(
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    link,
 | 
			
		||||
                    this.mainUrl,
 | 
			
		||||
                    quality!!,
 | 
			
		||||
                    true,
 | 
			
		||||
                    // Does not work without these headers!
 | 
			
		||||
                    headers = mapOf("range" to "bytes=0-"),
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								Extractors/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Extractors/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "Others" )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								Extractors/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								Extractors/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.extractors"/>
 | 
			
		||||
							
								
								
									
										62
									
								
								Extractors/src/main/kotlin/com/extractors/DoodExtractor.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								Extractors/src/main/kotlin/com/extractors/DoodExtractor.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
package com.stable
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorApi
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.getQualityFromName
 | 
			
		||||
 | 
			
		||||
class DoodCxExtractor : DoodLaExtractor() {
 | 
			
		||||
    override var mainUrl = "https://dood.cx"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DoodShExtractor : DoodLaExtractor() {
 | 
			
		||||
    override var mainUrl = "https://dood.sh"
 | 
			
		||||
}
 | 
			
		||||
class DoodWatchExtractor : DoodLaExtractor() {
 | 
			
		||||
    override var mainUrl = "https://dood.watch"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DoodPmExtractor : DoodLaExtractor() {
 | 
			
		||||
    override var mainUrl = "https://dood.pm"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DoodToExtractor : DoodLaExtractor() {
 | 
			
		||||
    override var mainUrl = "https://dood.to"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DoodSoExtractor : DoodLaExtractor() {
 | 
			
		||||
    override var mainUrl = "https://dood.so"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DoodWsExtractor : DoodLaExtractor() {
 | 
			
		||||
    override var mainUrl = "https://dood.ws"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
open class DoodLaExtractor : ExtractorApi() {
 | 
			
		||||
    override var name = "DoodStream"
 | 
			
		||||
    override var mainUrl = "https://dood.la"
 | 
			
		||||
    override val requiresReferer = false
 | 
			
		||||
 | 
			
		||||
    override fun getExtractorUrl(id: String): String {
 | 
			
		||||
        return "$mainUrl/d/$id"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
 | 
			
		||||
        val response0 = app.get(url).text // html of DoodStream page to look for /pass_md5/...
 | 
			
		||||
        val md5 =mainUrl+(Regex("/pass_md5/[^']*").find(response0)?.value ?: return null)  // get https://dood.ws/pass_md5/...
 | 
			
		||||
        val trueUrl = app.get(md5, referer = url).text + "zUEJeL3mUN?token=" + md5.substringAfterLast("/")   //direct link to extract  (zUEJeL3mUN is random)
 | 
			
		||||
        val quality = Regex("\\d{3,4}p").find(response0.substringAfter("<title>").substringBefore("</title>"))?.groupValues?.get(0)
 | 
			
		||||
        return listOf(
 | 
			
		||||
            ExtractorLink(
 | 
			
		||||
                trueUrl,
 | 
			
		||||
                this.name,
 | 
			
		||||
                trueUrl,
 | 
			
		||||
                mainUrl,
 | 
			
		||||
                getQualityFromName(quality),
 | 
			
		||||
                false
 | 
			
		||||
            )
 | 
			
		||||
        ) // links are valid in 8h
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								Extractors/src/main/kotlin/com/extractors/ExtractorPlugin.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Extractors/src/main/kotlin/com/extractors/ExtractorPlugin.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
package com.extractors
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class ExtractorPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerExtractorAPI(DoodLaExtractor())
 | 
			
		||||
        registerExtractorAPI(DoodCxExtractor())
 | 
			
		||||
        registerExtractorAPI(DoodShExtractor())
 | 
			
		||||
        registerExtractorAPI(DoodWatchExtractor())
 | 
			
		||||
        registerExtractorAPI(DoodPmExtractor())
 | 
			
		||||
        registerExtractorAPI(DoodToExtractor())
 | 
			
		||||
        registerExtractorAPI(DoodSoExtractor())
 | 
			
		||||
        registerExtractorAPI(DoodWsExtractor())
 | 
			
		||||
        registerExtractorAPI(Uqload())
 | 
			
		||||
        registerExtractorAPI(Uqload1())
 | 
			
		||||
        registerExtractorAPI(StreamTape())
 | 
			
		||||
        registerExtractorAPI(VoeExtractor())
 | 
			
		||||
        registerExtractorAPI(JWPlayer())
 | 
			
		||||
        registerExtractorAPI(VidBom())
 | 
			
		||||
        registerExtractorAPI(UpstreamExtractor())
 | 
			
		||||
        registerExtractorAPI(Streamlare())
 | 
			
		||||
        registerExtractorAPI(Slmaxed())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
package com.stable
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorApi
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
import com.lagradost.cloudstream3.utils.getQualityFromName
 | 
			
		||||
 | 
			
		||||
class VidBom : JWPlayer() {
 | 
			
		||||
    override val name = "Vidbom"
 | 
			
		||||
    override val mainUrl = "https://vidbam.org"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
open class JWPlayer : ExtractorApi() {
 | 
			
		||||
    override val name = "JWPlayer"
 | 
			
		||||
    override val mainUrl = "https://www.jwplayer.com"
 | 
			
		||||
    override val requiresReferer = false
 | 
			
		||||
 | 
			
		||||
    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
 | 
			
		||||
        val sources = mutableListOf<ExtractorLink>()
 | 
			
		||||
        with(app.get(url).document) {
 | 
			
		||||
            val data = this.select("script").mapNotNull { script ->
 | 
			
		||||
                if (script.data().contains("sources: [")) {
 | 
			
		||||
                    script.data().substringAfter("sources: [")
 | 
			
		||||
                        .substringBefore("],").replace("'", "\"")
 | 
			
		||||
                } else if (script.data().contains("otakudesu('")) {
 | 
			
		||||
                    script.data().substringAfter("otakudesu('")
 | 
			
		||||
                        .substringBefore("');")
 | 
			
		||||
                } else {
 | 
			
		||||
                    null
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            tryParseJson<List<ResponseSource>>("$data")?.map {
 | 
			
		||||
                sources.add(
 | 
			
		||||
                    ExtractorLink(
 | 
			
		||||
                        name,
 | 
			
		||||
                        name,
 | 
			
		||||
                        it.file,
 | 
			
		||||
                        referer = url,
 | 
			
		||||
                        quality = getQualityFromName(
 | 
			
		||||
                            Regex("(\\d{3,4}p)").find(it.file)?.groupValues?.get(
 | 
			
		||||
                                1
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return sources
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private data class ResponseSource(
 | 
			
		||||
        @JsonProperty("file") val file: String,
 | 
			
		||||
        @JsonProperty("type") val type: String?,
 | 
			
		||||
        @JsonProperty("label") val label: String?
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
package com.stable
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorApi
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
 | 
			
		||||
class StreamTape : ExtractorApi() {
 | 
			
		||||
    override var name = "StreamTape"
 | 
			
		||||
    override var mainUrl = "https://streamtape.com"
 | 
			
		||||
    override val requiresReferer = false
 | 
			
		||||
 | 
			
		||||
    private val linkRegex =
 | 
			
		||||
        Regex("""'robotlink'\)\.innerHTML = '(.+?)'\+ \('(.+?)'\)""")
 | 
			
		||||
 | 
			
		||||
    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
 | 
			
		||||
        with(app.get(url)) {
 | 
			
		||||
            linkRegex.find(this.text)?.let {
 | 
			
		||||
                val extractedUrl = "https:${it.groups[1]!!.value + it.groups[2]!!.value.substring(3,)}"
 | 
			
		||||
                return listOf(
 | 
			
		||||
                    ExtractorLink(
 | 
			
		||||
                        name,
 | 
			
		||||
                        name,
 | 
			
		||||
                        extractedUrl,
 | 
			
		||||
                        url,
 | 
			
		||||
                        Qualities.Unknown.value,
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
package com.stable
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorApi
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
import com.lagradost.nicehttp.RequestBodyTypes
 | 
			
		||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
 | 
			
		||||
import okhttp3.RequestBody.Companion.toRequestBody
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Streamlare : Slmaxed() {
 | 
			
		||||
    override val mainUrl = "https://streamlare.com/"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
open class Slmaxed : ExtractorApi() {
 | 
			
		||||
    override val name = "Streamlare"
 | 
			
		||||
    override val mainUrl = "https://slmaxed.com/"
 | 
			
		||||
    override val requiresReferer = true
 | 
			
		||||
 | 
			
		||||
    // https://slmaxed.com/e/oLvgezw3LjPzbp8E -> oLvgezw3LjPzbp8E
 | 
			
		||||
    val embedRegex = Regex("""/e/([^/]*)""")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    data class JsonResponse(
 | 
			
		||||
        @JsonProperty val status: String? = null,
 | 
			
		||||
        @JsonProperty val message: String? = null,
 | 
			
		||||
        @JsonProperty val type: String? = null,
 | 
			
		||||
        @JsonProperty val token: String? = null,
 | 
			
		||||
        @JsonProperty val result: Map<String, Result>? = null
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    data class Result(
 | 
			
		||||
        @JsonProperty val label: String? = null,
 | 
			
		||||
        @JsonProperty val file: String? = null,
 | 
			
		||||
        @JsonProperty val type: String? = null
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
 | 
			
		||||
        val id = embedRegex.find(url)!!.groupValues[1]
 | 
			
		||||
        val json = app.post(
 | 
			
		||||
            "${mainUrl}api/video/stream/get",
 | 
			
		||||
            requestBody = """{"id":"$id"}""".toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull())
 | 
			
		||||
        ).parsed<JsonResponse>()
 | 
			
		||||
        return json.result?.mapNotNull {
 | 
			
		||||
            it.value.let { result ->
 | 
			
		||||
                ExtractorLink(
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    result.file ?: return@mapNotNull null,
 | 
			
		||||
                    url,
 | 
			
		||||
                    result.label?.replace("p", "", ignoreCase = true)?.trim()?.toIntOrNull()
 | 
			
		||||
                        ?: Qualities.Unknown.value,
 | 
			
		||||
                    isM3u8 = result.type?.contains("hls", ignoreCase = true) == true
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
package com.stable
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorApi
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
 | 
			
		||||
class UpstreamExtractor: ExtractorApi() {
 | 
			
		||||
    override val name: String = "Upstream.to"
 | 
			
		||||
    override val mainUrl: String = "https://upstream.to"
 | 
			
		||||
    override val requiresReferer = true
 | 
			
		||||
 | 
			
		||||
    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
 | 
			
		||||
        // WIP: m3u8 link fetched but sometimes not playing
 | 
			
		||||
        //Log.i(this.name, "Result => (no extractor) ${url}")
 | 
			
		||||
        val sources: MutableList<ExtractorLink> = mutableListOf()
 | 
			
		||||
        val doc = app.get(url, referer = referer).text
 | 
			
		||||
        if (doc.isNotBlank()) {
 | 
			
		||||
            var reg = Regex("(?<=master)(.*)(?=hls)")
 | 
			
		||||
            val result = reg.find(doc)?.groupValues?.map {
 | 
			
		||||
                it.trim('|')
 | 
			
		||||
            }?.toList()
 | 
			
		||||
            reg = Regex("(?<=\\|file\\|)(.*)(?=\\|remove\\|)")
 | 
			
		||||
            val domainList = reg.find(doc)?.groupValues?.get(1)?.split("|")
 | 
			
		||||
            var domain = when (!domainList.isNullOrEmpty()) {
 | 
			
		||||
                true -> {
 | 
			
		||||
                    if (domainList.isNotEmpty()) {
 | 
			
		||||
                        var domName = ""
 | 
			
		||||
                        for (part in domainList) {
 | 
			
		||||
                            domName = "${part}.${domName}"
 | 
			
		||||
                        }
 | 
			
		||||
                        domName.trimEnd('.')
 | 
			
		||||
                    } else { "" }
 | 
			
		||||
                }
 | 
			
		||||
                false -> ""
 | 
			
		||||
            }
 | 
			
		||||
            //Log.i(this.name, "Result => (domain) ${domain}")
 | 
			
		||||
            if (domain.isEmpty()) {
 | 
			
		||||
                domain = "s96.upstreamcdn.co"
 | 
			
		||||
                //Log.i(this.name, "Result => (default domain) ${domain}")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            result?.forEach {
 | 
			
		||||
                val linkUrl = "https://${domain}/hls/${it}/master.m3u8"
 | 
			
		||||
                sources.add(
 | 
			
		||||
                    ExtractorLink(
 | 
			
		||||
                    name = "Upstream m3u8",
 | 
			
		||||
                    source = this.name,
 | 
			
		||||
                    url = linkUrl,
 | 
			
		||||
                    quality = Qualities.Unknown.value,
 | 
			
		||||
                    referer = referer ?: linkUrl,
 | 
			
		||||
                    isM3u8 = true
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return sources
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								Extractors/src/main/kotlin/com/extractors/UqloadExtractor.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Extractors/src/main/kotlin/com/extractors/UqloadExtractor.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
package com.stable
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.utils.*
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
 | 
			
		||||
class Uqload1 : Uqload() {
 | 
			
		||||
    override var mainUrl = "https://uqload.com"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
open class Uqload : ExtractorApi() {
 | 
			
		||||
    override val name: String = "Uqload"
 | 
			
		||||
    override val mainUrl: String = "https://www.uqload.com"
 | 
			
		||||
    private val srcRegex = Regex("""sources:.\[(.*?)\]""")  // would be possible to use the parse and find src attribute
 | 
			
		||||
    override val requiresReferer = true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
 | 
			
		||||
        val lang = url.substring(0, 2)
 | 
			
		||||
        val flag =
 | 
			
		||||
            if (lang == "vo") {
 | 
			
		||||
                " \uD83C\uDDEC\uD83C\uDDE7"
 | 
			
		||||
            }
 | 
			
		||||
            else if (lang == "vf"){
 | 
			
		||||
                " \uD83C\uDDE8\uD83C\uDDF5"
 | 
			
		||||
            } else {
 | 
			
		||||
                ""
 | 
			
		||||
            }
 | 
			
		||||
        
 | 
			
		||||
        val cleaned_url = if (lang == "ht") {  // if url doesn't contain a flag and the url starts with http://
 | 
			
		||||
            url
 | 
			
		||||
        } else {
 | 
			
		||||
            url.substring(2, url.length)
 | 
			
		||||
        }
 | 
			
		||||
        with(app.get(cleaned_url)) {  // raised error ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED (3003) is due to the response: "error_nofile"
 | 
			
		||||
            srcRegex.find(this.text)?.groupValues?.get(1)?.replace("\"", "")?.let { link ->
 | 
			
		||||
                return listOf(
 | 
			
		||||
                    ExtractorLink(
 | 
			
		||||
                        name,
 | 
			
		||||
                        name + flag,
 | 
			
		||||
                        link,
 | 
			
		||||
                        cleaned_url,
 | 
			
		||||
                        Qualities.Unknown.value,
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								Extractors/src/main/kotlin/com/extractors/VoeExtractor.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								Extractors/src/main/kotlin/com/extractors/VoeExtractor.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
package com.stable
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorApi
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.getQualityFromName
 | 
			
		||||
 | 
			
		||||
open class VoeExtractor : ExtractorApi() {
 | 
			
		||||
    override val name: String = "Voe"
 | 
			
		||||
    override val mainUrl: String = "https://voe.sx"
 | 
			
		||||
    override val requiresReferer = false
 | 
			
		||||
 | 
			
		||||
    private data class ResponseLinks(
 | 
			
		||||
        @JsonProperty("hls") val url: String?,
 | 
			
		||||
        @JsonProperty("video_height") val label: Int?
 | 
			
		||||
        //val type: String // Mp4
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
 | 
			
		||||
        val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
 | 
			
		||||
        val doc = app.get(url).text
 | 
			
		||||
        if (doc.isNotBlank()) {
 | 
			
		||||
            val start = "const sources ="
 | 
			
		||||
            var src = doc.substring(doc.indexOf(start))
 | 
			
		||||
            src = src.substring(start.length, src.indexOf(";"))
 | 
			
		||||
                .replace("0,", "0")
 | 
			
		||||
                .trim()
 | 
			
		||||
            //Log.i(this.name, "Result => (src) ${src}")
 | 
			
		||||
            parseJson<ResponseLinks?>(src)?.let { voelink ->
 | 
			
		||||
                //Log.i(this.name, "Result => (voelink) ${voelink}")
 | 
			
		||||
                val linkUrl = voelink.url
 | 
			
		||||
                val linkLabel = voelink.label?.toString() ?: ""
 | 
			
		||||
                if (!linkUrl.isNullOrEmpty()) {
 | 
			
		||||
                    extractedLinksList.add(
 | 
			
		||||
                        ExtractorLink(
 | 
			
		||||
                            name = this.name,
 | 
			
		||||
                            source = this.name,
 | 
			
		||||
                            url = linkUrl,
 | 
			
		||||
                            quality = getQualityFromName(linkLabel),
 | 
			
		||||
                            referer = url,
 | 
			
		||||
                            isM3u8 = true
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return extractedLinksList
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								FaselHDProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								FaselHDProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "TvSeries" , "Movie" , "Anime" , "AsianDrama" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=faselhd.io&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								FaselHDProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								FaselHDProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.faselhd"/>
 | 
			
		||||
							
								
								
									
										11
									
								
								FaselHDProvider/src/main/kotlin/com/faselhd/FaselHDPlugin.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								FaselHDProvider/src/main/kotlin/com/faselhd/FaselHDPlugin.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.faselhd
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class FaselHDPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(FaselHD())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										160
									
								
								FaselHDProvider/src/main/kotlin/com/faselhd/FaselHDProvider.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								FaselHDProvider/src/main/kotlin/com/faselhd/FaselHDProvider.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,160 @@
 | 
			
		|||
package com.faselhd
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class FaselHD : MainAPI() {
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://faselhd.io"
 | 
			
		||||
    override var name = "FaselHD"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.AsianDrama, TvType.Anime)
 | 
			
		||||
 | 
			
		||||
    private fun String.getIntFromText(): Int? {
 | 
			
		||||
        return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun Element.toSearchResponse(): SearchResponse? {
 | 
			
		||||
        val url = select("div.postDiv a").attr("href") ?: return null
 | 
			
		||||
        val posterUrl = select("div.postDiv a div img").attr("data-src") ?:
 | 
			
		||||
        select("div.postDiv a div img").attr("src")
 | 
			
		||||
        val title = select("div.postDiv a div img").attr("alt")
 | 
			
		||||
        val quality = select(".quality").first()?.text()?.replace("1080p |-".toRegex(), "")
 | 
			
		||||
        val type = if(title.contains("فيلم")) TvType.Movie else TvType.TvSeries
 | 
			
		||||
        return MovieSearchResponse(
 | 
			
		||||
            title.replace("الموسم الأول|برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي".toRegex(),""),
 | 
			
		||||
            url,
 | 
			
		||||
            this@FaselHD.name,
 | 
			
		||||
            type,
 | 
			
		||||
            posterUrl,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            quality = getQualityFromString(quality)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    override val mainPage = mainPageOf(
 | 
			
		||||
            "$mainUrl/all-movies/page/" to "Movies",
 | 
			
		||||
            "$mainUrl/series/page/" to "Series",
 | 
			
		||||
            "$mainUrl/movies_top_imdb/page/" to "Top Movies IMDB",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
 | 
			
		||||
        val doc = app.get(request.data + page).document
 | 
			
		||||
        val list = doc.select("div[id=\"postList\"] div[class=\"col-xl-2 col-lg-2 col-md-3 col-sm-3\"]")
 | 
			
		||||
            .mapNotNull { element ->
 | 
			
		||||
                element.toSearchResponse()
 | 
			
		||||
            }
 | 
			
		||||
        return newHomePageResponse(request.name, list)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val q = query.replace(" ","+")
 | 
			
		||||
        val d = app.get("$mainUrl/?s=$q").document
 | 
			
		||||
        return d.select("div[id=\"postList\"] div[class=\"col-xl-2 col-lg-2 col-md-3 col-sm-3\"]")
 | 
			
		||||
            .mapNotNull {
 | 
			
		||||
                it.toSearchResponse()
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
        val isMovie = doc.select("div.epAll").isEmpty()
 | 
			
		||||
        val posterUrl = doc.select("div.posterImg img").attr("src")
 | 
			
		||||
            .ifEmpty { doc.select("div.seasonDiv.active img").attr("data-src") }
 | 
			
		||||
 | 
			
		||||
        val year = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]").firstOrNull {
 | 
			
		||||
            it.text().contains("سنة|موعد".toRegex())
 | 
			
		||||
        }?.text()?.getIntFromText()
 | 
			
		||||
 | 
			
		||||
        val title =
 | 
			
		||||
            doc.select("title").text().replace(" - فاصل إعلاني", "")
 | 
			
		||||
                .replace("الموسم الأول|برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي|$year".toRegex(),"")
 | 
			
		||||
        // A bit iffy to parse twice like this, but it'll do.
 | 
			
		||||
        val duration = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]").firstOrNull {
 | 
			
		||||
            it.text().contains("مدة|توقيت".toRegex())
 | 
			
		||||
        }?.text()?.getIntFromText()
 | 
			
		||||
 | 
			
		||||
        val tags = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]:contains(تصنيف الفيلم) a").map {
 | 
			
		||||
            it.text()
 | 
			
		||||
        }
 | 
			
		||||
        val recommendations = doc.select("div#postList div.postDiv").mapNotNull {
 | 
			
		||||
            it.toSearchResponse()
 | 
			
		||||
        }
 | 
			
		||||
        val synopsis = doc.select("div.singleDesc p").text()
 | 
			
		||||
        return if (isMovie) {
 | 
			
		||||
            newMovieLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.Movie,
 | 
			
		||||
                url
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.duration = duration
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            val episodes = ArrayList<Episode>()
 | 
			
		||||
            doc.select("div.epAll a").map {
 | 
			
		||||
                episodes.add(
 | 
			
		||||
                    Episode(
 | 
			
		||||
                        it.attr("href"),
 | 
			
		||||
                        it.text(),
 | 
			
		||||
                        doc.select("div.seasonDiv.active div.title").text().getIntFromText() ?: 1,
 | 
			
		||||
                        it.text().getIntFromText(),
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            doc.select("div[id=\"seasonList\"] div[class=\"col-xl-2 col-lg-3 col-md-6\"] div.seasonDiv")
 | 
			
		||||
                .not(".active").apmap { it ->
 | 
			
		||||
                    val s = app.get("$mainUrl/?p="+it.attr("data-href")).document
 | 
			
		||||
                    s.select("div.epAll a").map {
 | 
			
		||||
                        episodes.add(
 | 
			
		||||
                            Episode(
 | 
			
		||||
                                it.attr("href"),
 | 
			
		||||
                                it.text(),
 | 
			
		||||
                                s.select("div.seasonDiv.active div.title").text().getIntFromText(),
 | 
			
		||||
                                it.text().getIntFromText(),
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
 | 
			
		||||
                this.duration = duration
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        val player = app.get(app.get(data).document.select("iframe[name=\"player_iframe\"]").attr("src")).document
 | 
			
		||||
        player.select("div.quality_change button.hd_btn").map {
 | 
			
		||||
            callback.invoke(
 | 
			
		||||
                ExtractorLink(
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    it.attr("data-url"),
 | 
			
		||||
                    this.mainUrl,
 | 
			
		||||
                    quality = it.text().getIntFromText() ?: 0,
 | 
			
		||||
                    isM3u8 = true
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								MovizlandProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								MovizlandProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "Movie" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=movizland.cyou&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								MovizlandProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								MovizlandProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.movizland"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.movizland
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class MovizlandPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(Movizland())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,151 @@
 | 
			
		|||
package com.movizland
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
import com.lagradost.cloudstream3.utils.getQualityFromName
 | 
			
		||||
import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class Movizland : MainAPI() {
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://movizland.cyou"
 | 
			
		||||
    override var name = "Movizland"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes = setOf(TvType.Movie)
 | 
			
		||||
 | 
			
		||||
    private fun String.getIntFromText(): Int? {
 | 
			
		||||
        return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun Element.toSearchResponse(): SearchResponse? {
 | 
			
		||||
        val url = select("div.BlockItem")
 | 
			
		||||
        val posterUrl = select("div img")?.attr("data-src")
 | 
			
		||||
        val year = select("ul.InfoEndBlock li").last()?.text()?.getIntFromText()
 | 
			
		||||
        var quality = select("ul.RestInformation li").last()?.text()?.replace(" |-|1080p|720p".toRegex(), "")
 | 
			
		||||
            ?.replace("WEB DL","WEBDL")?.replace("BluRay","BLURAY")
 | 
			
		||||
        val title = select("div.BlockTitle").text()
 | 
			
		||||
            .replace("اون لاين", "")
 | 
			
		||||
            .replace("مشاهدة و تحميل", "")
 | 
			
		||||
            .replace("4K", "")
 | 
			
		||||
            .replace("${year.toString()}", "")
 | 
			
		||||
            .replace("فيلم", "")
 | 
			
		||||
            .replace("مترجم", "")
 | 
			
		||||
            .replace("مشاهدة", "")
 | 
			
		||||
            .replace("بجودة", "")
 | 
			
		||||
            .replace("3D", "")
 | 
			
		||||
            .replace("وتحميل", "")
 | 
			
		||||
        // val quality =select("ul.RestInformation li").last()?.text()
 | 
			
		||||
        return MovieSearchResponse(
 | 
			
		||||
            title,
 | 
			
		||||
            url.select("a").attr("href"),
 | 
			
		||||
            this@Movizland.name,
 | 
			
		||||
            if(url.select("div.BlockTitle").text().contains("فيلم")) TvType.Movie else TvType.TvSeries,
 | 
			
		||||
            posterUrl,
 | 
			
		||||
            year,
 | 
			
		||||
            null,
 | 
			
		||||
            quality = getQualityFromString(quality),
 | 
			
		||||
            // rating = url.select("div.StarsIMDB").text()?.getIntFromText()?.toDouble()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    override val mainPage = mainPageOf(
 | 
			
		||||
        "$mainUrl/category/movies/page/" to "Movies",
 | 
			
		||||
        "$mainUrl/quality/4K/page/" to "4K",
 | 
			
		||||
        "$mainUrl/quality/1080p-bluray/page/" to "Bluray",
 | 
			
		||||
        "$mainUrl/category/movies/anime/page/" to "Animation",
 | 
			
		||||
        "$mainUrl/category/movies/documentary/page/" to "Documentary",
 | 
			
		||||
        "$mainUrl/category/movies/netflix/page/" to "Netflix",
 | 
			
		||||
        "$mainUrl/category/movies/foreign/page/" to "Foreign",
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
 | 
			
		||||
        val doc = app.get(request.data + page).document
 | 
			
		||||
        val list = doc.select("div.BlockItem").mapNotNull { element ->
 | 
			
		||||
            element.toSearchResponse()
 | 
			
		||||
        }
 | 
			
		||||
        return newHomePageResponse(request.name, list)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val q = query.replace(" ", "%20")
 | 
			
		||||
        val result = arrayListOf<SearchResponse>()
 | 
			
		||||
        listOf(
 | 
			
		||||
            "$mainUrl/category/movies/?s=$q",
 | 
			
		||||
            //"$mainUrl/category/series/?s=$q"
 | 
			
		||||
        ).apmap { url ->
 | 
			
		||||
            val d = app.get(url).document
 | 
			
		||||
            d.select("div.BlockItem").mapNotNull {
 | 
			
		||||
                if (it.text().contains("اعلان")) return@mapNotNull null
 | 
			
		||||
                it.toSearchResponse()?.let { it1 -> result.add(it1) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result.distinct().sortedBy { it.name }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        var doc = app.get(url).document
 | 
			
		||||
        val posterUrl = doc.select("img")?.attr("data-src")
 | 
			
		||||
        val year = doc.select("div.SingleDetails a").last()?.text()?.getIntFromText()
 | 
			
		||||
        val title = doc.select("h2.postTitle").text()
 | 
			
		||||
            .replace("اون لاين", "")
 | 
			
		||||
            .replace("مشاهدة و تحميل", "")
 | 
			
		||||
            .replace("4K", "")
 | 
			
		||||
            .replace("${year.toString()}", "")
 | 
			
		||||
            .replace("فيلم", "")
 | 
			
		||||
            .replace("مترجم", "")
 | 
			
		||||
            .replace("مشاهدة", "")
 | 
			
		||||
            .replace("بجودة", "")
 | 
			
		||||
            .replace("3D", "")
 | 
			
		||||
            .replace("وتحميل", "")
 | 
			
		||||
        val isMovie = doc.select("h2.postTitle").text().contains("فيلم".toRegex())
 | 
			
		||||
        val synopsis = doc.select("section.story").text()
 | 
			
		||||
        val trailer = doc.select("div.InnerTrailer iframe").attr("src")
 | 
			
		||||
        val tags = doc.select("div.SingleDetails").select("li")?.map { it.text() }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return newMovieLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.Movie,
 | 
			
		||||
                url
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                addTrailer(trailer)
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        val doc = app.get(data).document
 | 
			
		||||
//        doc.select(
 | 
			
		||||
//            "li:contains(dood), li:contains(streamlare), li:contains(streamtape), li:contains(uqload), li:contains(upstream)"
 | 
			
		||||
//        ).map {
 | 
			
		||||
//            val dataServer = it.attr("data-server")
 | 
			
		||||
//            val url = it.select("code#EmbedSc$dataServer iframe").attr("data-srcout")
 | 
			
		||||
//            println(url)
 | 
			
		||||
//            loadExtractor(url, data, subtitleCallback, callback)
 | 
			
		||||
//        }
 | 
			
		||||
        doc.select("table tbody tr").map {
 | 
			
		||||
                    callback.invoke(
 | 
			
		||||
                        ExtractorLink(
 | 
			
		||||
                            this.name,
 | 
			
		||||
                            this.name,
 | 
			
		||||
                            it.select("a").attr("href"),
 | 
			
		||||
                            this.mainUrl,
 | 
			
		||||
                            quality = getQualityFromName(it.select("td:nth-child(2)").text().replace("Original","1080"))
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								MyCimaProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								MyCimaProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "TvSeries" , "Movie" , "Anime" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=mycima.tv&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								MyCimaProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								MyCimaProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.mycima"/>
 | 
			
		||||
							
								
								
									
										11
									
								
								MyCimaProvider/src/main/kotlin/com/mycima/MyCimaPlugin.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								MyCimaProvider/src/main/kotlin/com/mycima/MyCimaPlugin.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.mycima
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class MyCimaPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(MyCima())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										327
									
								
								MyCimaProvider/src/main/kotlin/com/mycima/MyCimaProvider.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								MyCimaProvider/src/main/kotlin/com/mycima/MyCimaProvider.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,327 @@
 | 
			
		|||
package com.mycima
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import org.jsoup.Jsoup
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class MyCima : MainAPI() {
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://mycima.tv"
 | 
			
		||||
    override var name = "MyCima"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime)
 | 
			
		||||
 | 
			
		||||
    private fun String.getImageURL(): String? {
 | 
			
		||||
        return this.replace("--im(age|g):url\\(|\\);".toRegex(), "")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun String.getIntFromText(): Int? {
 | 
			
		||||
        return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun Element.toSearchResponse(): SearchResponse? {
 | 
			
		||||
        val url = select("div.Thumb--GridItem a")
 | 
			
		||||
        val posterUrl = select("span.BG--GridItem")?.attr("data-lazy-style")
 | 
			
		||||
            ?.getImageURL()
 | 
			
		||||
        val year = select("div.GridItem span.year")?.text()
 | 
			
		||||
        val title = select("div.Thumb--GridItem strong").text()
 | 
			
		||||
            .replace("$year", "")
 | 
			
		||||
            .replace("مشاهدة|فيلم|مسلسل|مترجم".toRegex(), "")
 | 
			
		||||
            .replace("( نسخة مدبلجة )", " ( نسخة مدبلجة ) ")
 | 
			
		||||
        // If you need to differentiate use the url.
 | 
			
		||||
        return MovieSearchResponse(
 | 
			
		||||
            title,
 | 
			
		||||
            url.attr("href"),
 | 
			
		||||
            this@MyCima.name,
 | 
			
		||||
            if(url.attr("title").contains("فيلم")) TvType.Movie else TvType.TvSeries,
 | 
			
		||||
            posterUrl,
 | 
			
		||||
            year?.getIntFromText(),
 | 
			
		||||
            null,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    override val mainPage = mainPageOf(
 | 
			
		||||
            "$mainUrl/movies/top/page/" to "Top Movies",
 | 
			
		||||
            "$mainUrl/movies/page/" to "New Movies",
 | 
			
		||||
            "$mainUrl/movies/recent/page/" to "Recently Added Movies",
 | 
			
		||||
            "$mainUrl/seriestv/top/page/" to "Top Series",
 | 
			
		||||
            "$mainUrl/seriestv/new/page/" to "New Series",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
 | 
			
		||||
        val doc = app.get(request.data + page).document
 | 
			
		||||
        val list = doc.select("div.Grid--MycimaPosts div.GridItem").mapNotNull { element ->
 | 
			
		||||
            element.toSearchResponse()
 | 
			
		||||
        }
 | 
			
		||||
        return newHomePageResponse(request.name, list)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val q = query.replace(" ", "%20")
 | 
			
		||||
        val result = arrayListOf<SearchResponse>()
 | 
			
		||||
        listOf(
 | 
			
		||||
            "$mainUrl/search/$q",
 | 
			
		||||
            "$mainUrl/search/$q/list/series/",
 | 
			
		||||
            "$mainUrl/search/$q/list/anime/"
 | 
			
		||||
        ).apmap { url ->
 | 
			
		||||
            val d = app.get(url).document
 | 
			
		||||
            d.select("div.Grid--MycimaPosts div.GridItem").mapNotNull {
 | 
			
		||||
                if (it.text().contains("اعلان")) return@mapNotNull null
 | 
			
		||||
                it.toSearchResponse()?.let { it1 -> result.add(it1) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result.distinct().sortedBy { it.name }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    data class MoreEPS(
 | 
			
		||||
        val output: String
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
        val isMovie = doc.select("ol li:nth-child(3)").text().contains("افلام")
 | 
			
		||||
        val posterUrl =
 | 
			
		||||
            doc.select("mycima.separated--top")?.attr("data-lazy-style")?.getImageURL()
 | 
			
		||||
                ?.ifEmpty { doc.select("meta[itemprop=\"thumbnailUrl\"]")?.attr("content") }
 | 
			
		||||
                ?.ifEmpty { doc.select("mycima.separated--top")?.attr("style")?.getImageURL() }
 | 
			
		||||
        val year =
 | 
			
		||||
            doc.select("div.Title--Content--Single-begin h1 a.unline")?.text()?.getIntFromText()
 | 
			
		||||
        val title = doc.select("div.Title--Content--Single-begin h1").text()
 | 
			
		||||
            .replace("($year)", "")
 | 
			
		||||
            .replace("مشاهدة|فيلم|مسلسل|مترجم|انمي".toRegex(), "")
 | 
			
		||||
        // A bit iffy to parse twice like this, but it'll do.
 | 
			
		||||
        val duration =
 | 
			
		||||
            doc.select("ul.Terms--Content--Single-begin li").firstOrNull {
 | 
			
		||||
                it.text().contains("المدة")
 | 
			
		||||
            }?.text()?.getIntFromText()
 | 
			
		||||
 | 
			
		||||
        val synopsis = doc.select("div.StoryMovieContent").text()
 | 
			
		||||
            .ifEmpty { doc.select("div.PostItemContent").text() }
 | 
			
		||||
 | 
			
		||||
        val tags = doc.select("li:nth-child(3) > p > a").map { it.text() }
 | 
			
		||||
 | 
			
		||||
        val actors = doc.select("div.List--Teamwork > ul.Inner--List--Teamwork > li")?.mapNotNull {
 | 
			
		||||
            val name = it?.selectFirst("a > div.ActorName > span")?.text() ?: return@mapNotNull null
 | 
			
		||||
            val image = it.attr("style")
 | 
			
		||||
                ?.getImageURL()
 | 
			
		||||
                ?: return@mapNotNull null
 | 
			
		||||
            Actor(name, image)
 | 
			
		||||
        }
 | 
			
		||||
        val recommendations =
 | 
			
		||||
            doc.select("div.Grid--MycimaPosts div.GridItem")?.mapNotNull { element ->
 | 
			
		||||
                element.toSearchResponse()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        return if (isMovie) {
 | 
			
		||||
            newMovieLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.Movie,
 | 
			
		||||
                url
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.duration = duration
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                addActors(actors)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            val episodes = ArrayList<Episode>()
 | 
			
		||||
            val seasons = doc.select("div.List--Seasons--Episodes a").not(".selected").map {
 | 
			
		||||
                it.attr("href")
 | 
			
		||||
            }
 | 
			
		||||
            val moreButton = doc.select("div.MoreEpisodes--Button")
 | 
			
		||||
            val season =
 | 
			
		||||
                doc.select("div.List--Seasons--Episodes a.selected").text().getIntFromText()
 | 
			
		||||
            doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a")
 | 
			
		||||
                .apmap {
 | 
			
		||||
                    episodes.add(
 | 
			
		||||
                        Episode(
 | 
			
		||||
                            it.attr("href"),
 | 
			
		||||
                            it.text(),
 | 
			
		||||
                            season,
 | 
			
		||||
                            it.text().getIntFromText(),
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            if (moreButton.isNotEmpty()) {
 | 
			
		||||
                val n = doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size
 | 
			
		||||
                val totals =
 | 
			
		||||
                    doc.select("div.Episodes--Seasons--Episodes a").first()!!.text().getIntFromText()
 | 
			
		||||
                val mEPS = arrayListOf(
 | 
			
		||||
                    n,
 | 
			
		||||
                    n + 40,
 | 
			
		||||
                    n + 80,
 | 
			
		||||
                    n + 120,
 | 
			
		||||
                    n + 160,
 | 
			
		||||
                    n + 200,
 | 
			
		||||
                    n + 240,
 | 
			
		||||
                    n + 280,
 | 
			
		||||
                    n + 320,
 | 
			
		||||
                    n + 360,
 | 
			
		||||
                    n + 400,
 | 
			
		||||
                    n + 440,
 | 
			
		||||
                    n + 480,
 | 
			
		||||
                    n + 520,
 | 
			
		||||
                    n + 660,
 | 
			
		||||
                    n + 700,
 | 
			
		||||
                    n + 740,
 | 
			
		||||
                    n + 780,
 | 
			
		||||
                    n + 820,
 | 
			
		||||
                    n + 860,
 | 
			
		||||
                    n + 900,
 | 
			
		||||
                    n + 940,
 | 
			
		||||
                    n + 980,
 | 
			
		||||
                    n + 1020,
 | 
			
		||||
                    n + 1060,
 | 
			
		||||
                    n + 1100,
 | 
			
		||||
                    n + 1140,
 | 
			
		||||
                    n + 1180,
 | 
			
		||||
                    n + 1220,
 | 
			
		||||
                    totals
 | 
			
		||||
                )
 | 
			
		||||
                mEPS.apmap { it ->
 | 
			
		||||
                    if (it != null) {
 | 
			
		||||
                        if (it > totals!!) return@apmap
 | 
			
		||||
                        val ajaxURL =
 | 
			
		||||
                            "$mainUrl/AjaxCenter/MoreEpisodes/${moreButton.attr("data-term")}/$it"
 | 
			
		||||
                        val jsonResponse = app.get(ajaxURL)
 | 
			
		||||
                        val json = parseJson<MoreEPS>(jsonResponse.text)
 | 
			
		||||
                        val document = Jsoup.parse(json.output?.replace("""\""", ""))
 | 
			
		||||
                        document.select("a").map {
 | 
			
		||||
                            episodes.add(
 | 
			
		||||
                                Episode(
 | 
			
		||||
                                    it.attr("href"),
 | 
			
		||||
                                    it.text(),
 | 
			
		||||
                                    season,
 | 
			
		||||
                                    it.text().getIntFromText(),
 | 
			
		||||
                                )
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (seasons.isNotEmpty()) {
 | 
			
		||||
                seasons.apmap { surl ->
 | 
			
		||||
                    if (surl.contains("%d9%85%d8%af%d8%a8%d9%84%d8%ac")) return@apmap
 | 
			
		||||
                    val seasonsite = app.get(surl).document
 | 
			
		||||
                    val fmoreButton = seasonsite.select("div.MoreEpisodes--Button")
 | 
			
		||||
                    val fseason = seasonsite.select("div.List--Seasons--Episodes a.selected").text()
 | 
			
		||||
                        .getIntFromText() ?: 1
 | 
			
		||||
                    seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a")
 | 
			
		||||
                        .map {
 | 
			
		||||
                            episodes.add(
 | 
			
		||||
                                Episode(
 | 
			
		||||
                                    it.attr("href"),
 | 
			
		||||
                                    it.text(),
 | 
			
		||||
                                    fseason,
 | 
			
		||||
                                    it.text().getIntFromText(),
 | 
			
		||||
                                )
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    if (fmoreButton.isNotEmpty()) {
 | 
			
		||||
                        val n =
 | 
			
		||||
                            seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size
 | 
			
		||||
                        val totals =
 | 
			
		||||
                            seasonsite.select("div.Episodes--Seasons--Episodes a").first()!!.text()
 | 
			
		||||
                                .getIntFromText()
 | 
			
		||||
                        val mEPS = arrayListOf(
 | 
			
		||||
                            n,
 | 
			
		||||
                            n + 40,
 | 
			
		||||
                            n + 80,
 | 
			
		||||
                            n + 120,
 | 
			
		||||
                            n + 160,
 | 
			
		||||
                            n + 200,
 | 
			
		||||
                            n + 240,
 | 
			
		||||
                            n + 280,
 | 
			
		||||
                            n + 320,
 | 
			
		||||
                            n + 360,
 | 
			
		||||
                            n + 400,
 | 
			
		||||
                            n + 440,
 | 
			
		||||
                            n + 480,
 | 
			
		||||
                            n + 520,
 | 
			
		||||
                            n + 660,
 | 
			
		||||
                            n + 700,
 | 
			
		||||
                            n + 740,
 | 
			
		||||
                            n + 780,
 | 
			
		||||
                            n + 820,
 | 
			
		||||
                            n + 860,
 | 
			
		||||
                            n + 900,
 | 
			
		||||
                            n + 940,
 | 
			
		||||
                            n + 980,
 | 
			
		||||
                            n + 1020,
 | 
			
		||||
                            n + 1060,
 | 
			
		||||
                            n + 1100,
 | 
			
		||||
                            n + 1140,
 | 
			
		||||
                            n + 1180,
 | 
			
		||||
                            n + 1220,
 | 
			
		||||
                            totals
 | 
			
		||||
                        )
 | 
			
		||||
                        mEPS.apmap { it ->
 | 
			
		||||
                            if (it != null) {
 | 
			
		||||
                                if (it > totals!!) return@apmap
 | 
			
		||||
                                val ajaxURL =
 | 
			
		||||
                                    "$mainUrl/AjaxCenter/MoreEpisodes/${fmoreButton.attr("data-term")}/$it"
 | 
			
		||||
                                val jsonResponse = app.get(ajaxURL)
 | 
			
		||||
                                val json = parseJson<MoreEPS>(jsonResponse.text)
 | 
			
		||||
                                val document = Jsoup.parse(json.output?.replace("""\""", ""))
 | 
			
		||||
                                document.select("a").map {
 | 
			
		||||
                                    episodes.add(
 | 
			
		||||
                                        Episode(
 | 
			
		||||
                                            it.attr("href"),
 | 
			
		||||
                                            it.text(),
 | 
			
		||||
                                            fseason,
 | 
			
		||||
                                            it.text().getIntFromText(),
 | 
			
		||||
                                        )
 | 
			
		||||
                                    )
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else return@apmap
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            newTvSeriesLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.TvSeries,
 | 
			
		||||
                episodes.distinct().sortedBy { it.episode }) {
 | 
			
		||||
                this.duration = duration
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                addActors(actors)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        app.get(data).document
 | 
			
		||||
            .select("ul.List--Download--Mycima--Single:nth-child(2) li").map {
 | 
			
		||||
                it.select("a").map { linkElement ->
 | 
			
		||||
                    callback.invoke(
 | 
			
		||||
                        ExtractorLink(
 | 
			
		||||
                            this.name,
 | 
			
		||||
                            this.name,
 | 
			
		||||
                            linkElement.attr("href"),
 | 
			
		||||
                            this.mainUrl,
 | 
			
		||||
                            quality = linkElement.select("resolution").text().getIntFromText() ?: 0
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }.flatten()
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								Shahid4uProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Shahid4uProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "TvSeries" , "Movie" , "Anime" , "AsianDrama" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=shahid4u.cc&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								Shahid4uProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								Shahid4uProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.shahid4u"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.shahid4u
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class Shahid4uPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(Shahid4u())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,174 @@
 | 
			
		|||
package com.shahid4u
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class Shahid4u : MainAPI() {
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://shahid4u.cc"
 | 
			
		||||
    override var name = "Shahid4u"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes =
 | 
			
		||||
        setOf(TvType.TvSeries, TvType.Movie, TvType.Anime, TvType.AsianDrama)
 | 
			
		||||
 | 
			
		||||
    private fun Element.toSearchResponse(): SearchResponse? {
 | 
			
		||||
        val urlElement = select("a.fullClick")
 | 
			
		||||
        val posterUrl =
 | 
			
		||||
            select("a.image img").let { it.attr("data-src").ifEmpty { it.attr("data-image") } }
 | 
			
		||||
        val quality = select("span.quality").text().replace("1080p |-".toRegex(), "")
 | 
			
		||||
        val type =
 | 
			
		||||
            if (select(".category").text().contains("افلام")) TvType.Movie else TvType.TvSeries
 | 
			
		||||
        return MovieSearchResponse(
 | 
			
		||||
            urlElement.attr("title")
 | 
			
		||||
                .replace("برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي".toRegex(), ""),
 | 
			
		||||
            urlElement.attr("href") ?: return null,
 | 
			
		||||
            this@Shahid4u.name,
 | 
			
		||||
            type,
 | 
			
		||||
            posterUrl,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            quality = getQualityFromString(quality)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    override val mainPage = mainPageOf(
 | 
			
		||||
            "$mainUrl/movies-2/page/" to "Movies",
 | 
			
		||||
            "$mainUrl/netflix/page/" to "Series & Anime",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
 | 
			
		||||
        val doc = app.get(request.data + page).document
 | 
			
		||||
        val list = doc.select("div.content-box")
 | 
			
		||||
            .mapNotNull { element ->
 | 
			
		||||
                element.toSearchResponse()
 | 
			
		||||
            }
 | 
			
		||||
        return newHomePageResponse(request.name, list)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val finalResult = arrayListOf<SearchResponse>()
 | 
			
		||||
        listOf(
 | 
			
		||||
            "$mainUrl/?s=$query&category=&type=movie",
 | 
			
		||||
            "$mainUrl/?s=$query&type=series"
 | 
			
		||||
        ).apmap { url ->
 | 
			
		||||
            app.get(url).document.select("div.content-box").mapNotNull {
 | 
			
		||||
                finalResult.add(it.toSearchResponse() ?: return@mapNotNull null)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return finalResult
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
        val isMovie =
 | 
			
		||||
            doc.select("ul.half-tags:contains(القسم) li:nth-child(2)").text().contains("افلام")
 | 
			
		||||
        val posterUrl =
 | 
			
		||||
            doc.select("a.poster-image").attr("style").replace(".*url\\(|\\);".toRegex(), "")
 | 
			
		||||
 | 
			
		||||
        val year = doc.select("ul.half-tags:contains(السنة) li:nth-child(2)").text().toIntOrNull()
 | 
			
		||||
 | 
			
		||||
        val title =
 | 
			
		||||
            doc.select("div.breadcrumb a:nth-child(3)").text()
 | 
			
		||||
                .replace(
 | 
			
		||||
                    "الموسم الأول|برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي|$year".toRegex(),
 | 
			
		||||
                    ""
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
        val tags = doc.select("ul.half-tags:contains(النوع) li").not(":nth-child(1)").map {
 | 
			
		||||
            it.text()
 | 
			
		||||
        }
 | 
			
		||||
        val recommendations =
 | 
			
		||||
            doc.select("div.MediaGrid").first()?.select("div.content-box")?.mapNotNull {
 | 
			
		||||
                it.toSearchResponse()
 | 
			
		||||
            }
 | 
			
		||||
        val synopsis = doc.select("div.post-story:contains(قصة) p").text()
 | 
			
		||||
 | 
			
		||||
        val rating = doc.select("div.imdbR div span").text().toRatingInt()
 | 
			
		||||
        return if (isMovie) {
 | 
			
		||||
            newMovieLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.Movie,
 | 
			
		||||
                url
 | 
			
		||||
            ) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                this.rating = rating
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            val episodes = ArrayList<Episode>()
 | 
			
		||||
            val episodeElement = doc.select("div.MediaGrid")
 | 
			
		||||
            val allEpisodesUrl = doc.select("div.btns:contains(جميع الحلقات) a").attr("href")
 | 
			
		||||
            if(allEpisodesUrl.isNotEmpty()) {
 | 
			
		||||
                app.get(allEpisodesUrl).document.select("div.row > div").let {
 | 
			
		||||
                    it.mapIndexedNotNull { index, element ->
 | 
			
		||||
                        episodes.add(
 | 
			
		||||
                            Episode(
 | 
			
		||||
                                element.select("a.fullClick").attr("href"),
 | 
			
		||||
                                element.select("a.fullClick").attr("title"),
 | 
			
		||||
                                1,
 | 
			
		||||
                                it.size - index
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                episodeElement[1].select("div.content-box").apmap {
 | 
			
		||||
                    val seasonNumber = it.select("div.number em").text().toIntOrNull()
 | 
			
		||||
                    val seasonUrl = it.select("a.fullClick").attr("href")
 | 
			
		||||
                    app.get(seasonUrl).document.select(".episode-block").map { episode ->
 | 
			
		||||
                        episodes.add(
 | 
			
		||||
                            Episode(
 | 
			
		||||
                                episode.select("a").attr("href"),
 | 
			
		||||
                                episode.select("div.title").text(),
 | 
			
		||||
                                seasonNumber,
 | 
			
		||||
                                episode.select("div.number em").text().toIntOrNull(),
 | 
			
		||||
                                episode.select("div.poster img").attr("data-image")
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            newTvSeriesLoadResponse(
 | 
			
		||||
                title,
 | 
			
		||||
                url,
 | 
			
		||||
                TvType.TvSeries,
 | 
			
		||||
                episodes.distinct().sortedBy { it.episode }) {
 | 
			
		||||
                this.posterUrl = posterUrl
 | 
			
		||||
                this.year = year
 | 
			
		||||
                this.plot = synopsis
 | 
			
		||||
                this.tags = tags
 | 
			
		||||
                this.recommendations = recommendations
 | 
			
		||||
                this.rating = rating
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        val watchUrl = "$data/watch"
 | 
			
		||||
        app.get(watchUrl).document.select(
 | 
			
		||||
            ".servers-list li:contains(ok), li:contains(Streamtape), li:contains(DoodStream), li:contains(Uqload), li:contains(Voe), li:contains(VIDBOM), li:contains(Upstream)"
 | 
			
		||||
        ).forEach {
 | 
			
		||||
            val id = it.attr("data-id")
 | 
			
		||||
            val i = it.attr("data-i")
 | 
			
		||||
            val sourceUrl = app.post(
 | 
			
		||||
                "https://shahed4u.mx/wp-content/themes/Shahid4u-WP_HOME/Ajaxat/Single/Server.php",
 | 
			
		||||
                headers = mapOf("referer" to watchUrl, "x-requested-with" to "XMLHttpRequest"),
 | 
			
		||||
                data = mapOf("id" to id, "i" to i)
 | 
			
		||||
            ).document.select("iframe").attr("src")
 | 
			
		||||
            loadExtractor(sourceUrl, watchUrl, subtitleCallback, callback)
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								YallaShootsProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								YallaShootsProvider/build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
version = 1
 | 
			
		||||
 | 
			
		||||
cloudstream {
 | 
			
		||||
    description = ""
 | 
			
		||||
    authors = listOf( "ImZaw" )
 | 
			
		||||
 | 
			
		||||
    status = 1
 | 
			
		||||
 | 
			
		||||
    tvTypes = listOf( "Live" )
 | 
			
		||||
 | 
			
		||||
    iconUrl = "https://www.google.com/s2/favicons?domain=www.yalla-shoots.com&sz=24"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								YallaShootsProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								YallaShootsProvider/src/main/AndroidManifest.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="com.yallashoots"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
package com.yallashoots
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
 | 
			
		||||
import com.lagradost.cloudstream3.plugins.Plugin
 | 
			
		||||
import android.content.Context
 | 
			
		||||
 | 
			
		||||
@CloudstreamPlugin
 | 
			
		||||
class YallaShootsPlugin: Plugin() {
 | 
			
		||||
    override fun load(context: Context) {
 | 
			
		||||
        registerMainAPI(YallaShoots())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
package com.yallashoots
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class YallaShoots : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://www.yalla-shoots.com"
 | 
			
		||||
    override var name = "Yalla Shoots"
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override val hasDownloadSupport = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
        TvType.Live
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
 | 
			
		||||
        val dataMap = mapOf(
 | 
			
		||||
            "Matches Today" to "$mainUrl",
 | 
			
		||||
        )
 | 
			
		||||
        return HomePageResponse(dataMap.apmap { (title, data) ->
 | 
			
		||||
            val document = app.get(data).document
 | 
			
		||||
            val shows = document.select("div.albaflex > div.live").mapNotNull {
 | 
			
		||||
                if(it.select("a").attr("href") === "$mainUrl/#/") return@mapNotNull null
 | 
			
		||||
                val linkElement = it.select("a")
 | 
			
		||||
                LiveSearchResponse(
 | 
			
		||||
                    linkElement.attr("title"),
 | 
			
		||||
                    linkElement.attr("href"),
 | 
			
		||||
                    this@YallaShoots.name,
 | 
			
		||||
                    TvType.Live,
 | 
			
		||||
                    document.select(".blog-post:contains(${linkElement.attr("title").replace("Vs ","و")}) img").attr("src"),
 | 
			
		||||
                    lang = "ar"
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            HomePageList(
 | 
			
		||||
                title,
 | 
			
		||||
                shows.ifEmpty {
 | 
			
		||||
                              arrayListOf(LiveSearchResponse(
 | 
			
		||||
                                  "لا يوجد اي مباراة حاليا",
 | 
			
		||||
                                  mainUrl,
 | 
			
		||||
                                  this@YallaShoots.name,
 | 
			
		||||
                                  TvType.Live,
 | 
			
		||||
                                  "$mainUrl/wp-content/uploads/2021/12/يلا-شوت-1.png",
 | 
			
		||||
                                  lang = "ar"
 | 
			
		||||
                              ))
 | 
			
		||||
                },
 | 
			
		||||
                isHorizontalImages = true
 | 
			
		||||
            )
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
        val title = doc.select("h1").text()
 | 
			
		||||
        val poster = fixUrl(doc.select("img.img-responsive").attr("src"))
 | 
			
		||||
        return LiveStreamLoadResponse(
 | 
			
		||||
            title,
 | 
			
		||||
            url,
 | 
			
		||||
            this.name,
 | 
			
		||||
            doc.select("iframe[loading=\"lazy\"]").attr("src"),
 | 
			
		||||
            poster,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
        subtitleCallback: (SubtitleFile) -> Unit,
 | 
			
		||||
        callback: (ExtractorLink) -> Unit
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        val doc = app.get("$data?serv=2").document
 | 
			
		||||
        val sourceLink = doc.select("script:contains(.m3u8)").html().replace(".*hls: \"|\"\\};.*".toRegex(),"")
 | 
			
		||||
        callback.invoke(
 | 
			
		||||
            ExtractorLink(
 | 
			
		||||
                this.name,
 | 
			
		||||
                this.name,
 | 
			
		||||
                sourceLink,
 | 
			
		||||
                mainUrl,
 | 
			
		||||
                Qualities.Unknown.value,
 | 
			
		||||
                isM3u8 = true
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								build.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
import com.lagradost.cloudstream3.gradle.CloudstreamExtension 
 | 
			
		||||
import com.android.build.gradle.BaseExtension
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    repositories {
 | 
			
		||||
        google()
 | 
			
		||||
        mavenCentral()
 | 
			
		||||
        // Shitpack repo which contains our tools and dependencies
 | 
			
		||||
        maven("https://jitpack.io")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath("com.android.tools.build:gradle:7.0.4")
 | 
			
		||||
        // Cloudstream gradle plugin which makes everything work and builds plugins
 | 
			
		||||
        classpath("com.github.recloudstream:gradle:master-SNAPSHOT")
 | 
			
		||||
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
allprojects {
 | 
			
		||||
    repositories {
 | 
			
		||||
        google()
 | 
			
		||||
        mavenCentral()
 | 
			
		||||
        maven("https://jitpack.io")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun Project.cloudstream(configuration: CloudstreamExtension.() -> Unit) = extensions.getByName<CloudstreamExtension>("cloudstream").configuration()
 | 
			
		||||
 | 
			
		||||
fun Project.android(configuration: BaseExtension.() -> Unit) = extensions.getByName<BaseExtension>("android").configuration()
 | 
			
		||||
 | 
			
		||||
subprojects {
 | 
			
		||||
    apply(plugin = "com.android.library")
 | 
			
		||||
    apply(plugin = "kotlin-android")
 | 
			
		||||
    apply(plugin = "com.lagradost.cloudstream3.gradle")
 | 
			
		||||
 | 
			
		||||
    cloudstream {
 | 
			
		||||
        // when running through github workflow, GITHUB_REPOSITORY should contain current repository name
 | 
			
		||||
        setRepo(System.getenv("GITHUB_REPOSITORY") ?: "user/repo")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    android {
 | 
			
		||||
        compileSdkVersion(30)
 | 
			
		||||
 | 
			
		||||
        defaultConfig {
 | 
			
		||||
            minSdk = 21
 | 
			
		||||
            targetSdk = 30
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compileOptions {
 | 
			
		||||
            sourceCompatibility = JavaVersion.VERSION_1_8
 | 
			
		||||
            targetCompatibility = JavaVersion.VERSION_1_8
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
 | 
			
		||||
            kotlinOptions {
 | 
			
		||||
                jvmTarget = "1.8" // Required
 | 
			
		||||
                // Disables some unnecessary features
 | 
			
		||||
                freeCompilerArgs = freeCompilerArgs +
 | 
			
		||||
                        "-Xno-call-assertions" +
 | 
			
		||||
                        "-Xno-param-assertions" +
 | 
			
		||||
                        "-Xno-receiver-assertions"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dependencies {
 | 
			
		||||
        val apk by configurations
 | 
			
		||||
        val implementation by configurations
 | 
			
		||||
 | 
			
		||||
        // Stubs for all Cloudstream classes
 | 
			
		||||
        apk("com.lagradost:cloudstream3:pre-release")
 | 
			
		||||
 | 
			
		||||
        // these dependencies can include any of those which are added by the app,
 | 
			
		||||
        // but you dont need to include any of them if you dont need them
 | 
			
		||||
        // https://github.com/recloudstream/cloudstream/blob/master/app/build.gradle
 | 
			
		||||
        implementation(kotlin("stdlib")) // adds standard kotlin features, like listOf, mapOf etc
 | 
			
		||||
        implementation("com.github.Blatzar:NiceHttp:0.3.2") // http library
 | 
			
		||||
        implementation("org.jsoup:jsoup:1.13.1") // html parser
 | 
			
		||||
        implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.+")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
task<Delete>("clean") {
 | 
			
		||||
    delete(rootProject.buildDir)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								gradle.properties
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								gradle.properties
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
# Project-wide Gradle settings.
 | 
			
		||||
# IDE (e.g. Android Studio) users:
 | 
			
		||||
# Gradle settings configured through the IDE *will override*
 | 
			
		||||
# any settings specified in this file.
 | 
			
		||||
# For more details on how to configure your build environment visit
 | 
			
		||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
 | 
			
		||||
# Specifies the JVM arguments used for the daemon process.
 | 
			
		||||
# The setting is particularly useful for tweaking memory settings.
 | 
			
		||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
 | 
			
		||||
# When configured, Gradle will run in incubating parallel mode.
 | 
			
		||||
# This option should only be used with decoupled projects. More details, visit
 | 
			
		||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 | 
			
		||||
# org.gradle.parallel=true
 | 
			
		||||
# AndroidX package structure to make it clearer which packages are bundled with the
 | 
			
		||||
# Android operating system, and which are packaged with your app"s APK
 | 
			
		||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
 | 
			
		||||
android.useAndroidX=true
 | 
			
		||||
# Automatically convert third-party libraries to use AndroidX
 | 
			
		||||
android.enableJetifier=true
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										6
									
								
								gradle/wrapper/gradle-wrapper.properties
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								gradle/wrapper/gradle-wrapper.properties
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
#Sun Feb 20 16:26:11 CET 2022
 | 
			
		||||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
							
								
								
									
										172
									
								
								gradlew
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								gradlew
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,172 @@
 | 
			
		|||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
##############################################################################
 | 
			
		||||
##
 | 
			
		||||
##  Gradle start up script for UN*X
 | 
			
		||||
##
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
# Attempt to set APP_HOME
 | 
			
		||||
# Resolve links: $0 may be a link
 | 
			
		||||
PRG="$0"
 | 
			
		||||
# Need this for relative symlinks.
 | 
			
		||||
while [ -h "$PRG" ] ; do
 | 
			
		||||
    ls=`ls -ld "$PRG"`
 | 
			
		||||
    link=`expr "$ls" : '.*-> \(.*\)$'`
 | 
			
		||||
    if expr "$link" : '/.*' > /dev/null; then
 | 
			
		||||
        PRG="$link"
 | 
			
		||||
    else
 | 
			
		||||
        PRG=`dirname "$PRG"`"/$link"
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
SAVED="`pwd`"
 | 
			
		||||
cd "`dirname \"$PRG\"`/" >/dev/null
 | 
			
		||||
APP_HOME="`pwd -P`"
 | 
			
		||||
cd "$SAVED" >/dev/null
 | 
			
		||||
 | 
			
		||||
APP_NAME="Gradle"
 | 
			
		||||
APP_BASE_NAME=`basename "$0"`
 | 
			
		||||
 | 
			
		||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
DEFAULT_JVM_OPTS=""
 | 
			
		||||
 | 
			
		||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
			
		||||
MAX_FD="maximum"
 | 
			
		||||
 | 
			
		||||
warn () {
 | 
			
		||||
    echo "$*"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
die () {
 | 
			
		||||
    echo
 | 
			
		||||
    echo "$*"
 | 
			
		||||
    echo
 | 
			
		||||
    exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# OS specific support (must be 'true' or 'false').
 | 
			
		||||
cygwin=false
 | 
			
		||||
msys=false
 | 
			
		||||
darwin=false
 | 
			
		||||
nonstop=false
 | 
			
		||||
case "`uname`" in
 | 
			
		||||
  CYGWIN* )
 | 
			
		||||
    cygwin=true
 | 
			
		||||
    ;;
 | 
			
		||||
  Darwin* )
 | 
			
		||||
    darwin=true
 | 
			
		||||
    ;;
 | 
			
		||||
  MINGW* )
 | 
			
		||||
    msys=true
 | 
			
		||||
    ;;
 | 
			
		||||
  NONSTOP* )
 | 
			
		||||
    nonstop=true
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 | 
			
		||||
 | 
			
		||||
# Determine the Java command to use to start the JVM.
 | 
			
		||||
if [ -n "$JAVA_HOME" ] ; then
 | 
			
		||||
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
 | 
			
		||||
        # IBM's JDK on AIX uses strange locations for the executables
 | 
			
		||||
        JAVACMD="$JAVA_HOME/jre/sh/java"
 | 
			
		||||
    else
 | 
			
		||||
        JAVACMD="$JAVA_HOME/bin/java"
 | 
			
		||||
    fi
 | 
			
		||||
    if [ ! -x "$JAVACMD" ] ; then
 | 
			
		||||
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
 | 
			
		||||
 | 
			
		||||
Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
location of your Java installation."
 | 
			
		||||
    fi
 | 
			
		||||
else
 | 
			
		||||
    JAVACMD="java"
 | 
			
		||||
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
 | 
			
		||||
Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
location of your Java installation."
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Increase the maximum file descriptors if we can.
 | 
			
		||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
 | 
			
		||||
    MAX_FD_LIMIT=`ulimit -H -n`
 | 
			
		||||
    if [ $? -eq 0 ] ; then
 | 
			
		||||
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
 | 
			
		||||
            MAX_FD="$MAX_FD_LIMIT"
 | 
			
		||||
        fi
 | 
			
		||||
        ulimit -n $MAX_FD
 | 
			
		||||
        if [ $? -ne 0 ] ; then
 | 
			
		||||
            warn "Could not set maximum file descriptor limit: $MAX_FD"
 | 
			
		||||
        fi
 | 
			
		||||
    else
 | 
			
		||||
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# For Darwin, add options to specify how the application appears in the dock
 | 
			
		||||
if $darwin; then
 | 
			
		||||
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# For Cygwin, switch paths to Windows format before running java
 | 
			
		||||
if $cygwin ; then
 | 
			
		||||
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
 | 
			
		||||
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
 | 
			
		||||
    JAVACMD=`cygpath --unix "$JAVACMD"`
 | 
			
		||||
 | 
			
		||||
    # We build the pattern for arguments to be converted via cygpath
 | 
			
		||||
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
 | 
			
		||||
    SEP=""
 | 
			
		||||
    for dir in $ROOTDIRSRAW ; do
 | 
			
		||||
        ROOTDIRS="$ROOTDIRS$SEP$dir"
 | 
			
		||||
        SEP="|"
 | 
			
		||||
    done
 | 
			
		||||
    OURCYGPATTERN="(^($ROOTDIRS))"
 | 
			
		||||
    # Add a user-defined pattern to the cygpath arguments
 | 
			
		||||
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
 | 
			
		||||
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
 | 
			
		||||
    fi
 | 
			
		||||
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
 | 
			
		||||
    i=0
 | 
			
		||||
    for arg in "$@" ; do
 | 
			
		||||
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
 | 
			
		||||
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
 | 
			
		||||
 | 
			
		||||
        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
 | 
			
		||||
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
 | 
			
		||||
        else
 | 
			
		||||
            eval `echo args$i`="\"$arg\""
 | 
			
		||||
        fi
 | 
			
		||||
        i=$((i+1))
 | 
			
		||||
    done
 | 
			
		||||
    case $i in
 | 
			
		||||
        (0) set -- ;;
 | 
			
		||||
        (1) set -- "$args0" ;;
 | 
			
		||||
        (2) set -- "$args0" "$args1" ;;
 | 
			
		||||
        (3) set -- "$args0" "$args1" "$args2" ;;
 | 
			
		||||
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
 | 
			
		||||
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
 | 
			
		||||
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
 | 
			
		||||
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
 | 
			
		||||
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
 | 
			
		||||
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
 | 
			
		||||
    esac
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Escape application args
 | 
			
		||||
save () {
 | 
			
		||||
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
 | 
			
		||||
    echo " "
 | 
			
		||||
}
 | 
			
		||||
APP_ARGS=$(save "$@")
 | 
			
		||||
 | 
			
		||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
 | 
			
		||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
 | 
			
		||||
 | 
			
		||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
 | 
			
		||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
 | 
			
		||||
  cd "$(dirname "$0")"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
exec "$JAVACMD" "$@"
 | 
			
		||||
							
								
								
									
										84
									
								
								gradlew.bat
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								gradlew.bat
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
@if "%DEBUG%" == "" @echo off
 | 
			
		||||
@rem ##########################################################################
 | 
			
		||||
@rem
 | 
			
		||||
@rem  Gradle startup script for Windows
 | 
			
		||||
@rem
 | 
			
		||||
@rem ##########################################################################
 | 
			
		||||
 | 
			
		||||
@rem Set local scope for the variables with windows NT shell
 | 
			
		||||
if "%OS%"=="Windows_NT" setlocal
 | 
			
		||||
 | 
			
		||||
set DIRNAME=%~dp0
 | 
			
		||||
if "%DIRNAME%" == "" set DIRNAME=.
 | 
			
		||||
set APP_BASE_NAME=%~n0
 | 
			
		||||
set APP_HOME=%DIRNAME%
 | 
			
		||||
 | 
			
		||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
set DEFAULT_JVM_OPTS=
 | 
			
		||||
 | 
			
		||||
@rem Find java.exe
 | 
			
		||||
if defined JAVA_HOME goto findJavaFromJavaHome
 | 
			
		||||
 | 
			
		||||
set JAVA_EXE=java.exe
 | 
			
		||||
%JAVA_EXE% -version >NUL 2>&1
 | 
			
		||||
if "%ERRORLEVEL%" == "0" goto init
 | 
			
		||||
 | 
			
		||||
echo.
 | 
			
		||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
echo.
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
echo location of your Java installation.
 | 
			
		||||
 | 
			
		||||
goto fail
 | 
			
		||||
 | 
			
		||||
:findJavaFromJavaHome
 | 
			
		||||
set JAVA_HOME=%JAVA_HOME:"=%
 | 
			
		||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 | 
			
		||||
 | 
			
		||||
if exist "%JAVA_EXE%" goto init
 | 
			
		||||
 | 
			
		||||
echo.
 | 
			
		||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
 | 
			
		||||
echo.
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
echo location of your Java installation.
 | 
			
		||||
 | 
			
		||||
goto fail
 | 
			
		||||
 | 
			
		||||
:init
 | 
			
		||||
@rem Get command-line arguments, handling Windows variants
 | 
			
		||||
 | 
			
		||||
if not "%OS%" == "Windows_NT" goto win9xME_args
 | 
			
		||||
 | 
			
		||||
:win9xME_args
 | 
			
		||||
@rem Slurp the command line arguments.
 | 
			
		||||
set CMD_LINE_ARGS=
 | 
			
		||||
set _SKIP=2
 | 
			
		||||
 | 
			
		||||
:win9xME_args_slurp
 | 
			
		||||
if "x%~1" == "x" goto execute
 | 
			
		||||
 | 
			
		||||
set CMD_LINE_ARGS=%*
 | 
			
		||||
 | 
			
		||||
:execute
 | 
			
		||||
@rem Setup the command line
 | 
			
		||||
 | 
			
		||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 | 
			
		||||
 | 
			
		||||
@rem Execute Gradle
 | 
			
		||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
 | 
			
		||||
 | 
			
		||||
:end
 | 
			
		||||
@rem End local scope for the variables with windows NT shell
 | 
			
		||||
if "%ERRORLEVEL%"=="0" goto mainEnd
 | 
			
		||||
 | 
			
		||||
:fail
 | 
			
		||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
 | 
			
		||||
rem the _cmd.exe /c_ return code!
 | 
			
		||||
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
 | 
			
		||||
exit /b 1
 | 
			
		||||
 | 
			
		||||
:mainEnd
 | 
			
		||||
if "%OS%"=="Windows_NT" endlocal
 | 
			
		||||
 | 
			
		||||
:omega
 | 
			
		||||
							
								
								
									
										13
									
								
								settings.gradle.kts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								settings.gradle.kts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
rootProject.name = "CloudstreamExtensionsArabic"
 | 
			
		||||
 | 
			
		||||
val disabled = listOf<String>("")
 | 
			
		||||
 | 
			
		||||
File(rootDir, ".").eachDir { dir ->
 | 
			
		||||
    if (!disabled.contains(dir.name) && File(dir, "build.gradle.kts").exists()) {
 | 
			
		||||
        include(dir.name)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun File.eachDir(block: (File) -> Unit) {
 | 
			
		||||
    listFiles()?.filter { it.isDirectory }?.forEach { block(it) }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue