forked from recloudstream/cloudstream
		
	add pinoy-hd.xyz provider (#338)
* Add pinoy-hd.xyz to movie providers. * Add pinoymovies.es site * Add download option for pinoymoviepedia, and various cleanups.
This commit is contained in:
		
							parent
							
								
									ebc0485233
								
							
						
					
					
						commit
						f8883e3692
					
				
					 8 changed files with 798 additions and 329 deletions
				
			
		|  | @ -59,7 +59,9 @@ object APIHolder { | ||||||
|         FilmanProvider(), |         FilmanProvider(), | ||||||
| 
 | 
 | ||||||
|         ZoroProvider(), |         ZoroProvider(), | ||||||
|         PinoyMoviePedia() |         PinoyMoviePediaProvider(), | ||||||
|  |         PinoyHDXyzProvider(), | ||||||
|  |         PinoyMoviesEsProvider() | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     val restrictedApis = arrayListOf( |     val restrictedApis = arrayListOf( | ||||||
|  |  | ||||||
|  | @ -0,0 +1,59 @@ | ||||||
|  | package com.lagradost.cloudstream3.extractors | ||||||
|  | 
 | ||||||
|  | import com.lagradost.cloudstream3.app | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorApi | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.Qualities | ||||||
|  | 
 | ||||||
|  | class UpstreamExtractor: ExtractorApi() { | ||||||
|  |     override val name: String = "Upstream.to" | ||||||
|  |     override val mainUrl: String = "https://upstream.to" | ||||||
|  |     override val requiresReferer = true | ||||||
|  | 
 | ||||||
|  |     override fun getUrl(url: String, referer: String?): List<ExtractorLink> { | ||||||
|  |         // WIP: m3u8 link fetched but sometimes not playing | ||||||
|  |         //Log.i(this.name, "Result => (no extractor) ${url}") | ||||||
|  |         val sources: MutableList<ExtractorLink> = mutableListOf() | ||||||
|  |         val doc = app.get(url, referer = referer).text | ||||||
|  |         if (doc.isNotEmpty()) { | ||||||
|  |             var reg = Regex("(?<=master)(.*)(?=hls)") | ||||||
|  |             val result = reg.find(doc)?.groupValues?.map { | ||||||
|  |                 it.trim('|') | ||||||
|  |             }?.toList() | ||||||
|  |             reg = Regex("(?<=\\|file\\|)(.*)(?=\\|remove\\|)") | ||||||
|  |             val domainList = reg.find(doc)?.groupValues?.get(1)?.split("|") | ||||||
|  |             var domain = when (!domainList.isNullOrEmpty()) { | ||||||
|  |                 true -> { | ||||||
|  |                     if (domainList.isNotEmpty()) { | ||||||
|  |                         var domName = "" | ||||||
|  |                         for (part in domainList) { | ||||||
|  |                             domName = "${part}.${domName}" | ||||||
|  |                         } | ||||||
|  |                         domName.trimEnd('.') | ||||||
|  |                     } else { "" } | ||||||
|  |                 } | ||||||
|  |                 false -> "" | ||||||
|  |             } | ||||||
|  |             //Log.i(this.name, "Result => (domain) ${domain}") | ||||||
|  |             if (domain.isEmpty()) { | ||||||
|  |                 domain = "s96.upstreamcdn.co" | ||||||
|  |                 //Log.i(this.name, "Result => (default domain) ${domain}") | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             result?.forEach { | ||||||
|  |                 val linkUrl = "https://${domain}/hls/${it}/master.m3u8" | ||||||
|  |                 sources.add( | ||||||
|  |                     ExtractorLink( | ||||||
|  |                     name = "Upstream m3u8", | ||||||
|  |                     source = this.name, | ||||||
|  |                     url = linkUrl, | ||||||
|  |                     quality = Qualities.Unknown.value, | ||||||
|  |                     referer = referer!!, | ||||||
|  |                     isM3u8 = true | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return sources | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,52 @@ | ||||||
|  | package com.lagradost.cloudstream3.extractors | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
|  | import com.fasterxml.jackson.module.kotlin.readValue | ||||||
|  | import com.lagradost.cloudstream3.app | ||||||
|  | import com.lagradost.cloudstream3.mapper | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorApi | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.getQualityFromName | ||||||
|  | 
 | ||||||
|  | open class VoeExtractor : ExtractorApi() { | ||||||
|  |     override val name: String = "Voe" | ||||||
|  |     override val mainUrl: String = "https://voe.sx" | ||||||
|  |     override val requiresReferer = false | ||||||
|  | 
 | ||||||
|  |     private data class ResponseLinks( | ||||||
|  |         @JsonProperty("hls") val url: String?, | ||||||
|  |         @JsonProperty("video_height") val label: Int? | ||||||
|  |         //val type: String // Mp4 | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     override fun getUrl(url: String, referer: String?): List<ExtractorLink> { | ||||||
|  |         val extractedLinksList: MutableList<ExtractorLink> = mutableListOf() | ||||||
|  |         val doc = app.get(url).text | ||||||
|  |         if (doc.isNotEmpty()) { | ||||||
|  |             val start = "const sources =" | ||||||
|  |             var src = doc.substring(doc.indexOf(start)) | ||||||
|  |             src = src.substring(start.length, src.indexOf(";")) | ||||||
|  |                 .replace("0,", "0") | ||||||
|  |                 .trim() | ||||||
|  |             //Log.i(this.name, "Result => (src) ${src}") | ||||||
|  |             mapper.readValue<ResponseLinks?>(src)?.let { voelink -> | ||||||
|  |                 //Log.i(this.name, "Result => (voelink) ${voelink}") | ||||||
|  |                 val linkUrl = voelink.url | ||||||
|  |                 val linkLabel = voelink.label?.toString() ?: "" | ||||||
|  |                 if (!linkUrl.isNullOrEmpty()) { | ||||||
|  |                     extractedLinksList.add( | ||||||
|  |                         ExtractorLink( | ||||||
|  |                             name = "Voe ${linkLabel}", | ||||||
|  |                             source = this.name, | ||||||
|  |                             url = linkUrl, | ||||||
|  |                             quality = getQualityFromName(linkLabel), | ||||||
|  |                             referer = url, | ||||||
|  |                             isM3u8 = true | ||||||
|  |                         ) | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return extractedLinksList | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,224 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import android.util.Log | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
|  | import org.jsoup.Jsoup | ||||||
|  | 
 | ||||||
|  | class PinoyHDXyzProvider : MainAPI() { | ||||||
|  |     override val name = "Pinoy-HD" | ||||||
|  |     override val mainUrl = "https://www.pinoy-hd.xyz" | ||||||
|  |     override val lang = "tl" | ||||||
|  |     override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries) | ||||||
|  |     override val hasDownloadSupport = false | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasQuickSearch = false | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     override fun getMainPage(): HomePageResponse { | ||||||
|  |         val all = ArrayList<HomePageList>() | ||||||
|  |         val html = app.get(mainUrl, referer = mainUrl).text | ||||||
|  |         val document = Jsoup.parse(html) | ||||||
|  |         val mainbody = document.getElementsByTag("body") | ||||||
|  | 
 | ||||||
|  |         mainbody?.select("div.section-cotent.col-md-12.bordert")?.forEach { row -> | ||||||
|  |             val title = row?.select("div.title-section.tt")?.text() ?: "<Row>" | ||||||
|  |             val inner = row?.select("li.img_frame.preview-tumb7") | ||||||
|  |             if (inner != null) { | ||||||
|  |                 val elements: List<SearchResponse> = inner.map { | ||||||
|  |                     // Get inner div from article | ||||||
|  |                     val innerBody = it?.select("a")?.firstOrNull() | ||||||
|  |                     // Fetch details | ||||||
|  |                     val name = it?.text() ?: "" | ||||||
|  |                     val link = innerBody?.attr("href") ?: "" | ||||||
|  |                     val imgsrc = innerBody?.select("img")?.attr("src") | ||||||
|  |                     val image = when (!imgsrc.isNullOrEmpty()) { | ||||||
|  |                         true -> "${mainUrl}${imgsrc}" | ||||||
|  |                         false -> null | ||||||
|  |                     } | ||||||
|  |                     //Log.i(this.name, "Result => (innerBody, image) ${innerBody} / ${image}") | ||||||
|  |                     // Get Year from Link | ||||||
|  |                     val rex = Regex("_(\\d+)_") | ||||||
|  |                     val yearRes = rex.find(link)?.value ?: "" | ||||||
|  |                     val year = yearRes.replace("_", "").toIntOrNull() | ||||||
|  |                     //Log.i(this.name, "Result => (yearRes, year) ${yearRes} / ${year}") | ||||||
|  |                     MovieSearchResponse( | ||||||
|  |                         name, | ||||||
|  |                         link, | ||||||
|  |                         this.name, | ||||||
|  |                         TvType.Movie, | ||||||
|  |                         image, | ||||||
|  |                         year, | ||||||
|  |                         null, | ||||||
|  |                     ) | ||||||
|  |                 }.filter { a -> a.url.isNotEmpty() } | ||||||
|  |                         .filter { b -> b.name.isNotEmpty() } | ||||||
|  |                         .distinctBy { c -> c.url } | ||||||
|  |                 // Add | ||||||
|  |                 all.add( | ||||||
|  |                     HomePageList( | ||||||
|  |                         title, elements | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return HomePageResponse(all) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun search(query: String): List<SearchResponse> { | ||||||
|  |         val url = "$mainUrl/search/?q=${query.replace(" ", "+")}" | ||||||
|  |         val html = app.get(url).text | ||||||
|  |         val document = Jsoup.parse(html).select("div.portfolio-thumb") | ||||||
|  |         if (document != null) { | ||||||
|  |             return document.map { | ||||||
|  | 
 | ||||||
|  |                 val link = it?.select("a")?.firstOrNull()?.attr("href") ?: "" | ||||||
|  |                 val title = it?.text() ?: "" | ||||||
|  |                 val year = null | ||||||
|  |                 val image = null // site provides no image on search page | ||||||
|  | 
 | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     title, | ||||||
|  |                     link, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.Movie, | ||||||
|  |                     image, | ||||||
|  |                     year | ||||||
|  |                 ) | ||||||
|  |             }.filter { a -> a.url.isNotEmpty() } | ||||||
|  |                     .filter { b -> b.name.isNotEmpty() } | ||||||
|  |                     .distinctBy { c -> c.url } | ||||||
|  |         } | ||||||
|  |         return listOf() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun load(url: String): LoadResponse { | ||||||
|  |         val response = app.get(url).text | ||||||
|  |         val doc = Jsoup.parse(response) | ||||||
|  |         val body = doc.getElementsByTag("body") | ||||||
|  |         val inner = body?.select("div.info") | ||||||
|  | 
 | ||||||
|  |         // Video details | ||||||
|  |         val tvtype = when (url.contains("/pinoy_tv_series/", ignoreCase = true)) { | ||||||
|  |             true -> TvType.TvSeries | ||||||
|  |             false -> TvType.Movie | ||||||
|  |         } | ||||||
|  |         val imgLinkCode = inner?.select("div.portfolio-tumb.ph-link > img")?.attr("src") | ||||||
|  |         val poster = if (!imgLinkCode.isNullOrEmpty()) { "${mainUrl}${imgLinkCode}" } else { null } | ||||||
|  |         //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}") | ||||||
|  |         val title = inner?.select("td.trFon2.entt")?.firstOrNull()?.text() ?: "<Untitled>" | ||||||
|  |         var yearRes = inner?.select("td.trFon2")?.toString() | ||||||
|  |         if (!yearRes.isNullOrEmpty()) { | ||||||
|  |             if (yearRes.contains("var year =")) { | ||||||
|  |                 yearRes = yearRes.substring(yearRes.indexOf("var year =")) | ||||||
|  |                 yearRes = yearRes.substring(0, yearRes.indexOf(';')).replace("var year =", "") | ||||||
|  |                     .trim().trim('\'') | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         //Log.i(this.name, "Result => (yearRes) ${yearRes}") | ||||||
|  |         val year = yearRes?.toIntOrNull() | ||||||
|  | 
 | ||||||
|  |         var descript = body?.select("div.eText")?.text() | ||||||
|  |         if (!descript.isNullOrEmpty()) { | ||||||
|  |             descript = descript.substring(0, descript.indexOf("_x_Polus1")) | ||||||
|  |                 .replace("_x_Polus1", "") | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Video links | ||||||
|  |         val listOfLinks: MutableList<String> = mutableListOf() | ||||||
|  |         val linkMain = body?.select("div.tabcontent > iframe")?.attr("src") | ||||||
|  |         if (!linkMain.isNullOrEmpty()) { | ||||||
|  |             listOfLinks.add(linkMain) | ||||||
|  |         } | ||||||
|  |         var extraLinks = body?.select("div.tabcontent.hide")?.text() | ||||||
|  |         if (!extraLinks.isNullOrEmpty()) { | ||||||
|  |             extraLinks = extraLinks.substring(extraLinks.indexOf("_x_Polus1")) | ||||||
|  |             extraLinks = extraLinks.trim().substring("_x_Polus1".length) | ||||||
|  |             extraLinks = extraLinks.substring(0, extraLinks.indexOf("<script>")) | ||||||
|  |             val lnks = extraLinks.split("_x_Polus") | ||||||
|  |             //Log.i(this.name, "Result => (lnks) ${lnks}") | ||||||
|  |             for (item in lnks) { | ||||||
|  |                 if (item.contains("https://")) { | ||||||
|  |                     val lnkurl = item.substring(item.indexOf("https://")).trim() | ||||||
|  |                     listOfLinks.add(lnkurl) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         val streamlinks = listOfLinks.toString() | ||||||
|  |         //Log.i(this.name, "Result => (streamlinks) ${streamlinks}") | ||||||
|  | 
 | ||||||
|  |         // Parse episodes if series | ||||||
|  |         if (tvtype == TvType.TvSeries) { | ||||||
|  |             val indexStart = "ses=(" | ||||||
|  |             val episodeList = ArrayList<TvSeriesEpisode>() | ||||||
|  |             val bodyText = body?.select("div.section-cotent1.col-md-12")?.select("section") | ||||||
|  |                 ?.select("script")?.toString() ?: "" | ||||||
|  |             //Log.i(this.name, "Result => (bodyText) ${bodyText}") | ||||||
|  |             if (bodyText.contains(indexStart)) { | ||||||
|  |                 var epListText = bodyText.substring(bodyText.indexOf(indexStart)) | ||||||
|  |                 if (epListText.isNotEmpty()) { | ||||||
|  |                     epListText = epListText.substring(indexStart.length, epListText.indexOf(")")) | ||||||
|  |                         .trim().trim('\'') | ||||||
|  |                     //Log.i(this.name, "Result => (epListText) ${epListText}") | ||||||
|  |                     val epList = epListText.split(',') | ||||||
|  |                     //Log.i(this.name, "Result => (epLinks) ${epLinks}") | ||||||
|  |                     if (!epList.isNullOrEmpty()) { | ||||||
|  |                         var count = 0 | ||||||
|  |                         epList.forEach { ep -> | ||||||
|  |                             count++ | ||||||
|  |                             val epTitle = " Episode $count" | ||||||
|  |                             //Log.i(this.name, "Result => (epLinks href) ${href}") | ||||||
|  |                             episodeList.add( | ||||||
|  |                                 TvSeriesEpisode( | ||||||
|  |                                     name = name + epTitle, | ||||||
|  |                                     season = null, | ||||||
|  |                                     episode = count, | ||||||
|  |                                     data = ep.trim(), | ||||||
|  |                                     posterUrl = poster, | ||||||
|  |                                     date = null | ||||||
|  |                                 ) | ||||||
|  |                             ) | ||||||
|  |                         } | ||||||
|  |                         return TvSeriesLoadResponse( | ||||||
|  |                             title, | ||||||
|  |                             url, | ||||||
|  |                             this.name, | ||||||
|  |                             tvtype, | ||||||
|  |                             episodeList, | ||||||
|  |                             poster, | ||||||
|  |                             year, | ||||||
|  |                             descript, | ||||||
|  |                             null, | ||||||
|  |                             null, | ||||||
|  |                             null | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return MovieLoadResponse(title, url, this.name, tvtype, streamlinks, poster, year, descript, null, null) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         if (data == "about:blank") return false | ||||||
|  |         if (data.isEmpty()) return false | ||||||
|  |         try { | ||||||
|  |             data.trim('[').trim(']').split(',').map { item -> | ||||||
|  |                 if (item.isNotEmpty()) { | ||||||
|  |                     val url = item.trim() | ||||||
|  |                     loadExtractor(url, url, callback) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             e.printStackTrace() | ||||||
|  |             Log.i(this.name, "Result => (e) $e") | ||||||
|  |         } | ||||||
|  |         return false | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,328 +0,0 @@ | ||||||
| package com.lagradost.cloudstream3.movieproviders |  | ||||||
| 
 |  | ||||||
| import android.util.Log |  | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty |  | ||||||
| import com.fasterxml.jackson.module.kotlin.readValue |  | ||||||
| import com.lagradost.cloudstream3.* |  | ||||||
| import com.lagradost.cloudstream3.extractors.DoodLaExtractor |  | ||||||
| import com.lagradost.cloudstream3.extractors.FEmbed |  | ||||||
| import com.lagradost.cloudstream3.extractors.MixDrop |  | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink |  | ||||||
| import com.lagradost.cloudstream3.utils.Qualities |  | ||||||
| import com.lagradost.cloudstream3.utils.getQualityFromName |  | ||||||
| import org.jsoup.Jsoup |  | ||||||
| 
 |  | ||||||
| class PinoyMoviePedia : MainAPI() { |  | ||||||
|     override val name = "Pinoy Moviepedia" |  | ||||||
|     override val mainUrl = "https://pinoymoviepedia.ru" |  | ||||||
|     override val lang = "tl" |  | ||||||
| 
 |  | ||||||
|     override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries) |  | ||||||
| 
 |  | ||||||
|     override val hasDownloadSupport = false |  | ||||||
|     override val hasMainPage = true |  | ||||||
|     override val hasQuickSearch = false |  | ||||||
| 
 |  | ||||||
|     private data class JsonVoeLinks( |  | ||||||
|         @JsonProperty("hls") val url: String?, |  | ||||||
|         @JsonProperty("video_height") val label: Int? |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
|     override fun getMainPage(): HomePageResponse { |  | ||||||
|         val all = ArrayList<HomePageList>() |  | ||||||
|         try { |  | ||||||
|             val html = app.get(mainUrl, timeout = 15).text |  | ||||||
|             val document = Jsoup.parse(html) |  | ||||||
|             val mainbody = document.getElementsByTag("body") |  | ||||||
|             // All rows will be hardcoded bc of the nature of the site |  | ||||||
|             val rows: List<Pair<String, String>> = listOf( |  | ||||||
|                 Pair("Latest Movies", "featured-titles"), |  | ||||||
|                 Pair("Movies", "dt-movies"), |  | ||||||
|                 Pair("Digitally Restored", "genre_digitally-restored"), |  | ||||||
|                 Pair("Action", "genre_action"), |  | ||||||
|                 Pair("Romance", "genre_romance"), |  | ||||||
|                 Pair("Comedy", "genre_comedy"), |  | ||||||
|                 Pair("Family", "genre_family") |  | ||||||
|                 //Pair("Adult +18", "genre_pinay-sexy-movies") |  | ||||||
|             ) |  | ||||||
|             for (item in rows) { |  | ||||||
|                 val title = item.first |  | ||||||
|                 val inner = mainbody?.select("div#${item.second} > article") |  | ||||||
|                 if (inner != null) { |  | ||||||
|                     val elements: List<SearchResponse> = inner.map { |  | ||||||
|                         // Get inner div from article |  | ||||||
|                         val urlTitle = it?.select("div.data") |  | ||||||
|                         // Fetch details |  | ||||||
|                         val link = urlTitle?.select("a")?.attr("href") ?: "" |  | ||||||
|                         val name = urlTitle?.text() ?: "<No Title>" |  | ||||||
|                         val image = it?.select("div.poster > img")?.attr("src") |  | ||||||
|                         // Get Year from Title |  | ||||||
|                         val rex = Regex("\\((\\d+)") |  | ||||||
|                         val yearRes = rex.find(name)?.value ?: "" |  | ||||||
|                         val year = yearRes.replace("(", "").toIntOrNull() |  | ||||||
| 
 |  | ||||||
|                         val tvType = TvType.Movie |  | ||||||
|                         MovieSearchResponse( |  | ||||||
|                             name, |  | ||||||
|                             link, |  | ||||||
|                             this.name, |  | ||||||
|                             tvType, |  | ||||||
|                             image, |  | ||||||
|                             year, |  | ||||||
|                             null, |  | ||||||
|                         ) |  | ||||||
|                     } |  | ||||||
|                     // Add |  | ||||||
|                     all.add( |  | ||||||
|                         HomePageList( |  | ||||||
|                             title, elements |  | ||||||
|                         ) |  | ||||||
|                     ) |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } catch (e: Exception) { |  | ||||||
|             e.printStackTrace() |  | ||||||
|             Log.i(this.name, "Result => (Exception) ${e}") |  | ||||||
|         } |  | ||||||
|         return HomePageResponse(all) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun search(query: String): List<SearchResponse> { |  | ||||||
|         val url = "$mainUrl/?s=${query}" |  | ||||||
|         val html = app.get(url).text |  | ||||||
|         val document = Jsoup.parse(html).select("div.search-page")?.firstOrNull() |  | ||||||
|             ?.select("div.result-item") |  | ||||||
|         if (document != null) { |  | ||||||
|             return document.map { |  | ||||||
|                 val inner = it.select("article") |  | ||||||
|                 val details = inner.select("div.details") |  | ||||||
|                 val href = details?.select("div.title > a")?.attr("href") ?: "" |  | ||||||
| 
 |  | ||||||
|                 val title = details?.select("div.title")?.text() ?: "<Untitled>" |  | ||||||
|                 val link: String = when (href != "") { |  | ||||||
|                     true -> fixUrl(href) |  | ||||||
|                     false -> "" |  | ||||||
|                 } |  | ||||||
|                 val year = details?.select("div.meta > span.year")?.text()?.toIntOrNull() |  | ||||||
|                 val image = inner.select("div.image > div > a > img")?.attr("src") |  | ||||||
| 
 |  | ||||||
|                 MovieSearchResponse( |  | ||||||
|                     title, |  | ||||||
|                     link, |  | ||||||
|                     this.name, |  | ||||||
|                     TvType.Movie, |  | ||||||
|                     image, |  | ||||||
|                     year |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return listOf<SearchResponse>() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun load(url: String): LoadResponse { |  | ||||||
|         val response = app.get(url).text |  | ||||||
|         val doc = Jsoup.parse(response) |  | ||||||
|         val body = doc.getElementsByTag("body") |  | ||||||
|         val inner = body?.select("div.sheader") |  | ||||||
|         // Identify if movie or series |  | ||||||
|         val isTvSeries = doc?.select("title")?.text()?.lowercase()?.contains("full episode -") ?: false |  | ||||||
| 
 |  | ||||||
|         // Video details |  | ||||||
|         val poster = doc.select("meta[property=og:image]").firstOrNull()?.attr("content") |  | ||||||
|         val title = inner?.select("div.data > h1")?.firstOrNull()?.text() ?: "<Untitled>" |  | ||||||
|         val descript = body?.select("div#info")?.text() |  | ||||||
|         val rex = Regex("\\((\\d+)") |  | ||||||
|         val yearRes = rex.find(title)?.value ?: "" |  | ||||||
|         //Log.i(this.name, "Result => (yearRes) ${yearRes}") |  | ||||||
|         val year = yearRes.replace("(", "").toIntOrNull() |  | ||||||
| 
 |  | ||||||
|         // Video links |  | ||||||
|         val linksContainer = body?.select("div#playcontainer") |  | ||||||
|         val streamlinks = linksContainer?.toString() ?: "" |  | ||||||
|         //Log.i(this.name, "Result => (streamlinks) ${streamlinks}") |  | ||||||
| 
 |  | ||||||
|         // Parse episodes if series |  | ||||||
|         if (isTvSeries) { |  | ||||||
|             val episodeList = ArrayList<TvSeriesEpisode>() |  | ||||||
|             val epList = body?.select("div#playeroptions > ul > li") |  | ||||||
|             //Log.i(this.name, "Result => (epList) ${epList}") |  | ||||||
|             val epLinks = linksContainer?.select("div > div > div.source-box") |  | ||||||
|             //Log.i(this.name, "Result => (epLinks) ${epLinks}") |  | ||||||
|             if (epList != null) { |  | ||||||
|                 for (ep in epList) { |  | ||||||
|                     val epTitle = ep.select("span.title")?.text() ?: "" |  | ||||||
|                     if (epTitle.isNotEmpty()) { |  | ||||||
|                         val epNum = epTitle.lowercase().replace("episode", "").trim().toIntOrNull() |  | ||||||
|                         //Log.i(this.name, "Result => (epNum) ${epNum}") |  | ||||||
|                         val href = when (epNum != null && epLinks != null) { |  | ||||||
|                             true -> epLinks.select("div#source-player-${epNum}") |  | ||||||
|                                 ?.select("iframe")?.attr("src") ?: "" |  | ||||||
|                             false -> "" |  | ||||||
|                         } |  | ||||||
|                         //Log.i(this.name, "Result => (epLinks href) ${href}") |  | ||||||
|                         episodeList.add( |  | ||||||
|                             TvSeriesEpisode( |  | ||||||
|                                 name, |  | ||||||
|                                 null, |  | ||||||
|                                 epNum, |  | ||||||
|                                 href, |  | ||||||
|                                 poster, |  | ||||||
|                                 null |  | ||||||
|                             ) |  | ||||||
|                         ) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 return TvSeriesLoadResponse( |  | ||||||
|                     title, |  | ||||||
|                     url, |  | ||||||
|                     this.name, |  | ||||||
|                     TvType.TvSeries, |  | ||||||
|                     episodeList, |  | ||||||
|                     poster, |  | ||||||
|                     year, |  | ||||||
|                     descript, |  | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     null |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return MovieLoadResponse(title, url, this.name, TvType.Movie, streamlinks, poster, year, descript, null, null) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun loadLinks( |  | ||||||
|         data: String, |  | ||||||
|         isCasting: Boolean, |  | ||||||
|         subtitleCallback: (SubtitleFile) -> Unit, |  | ||||||
|         callback: (ExtractorLink) -> Unit |  | ||||||
|     ): Boolean { |  | ||||||
|         if (data == "about:blank") return false |  | ||||||
|         if (data == "") return false |  | ||||||
|         val sources = mutableListOf<ExtractorLink>() |  | ||||||
|         try { |  | ||||||
|             if (data.contains("playcontainer")) { |  | ||||||
|                 // parse movie servers |  | ||||||
|                 //Log.i(this.name, "Result => (data) ${data}") |  | ||||||
|                 val urls = Jsoup.parse(data).select("div")?.map { item -> |  | ||||||
|                     item.select("iframe")?.attr("src") |  | ||||||
|                 } |  | ||||||
|                 if (!urls.isNullOrEmpty()) { |  | ||||||
|                     for (url in urls) { |  | ||||||
|                         if (!url.isNullOrEmpty()) { |  | ||||||
|                             //Log.i(this.name, "Result => (url) ${url}") |  | ||||||
|                             if (url.contains("dood.watch")) { |  | ||||||
|                                 // WIP: Not working for current domain. Still, adding it. |  | ||||||
|                                 val extractor = DoodLaExtractor() |  | ||||||
|                                 val src = extractor.getUrl(url) |  | ||||||
|                                 if (src != null) { |  | ||||||
|                                     sources.addAll(src) |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             if (url.contains("voe.sx/")) { |  | ||||||
|                                 val doc = Jsoup.parse(app.get(url).text)?.toString() ?: "" |  | ||||||
|                                 if (doc.isNotEmpty()) { |  | ||||||
|                                     val start = "const sources =" |  | ||||||
|                                     var src = doc.substring(doc.indexOf(start)) |  | ||||||
|                                     src = src.substring(start.length, src.indexOf(";")) |  | ||||||
|                                         .replace("0,", "0") |  | ||||||
|                                         .trim() |  | ||||||
|                                     //Log.i(this.name, "Result => (src) ${src}") |  | ||||||
|                                     mapper.readValue<JsonVoeLinks?>(src)?.let { voelink -> |  | ||||||
|                                         //Log.i(this.name, "Result => (voelink) ${voelink}") |  | ||||||
|                                         val linkUrl = voelink.url |  | ||||||
|                                         val linkLabel = voelink.label?.toString() ?: "" |  | ||||||
|                                         if (!linkUrl.isNullOrEmpty()) { |  | ||||||
|                                             sources.add( |  | ||||||
|                                                 ExtractorLink( |  | ||||||
|                                                     name = "Voe m3u8 ${linkLabel}", |  | ||||||
|                                                     source = "Voe", |  | ||||||
|                                                     url = linkUrl, |  | ||||||
|                                                     quality = getQualityFromName(linkLabel), |  | ||||||
|                                                     referer = url, |  | ||||||
|                                                     isM3u8 = true |  | ||||||
|                                                 ) |  | ||||||
|                                             ) |  | ||||||
|                                         } |  | ||||||
|                                     } |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             if (url.startsWith("https://upstream.to")) { |  | ||||||
|                                 // WIP: m3u8 link fetched but not playing |  | ||||||
|                                 //Log.i(this.name, "Result => (no extractor) ${url}") |  | ||||||
|                                 val doc = Jsoup.parse(app.get(url, referer = "https://upstream.to").text)?.toString() ?: "" |  | ||||||
|                                 if (doc.isNotEmpty()) { |  | ||||||
|                                     var reg = Regex("(?<=master)(.*)(?=hls)") |  | ||||||
|                                     val result = reg.find(doc)?.groupValues?.map { |  | ||||||
|                                         it.trim('|') |  | ||||||
|                                     }?.toList() |  | ||||||
|                                     reg = Regex("(?<=\\|file\\|)(.*)(?=\\|remove\\|)") |  | ||||||
|                                     val domainList = reg.find(doc)?.groupValues?.get(1)?.split("|") |  | ||||||
|                                     var domain = when (!domainList.isNullOrEmpty()) { |  | ||||||
|                                         true -> { |  | ||||||
|                                             if (domainList.isNotEmpty()) { |  | ||||||
|                                                 var domName = "" |  | ||||||
|                                                 for (part in domainList) { |  | ||||||
|                                                     domName = "${part}.${domName}" |  | ||||||
|                                                 } |  | ||||||
|                                                 domName.trimEnd('.') |  | ||||||
|                                             } else { "" } |  | ||||||
|                                         } |  | ||||||
|                                         false -> "" |  | ||||||
|                                     } |  | ||||||
|                                     //Log.i(this.name, "Result => (domain) ${domain}") |  | ||||||
|                                     if (domain.isEmpty()) { |  | ||||||
|                                         domain = "s96.upstreamcdn.co" |  | ||||||
|                                         //Log.i(this.name, "Result => (default domain) ${domain}") |  | ||||||
|                                     } |  | ||||||
|                                     result?.forEach { |  | ||||||
|                                         val linkUrl = "https://${domain}/hls/${it}/master.m3u8" |  | ||||||
|                                         sources.add( |  | ||||||
|                                             ExtractorLink( |  | ||||||
|                                                 name = "Upstream m3u8", |  | ||||||
|                                                 source = "Voe", |  | ||||||
|                                                 url = linkUrl, |  | ||||||
|                                                 quality = Qualities.Unknown.value, |  | ||||||
|                                                 referer = "https://upstream.to", |  | ||||||
|                                                 isM3u8 = true |  | ||||||
|                                             ) |  | ||||||
|                                         ) |  | ||||||
|                                     } |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             if (url.startsWith("https://mixdrop.co/")) { |  | ||||||
|                                 val extractor = MixDrop() |  | ||||||
|                                 val src = extractor.getUrl(url) |  | ||||||
|                                 if (src != null) { |  | ||||||
|                                     sources.addAll(src) |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             // end if |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 // parse single link |  | ||||||
|                 if (data.contains("fembed.com")) { |  | ||||||
|                     val extractor = FEmbed() |  | ||||||
|                     extractor.domainUrl = "diasfem.com" |  | ||||||
|                     val src = extractor.getUrl(data) |  | ||||||
|                     if (src.isNotEmpty()) { |  | ||||||
|                         sources.addAll(src) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             // Invoke sources |  | ||||||
|             if (sources.isNotEmpty()) { |  | ||||||
|                 for (source in sources) { |  | ||||||
|                     callback.invoke(source) |  | ||||||
|                     //Log.i(this.name, "Result => (source) ${source.url}") |  | ||||||
|                 } |  | ||||||
|                 return true |  | ||||||
|             } |  | ||||||
|         } catch (e: Exception) { |  | ||||||
|             e.printStackTrace() |  | ||||||
|             Log.i(this.name, "Result => (e) ${e}") |  | ||||||
|         } |  | ||||||
|         return false |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,225 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import android.util.Log | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.extractors.FEmbed | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
|  | import org.jsoup.Jsoup | ||||||
|  | import java.lang.Exception | ||||||
|  | 
 | ||||||
|  | class PinoyMoviePediaProvider : MainAPI() { | ||||||
|  |     override val name = "Pinoy Moviepedia" | ||||||
|  |     override val mainUrl = "https://pinoymoviepedia.ru" | ||||||
|  |     override val lang = "tl" | ||||||
|  |     override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries) | ||||||
|  |     override val hasDownloadSupport = true | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasQuickSearch = false | ||||||
|  | 
 | ||||||
|  |     override fun getMainPage(): HomePageResponse { | ||||||
|  |         val all = ArrayList<HomePageList>() | ||||||
|  |         val html = app.get(mainUrl).text | ||||||
|  |         val document = Jsoup.parse(html) | ||||||
|  |         val mainbody = document.getElementsByTag("body") | ||||||
|  |         // All rows will be hardcoded bc of the nature of the site | ||||||
|  |         val rows: List<Pair<String, String>> = listOf( | ||||||
|  |             Pair("Latest Movies", "featured-titles"), | ||||||
|  |             Pair("Movies", "dt-movies"), | ||||||
|  |             Pair("Digitally Restored", "genre_digitally-restored"), | ||||||
|  |             Pair("Action", "genre_action"), | ||||||
|  |             Pair("Romance", "genre_romance"), | ||||||
|  |             Pair("Comedy", "genre_comedy"), | ||||||
|  |             Pair("Family", "genre_family") | ||||||
|  |             //Pair("Adult +18", "genre_pinay-sexy-movies") | ||||||
|  |         ) | ||||||
|  |         for (item in rows) { | ||||||
|  |             val title = item.first | ||||||
|  |             val inner = mainbody?.select("div#${item.second} > article") | ||||||
|  |             if (inner != null) { | ||||||
|  |                 val elements: List<SearchResponse> = inner.map { | ||||||
|  |                     // Get inner div from article | ||||||
|  |                     val urlTitle = it?.select("div.data") | ||||||
|  |                     // Fetch details | ||||||
|  |                     val link = urlTitle?.select("a")?.attr("href") ?: "" | ||||||
|  |                     val name = urlTitle?.text() ?: "" | ||||||
|  |                     val image = it?.select("div.poster > img")?.attr("src") | ||||||
|  |                     // Get Year from Title | ||||||
|  |                     val rex = Regex("\\((\\d+)") | ||||||
|  |                     val yearRes = rex.find(name)?.value ?: "" | ||||||
|  |                     val year = yearRes.replace("(", "").toIntOrNull() | ||||||
|  | 
 | ||||||
|  |                     val tvType = TvType.Movie | ||||||
|  |                     MovieSearchResponse( | ||||||
|  |                         name, | ||||||
|  |                         link, | ||||||
|  |                         this.name, | ||||||
|  |                         tvType, | ||||||
|  |                         image, | ||||||
|  |                         year, | ||||||
|  |                         null, | ||||||
|  |                     ) | ||||||
|  |                 }.filter { a -> a.url.isNotEmpty() } | ||||||
|  |                         .filter { b -> b.name.isNotEmpty() } | ||||||
|  |                         .distinctBy { c -> c.url } | ||||||
|  |                 // Add | ||||||
|  |                 all.add( | ||||||
|  |                     HomePageList( | ||||||
|  |                         title, elements | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return HomePageResponse(all) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun search(query: String): List<SearchResponse> { | ||||||
|  |         val url = "$mainUrl/?s=${query}" | ||||||
|  |         val html = app.get(url).text | ||||||
|  |         val document = Jsoup.parse(html).select("div.search-page")?.firstOrNull() | ||||||
|  |             ?.select("div.result-item") | ||||||
|  |         if (document != null) { | ||||||
|  |             return document.map { | ||||||
|  |                 val inner = it.select("article") | ||||||
|  |                 val details = inner.select("div.details") | ||||||
|  |                 val href = details?.select("div.title > a")?.attr("href") ?: "" | ||||||
|  | 
 | ||||||
|  |                 val title = details?.select("div.title")?.text() ?: "" | ||||||
|  |                 val link: String = when (href != "") { | ||||||
|  |                     true -> fixUrl(href) | ||||||
|  |                     false -> "" | ||||||
|  |                 } | ||||||
|  |                 val year = details?.select("div.meta > span.year")?.text()?.toIntOrNull() | ||||||
|  |                 val image = inner.select("div.image > div > a > img")?.attr("src") | ||||||
|  | 
 | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     title, | ||||||
|  |                     link, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.Movie, | ||||||
|  |                     image, | ||||||
|  |                     year | ||||||
|  |                 ) | ||||||
|  |             }.filter { a -> a.url.isNotEmpty() } | ||||||
|  |                     .filter { b -> b.name.isNotEmpty() } | ||||||
|  |                     .distinctBy { c -> c.url } | ||||||
|  |         } | ||||||
|  |         return listOf() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun load(url: String): LoadResponse { | ||||||
|  |         val response = app.get(url).text | ||||||
|  |         val doc = Jsoup.parse(response) | ||||||
|  |         val body = doc.getElementsByTag("body") | ||||||
|  |         val inner = body?.select("div.sheader") | ||||||
|  |         // Identify if movie or series | ||||||
|  |         val isTvSeries = doc?.select("title")?.text()?.lowercase()?.contains("full episode -") ?: false | ||||||
|  | 
 | ||||||
|  |         // Video details | ||||||
|  |         val poster = doc.select("meta[property=og:image]").firstOrNull()?.attr("content") | ||||||
|  |         val title = inner?.select("div.data > h1")?.firstOrNull()?.text() ?: "<Untitled>" | ||||||
|  |         val descript = body?.select("div#info")?.text() | ||||||
|  |         val rex = Regex("\\((\\d+)") | ||||||
|  |         val yearRes = rex.find(title)?.value ?: "" | ||||||
|  |         //Log.i(this.name, "Result => (yearRes) ${yearRes}") | ||||||
|  |         val year = yearRes.replace("(", "").toIntOrNull() | ||||||
|  | 
 | ||||||
|  |         // Video links | ||||||
|  |         val linksContainer = body?.select("div#playcontainer") | ||||||
|  |         val streamlinks = linksContainer?.toString() ?: "" | ||||||
|  |         //Log.i(this.name, "Result => (streamlinks) ${streamlinks}") | ||||||
|  | 
 | ||||||
|  |         // Parse episodes if series | ||||||
|  |         if (isTvSeries) { | ||||||
|  |             val episodeList = ArrayList<TvSeriesEpisode>() | ||||||
|  |             val epList = body?.select("div#playeroptions > ul > li") | ||||||
|  |             //Log.i(this.name, "Result => (epList) ${epList}") | ||||||
|  |             val epLinks = linksContainer?.select("div > div > div.source-box") | ||||||
|  |             //Log.i(this.name, "Result => (epLinks) ${epLinks}") | ||||||
|  |             if (epList != null) { | ||||||
|  |                 for (ep in epList) { | ||||||
|  |                     val epTitle = ep.select("span.title")?.text() ?: "" | ||||||
|  |                     if (epTitle.isNotEmpty()) { | ||||||
|  |                         val epNum = epTitle.lowercase().replace("episode", "").trim().toIntOrNull() | ||||||
|  |                         //Log.i(this.name, "Result => (epNum) ${epNum}") | ||||||
|  |                         val href = when (epNum != null && epLinks != null) { | ||||||
|  |                             true -> epLinks.select("div#source-player-${epNum}") | ||||||
|  |                                 ?.select("iframe")?.attr("src") ?: "" | ||||||
|  |                             false -> "" | ||||||
|  |                         } | ||||||
|  |                         //Log.i(this.name, "Result => (epLinks href) ${href}") | ||||||
|  |                         episodeList.add( | ||||||
|  |                             TvSeriesEpisode( | ||||||
|  |                                 name, | ||||||
|  |                                 null, | ||||||
|  |                                 epNum, | ||||||
|  |                                 href, | ||||||
|  |                                 poster, | ||||||
|  |                                 null | ||||||
|  |                             ) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 return TvSeriesLoadResponse( | ||||||
|  |                     title, | ||||||
|  |                     url, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.TvSeries, | ||||||
|  |                     episodeList, | ||||||
|  |                     poster, | ||||||
|  |                     year, | ||||||
|  |                     descript, | ||||||
|  |                     null, | ||||||
|  |                     null, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return MovieLoadResponse(title, url, this.name, TvType.Movie, streamlinks, poster, year, descript, null, null) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         if (data == "about:blank") return false | ||||||
|  |         if (data.isEmpty()) return false | ||||||
|  |         val sources = mutableListOf<ExtractorLink>() | ||||||
|  | 
 | ||||||
|  |         // parse movie servers | ||||||
|  |         if (data.contains("playcontainer")) { | ||||||
|  |             Jsoup.parse(data).select("div")?.map { item -> | ||||||
|  |                 val url = item.select("iframe")?.attr("src") | ||||||
|  |                 if (!url.isNullOrEmpty()) { | ||||||
|  |                     //Log.i(this.name, "Result => (url) ${url}") | ||||||
|  |                     loadExtractor(url, url, callback) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             // parse single link | ||||||
|  |             try { | ||||||
|  |                 if (data.contains("fembed.com")) { | ||||||
|  |                     val extractor = FEmbed() | ||||||
|  |                     extractor.domainUrl = "diasfem.com" | ||||||
|  |                     val src = extractor.getUrl(data) | ||||||
|  |                     if (src.isNotEmpty()) { | ||||||
|  |                         sources.addAll(src) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 Log.i(this.name, "Result => (exception) $e") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // Invoke sources | ||||||
|  |         if (sources.isNotEmpty()) { | ||||||
|  |             for (source in sources) { | ||||||
|  |                 callback.invoke(source) | ||||||
|  |                 //Log.i(this.name, "Result => (source) ${source.url}") | ||||||
|  |                 return true | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return false | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,233 @@ | ||||||
|  | package com.lagradost.cloudstream3.movieproviders | ||||||
|  | 
 | ||||||
|  | import android.util.Log | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.extractors.* | ||||||
|  | import com.lagradost.cloudstream3.network.DdosGuardKiller | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
|  | import org.jsoup.Jsoup | ||||||
|  | import org.jsoup.select.Elements | ||||||
|  | 
 | ||||||
|  | class PinoyMoviesEsProvider : MainAPI() { | ||||||
|  |     override val name = "Pinoy Movies" | ||||||
|  |     override val mainUrl = "https://pinoymovies.es/" | ||||||
|  |     override val lang = "tl" | ||||||
|  |     override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries) | ||||||
|  |     override val hasDownloadSupport = false | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasQuickSearch = false | ||||||
|  | 
 | ||||||
|  |     private fun getRowElements(mainbody: Elements, rows: List<Pair<String, String>>, sep: String): MutableList<HomePageList> { | ||||||
|  |         val all = mutableListOf<HomePageList>() | ||||||
|  |         for (item in rows) { | ||||||
|  |             val title = item.first | ||||||
|  |             val inner = mainbody.select("div${sep}${item.second} > article") | ||||||
|  |             if (inner != null) { | ||||||
|  |                 val elements: List<SearchResponse> = inner.map { | ||||||
|  |                     // Get inner div from article | ||||||
|  |                     var urlTitle = it?.select("div.data.dfeatur") | ||||||
|  |                     if (urlTitle.isNullOrEmpty()) { | ||||||
|  |                         urlTitle = it?.select("div.data") | ||||||
|  |                     } | ||||||
|  |                     // Fetch details | ||||||
|  |                     val link = urlTitle?.select("a")?.attr("href") ?: "" | ||||||
|  |                     val name = urlTitle?.text() ?: "" | ||||||
|  |                     val year = urlTitle?.select("span")?.text()?.toIntOrNull() | ||||||
|  |                     //Log.i(this.name, "Result => (link) ${link}") | ||||||
|  |                     val image = it?.select("div.poster > img")?.attr("data-src") | ||||||
|  | 
 | ||||||
|  |                     MovieSearchResponse( | ||||||
|  |                         name, | ||||||
|  |                         link, | ||||||
|  |                         this.name, | ||||||
|  |                         TvType.Movie, | ||||||
|  |                         image, | ||||||
|  |                         year, | ||||||
|  |                         null, | ||||||
|  |                     ) | ||||||
|  |                 }.filter { a -> a.url.isNotEmpty() } | ||||||
|  |                         .filter { b -> b.name.isNotEmpty() } | ||||||
|  |                         .distinctBy { c -> c.url } | ||||||
|  |                 if (!elements.isNullOrEmpty()) { | ||||||
|  |                     all.add(HomePageList( | ||||||
|  |                             title, elements | ||||||
|  |                     )) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return all | ||||||
|  |     } | ||||||
|  |     override fun getMainPage(): HomePageResponse { | ||||||
|  |         val all = ArrayList<HomePageList>() | ||||||
|  |         val html = app.get(mainUrl).text | ||||||
|  |         val document = Jsoup.parse(html) | ||||||
|  |         val mainbody = document.getElementsByTag("body") | ||||||
|  |         if (mainbody != null) { | ||||||
|  |             // All rows will be hardcoded bc of the nature of the site | ||||||
|  |             val homepage1 = getRowElements(mainbody, listOf( | ||||||
|  |                 Pair("Suggestion", "items.featured"), | ||||||
|  |                 Pair("All Movies", "items.full") | ||||||
|  |             ), ".") | ||||||
|  |             if (homepage1.isNotEmpty()) { | ||||||
|  |                 all.addAll(homepage1) | ||||||
|  |             } | ||||||
|  |             //2nd rows | ||||||
|  |             val homepage2 = getRowElements(mainbody, listOf( | ||||||
|  |                 Pair("Action", "genre_action"), | ||||||
|  |                 Pair("Comedy", "genre_comedy"), | ||||||
|  |                 Pair("Romance", "genre_romance"), | ||||||
|  |                 Pair("Horror", "genre_horror") | ||||||
|  |                 //Pair("Rated-R", "genre_rated-r") | ||||||
|  |             ), "#") | ||||||
|  |             if (homepage2.isNotEmpty()) { | ||||||
|  |                 all.addAll(homepage2) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return HomePageResponse(all) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun search(query: String): List<SearchResponse> { | ||||||
|  |         val url = "$mainUrl/?s=${query}" | ||||||
|  |         val html = app.get(url, interceptor = DdosGuardKiller(true)).text | ||||||
|  |         Log.i(this.name, "Result => (html) ${Jsoup.parse(html).getElementsByTag("body")}") | ||||||
|  |         val document = Jsoup.parse(html).select("div#archive-content > article") | ||||||
|  |         if (document != null) { | ||||||
|  |             return document.map { | ||||||
|  |                 val urlTitle = it?.select("div.data") | ||||||
|  |                 // Fetch details | ||||||
|  |                 val link = urlTitle?.select("a")?.attr("href") ?: "" | ||||||
|  |                 val title = urlTitle?.text() ?: "<No Title>" | ||||||
|  |                 val year = urlTitle?.select("span.year")?.text()?.toIntOrNull() | ||||||
|  | 
 | ||||||
|  |                 val image = it?.select("div.poster > img")?.attr("src") | ||||||
|  | 
 | ||||||
|  |                 MovieSearchResponse( | ||||||
|  |                     title, | ||||||
|  |                     link, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.Movie, | ||||||
|  |                     image, | ||||||
|  |                     year | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return listOf() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun load(url: String): LoadResponse { | ||||||
|  |         val response = app.get(url).text | ||||||
|  |         val doc = Jsoup.parse(response) | ||||||
|  |         val body = doc.getElementsByTag("body") | ||||||
|  |         val inner = body?.select("div.sheader") | ||||||
|  |         // Identify if movie or series | ||||||
|  |         val isTvSeries = doc?.select("title")?.text()?.lowercase()?.contains("full episode -") ?: false | ||||||
|  | 
 | ||||||
|  |         // Video details | ||||||
|  |         val data = inner?.select("div.sheader > div.data") | ||||||
|  |         val title = data?.select("h1")?.firstOrNull()?.text() ?: "<Untitled>" | ||||||
|  |         val year = data?.select("span.date")?.text()?.takeLast(4)?.toIntOrNull() | ||||||
|  | 
 | ||||||
|  |         val descript = body?.select("div#info > div.wp-content")?.text() | ||||||
|  |         val poster = body?.select("div.poster > img")?.attr("src") | ||||||
|  | 
 | ||||||
|  |         // Video links | ||||||
|  |         val linksContainer = body?.select("div#playcontainer") | ||||||
|  |         val streamlinks = linksContainer?.toString() ?: "" | ||||||
|  |         //Log.i(this.name, "Result => (streamlinks) ${streamlinks}") | ||||||
|  | 
 | ||||||
|  |         // Parse episodes if series | ||||||
|  |         if (isTvSeries) { | ||||||
|  |             val episodeList = ArrayList<TvSeriesEpisode>() | ||||||
|  |             val epList = body?.select("div#playeroptions > ul > li") | ||||||
|  |             //Log.i(this.name, "Result => (epList) ${epList}") | ||||||
|  |             val epLinks = linksContainer?.select("div > div > div.source-box") | ||||||
|  |             //Log.i(this.name, "Result => (epLinks) ${epLinks}") | ||||||
|  |             if (epList != null) { | ||||||
|  |                 for (ep in epList) { | ||||||
|  |                     val epTitle = ep.select("span.title")?.text() ?: "" | ||||||
|  |                     if (epTitle.isNotEmpty()) { | ||||||
|  |                         val epNum = epTitle.lowercase().replace("episode", "").trim().toIntOrNull() | ||||||
|  |                         //Log.i(this.name, "Result => (epNum) ${epNum}") | ||||||
|  |                         val href = when (epNum != null && epLinks != null) { | ||||||
|  |                             true -> epLinks.select("div#source-player-${epNum}") | ||||||
|  |                                     ?.select("iframe")?.attr("src") ?: "" | ||||||
|  |                             false -> "" | ||||||
|  |                         } | ||||||
|  |                         //Log.i(this.name, "Result => (epLinks href) ${href}") | ||||||
|  |                         episodeList.add( | ||||||
|  |                             TvSeriesEpisode( | ||||||
|  |                                 name = name, | ||||||
|  |                                 season = null, | ||||||
|  |                                 episode = epNum, | ||||||
|  |                                 data = href, | ||||||
|  |                                 posterUrl = poster, | ||||||
|  |                                 date = year.toString() | ||||||
|  |                             ) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 return TvSeriesLoadResponse( | ||||||
|  |                     title, | ||||||
|  |                     url, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.TvSeries, | ||||||
|  |                     episodeList, | ||||||
|  |                     poster, | ||||||
|  |                     year, | ||||||
|  |                     descript, | ||||||
|  |                     null, | ||||||
|  |                     null, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return MovieLoadResponse(title, url, this.name, TvType.Movie, streamlinks, poster, year, descript, null, null) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun loadLinks( | ||||||
|  |             data: String, | ||||||
|  |             isCasting: Boolean, | ||||||
|  |             subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |             callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         if (data == "about:blank") return false | ||||||
|  |         if (data.isEmpty()) return false | ||||||
|  |         val sources = mutableListOf<ExtractorLink>() | ||||||
|  |         try { | ||||||
|  |             if (data.contains("playcontainer")) { | ||||||
|  |                 // parse movie servers | ||||||
|  |                 //Log.i(this.name, "Result => (data) ${data}") | ||||||
|  |                 Jsoup.parse(data).select("div")?.map { item -> | ||||||
|  |                     val url = item.select("iframe")?.attr("src") | ||||||
|  |                     if (!url.isNullOrEmpty()) { | ||||||
|  |                         //Log.i(this.name, "Result => (url) ${url}") | ||||||
|  |                         loadExtractor(url, url, callback) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 // parse single link | ||||||
|  |                 if (data.contains("fembed.com")) { | ||||||
|  |                     val extractor = FEmbed() | ||||||
|  |                     extractor.domainUrl = "diasfem.com" | ||||||
|  |                     val src = extractor.getUrl(data) | ||||||
|  |                     if (src.isNotEmpty()) { | ||||||
|  |                         sources.addAll(src) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             // Invoke sources | ||||||
|  |             if (sources.isNotEmpty()) { | ||||||
|  |                 for (source in sources) { | ||||||
|  |                     callback.invoke(source) | ||||||
|  |                     //Log.i(this.name, "Result => (source) ${source.url}") | ||||||
|  |                 } | ||||||
|  |                 return true | ||||||
|  |             } | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             e.printStackTrace() | ||||||
|  |             Log.i(this.name, "Result => (e) ${e}") | ||||||
|  |         } | ||||||
|  |         return false | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -83,6 +83,8 @@ val extractorApis: Array<ExtractorApi> = arrayOf( | ||||||
|     SBPlay(), |     SBPlay(), | ||||||
|     FEmbed(), |     FEmbed(), | ||||||
|     WatchSB(), |     WatchSB(), | ||||||
|  |     VoeExtractor(), | ||||||
|  |     UpstreamExtractor(), | ||||||
| 
 | 
 | ||||||
|     // dood extractors |     // dood extractors | ||||||
|     DoodToExtractor(), |     DoodToExtractor(), | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue