forked from recloudstream/cloudstream
		
	4 new spanish providers and extractors (#556)
* Cuevana, Pelisflix, Seriesflix, EntrePeliculasySeries, Okru Extractor Co-authored-by: Osten <balt.758@gmail.com>
This commit is contained in:
		
							parent
							
								
									5053dff3f2
								
							
						
					
					
						commit
						bd14fad607
					
				
					 9 changed files with 952 additions and 0 deletions
				
			
		
							
								
								
									
										1
									
								
								.idea/gradle.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/gradle.xml
									
										
									
										generated
									
									
									
								
							|  | @ -8,6 +8,7 @@ | ||||||
|         <option name="testRunner" value="GRADLE" /> |         <option name="testRunner" value="GRADLE" /> | ||||||
|         <option name="distributionType" value="DEFAULT_WRAPPED" /> |         <option name="distributionType" value="DEFAULT_WRAPPED" /> | ||||||
|         <option name="externalProjectPath" value="$PROJECT_DIR$" /> |         <option name="externalProjectPath" value="$PROJECT_DIR$" /> | ||||||
|  |         <option name="gradleJvm" value="11" /> | ||||||
|         <option name="modules"> |         <option name="modules"> | ||||||
|           <set> |           <set> | ||||||
|             <option value="$PROJECT_DIR$" /> |             <option value="$PROJECT_DIR$" /> | ||||||
|  |  | ||||||
|  | @ -44,6 +44,10 @@ object APIHolder { | ||||||
|         DubbedAnimeProvider(), |         DubbedAnimeProvider(), | ||||||
|         DoramasYTProvider(), |         DoramasYTProvider(), | ||||||
|         CinecalidadProvider(), |         CinecalidadProvider(), | ||||||
|  |         CuevanaProvider(), | ||||||
|  |         EntrepeliculasyseriesProvider(), | ||||||
|  |         PelisflixProvider(), | ||||||
|  |         SeriesflixProvider(), | ||||||
|         IHaveNoTvProvider(), // Documentaries provider |         IHaveNoTvProvider(), // Documentaries provider | ||||||
|         //LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...) |         //LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...) | ||||||
|         VMoveeProvider(), |         VMoveeProvider(), | ||||||
|  |  | ||||||
|  | @ -0,0 +1,35 @@ | ||||||
|  | package com.lagradost.cloudstream3.extractors | ||||||
|  | 
 | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | import com.lagradost.cloudstream3.app | ||||||
|  | 
 | ||||||
|  | open class OkRu : ExtractorApi() { | ||||||
|  |     override val name = "Okru" | ||||||
|  |     override val mainUrl = "http://ok.ru" | ||||||
|  |     override val requiresReferer = false | ||||||
|  | 
 | ||||||
|  |     override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||||
|  |         val doc = app.get(url).document | ||||||
|  |         val urlString = doc.select("div[data-options]").attr("data-options") | ||||||
|  |             .substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") | ||||||
|  |             .substringBefore("]") | ||||||
|  |         urlString.split("{\\\"name\\\":\\\"").reversed().forEach { | ||||||
|  |             val extractedUrl = it.substringAfter("url\\\":\\\"") | ||||||
|  |                 .substringBefore("\\\"") | ||||||
|  |                 .replace("\\\\u0026", "&") | ||||||
|  |             val Quality = it.uppercase().substringBefore("\\\"") | ||||||
|  | 
 | ||||||
|  |             if (extractedUrl.isNotBlank())  return listOf( | ||||||
|  |                 ExtractorLink( | ||||||
|  |                     name, | ||||||
|  |                     "$name ${Quality}", | ||||||
|  |                     extractedUrl, | ||||||
|  |                     url, | ||||||
|  |                     Qualities.Unknown.value, | ||||||
|  |                     isM3u8 = false | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |         return null | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,39 @@ | ||||||
|  | package com.lagradost.cloudstream3.extractors | ||||||
|  | 
 | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | import com.lagradost.cloudstream3.app | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
|  | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
|  | 
 | ||||||
|  | class Cinestart: Tomatomatela() { | ||||||
|  |     override val name: String = "Cinestart" | ||||||
|  |     override val mainUrl: String = "https://cinestart.net" | ||||||
|  |     override val details = "vr.php?v=" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | open class Tomatomatela : ExtractorApi() { | ||||||
|  |     override val name = "Tomatomatela" | ||||||
|  |     override val mainUrl = "https://tomatomatela.com" | ||||||
|  |     override val requiresReferer = false | ||||||
|  |     private data class Tomato ( | ||||||
|  |         @JsonProperty("status") val status: Int, | ||||||
|  |         @JsonProperty("file") val file: String | ||||||
|  |     ) | ||||||
|  |     open val details = "details.php?v=" | ||||||
|  |     override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||||
|  |         val link = url.replace("$mainUrl/embed.html#","$mainUrl/$details") | ||||||
|  |         val server = app.get(link, allowRedirects = false).text | ||||||
|  |         val json = parseJson<Tomato>(server) | ||||||
|  |         if (json.status == 200) return listOf( | ||||||
|  |             ExtractorLink( | ||||||
|  |                 name, | ||||||
|  |                 name, | ||||||
|  |                 json.file, | ||||||
|  |                 "", | ||||||
|  |                 Qualities.Unknown.value, | ||||||
|  |                 isM3u8 = false | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         return null | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,251 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
|  | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.mvvm.logError | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | import java.util.* | ||||||
|  | 
 | ||||||
|  | class CuevanaProvider:MainAPI() { | ||||||
|  |     override val mainUrl = "https://cuevana3.io" | ||||||
|  |     override val name = "Cuevana" | ||||||
|  |     override val lang = "es" | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasChromecastSupport = true | ||||||
|  |     override val hasDownloadSupport = true | ||||||
|  |     override val supportedTypes = setOf( | ||||||
|  |         TvType.Movie, | ||||||
|  |         TvType.TvSeries, | ||||||
|  |     ) | ||||||
|  |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|  |         val items = ArrayList<HomePageList>() | ||||||
|  |         val urls = listOf( | ||||||
|  |             Pair(mainUrl, "Recientemente actualizadas"), | ||||||
|  |             Pair("$mainUrl/estrenos/", "Estrenos"), | ||||||
|  |         ) | ||||||
|  |         for (i in urls) { | ||||||
|  |             try { | ||||||
|  |                 val soup = app.get(i.first).document | ||||||
|  |                 val home = soup.select("section li.xxx.TPostMv").map { | ||||||
|  |                     val title = it.selectFirst("h2.Title").text() | ||||||
|  |                     val link = it.selectFirst("a").attr("href") | ||||||
|  |                     TvSeriesSearchResponse( | ||||||
|  |                         title, | ||||||
|  |                         link, | ||||||
|  |                         this.name, | ||||||
|  |                         if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries, | ||||||
|  |                         it.selectFirst("img.lazy").attr("data-src"), | ||||||
|  |                         null, | ||||||
|  |                         null, | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 items.add(HomePageList(i.second, home)) | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 logError(e) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (items.size <= 0) throw ErrorLoadingException() | ||||||
|  |         return HomePageResponse(items) | ||||||
|  |     } | ||||||
|  |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|  |         val url = "$mainUrl/?s=${query}" | ||||||
|  |         val document = app.get(url).document | ||||||
|  | 
 | ||||||
|  |         return document.select("li.xxx.TPostMv").map { | ||||||
|  |             val title = it.selectFirst("h2.Title").text() | ||||||
|  |             val href = it.selectFirst("a").attr("href") | ||||||
|  |             val image = it.selectFirst("img.lazy").attr("data-src") | ||||||
|  |             val isSerie = href.contains("/serie/") | ||||||
|  | 
 | ||||||
|  |             if (isSerie) { | ||||||
|  |                 TvSeriesSearchResponse( | ||||||
|  |                     title, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.TvSeries, | ||||||
|  |                     image, | ||||||
|  |                     null, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } else { | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     title, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.Movie, | ||||||
|  |                     image, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         }.toList() | ||||||
|  |     } | ||||||
|  |     override suspend fun load(url: String): LoadResponse? { | ||||||
|  |         val soup = app.get(url, timeout = 120).document | ||||||
|  |         val title = soup.selectFirst("h1.Title").text() | ||||||
|  |         val description = soup.selectFirst(".Description p")?.text()?.trim() | ||||||
|  |         val poster: String? = soup.selectFirst(".movtv-info div.Image img").attr("data-src") | ||||||
|  |         val year1 = soup.selectFirst("footer p.meta").toString() | ||||||
|  |         val yearRegex = Regex("(\\d+)<\\/span>") | ||||||
|  |         val year =  yearRegex.findAll(year1).map { | ||||||
|  |             it.value.replace("</span>","") | ||||||
|  |         }.toList().first().toIntOrNull() | ||||||
|  |         val episodes = soup.select(".all-episodes li.TPostMv article").map { li -> | ||||||
|  |             val href = li.select("a").attr("href") | ||||||
|  |             val epThumb = | ||||||
|  |                 li.selectFirst("div.Image img").attr("data-src") ?: li.selectFirst("img.lazy").attr("data-srcc") | ||||||
|  |             val name = li.selectFirst("h2.Title").text() | ||||||
|  |             TvSeriesEpisode( | ||||||
|  |                 name, | ||||||
|  |                 null, | ||||||
|  |                 null, | ||||||
|  |                 href, | ||||||
|  |                 fixUrl(epThumb) | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |         return when (val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries) { | ||||||
|  |             TvType.TvSeries -> { | ||||||
|  |                 TvSeriesLoadResponse( | ||||||
|  |                     title, | ||||||
|  |                     url, | ||||||
|  |                     this.name, | ||||||
|  |                     tvType, | ||||||
|  |                     episodes, | ||||||
|  |                     poster, | ||||||
|  |                     year, | ||||||
|  |                     description, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             TvType.Movie -> { | ||||||
|  |                 MovieLoadResponse( | ||||||
|  |                     title, | ||||||
|  |                     url, | ||||||
|  |                     this.name, | ||||||
|  |                     tvType, | ||||||
|  |                     url, | ||||||
|  |                     poster, | ||||||
|  |                     year, | ||||||
|  |                     description, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             else -> null | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     data class Femcuevana( | ||||||
|  |         @JsonProperty("url") val url: String, | ||||||
|  |     ) | ||||||
|  |     override suspend fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         app.get(data).document.select("div.TPlayer.embed_div iframe").apmap { | ||||||
|  |             val iframe = fixUrl(it.attr("data-src")) | ||||||
|  |             if (iframe.contains("api.cuevana3.io/fembed/")) { | ||||||
|  |                 val femregex = Regex("(https.\\/\\/api\\.cuevana3\\.io\\/fembed\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|  |                 femregex.findAll(iframe).map { femreg -> | ||||||
|  |                     femreg.value | ||||||
|  |                 }.toList().apmap { fem -> | ||||||
|  |                     val key = fem.replace("https://api.cuevana3.io/fembed/?h=","") | ||||||
|  |                     val url = app.post("https://api.cuevana3.io/fembed/api.php", allowRedirects = false, headers = mapOf("Host" to "api.cuevana3.io", | ||||||
|  |                         "User-Agent" to USER_AGENT, | ||||||
|  |                         "Accept" to "application/json, text/javascript, */*; q=0.01", | ||||||
|  |                         "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  |                         "Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8", | ||||||
|  |                         "X-Requested-With" to "XMLHttpRequest", | ||||||
|  |                         "Origin" to "https://api.cuevana3.io", | ||||||
|  |                         "DNT" to "1", | ||||||
|  |                         "Connection" to "keep-alive", | ||||||
|  |                         "Sec-Fetch-Dest" to "empty", | ||||||
|  |                         "Sec-Fetch-Mode" to "cors", | ||||||
|  |                         "Sec-Fetch-Site" to "same-origin",), | ||||||
|  |                         data = mapOf(Pair("h",key))).text | ||||||
|  |                     val json = parseJson<Femcuevana>(url) | ||||||
|  |                     val link = json.url | ||||||
|  |                     if (link.contains("fembed")) { | ||||||
|  |                         loadExtractor(link, data, callback) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (iframe.contains("tomatomatela")) { | ||||||
|  |                 val tomatoRegex = Regex("(\\/\\/apialfa.tomatomatela.com\\/ir\\/player.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|  |                 tomatoRegex.findAll(iframe).map { tomreg -> | ||||||
|  |                     tomreg.value | ||||||
|  |                 }.toList().apmap { tom -> | ||||||
|  |                     val tomkey = tom.replace("//apialfa.tomatomatela.com/ir/player.php?h=","") | ||||||
|  |                     app.post("https://apialfa.tomatomatela.com/ir/rd.php", allowRedirects = false, | ||||||
|  |                         headers = mapOf("Host" to "apialfa.tomatomatela.com", | ||||||
|  |                             "User-Agent" to USER_AGENT, | ||||||
|  |                             "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|  |                             "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  |                             "Content-Type" to "application/x-www-form-urlencoded", | ||||||
|  |                             "Origin" to "null", | ||||||
|  |                             "DNT" to "1", | ||||||
|  |                             "Connection" to "keep-alive", | ||||||
|  |                             "Upgrade-Insecure-Requests" to "1", | ||||||
|  |                             "Sec-Fetch-Dest" to "iframe", | ||||||
|  |                             "Sec-Fetch-Mode" to "navigate", | ||||||
|  |                             "Sec-Fetch-Site" to "same-origin",), | ||||||
|  |                         data = mapOf(Pair("url",tomkey)) | ||||||
|  |                     ).response.headers.values("location").apmap { loc -> | ||||||
|  |                         if (loc.contains("goto_ddh.php")) { | ||||||
|  |                             val gotoregex = Regex("(\\/\\/api.cuevana3.io\\/ir\\/goto_ddh.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|  |                             gotoregex.findAll(loc).map { goreg -> | ||||||
|  |                                 goreg.value.replace("//api.cuevana3.io/ir/goto_ddh.php?h=","") | ||||||
|  |                             }.toList().apmap { gotolink -> | ||||||
|  |                                 app.post("https://api.cuevana3.io/ir/redirect_ddh.php", allowRedirects = false, | ||||||
|  |                                     headers = mapOf("Host" to "api.cuevana3.io", | ||||||
|  |                                         "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0", | ||||||
|  |                                         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|  |                                         "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  |                                         "Content-Type" to "application/x-www-form-urlencoded", | ||||||
|  |                                         "Origin" to "null", | ||||||
|  |                                         "DNT" to "1", | ||||||
|  |                                         "Connection" to "keep-alive", | ||||||
|  |                                         "Upgrade-Insecure-Requests" to "1", | ||||||
|  |                                         "Sec-Fetch-Dest" to "iframe", | ||||||
|  |                                         "Sec-Fetch-Mode" to "navigate", | ||||||
|  |                                         "Sec-Fetch-Site" to "same-origin",), | ||||||
|  |                                     data = mapOf(Pair("url",gotolink)) | ||||||
|  |                                 ).response.headers.values("location").apmap { golink -> | ||||||
|  |                                     loadExtractor(golink, data, callback) | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         if (loc.contains("index.php?h=")) { | ||||||
|  |                             val indexRegex = Regex("(\\/\\/api.cuevana3.io\\/sc\\/index.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|  |                             indexRegex.findAll(loc).map { indreg -> | ||||||
|  |                                 indreg.value.replace("//api.cuevana3.io/sc/index.php?h=","") | ||||||
|  |                             }.toList().apmap { inlink -> | ||||||
|  |                                 app.post("https://api.cuevana3.io/sc/r.php", allowRedirects = false, | ||||||
|  |                                     headers = mapOf("Host" to "api.cuevana3.io", | ||||||
|  |                                         "User-Agent" to USER_AGENT, | ||||||
|  |                                         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|  |                                         "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  |                                         "Accept-Encoding" to "gzip, deflate, br", | ||||||
|  |                                         "Content-Type" to "application/x-www-form-urlencoded", | ||||||
|  |                                         "Origin" to "null", | ||||||
|  |                                         "DNT" to "1", | ||||||
|  |                                         "Connection" to "keep-alive", | ||||||
|  |                                         "Upgrade-Insecure-Requests" to "1", | ||||||
|  |                                         "Sec-Fetch-Dest" to "iframe", | ||||||
|  |                                         "Sec-Fetch-Mode" to "navigate", | ||||||
|  |                                         "Sec-Fetch-Site" to "same-origin", | ||||||
|  |                                         "Sec-Fetch-User" to "?1",), | ||||||
|  |                                     data = mapOf(Pair("h",inlink)) | ||||||
|  |                                 ).response.headers.values("location").apmap { link -> | ||||||
|  |                                     loadExtractor(link, data, callback) | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,174 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.mvvm.logError | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | import java.util.* | ||||||
|  | 
 | ||||||
|  | class EntrepeliculasyseriesProvider:MainAPI() { | ||||||
|  |     override val mainUrl = "https://entrepeliculasyseries.nu" | ||||||
|  |     override val name = "EntrePeliculasySeries" | ||||||
|  |     override val lang = "es" | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasChromecastSupport = true | ||||||
|  |     override val hasDownloadSupport = true | ||||||
|  |     override val supportedTypes = setOf( | ||||||
|  |         TvType.Movie, | ||||||
|  |         TvType.TvSeries, | ||||||
|  |     ) | ||||||
|  |     override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading | ||||||
|  | 
 | ||||||
|  |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|  |         val items = ArrayList<HomePageList>() | ||||||
|  |         val urls = listOf( | ||||||
|  |             Pair("$mainUrl/series/", "Series"), | ||||||
|  |             Pair("$mainUrl/peliculas/", "Peliculas"), | ||||||
|  |             Pair("$mainUrl/anime/", "Animes"), | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         for (i in urls) { | ||||||
|  |             try { | ||||||
|  |                 val soup = app.get(i.first).document | ||||||
|  |                 val home = soup.select("ul.list-movie li").map { | ||||||
|  |                     val title = it.selectFirst("a.link-title h2").text() | ||||||
|  |                     val link = it.selectFirst("a").attr("href") | ||||||
|  |                     TvSeriesSearchResponse( | ||||||
|  |                         title, | ||||||
|  |                         link, | ||||||
|  |                         this.name, | ||||||
|  |                         if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries, | ||||||
|  |                         it.selectFirst("a.poster img").attr("src"), | ||||||
|  |                         null, | ||||||
|  |                         null, | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 items.add(HomePageList(i.second, home)) | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 logError(e) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (items.size <= 0) throw ErrorLoadingException() | ||||||
|  |         return HomePageResponse(items) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|  |         val url = "$mainUrl/?s=${query}" | ||||||
|  |         val document = app.get(url).document | ||||||
|  | 
 | ||||||
|  |         return document.select("li.xxx.TPostMv").map { | ||||||
|  |             val title = it.selectFirst("h2.Title").text() | ||||||
|  |             val href = it.selectFirst("a").attr("href") | ||||||
|  |             val image = it.selectFirst("img.lazy").attr("data-src") | ||||||
|  |             val isMovie = href.contains("/pelicula/") | ||||||
|  | 
 | ||||||
|  |             if (isMovie) { | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     title, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.Movie, | ||||||
|  |                     image, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } else { | ||||||
|  |                 TvSeriesSearchResponse( | ||||||
|  |                     title, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.TvSeries, | ||||||
|  |                     image, | ||||||
|  |                     null, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         }.toList() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     override suspend fun load(url: String): LoadResponse? { | ||||||
|  |         val soup = app.get(url, timeout = 120).document | ||||||
|  | 
 | ||||||
|  |         val title = soup.selectFirst("h1.title-post").text() | ||||||
|  |         val description = soup.selectFirst("p.text-content:nth-child(3)")?.text()?.trim() | ||||||
|  |         val poster: String? = soup.selectFirst("article.TPost img.lazy").attr("data-src") | ||||||
|  |         val episodes = soup.select(".TPostMv article").map { li -> | ||||||
|  |             val href = (li.select("a") ?: li.select(".C a") ?: li.select("article a")).attr("href") | ||||||
|  |             val epThumb = li.selectFirst("div.Image img").attr("data-src") | ||||||
|  |             val name = li.selectFirst("h2.Title").text() | ||||||
|  |             TvSeriesEpisode( | ||||||
|  |                 name, | ||||||
|  |                 null, | ||||||
|  |                 null, | ||||||
|  |                 href, | ||||||
|  |                 epThumb | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |         return when (val tvType = if (url.contains("/pelicula/")) TvType.Movie else TvType.TvSeries) { | ||||||
|  |             TvType.TvSeries -> { | ||||||
|  |                 TvSeriesLoadResponse( | ||||||
|  |                     title, | ||||||
|  |                     url, | ||||||
|  |                     this.name, | ||||||
|  |                     tvType, | ||||||
|  |                     episodes, | ||||||
|  |                     poster, | ||||||
|  |                     null, | ||||||
|  |                     description, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             TvType.Movie -> { | ||||||
|  |                 MovieLoadResponse( | ||||||
|  |                     title, | ||||||
|  |                     url, | ||||||
|  |                     this.name, | ||||||
|  |                     tvType, | ||||||
|  |                     url, | ||||||
|  |                     poster, | ||||||
|  |                     null, | ||||||
|  |                     description, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             else -> null | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     override suspend fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         app.get(data).document.select(".video ul.dropdown-menu li").apmap { | ||||||
|  |             val servers = it.attr("data-link") | ||||||
|  |             val doc = app.get(servers).document | ||||||
|  |             doc.select("input").apmap { | ||||||
|  |                 val postkey = it.attr("value") | ||||||
|  |                 app.post("https://entrepeliculasyseries.nu/r.php", | ||||||
|  |                     headers = mapOf("Host" to "entrepeliculasyseries.nu", | ||||||
|  |                         "User-Agent" to USER_AGENT, | ||||||
|  |                         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|  |                         "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  |                         "Content-Type" to "application/x-www-form-urlencoded", | ||||||
|  |                         "Origin" to "https://entrepeliculasyseries.nu", | ||||||
|  |                         "DNT" to "1", | ||||||
|  |                         "Connection" to "keep-alive", | ||||||
|  |                         "Referer" to servers, | ||||||
|  |                         "Upgrade-Insecure-Requests" to "1", | ||||||
|  |                         "Sec-Fetch-Dest" to "document", | ||||||
|  |                         "Sec-Fetch-Mode" to "navigate", | ||||||
|  |                         "Sec-Fetch-Site" to "same-origin", | ||||||
|  |                         "Sec-Fetch-User" to "?1",), | ||||||
|  |                     //params = mapOf(Pair("h", postkey)), | ||||||
|  |                     data =  mapOf(Pair("h", postkey)), | ||||||
|  |                     allowRedirects = false | ||||||
|  |                 ).response.headers.values("location").apmap { | ||||||
|  |                     loadExtractor(it, data, callback) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,223 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.mvvm.logError | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | import kotlin.collections.ArrayList | ||||||
|  | 
 | ||||||
|  | class PelisflixProvider:MainAPI() { | ||||||
|  |     override val mainUrl = "https://pelisflix.li" | ||||||
|  |     override val name = "Pelisflix" | ||||||
|  |     override val lang = "es" | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasChromecastSupport = true | ||||||
|  |     override val hasDownloadSupport = true | ||||||
|  |     override val supportedTypes = setOf( | ||||||
|  |         TvType.Movie, | ||||||
|  |         TvType.TvSeries, | ||||||
|  |     ) | ||||||
|  |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|  |         val items = ArrayList<HomePageList>() | ||||||
|  |         val urls = listOf( | ||||||
|  |             Pair("$mainUrl/ver-peliculas-online-gratis-fullhdc3/", "Películas"), | ||||||
|  |             Pair("$mainUrl/ver-series-online-gratis/", "Series"), | ||||||
|  |         ) | ||||||
|  |         for (i in urls) { | ||||||
|  |             try { | ||||||
|  |                 val soup = app.get(i.first).document | ||||||
|  |                 val home = soup.select("article.TPost.B").map { | ||||||
|  |                     val title = it.selectFirst("h2.title").text() | ||||||
|  |                     val link = it.selectFirst("a").attr("href") | ||||||
|  |                     TvSeriesSearchResponse( | ||||||
|  |                         title, | ||||||
|  |                         link, | ||||||
|  |                         this.name, | ||||||
|  |                         TvType.Movie, | ||||||
|  |                         it.selectFirst("figure img").attr("data-src"), | ||||||
|  |                         null, | ||||||
|  |                         null, | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 items.add(HomePageList(i.second, home)) | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                logError(e) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (items.size <= 0) throw ErrorLoadingException() | ||||||
|  |         return HomePageResponse(items) | ||||||
|  |     } | ||||||
|  |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|  |         val url = "$mainUrl/?s=$query" | ||||||
|  |         val doc = app.get(url).document | ||||||
|  |         return doc.select("article.TPost.B").map { | ||||||
|  |             val href = it.selectFirst("a").attr("href") | ||||||
|  |             val poster = it.selectFirst("figure img").attr("data-src") | ||||||
|  |             val name = it.selectFirst("h2.title").text() | ||||||
|  |             val isMovie = href.contains("/pelicula/") | ||||||
|  |             if (isMovie) { | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     name, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.Movie, | ||||||
|  |                     poster, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } else { | ||||||
|  |                 TvSeriesSearchResponse( | ||||||
|  |                     name, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.TvSeries, | ||||||
|  |                     poster, | ||||||
|  |                     null, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         }.toList() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun load(url: String): LoadResponse? { | ||||||
|  |         val type = if (url.contains("/pelicula/")) TvType.Movie else TvType.TvSeries | ||||||
|  | 
 | ||||||
|  |         val document = app.get(url).document | ||||||
|  | 
 | ||||||
|  |         val title = document.selectFirst("h1.Title").text() | ||||||
|  |         val descRegex = Regex("(.Recuerda.*Pelisflix.+)") | ||||||
|  |         val descRegex2 = Regex("(Actualmente.*.)") | ||||||
|  |         val descRegex3 = Regex("(.*Director:.*)") | ||||||
|  |         val descRegex4 = Regex("(.*Actores:.*)") | ||||||
|  |         val descRegex5 = Regex("(Ver.*(\\)|)((\\d+).))") | ||||||
|  |         val descipt = document.selectFirst("div.Description").text().replace(descRegex, "") | ||||||
|  |             .replace(descRegex2, "").replace(descRegex3, "") | ||||||
|  |             .replace(descRegex4, "").replace(descRegex5, "") | ||||||
|  |         val desc2Regex = Regex("(G(e|é)nero:.*..)") | ||||||
|  |         val descipt2 = document.selectFirst("div.Description").text().replace(desc2Regex,"") | ||||||
|  |         val rating = | ||||||
|  |             document.selectFirst("div.rating-content button.like-mov span.vot_cl")?.text()?.toFloatOrNull() | ||||||
|  |                 ?.times(0)?.toInt() | ||||||
|  |         val year = document.selectFirst("span.Date")?.text() | ||||||
|  |         val duration = if (type == TvType.Movie) document.selectFirst(".Container .Container  span.Time").text() else null | ||||||
|  |         val postercss = document.selectFirst("head").toString() | ||||||
|  |         val posterRegex = Regex("(\"og:image\" content=\"https:\\/\\/seriesflix.video\\/wp-content\\/uploads\\/(\\d+)\\/(\\d+)\\/?.*.jpg)") | ||||||
|  |         val poster = try { | ||||||
|  |             posterRegex.findAll(postercss).map { | ||||||
|  |                 it.value.replace("\"og:image\" content=\"","") | ||||||
|  |             }.toList().first() | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             document.select(".TPostBg").attr("src") | ||||||
|  |         } | ||||||
|  |         if (type == TvType.TvSeries) { | ||||||
|  |             val list = ArrayList<Pair<Int, String>>() | ||||||
|  | 
 | ||||||
|  |             document.select("main > section.SeasonBx > div > div.Title > a").forEach { element -> | ||||||
|  |                 val season = element.selectFirst("> span")?.text()?.toIntOrNull() | ||||||
|  |                 val href = element.attr("href") | ||||||
|  |                 if (season != null && season > 0 && !href.isNullOrBlank()) { | ||||||
|  |                     list.add(Pair(season, fixUrl(href))) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") | ||||||
|  | 
 | ||||||
|  |             val episodeList = ArrayList<TvSeriesEpisode>() | ||||||
|  | 
 | ||||||
|  |             for (season in list)  { | ||||||
|  |                 val seasonDocument = app.get(season.second).document | ||||||
|  |                 val episodes = seasonDocument.select("table > tbody > tr") | ||||||
|  |                 if (episodes.isNotEmpty()) { | ||||||
|  |                     episodes.forEach { episode -> | ||||||
|  |                         val epNum = episode.selectFirst("> td > span.Num")?.text()?.toIntOrNull() | ||||||
|  |                         val epthumb = episode.selectFirst("img")?.attr("src") | ||||||
|  |                         val aName = episode.selectFirst("> td.MvTbTtl > a") | ||||||
|  |                         val name = aName.text() | ||||||
|  |                         val href = aName.attr("href") | ||||||
|  |                         val date = episode.selectFirst("> td.MvTbTtl > span")?.text() | ||||||
|  |                         episodeList.add( | ||||||
|  |                             TvSeriesEpisode( | ||||||
|  |                                 name, | ||||||
|  |                                 season.first, | ||||||
|  |                                 epNum, | ||||||
|  |                                 href, | ||||||
|  |                                 fixUrlNull(epthumb), | ||||||
|  |                                 date | ||||||
|  |                             ) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return TvSeriesLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url, | ||||||
|  |                 this.name, | ||||||
|  |                 type, | ||||||
|  |                 episodeList, | ||||||
|  |                 fixUrlNull(poster), | ||||||
|  |                 year?.toIntOrNull(), | ||||||
|  |                 descipt2, | ||||||
|  |                 null, | ||||||
|  |                 null, | ||||||
|  |                 rating | ||||||
|  |             ) | ||||||
|  |         } else { | ||||||
|  | 
 | ||||||
|  |             return newMovieLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url, | ||||||
|  |                 type, | ||||||
|  |                 url | ||||||
|  |             ) { | ||||||
|  |                 posterUrl = fixUrlNull(poster) | ||||||
|  |                 this.year = year?.toIntOrNull() | ||||||
|  |                 this.plot = descipt | ||||||
|  |                 this.rating = rating | ||||||
|  |                 setDuration(duration) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         app.get(data).document.select("li button.Button.sgty").forEach { | ||||||
|  |             val movieID = it.attr("data-id") | ||||||
|  |             val serverID = it.attr("data-key") | ||||||
|  |             val type = if (data.contains("pelicula")) 1 else 2 | ||||||
|  |             val url = "$mainUrl/?trembed=$serverID&trid=$movieID&trtype=$type" //This is to get the POST key value | ||||||
|  |             val doc1 = app.get(url).document | ||||||
|  |             doc1.select("div.Video iframe").apmap { | ||||||
|  |                 val iframe = it.attr("src") | ||||||
|  |                 val postkey = iframe.replace("/stream/index.php?h=","") // this obtains | ||||||
|  |                 // djNIdHNCR2lKTGpnc3YwK3pyRCs3L2xkQmljSUZ4ai9ibTcza0JRODNMcmFIZ0hPejdlYW0yanJIL2prQ1JCZA POST KEY | ||||||
|  |                 app.post("https://pelisflix.li/stream/r.php", | ||||||
|  |                     headers = mapOf("Host" to "pelisflix.li", | ||||||
|  |                         "User-Agent" to USER_AGENT, | ||||||
|  |                         "Accept" to "ext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|  |                         "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  |                         "Content-Type" to "application/x-www-form-urlencoded", | ||||||
|  |                         "Origin" to "null", | ||||||
|  |                         "DNT" to "1", | ||||||
|  |                         "Connection" to "keep-alive", | ||||||
|  |                         "Upgrade-Insecure-Requests" to "1", | ||||||
|  |                         "Sec-Fetch-Dest" to "iframe", | ||||||
|  |                         "Sec-Fetch-Mode" to "navigate", | ||||||
|  |                         "Sec-Fetch-Site" to "same-origin", | ||||||
|  |                         "Sec-Fetch-User" to "?1", | ||||||
|  |                         "Pragma" to "no-cache", | ||||||
|  |                         "Cache-Control" to "no-cache", | ||||||
|  |                         "TE" to "trailers"), | ||||||
|  |                     params = mapOf(Pair("h", postkey)), | ||||||
|  |                     data =  mapOf(Pair("h", postkey)), | ||||||
|  |                     allowRedirects = false | ||||||
|  |                 ).response.headers.values("location").apmap { link -> | ||||||
|  |                     val url1 = link.replace("#bu","") | ||||||
|  |                     loadExtractor(url1, data, callback) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,221 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.mvvm.logError | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | import kotlin.collections.ArrayList | ||||||
|  | 
 | ||||||
|  | class SeriesflixProvider:MainAPI() { | ||||||
|  |     override val mainUrl = "https://seriesflix.video" | ||||||
|  |     override val name = "Seriesflix" | ||||||
|  |     override val lang = "es" | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasChromecastSupport = true | ||||||
|  |     override val hasDownloadSupport = true | ||||||
|  |     override val supportedTypes = setOf( | ||||||
|  |         TvType.Movie, | ||||||
|  |         TvType.TvSeries, | ||||||
|  |     ) | ||||||
|  |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|  |         val items = ArrayList<HomePageList>() | ||||||
|  |         val urls = listOf( | ||||||
|  |             Pair("$mainUrl/ver-series-online/", "Series"), | ||||||
|  |             Pair("$mainUrl/genero/accion/", "Acción"), | ||||||
|  |             Pair("$mainUrl/genero/ciencia-ficcion/", "Ciencia ficción"), | ||||||
|  |         ) | ||||||
|  |         for (i in urls) { | ||||||
|  |             try { | ||||||
|  |                 val soup = app.get(i.first).document | ||||||
|  |                 val home = soup.select("article.TPost.B").map { | ||||||
|  |                     val title = it.selectFirst("h2.title").text() | ||||||
|  |                     val link = it.selectFirst("a").attr("href") | ||||||
|  |                     TvSeriesSearchResponse( | ||||||
|  |                         title, | ||||||
|  |                         link, | ||||||
|  |                         this.name, | ||||||
|  |                         TvType.Movie, | ||||||
|  |                         it.selectFirst("figure img").attr("src"), | ||||||
|  |                         null, | ||||||
|  |                         null, | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 items.add(HomePageList(i.second, home)) | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 logError(e) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (items.size <= 0) throw ErrorLoadingException() | ||||||
|  |         return HomePageResponse(items) | ||||||
|  |     } | ||||||
|  |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|  |         val url = "$mainUrl/?s=$query" | ||||||
|  |         val doc = app.get(url).document | ||||||
|  |         return doc.select("article.TPost.B").map { | ||||||
|  |             val href = it.selectFirst("a").attr("href") | ||||||
|  |             val poster = it.selectFirst("figure img").attr("src") | ||||||
|  |             val name = it.selectFirst("h2.title").text() | ||||||
|  |             val isMovie = href.contains("/movies/") | ||||||
|  |             if (isMovie) { | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     name, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.Movie, | ||||||
|  |                     poster, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } else { | ||||||
|  |                 TvSeriesSearchResponse( | ||||||
|  |                     name, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.TvSeries, | ||||||
|  |                     poster, | ||||||
|  |                     null, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         }.toList() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     override suspend fun load(url: String): LoadResponse? { | ||||||
|  |         val type = if (url.contains("/movies/")) TvType.Movie else TvType.TvSeries | ||||||
|  | 
 | ||||||
|  |         val document = app.get(url).document | ||||||
|  | 
 | ||||||
|  |         val title = document.selectFirst("h1.Title").text() | ||||||
|  |         val descRegex = Regex("(Recuerda.*Seriesflix.)") | ||||||
|  |         val descipt = document.selectFirst("div.Description > p").text().replace(descRegex,"") | ||||||
|  |         val rating = | ||||||
|  |             document.selectFirst("div.Vote > div.post-ratings > span")?.text()?.toFloatOrNull() | ||||||
|  |                 ?.times(1000)?.toInt() | ||||||
|  |         val year = document.selectFirst("span.Date")?.text() | ||||||
|  |         // ?: does not work | ||||||
|  |         val duration = try { | ||||||
|  |             document.selectFirst("span.Time").text() | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             null | ||||||
|  |         } | ||||||
|  |         val postercss = document.selectFirst("head").toString() | ||||||
|  |         val posterRegex = Regex("(\"og:image\" content=\"https:\\/\\/seriesflix.video\\/wp-content\\/uploads\\/(\\d+)\\/(\\d+)\\/?.*.jpg)") | ||||||
|  |         val poster = try { | ||||||
|  |             posterRegex.findAll(postercss).map { | ||||||
|  |                 it.value.replace("\"og:image\" content=\"","") | ||||||
|  |             }.toList().first() | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             document.select(".TPostBg").attr("src") | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (type == TvType.TvSeries) { | ||||||
|  |             val list = ArrayList<Pair<Int, String>>() | ||||||
|  | 
 | ||||||
|  |             document.select("main > section.SeasonBx > div > div.Title > a").forEach { element -> | ||||||
|  |                 val season = element.selectFirst("> span")?.text()?.toIntOrNull() | ||||||
|  |                 val href = element.attr("href") | ||||||
|  |                 if (season != null && season > 0 && !href.isNullOrBlank()) { | ||||||
|  |                     list.add(Pair(season, fixUrl(href))) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") | ||||||
|  | 
 | ||||||
|  |             val episodeList = ArrayList<TvSeriesEpisode>() | ||||||
|  | 
 | ||||||
|  |             for (season in list) { | ||||||
|  |                 val seasonDocument = app.get(season.second).document | ||||||
|  |                 val episodes = seasonDocument.select("table > tbody > tr") | ||||||
|  |                 if (episodes.isNotEmpty()) { | ||||||
|  |                     episodes.forEach { episode -> | ||||||
|  |                         val epNum = episode.selectFirst("> td > span.Num")?.text()?.toIntOrNull() | ||||||
|  |                         val epthumb = episode.selectFirst("img")?.attr("src") | ||||||
|  |                         val aName = episode.selectFirst("> td.MvTbTtl > a") | ||||||
|  |                         val name = aName.text() | ||||||
|  |                         val href = aName.attr("href") | ||||||
|  |                         val date = episode.selectFirst("> td.MvTbTtl > span")?.text() | ||||||
|  |                         episodeList.add( | ||||||
|  |                             TvSeriesEpisode( | ||||||
|  |                                 name, | ||||||
|  |                                 season.first, | ||||||
|  |                                 epNum, | ||||||
|  |                                 href, | ||||||
|  |                                 fixUrlNull(epthumb), | ||||||
|  |                                 date | ||||||
|  |                             ) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return TvSeriesLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url, | ||||||
|  |                 this.name, | ||||||
|  |                 type, | ||||||
|  |                 episodeList, | ||||||
|  |                 fixUrlNull(poster), | ||||||
|  |                 year?.toIntOrNull(), | ||||||
|  |                 descipt, | ||||||
|  |                 null, | ||||||
|  |                 null, | ||||||
|  |                 rating | ||||||
|  |             ) | ||||||
|  |         } else { | ||||||
|  |             return newMovieLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url, | ||||||
|  |                 type, | ||||||
|  |                 url | ||||||
|  |             ) { | ||||||
|  |                 posterUrl = fixUrlNull(poster) | ||||||
|  |                 this.year = year?.toIntOrNull() | ||||||
|  |                 this.plot = descipt | ||||||
|  |                 this.rating = rating | ||||||
|  |                 setDuration(duration) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         app.get(data).document.select("ul.ListOptions li").forEach { | ||||||
|  |             val movieID = it.attr("data-id") | ||||||
|  |             val serverID = it.attr("data-key") | ||||||
|  |             val type = if (data.contains("movies")) 1 else 2 | ||||||
|  |             val url = "$mainUrl/?trembed=$serverID&trid=$movieID&trtype=$type" //This is to get the POST key value | ||||||
|  |             val doc1 = app.get(url).document | ||||||
|  |             doc1.select("div.Video iframe").apmap { | ||||||
|  |                 val iframe = it.attr("src") | ||||||
|  |                 val postkey = iframe.replace("https://sc.seriesflix.video/index.php?h=","") // this obtains | ||||||
|  |                 // djNIdHNCR2lKTGpnc3YwK3pyRCs3L2xkQmljSUZ4ai9ibTcza0JRODNMcmFIZ0hPejdlYW0yanJIL2prQ1JCZA POST KEY | ||||||
|  |                 app.post("https://sc.seriesflix.video/r.php", | ||||||
|  |                     headers = mapOf("Host" to "sc.seriesflix.video", | ||||||
|  |                         "User-Agent" to USER_AGENT, | ||||||
|  |                         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|  |                         "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  |                         "Content-Type" to "application/x-www-form-urlencoded", | ||||||
|  |                         "Origin" to "null", | ||||||
|  |                         "DNT" to "1", | ||||||
|  |                         "Alt-Used" to "sc.seriesflix.video", | ||||||
|  |                         "Connection" to "keep-alive", | ||||||
|  |                         "Upgrade-Insecure-Requests" to "1", | ||||||
|  |                         "Sec-Fetch-Dest" to "iframe", | ||||||
|  |                         "Sec-Fetch-Mode" to "navigate", | ||||||
|  |                         "Sec-Fetch-Site" to "same-origin", | ||||||
|  |                         "Sec-Fetch-User" to "?1",), | ||||||
|  |                     params = mapOf(Pair("h", postkey)), | ||||||
|  |                     data =  mapOf(Pair("h", postkey)), | ||||||
|  |                     allowRedirects = false | ||||||
|  |                 ).response.headers.values("location").apmap {link -> | ||||||
|  |                     val url1 = link.replace("#bu","") | ||||||
|  |                     loadExtractor(url1, data, callback) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -110,6 +110,10 @@ val extractorApis: Array<ExtractorApi> = arrayOf( | ||||||
|     VoeExtractor(), |     VoeExtractor(), | ||||||
|     UpstreamExtractor(), |     UpstreamExtractor(), | ||||||
| 
 | 
 | ||||||
|  |     Tomatomatela(), | ||||||
|  |     Cinestart(), | ||||||
|  |     OkRu(), | ||||||
|  | 
 | ||||||
|     // dood extractors |     // dood extractors | ||||||
|     DoodToExtractor(), |     DoodToExtractor(), | ||||||
|     DoodSoExtractor(), |     DoodSoExtractor(), | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue