forked from recloudstream/cloudstream
		
	Added 2 New Italian Providers (#973) By Adippe
This commit is contained in:
		
							parent
							
								
									fd50e2cccb
								
							
						
					
					
						commit
						c48e45c9c6
					
				
					 4 changed files with 695 additions and 24 deletions
				
			
		|  | @ -83,6 +83,8 @@ object APIHolder { | ||||||
|             SoaptwoDayProvider(), |             SoaptwoDayProvider(), | ||||||
|             HDMProvider(),// disabled due to cloudflare |             HDMProvider(),// disabled due to cloudflare | ||||||
|             TheFlixToProvider(), |             TheFlixToProvider(), | ||||||
|  |             StreamingcommunityProvider(), | ||||||
|  |             TantifilmProvider(), | ||||||
| 
 | 
 | ||||||
|             // Metadata providers |             // Metadata providers | ||||||
|             //TmdbProvider(), |             //TmdbProvider(), | ||||||
|  |  | ||||||
|  | @ -29,29 +29,19 @@ open class DoodLaExtractor : ExtractorApi() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? { |     override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||||
|         val id = url.removePrefix("$mainUrl/e/").removePrefix("$mainUrl/d/") |         val response0 = app.get(url).text // html of DoodStream page to look for /pass_md5/... | ||||||
|         val trueUrl = getExtractorUrl(id) |         val md5 =mainUrl+(Regex("/pass_md5/[^']*").find(response0)?.value ?: return null)  // get https://dood.ws/pass_md5/... | ||||||
|         val response = app.get(trueUrl).text |         val trueUrl = app.get(md5, referer = url).text + "zUEJeL3mUN?token=" + md5.substringAfterLast("/")   //direct link to extract  (zUEJeL3mUN is random) | ||||||
|         Regex("href=\".*/download/(.*?)\"").find(response)?.groupValues?.get(1)?.let { link -> |         return listOf( | ||||||
|             if (link.isEmpty()) return null |             ExtractorLink( | ||||||
|             delay(5000) // might need this to not trigger anti bot |                 trueUrl, | ||||||
|             val downloadLink = "$mainUrl/download/$link" |                 this.name, | ||||||
|             val downloadResponse = app.get(downloadLink).text |                 trueUrl, | ||||||
|             Regex("onclick=\"window\\.open\\((['\"])(.*?)(['\"])").find(downloadResponse)?.groupValues?.get(2) |                 mainUrl, | ||||||
|                 ?.let { trueLink -> |                 Qualities.Unknown.value, | ||||||
|                     return listOf( |                 false | ||||||
|                         ExtractorLink( |             ) | ||||||
|                             trueLink, |         ) // links are valid in 8h | ||||||
|                             this.name, |  | ||||||
|                             trueLink, |  | ||||||
|                             mainUrl, |  | ||||||
|                             Qualities.Unknown.value, |  | ||||||
|                             false |  | ||||||
|                         ) |  | ||||||
|                     ) // links are valid in 8h |  | ||||||
|                 } |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         return null |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -0,0 +1,436 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import android.text.Html | ||||||
|  | import com.fasterxml.jackson.annotation.* | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
|  | import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | import org.json.JSONObject | ||||||
|  | import java.net.URI | ||||||
|  | import java.security.MessageDigest | ||||||
|  | 
 | ||||||
|  | data class Moviedata( | ||||||
|  |     @JsonProperty("id") val id: Long, | ||||||
|  |     @JsonProperty("name") val name: String, | ||||||
|  |     @JsonProperty("type") val type: String, | ||||||
|  |     @JsonProperty("release_date") val releaseDate: String, | ||||||
|  |     @JsonProperty("seasons_count") val seasonsCount: Long? = null, | ||||||
|  |     @JsonProperty("genres") val genres: List<Genre>, | ||||||
|  |     @JsonProperty("votes") val votes: List<Vote>, | ||||||
|  |     @JsonProperty("runtime") val runtime: Long? = null | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class Genre( | ||||||
|  |     @JsonProperty("name") val name: String, | ||||||
|  |     @JsonProperty("pivot") val pivot: Pivot, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class Pivot( | ||||||
|  |     @JsonProperty("titleID") val titleID: Long, | ||||||
|  |     @JsonProperty("genreID") val genreID: Long, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class Vote( | ||||||
|  |     @JsonProperty("title_id") val title_id: Long, | ||||||
|  |     @JsonProperty("average") val average: String, | ||||||
|  |     @JsonProperty("count") val count: Long, | ||||||
|  |     @JsonProperty("type") val type: String, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class VideoElement( | ||||||
|  |     @JsonProperty("id") val id: Long, | ||||||
|  |     @JsonProperty("slug") val slug: String, | ||||||
|  |     @JsonProperty("images") val images: List<Image>, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class Image( | ||||||
|  |     @JsonProperty("imageable_id") val imageableID: Long, | ||||||
|  |     @JsonProperty("imageable_type") val imageableType: String, | ||||||
|  |     @JsonProperty("server_id") val serverID: Long, | ||||||
|  |     @JsonProperty("proxy_id") val proxyID: Long, | ||||||
|  |     @JsonProperty("url") val url: String, | ||||||
|  |     @JsonProperty("type") val type: String, | ||||||
|  |     @JsonProperty("sc_url") val scURL: String, | ||||||
|  |     @JsonProperty("proxy") val proxy: Proxy, | ||||||
|  |     @JsonProperty("server") val server: Proxy | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class Proxy( | ||||||
|  |     @JsonProperty("id") val id: Long, | ||||||
|  |     @JsonProperty("type") val type: String, | ||||||
|  |     @JsonProperty("ip") val ip: String, | ||||||
|  |     @JsonProperty("number") val number: Long, | ||||||
|  |     @JsonProperty("storage") val storage: Long, | ||||||
|  |     @JsonProperty("max_storage") val maxStorage: Long, | ||||||
|  |     @JsonProperty("max_conversions") val maxConversions: Any? = null, | ||||||
|  |     @JsonProperty("max_publications") val maxPublications: Any? = null, | ||||||
|  |     @JsonProperty("created_at") val createdAt: String, | ||||||
|  |     @JsonProperty("updated_at") val updatedAt: String, | ||||||
|  |     @JsonProperty("upload_bandwidth") val uploadBandwidth: Any? = null, | ||||||
|  |     @JsonProperty("upload_bandwidth_limit") val uploadBandwidthLimit: Any? = null | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class Season( | ||||||
|  |     @JsonProperty("id") val id: Long, | ||||||
|  |     @JsonProperty("name") val name: String? = "", | ||||||
|  |     @JsonProperty("plot") val plot: String? = "", | ||||||
|  |     @JsonProperty("date") val date: String? = "", | ||||||
|  |     @JsonProperty("number") val number: Long, | ||||||
|  |     @JsonProperty("title_id") val title_id: Long, | ||||||
|  |     @JsonProperty("createdAt") val createdAt: String? = "", | ||||||
|  |     @JsonProperty("updated_at") val updatedAt: String? = "", | ||||||
|  |     @JsonProperty("episodes") val episodes: List<Episodejson> | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class Episodejson( | ||||||
|  |     @JsonProperty("id") val id: Long, | ||||||
|  |     @JsonProperty("number") val number: Long, | ||||||
|  |     @JsonProperty("name") val name: String? = "", | ||||||
|  |     @JsonProperty("plot") val plot: String? = "", | ||||||
|  |     @JsonProperty("season_id") val seasonID: Long, | ||||||
|  |     @JsonProperty("images") val images: List<ImageSeason> | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class ImageSeason( | ||||||
|  |     @JsonProperty("imageable_id") val imageableID: Long, | ||||||
|  |     @JsonProperty("imageable_type") val imageableType: String, | ||||||
|  |     @JsonProperty("server_id") val serverID: Long, | ||||||
|  |     @JsonProperty("proxy_id") val proxyID: Long, | ||||||
|  |     @JsonProperty("url") val url: String, | ||||||
|  |     @JsonProperty("type") val type: String, | ||||||
|  |     @JsonProperty("original_url") val originalURL: String | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | data class TrailerElement( | ||||||
|  |     @JsonProperty("id") val id: Long? = null, | ||||||
|  |     @JsonProperty("url") val url: String? = null, | ||||||
|  |     @JsonProperty("host") val host: String? = null, | ||||||
|  |     @JsonProperty("videoable_id") val videoableID: Long? = null, | ||||||
|  |     @JsonProperty("videoable_type") val videoableType: String? = null, | ||||||
|  |     @JsonProperty("created_at") val createdAt: String? = null, | ||||||
|  |     @JsonProperty("updated_at") val updatedAt: String? = null, | ||||||
|  |     @JsonProperty("size") val size: String? = null, | ||||||
|  |     @JsonProperty("created_by") val createdBy: String? = null, | ||||||
|  |     @JsonProperty("server_id") val serverID: Long? = null, | ||||||
|  |     @JsonProperty("name") val name: String? = null, | ||||||
|  |     @JsonProperty("quality") val quality: String? = null, | ||||||
|  |     @JsonProperty("original_name") val originalName: Any? = null, | ||||||
|  |     @JsonProperty("views") val views: Long? = null, | ||||||
|  |     @JsonProperty("public") val public: Long? = null, | ||||||
|  |     @JsonProperty("proxy_id") val proxyID: Any? = null, | ||||||
|  |     @JsonProperty("proxy_default_id") val proxyDefaultID: Any? = null, | ||||||
|  |     @JsonProperty("scws_id") val scwsID: Any? = null | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class StreamingcommunityProvider : MainAPI() { | ||||||
|  |     override val lang = "it" | ||||||
|  |     override var mainUrl = "https://streamingcommunity.top" | ||||||
|  |     override var name = "Streamingcommunity" | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasChromecastSupport = true | ||||||
|  |     override val supportedTypes = setOf( | ||||||
|  |         TvType.Movie, | ||||||
|  |         TvType.TvSeries, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     private fun translatenumber(num: Int): Int? { | ||||||
|  |         return when (num) { | ||||||
|  |             67 -> 1 | ||||||
|  |             71 -> 2 | ||||||
|  |             72 -> 3 | ||||||
|  |             73 -> 4 | ||||||
|  |             74 -> 5 | ||||||
|  |             75 -> 6 | ||||||
|  |             76 -> 7 | ||||||
|  |             77 -> 8 | ||||||
|  |             78 -> 9 | ||||||
|  |             79 -> 10 | ||||||
|  |             133 -> 11 | ||||||
|  |             else -> null | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun translateip(num: Int): String? { | ||||||
|  |         return when (num) { | ||||||
|  |             16 -> "sc-b1-01.scws-content.net" | ||||||
|  |             17 -> "sc-b1-02.scws-content.net" | ||||||
|  |             18 -> "sc-b1-03.scws-content.net" | ||||||
|  |             85 -> "sc-b1-04.scws-content.net" | ||||||
|  |             95 -> "sc-b1-05.scws-content.net" | ||||||
|  |             117 -> "sc-b1-06.scws-content.net" | ||||||
|  |             141 -> "sc-b1-07.scws-content.net" | ||||||
|  |             142 -> "sc-b1-08.scws-content.net" | ||||||
|  |             143 -> "sc-b1-09.scws-content.net" | ||||||
|  |             144 -> "sc-b1-10.scws-content.net" | ||||||
|  |             else -> null | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         val posterMap = hashMapOf<String, String>() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|  |         val items = ArrayList<HomePageList>() | ||||||
|  |         val document = app.get(mainUrl).document | ||||||
|  |         document.select("slider-title").subList(2, 6).map { it -> | ||||||
|  |             if (it.attr("slider-name") != "In arrivo") { | ||||||
|  |                 val films = it.attr("titles-json") | ||||||
|  |                 val lista = mutableListOf<MovieSearchResponse>() | ||||||
|  |                 val videoData = parseJson<List<VideoElement>>(films) | ||||||
|  | 
 | ||||||
|  |                 videoData.subList(0, 12).map { searchr -> | ||||||
|  |                     val id = searchr.id | ||||||
|  |                     val name = searchr.slug | ||||||
|  |                     val img = searchr.images[0].url | ||||||
|  |                     val number = translatenumber(searchr.images[0].serverID.toInt()) | ||||||
|  |                     val ip = translateip(searchr.images[0].proxyID.toInt()) | ||||||
|  |                     val posterurl = "https://$ip/images/$number/$img" | ||||||
|  |                     val videourl = "$mainUrl/titles/$id-$name" | ||||||
|  |                     posterMap[videourl] = posterurl | ||||||
|  |                     val data = app.post("$mainUrl/api/titles/preview/$id", referer = mainUrl).text | ||||||
|  |                     val datajs = parseJson<Moviedata>(data) | ||||||
|  |                     val type: TvType = if (datajs.type == "movie") { | ||||||
|  |                         TvType.Movie | ||||||
|  |                     } else { | ||||||
|  |                         TvType.TvSeries | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     lista.add( | ||||||
|  |                         MovieSearchResponse( | ||||||
|  |                             datajs.name, | ||||||
|  |                             videourl, | ||||||
|  |                             this.name, | ||||||
|  |                             type, | ||||||
|  |                             posterurl, | ||||||
|  |                             datajs.releaseDate.substringBefore("-").filter { it.isDigit() } | ||||||
|  |                                 .toIntOrNull(), | ||||||
|  |                             null, | ||||||
|  |                         ) | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |                 items.add(HomePageList(it.attr("slider-name"), lista)) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (items.size <= 0) throw ErrorLoadingException() | ||||||
|  |         return HomePageResponse(items) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|  |         val queryformatted = query.replace(" ", "%20") | ||||||
|  |         val url = "$mainUrl/search?q=$queryformatted" | ||||||
|  |         val document = app.get(url).document | ||||||
|  | 
 | ||||||
|  |         val films = | ||||||
|  |             document.selectFirst("the-search-page").attr("records-json").replace(""", """"""") | ||||||
|  | 
 | ||||||
|  |         val searchresults = parseJson<List<VideoElement>>(films) | ||||||
|  |         return searchresults.map { result -> | ||||||
|  |             val id = result.id | ||||||
|  |             val name = result.slug | ||||||
|  |             val img = result.images[0].url | ||||||
|  |             val number = translatenumber(result.images[0].serverID.toInt()) | ||||||
|  |             val ip = translateip(result.images[0].proxyID.toInt()) | ||||||
|  |             val data = app.post("$mainUrl/api/titles/preview/$id", referer = mainUrl).text | ||||||
|  |             val datajs = parseJson<Moviedata>(data) | ||||||
|  |             val posterurl = "https://$ip/images/$number/$img" | ||||||
|  |             val videourl = "$mainUrl/titles/$id-$name" | ||||||
|  |             posterMap[videourl] = posterurl | ||||||
|  |             if (datajs.type == "movie") { | ||||||
|  |                 val type = TvType.Movie | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     datajs.name, | ||||||
|  |                     videourl, | ||||||
|  |                     this.name, | ||||||
|  |                     type, | ||||||
|  |                     posterurl, | ||||||
|  |                     datajs.releaseDate.substringBefore("-").filter { it.isDigit() }.toIntOrNull(), | ||||||
|  |                     null, | ||||||
|  |                 ) | ||||||
|  |             } else { | ||||||
|  |                 val type = TvType.TvSeries | ||||||
|  |                 TvSeriesSearchResponse( | ||||||
|  |                     datajs.name, | ||||||
|  |                     videourl, | ||||||
|  |                     this.name, | ||||||
|  |                     type, | ||||||
|  |                     posterurl, | ||||||
|  |                     datajs.releaseDate.substringBefore("-").filter { it.isDigit() }.toIntOrNull(), | ||||||
|  |                     null, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun load(url: String): LoadResponse { | ||||||
|  | 
 | ||||||
|  |         val document = app.get(url).document | ||||||
|  |         val poster = posterMap[url] | ||||||
|  |         val id = url.substringBefore("-").filter { it.isDigit() } | ||||||
|  |         val data = app.post("$mainUrl/api/titles/preview/$id", referer = mainUrl).text | ||||||
|  | 
 | ||||||
|  |         val datajs = parseJson<Moviedata>(data) | ||||||
|  |         val type: TvType = if (datajs.type == "movie") { | ||||||
|  |             TvType.Movie | ||||||
|  |         } else { | ||||||
|  |             TvType.TvSeries | ||||||
|  |         } | ||||||
|  |         val trailerinfojs = document.select("slider-trailer").attr("videos") | ||||||
|  |         val trailerinfo = parseJson<List<TrailerElement>>(trailerinfojs) | ||||||
|  |         val trailerurl: String? = if (trailerinfo.isNotEmpty()) { | ||||||
|  |             "https://www.youtube.com/watch?v=${trailerinfo[0].id}" | ||||||
|  |         } else { | ||||||
|  |             null | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         val year = datajs.releaseDate.substringBefore("-") | ||||||
|  | 
 | ||||||
|  |         val correlatijs = document.selectFirst("slider-title").attr("titles-json") | ||||||
|  |         val listacorr = mutableListOf<MovieSearchResponse>() | ||||||
|  |         val correlatidata = parseJson<List<VideoElement>>(correlatijs) | ||||||
|  |         val number : Int = if (correlatidata.size<=15) {correlatidata.size} else correlatidata.size-15 | ||||||
|  | 
 | ||||||
|  |         correlatidata.take(number).map { searchr -> | ||||||
|  |             val idcorr = searchr.id | ||||||
|  |             val name = searchr.slug | ||||||
|  |             val img = searchr.images[0].url | ||||||
|  |             val number = translatenumber(searchr.images[0].serverID.toInt()) | ||||||
|  |             val ip = translateip(searchr.images[0].proxyID.toInt()) | ||||||
|  |             val datacorrel = app.post("$mainUrl/api/titles/preview/$idcorr", referer = mainUrl).text | ||||||
|  |             val datajscorrel = parseJson<Moviedata>(datacorrel) | ||||||
|  |             val videourl = "$mainUrl/titles/$idcorr-$name" | ||||||
|  |             val posterurl = "https://$ip/images/$number/$img" | ||||||
|  | 
 | ||||||
|  |             posterMap[videourl] = posterurl | ||||||
|  |             val typecorr: TvType = if (datajscorrel.type == "movie") { | ||||||
|  |                 TvType.Movie | ||||||
|  |             } else { | ||||||
|  |                 TvType.TvSeries | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             listacorr.add( | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     datajscorrel.name, | ||||||
|  |                     videourl, | ||||||
|  |                     this.name, | ||||||
|  |                     typecorr, | ||||||
|  |                     posterurl, | ||||||
|  |                     datajscorrel.releaseDate.substringBefore("-").filter { it.isDigit() } | ||||||
|  |                         .toIntOrNull(), | ||||||
|  |                     null, | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (type == TvType.TvSeries) { | ||||||
|  | 
 | ||||||
|  |             val name = datajs.name | ||||||
|  |             val episodeList = arrayListOf<Episode>() | ||||||
|  | 
 | ||||||
|  |             val episodes = | ||||||
|  |                 Html.fromHtml(document.selectFirst("season-select").attr("seasons")).toString() | ||||||
|  |             val jsonEpisodes = parseJson<List<Season>>(episodes) | ||||||
|  | 
 | ||||||
|  |             jsonEpisodes.map { seasons -> | ||||||
|  |                 val stagione = seasons.number.toInt() | ||||||
|  |                 val sid = seasons.title_id | ||||||
|  |                 val episodio = seasons.episodes | ||||||
|  |                 episodio.map { ep -> | ||||||
|  |                     val href = "$mainUrl/watch/$sid?e=${ep.id}" | ||||||
|  |                     val postimage = if (ep.images.isNotEmpty()) { | ||||||
|  |                         ep.images.first().originalURL | ||||||
|  |                     } else { | ||||||
|  |                         "" | ||||||
|  |                     } | ||||||
|  |                     episodeList.add( | ||||||
|  | 
 | ||||||
|  |                         newEpisode(href) { | ||||||
|  |                             this.name = ep.name | ||||||
|  |                             this.season = stagione | ||||||
|  |                             this.episode = ep.number.toInt() | ||||||
|  |                             this.description = ep.plot | ||||||
|  |                             this.posterUrl = postimage | ||||||
|  |                         } | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |             if (episodeList.isEmpty()) throw ErrorLoadingException("No Seasons Found") | ||||||
|  | 
 | ||||||
|  |             return newTvSeriesLoadResponse(name, url, type, episodeList) { | ||||||
|  |                 this.posterUrl = poster | ||||||
|  |                 this.year = year.filter { it.isDigit() }.toInt() | ||||||
|  |                 this.plot = document.selectFirst("div.plot-wrap > p").text() | ||||||
|  |                 this.duration = datajs.runtime?.toInt() | ||||||
|  |                 this.rating = (datajs.votes[0].average.toFloatOrNull()?.times(1000))?.toInt() | ||||||
|  |                 this.tags = datajs.genres.map { it.name } | ||||||
|  |                 addTrailer(trailerurl) | ||||||
|  |                 this.recommendations = listacorr | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  | 
 | ||||||
|  |             return newMovieLoadResponse( | ||||||
|  |                 document.selectFirst("div > div > h1").text(), | ||||||
|  |                 document.select("a.play-hitzone").attr("href"), | ||||||
|  |                 type, | ||||||
|  |                 document.select("a.play-hitzone").attr("href") | ||||||
|  |             ) { | ||||||
|  |                 posterUrl = fixUrlNull(poster) | ||||||
|  |                 this.year = year.filter { it.isDigit() }.toInt() | ||||||
|  |                 this.plot = document.selectFirst("p.plot").text() | ||||||
|  |                 this.rating = datajs.votes[0].average.toFloatOrNull()?.times(1000)?.toInt() | ||||||
|  |                 this.tags = datajs.genres.map { it.name } | ||||||
|  |                 this.duration = datajs.runtime?.toInt() | ||||||
|  |                 addTrailer(trailerurl) | ||||||
|  |                 this.recommendations = listacorr | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     private fun getM3u8Qualities( | ||||||
|  |         m3u8Link: String, | ||||||
|  |         referer: String, | ||||||
|  |         qualityName: String, | ||||||
|  |     ): List<ExtractorLink> { | ||||||
|  |         return M3u8Helper.generateM3u8( | ||||||
|  |             this.name, | ||||||
|  |             m3u8Link, | ||||||
|  |             referer, | ||||||
|  |             name = "${this.name} - $qualityName" | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     override suspend fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         val ip = app.get("https://api.ipify.org/").text | ||||||
|  |         val videors = app.get(data).document | ||||||
|  |         val scwsidjs = videors.select("video-player").attr("response").replace(""", """"""") | ||||||
|  |         val jsn = JSONObject(scwsidjs) | ||||||
|  |         val scwsid = jsn.getString("scws_id") | ||||||
|  |         val expire = (System.currentTimeMillis() / 1000 + 172800).toString() | ||||||
|  | 
 | ||||||
|  |         val uno = "$expire$ip Yc8U6r8KjAKAepEA".toByteArray() | ||||||
|  |         val due = MessageDigest.getInstance("MD5").digest(uno) | ||||||
|  |         val tre = base64Encode(due) | ||||||
|  |         val token = tre.replace("=", "").replace("+", "-").replace("/", "_") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         val link = "https://scws.xyz/master/$scwsid?token=$token&expires=$expire&n=1&n=1" | ||||||
|  |         getM3u8Qualities(link, data, URI(link).host).forEach(callback) | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,243 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.mvvm.logError | ||||||
|  | import com.lagradost.cloudstream3.app | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | 
 | ||||||
|  | class TantifilmProvider : MainAPI() { | ||||||
|  |     override val lang = "it" | ||||||
|  |     override var mainUrl = "https://www.tantifilm.rodeo" | ||||||
|  |     override var name = "Tantifilm" | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasChromecastSupport = true | ||||||
|  |     override val supportedTypes = setOf( | ||||||
|  |         TvType.Movie, | ||||||
|  |         TvType.TvSeries, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|  |         val items = ArrayList<HomePageList>() | ||||||
|  |         val urls = listOf( | ||||||
|  |             Pair("$mainUrl/watch-genre/serie-tv/", "Serie Tv"), | ||||||
|  |             Pair("$mainUrl/watch-genre/azione/", "Azione"), | ||||||
|  |             Pair("$mainUrl/watch-genre/avventura/", "Avventura"), | ||||||
|  |         ) | ||||||
|  |         for ((url, name) in urls) { | ||||||
|  |             try { | ||||||
|  |                 val soup = app.get(url).document | ||||||
|  |                 val home = soup.select("div.media3").map { | ||||||
|  |                     val title = it.selectFirst("p").text().substringBefore("(") | ||||||
|  |                     val link = it.selectFirst("a").attr("href") | ||||||
|  |                     TvSeriesSearchResponse( | ||||||
|  |                         title, | ||||||
|  |                         link, | ||||||
|  |                         this.name, | ||||||
|  |                         TvType.Movie, | ||||||
|  |                         it.selectFirst("img").attr("src"), | ||||||
|  |                         null, | ||||||
|  |                         null, | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 items.add(HomePageList(name, home)) | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 logError(e) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (items.size <= 0) throw ErrorLoadingException() | ||||||
|  |         return HomePageResponse(items) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|  |         val queryformatted = query.replace(" ", "+") | ||||||
|  |         val url = "$mainUrl/search/$queryformatted" | ||||||
|  |         val doc = app.get(url).document | ||||||
|  |         return doc.select("div.film.film-2").map { | ||||||
|  |             val href = it.selectFirst("a").attr("href") | ||||||
|  |             val poster = it.selectFirst("img").attr("src") | ||||||
|  |             val name = it.selectFirst("a").text().substringBefore("(") | ||||||
|  |             MovieSearchResponse( | ||||||
|  |                 name, | ||||||
|  |                 href, | ||||||
|  |                 this.name, | ||||||
|  |                 TvType.Movie, | ||||||
|  |                 poster, | ||||||
|  |                 null | ||||||
|  |             ) | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     override suspend fun load(url: String): LoadResponse { | ||||||
|  |         val document = app.get(url).document | ||||||
|  |         val type = if (document.selectFirst("div.category-film").text().contains("Serie") | ||||||
|  |                 .not() | ||||||
|  |         ) TvType.Movie else TvType.TvSeries | ||||||
|  |         val title = document.selectFirst("div.title-film-left").text().substringBefore("(") | ||||||
|  |         val descipt = document.select("div.content-left-film > p").map { it.text() } | ||||||
|  |         val rating = | ||||||
|  |             document.selectFirst("div.star-rating.star-rating-f > span > span") | ||||||
|  |                 .attr("data-rateit-value")?.toFloatOrNull() | ||||||
|  |                 ?.times(2857)?.toInt()?.let { minOf(it, 10000) } | ||||||
|  | 
 | ||||||
|  |         var year = document.selectFirst("div.title-film-left").text().substringAfter("(") | ||||||
|  |             .filter { it.isDigit() } | ||||||
|  |         if (year.length > 4) { | ||||||
|  |             year = year.dropLast(4) | ||||||
|  |         } else { | ||||||
|  |             year = year | ||||||
|  |         } | ||||||
|  |         // ?: does not wor | ||||||
|  |         val poster = document.selectFirst("div.image-right-film > img").attr("src") | ||||||
|  | 
 | ||||||
|  |         val recomm = document.select("div.mediaWrap.mediaWrapAlt.recomended_videos").map { | ||||||
|  |             val href = it.selectFirst("a").attr("href") | ||||||
|  |             val poster = it.selectFirst("img").attr("src") | ||||||
|  |             val name = it.selectFirst("a").attr("title").substringBeforeLast("(") | ||||||
|  |             MovieSearchResponse( | ||||||
|  |                 name, | ||||||
|  |                 href, | ||||||
|  |                 this.name, | ||||||
|  |                 TvType.Movie, | ||||||
|  |                 poster, | ||||||
|  |                 null | ||||||
|  |             ) | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         if (type == TvType.TvSeries) { | ||||||
|  |             val list = ArrayList<Pair<Int, String>>() | ||||||
|  |             val urlvideocontainer = document.selectFirst("iframe").attr("src") | ||||||
|  |             val videocontainer = app.get(urlvideocontainer).document | ||||||
|  |             videocontainer.select("nav.nav1 > select > option").forEach { element -> | ||||||
|  |                 val season = element.text()?.toIntOrNull() | ||||||
|  |                 val href = element.attr("value") | ||||||
|  |                 if (season != null && season > 0 && !href.isNullOrBlank()) { | ||||||
|  |                     list.add(Pair(season, fixUrl(href))) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") | ||||||
|  | 
 | ||||||
|  |             val episodeList = ArrayList<Episode>() | ||||||
|  | 
 | ||||||
|  |             for ((season,seasonurl) in list) { | ||||||
|  |                 val seasonDocument = app.get(seasonurl).document | ||||||
|  |                 val episodes = seasonDocument.select("nav.second_nav > select > option") | ||||||
|  |                 if (episodes.isNotEmpty()) { | ||||||
|  |                     episodes.forEach { episode -> | ||||||
|  |                         val href = episode.attr("value") | ||||||
|  |                         val epNum = episode.text()?.toIntOrNull() | ||||||
|  |                         episodeList.add( | ||||||
|  |                             Episode( | ||||||
|  |                                 href, | ||||||
|  |                                 title, | ||||||
|  |                                 season, | ||||||
|  |                                 epNum, | ||||||
|  |                             ) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return TvSeriesLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url, | ||||||
|  |                 this.name, | ||||||
|  |                 type, | ||||||
|  |                 episodeList, | ||||||
|  |                 fixUrlNull(poster), | ||||||
|  |                 year?.toIntOrNull(), | ||||||
|  |                 descipt[0], | ||||||
|  |                 null, | ||||||
|  |                 rating, | ||||||
|  |                 null, | ||||||
|  |                 null, | ||||||
|  |                 null, | ||||||
|  |                 recomm | ||||||
|  |             ) | ||||||
|  |         } else { | ||||||
|  |             val url2 = document.selectFirst("iframe").attr("src") | ||||||
|  |             val actorpagelink = | ||||||
|  |                 document.select("div.content-left-film > p:nth-child(2) > a").attr("href") | ||||||
|  |             val actorpagelink2 = document.select("div.content-left-film > p > a").attr("href") | ||||||
|  |             val Linkactor: String = if (actorpagelink.isNotEmpty()) { | ||||||
|  |                 actorpagelink | ||||||
|  |             } else { | ||||||
|  |                 actorpagelink2 | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             val actors: List<ActorData>? = if (Linkactor.isNotEmpty()) { | ||||||
|  |                 val actorpage = app.get(Linkactor + "cast/").document | ||||||
|  |                 actorpage.select("article.membro-cast")?.filter { | ||||||
|  |                     it.selectFirst("img") | ||||||
|  |                         ?.attr("src") != "https://www.filmtv.it/imgbank/DUMMY/no_portrait.jpg" | ||||||
|  |                 }?.mapNotNull { it -> | ||||||
|  |                     val name = it.selectFirst("div.info > h3").text() | ||||||
|  |                     val image = it.selectFirst("img")?.attr("src") | ||||||
|  |                     val roleString: String = if (it.selectFirst("h2")?.text() == "Regia") { | ||||||
|  |                         "Regia" | ||||||
|  |                     } else { | ||||||
|  |                         "Attore" | ||||||
|  |                     } | ||||||
|  |                     val mainActor = Actor(name, image) | ||||||
|  |                     ActorData(actor = mainActor, roleString = roleString) | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 null | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |             val duratio: Int? = if (descipt.size == 2) { | ||||||
|  |                 descipt[0].filter { it.isDigit() }.toInt() | ||||||
|  |             } else { | ||||||
|  |                 null | ||||||
|  |             } | ||||||
|  |             val tags: List<String>? = if (descipt.size == 2) { | ||||||
|  |                 descipt[0].let { mutableListOf(it.substringBefore(" ")) } | ||||||
|  |             } else { | ||||||
|  |                 null | ||||||
|  |             } | ||||||
|  |             val plot: String = if (descipt.size == 2) { | ||||||
|  |                 descipt[1] | ||||||
|  |             } else { | ||||||
|  |                 descipt[0] | ||||||
|  |             } | ||||||
|  |             return newMovieLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url2, | ||||||
|  |                 type, | ||||||
|  |                 url2 | ||||||
|  |             ) { | ||||||
|  |                 posterUrl = fixUrlNull(poster) | ||||||
|  |                 this.year = year?.toIntOrNull() | ||||||
|  |                 this.plot = plot | ||||||
|  |                 this.rating = rating | ||||||
|  |                 this.recommendations = recomm | ||||||
|  |                 this.tags = tags | ||||||
|  |                 this.duration = duratio | ||||||
|  |                 this.actors = actors | ||||||
|  | 
 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         val doc = app.get(data).document | ||||||
|  |         val iframe = | ||||||
|  |             doc.select("option").map { fixUrl(it.attr("value")) }.filter { it.contains("label") } | ||||||
|  |         iframe.forEach { id -> | ||||||
|  |             val doc2 = app.get(id).document | ||||||
|  |             val id2 = app.get(doc2.selectFirst("iframe").attr("src")).url | ||||||
|  |             loadExtractor(id2, data, callback) | ||||||
|  |         } | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue