forked from recloudstream/cloudstream
		
	Added Arabic provider (Akwwam.io)
Note that some movies dont work because they're .rar files
This commit is contained in:
		
							parent
							
								
									735a418df7
								
							
						
					
					
						commit
						b106b86fdd
					
				
					 2 changed files with 210 additions and 1 deletions
				
			
		|  | @ -66,7 +66,8 @@ object APIHolder { | ||||||
|         TrailersTwoProvider(), |         TrailersTwoProvider(), | ||||||
|         DramaSeeProvider(), |         DramaSeeProvider(), | ||||||
|         WatchAsianProvider(), |         WatchAsianProvider(), | ||||||
|         KdramaHoodProvider() |         KdramaHoodProvider(), | ||||||
|  |         AkwamProvider() | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     val restrictedApis = arrayListOf( |     val restrictedApis = arrayListOf( | ||||||
|  |  | ||||||
|  | @ -0,0 +1,208 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.network.AppResponse | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.Qualities | ||||||
|  | import org.jsoup.nodes.Element | ||||||
|  | 
 | ||||||
|  | class AkwamProvider : MainAPI() { | ||||||
|  | 
 | ||||||
|  |     override val lang = "ar" | ||||||
|  |     override val mainUrl = "https://akwam.io" | ||||||
|  |     override val 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") | ||||||
|  |         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@AkwamProvider.name, | ||||||
|  |             TvType.TvSeries, | ||||||
|  |             posterUrl, | ||||||
|  |             year, | ||||||
|  |             null, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun getMainPage(): HomePageResponse? { | ||||||
|  |         // Title, Url | ||||||
|  |         val moviesUrl = listOf("Movies" to "$mainUrl/movies", "Series" to "$mainUrl/series", "Shows" to "$mainUrl/shows") | ||||||
|  |         val pages = moviesUrl.pmap { | ||||||
|  |             val doc = app.get(it.second).document | ||||||
|  |             val list = doc.select("div.col-lg-auto.col-md-4.col-6.mb-12").map { element -> | ||||||
|  |                 element.toSearchResponse() | ||||||
|  |             } | ||||||
|  |             HomePageList(it.first, list) | ||||||
|  |         }.sortedBy { it.name } | ||||||
|  |         return HomePageResponse(pages) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override 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").map { | ||||||
|  |             it.toSearchResponse() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun String.getIntFromText(): Int? { | ||||||
|  |         return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun Element.toTvSeriesEpisode(): TvSeriesEpisode { | ||||||
|  |         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 TvSeriesEpisode( | ||||||
|  |             title, | ||||||
|  |             null, | ||||||
|  |             title.getIntFromText(), | ||||||
|  |             url, | ||||||
|  |             thumbUrl, | ||||||
|  |             date | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     override 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").text() | ||||||
|  | 
 | ||||||
|  |         val rating = doc.select("span.mx-2").text().split("/").lastOrNull()?.replace(" ", "") | ||||||
|  |             ?.toDoubleOrNull() | ||||||
|  |             ?.times(1000)?.toInt() | ||||||
|  | 
 | ||||||
|  |         val tags = doc.select("div.font-size-16.d-flex.align-items-center.mt-3 > a").map { | ||||||
|  |             it.text() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Commented out as no use yet | ||||||
|  | //        val recommendations = doc.select("div.entry-image").map { | ||||||
|  | //            it.toSearchResponse() | ||||||
|  | //        } | ||||||
|  | 
 | ||||||
|  |         return if (isMovie) { | ||||||
|  |             MovieLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url, | ||||||
|  |                 this@AkwamProvider.name, | ||||||
|  |                 TvType.Movie, | ||||||
|  |                 url, | ||||||
|  |                 posterUrl, | ||||||
|  |                 year, | ||||||
|  |                 synopsis, | ||||||
|  |                 null, // Possible | ||||||
|  |                 rating, | ||||||
|  |                 tags, | ||||||
|  |                 duration, | ||||||
|  |                 null, | ||||||
|  |                 null | ||||||
|  |             ) | ||||||
|  |         } else { | ||||||
|  | 
 | ||||||
|  |             val episodes = doc.select("div.bg-primary2.p-4.col-lg-4.col-md-6.col-12").map { | ||||||
|  |                 it.toTvSeriesEpisode() | ||||||
|  |             }.let { | ||||||
|  |                 val isReversed = it.lastOrNull()?.episode ?: 1 < it.firstOrNull()?.episode ?: 0 | ||||||
|  |                 if (isReversed) | ||||||
|  |                     it.reversed() | ||||||
|  |                 else it | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             TvSeriesLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url, | ||||||
|  |                 this@AkwamProvider.name, | ||||||
|  |                 TvType.Movie, | ||||||
|  |                 episodes, | ||||||
|  |                 posterUrl, | ||||||
|  |                 year, | ||||||
|  |                 synopsis, | ||||||
|  |                 null, | ||||||
|  |                 null, | ||||||
|  |                 rating, | ||||||
|  |                 tags, | ||||||
|  |                 duration, | ||||||
|  |                 null, | ||||||
|  |                 null | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     // Maybe possible to not use the url shortener but cba investigating that. | ||||||
|  |     private 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 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 { | ||||||
|  |             val quality = getQualityFromId(it.attr("id").getIntFromText()) | ||||||
|  |             doc.select(".col-lg-6 > a").map { linkElement -> | ||||||
|  |                 linkElement.attr("href") to quality | ||||||
|  |                 // Only uses the download links, primarily to prevent unnecessary duplicate requests. | ||||||
|  |             }.filter { link -> link.first.contains("/link/") } | ||||||
|  |         }.flatten() | ||||||
|  | 
 | ||||||
|  |         links.pmap { | ||||||
|  |             val linkDoc = skipUrlShortener(it.first).document | ||||||
|  |             val button = linkDoc.select("div.btn-loader > a") | ||||||
|  |             val url = button.attr("href") | ||||||
|  | 
 | ||||||
|  |             callback.invoke( | ||||||
|  |                 ExtractorLink( | ||||||
|  |                     this.name, | ||||||
|  |                     this.name + " - ${it.second.name.replace("P", "")}p", | ||||||
|  |                     url, | ||||||
|  |                     this.mainUrl, | ||||||
|  |                     it.second.value | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue