forked from recloudstream/cloudstream
		
	[Feature] Add Recommendations and Tags to various providers. (#583)
* PinoyMoviePedia: Add recommendations and tags. * PinoyMoviesEs: Add recs and tags. * pinoyHD: Add tags. Fetch hidden links in movie description. * DramaSee: Add tags and recs. * WatchAsian: Load tags from details page of url. * Kdramahood: Add recs. * [skip ci] Replace isNotEmpty() with isNotBlank() * Minor refactor to PinoyHD and PinoyMoviesEs HomePage entries.
This commit is contained in:
		
							parent
							
								
									11e10a9bd8
								
							
						
					
					
						commit
						765aa7c5af
					
				
					 10 changed files with 350 additions and 190 deletions
				
			
		|  | @ -15,7 +15,7 @@ class UpstreamExtractor: ExtractorApi() { | |||
|         //Log.i(this.name, "Result => (no extractor) ${url}") | ||||
|         val sources: MutableList<ExtractorLink> = mutableListOf() | ||||
|         val doc = app.get(url, referer = referer).text | ||||
|         if (doc.isNotEmpty()) { | ||||
|         if (doc.isNotBlank()) { | ||||
|             var reg = Regex("(?<=master)(.*)(?=hls)") | ||||
|             val result = reg.find(doc)?.groupValues?.map { | ||||
|                 it.trim('|') | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ open class VoeExtractor : ExtractorApi() { | |||
|     override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> { | ||||
|         val extractedLinksList: MutableList<ExtractorLink> = mutableListOf() | ||||
|         val doc = app.get(url).text | ||||
|         if (doc.isNotEmpty()) { | ||||
|         if (doc.isNotBlank()) { | ||||
|             val start = "const sources =" | ||||
|             var src = doc.substring(doc.indexOf(start)) | ||||
|             src = src.substring(start.length, src.indexOf(";")) | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ class AsianEmbedHelper { | |||
|                 links.apmap { | ||||
|                     val datavid = it.attr("data-video") ?: "" | ||||
|                     //Log.i("AsianEmbed", "Result => (datavid) ${datavid}") | ||||
|                     if (datavid.isNotEmpty()) { | ||||
|                     if (datavid.isNotBlank()) { | ||||
|                         val res = loadExtractor(datavid, url, callback) | ||||
|                         Log.i("AsianEmbed", "Result => ($res) (datavid) $datavid") | ||||
|                     } | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ class VstreamhubHelper { | |||
|                             val startString = "window.open([" | ||||
|                             val bb = aa.substring(aa.indexOf(startString)) | ||||
|                             val datavid = bb.substring(startString.length, bb.indexOf("]")).removeSurrounding("\"") | ||||
|                             if (datavid.isNotEmpty()) { | ||||
|                             if (datavid.isNotBlank()) { | ||||
|                                 loadExtractor(datavid, url, callback) | ||||
|                                 //Log.i(baseName, "Result => (datavid) ${datavid}") | ||||
|                             } | ||||
|  |  | |||
|  | @ -91,8 +91,24 @@ class DramaSeeProvider : MainAPI() { | |||
|         val year = if (title.length > 5) { title.substring(title.length - 5) | ||||
|             .trim().trimEnd(')').toIntOrNull() } else { null } | ||||
|         //Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}") | ||||
|         val descript = body?.select("div.series-body")?.firstOrNull() | ||||
|             ?.select("div.js-content")?.text() | ||||
|         val seriesBody = body?.select("div.series-body") | ||||
|         val descript = seriesBody?.firstOrNull()?.select("div.js-content")?.text() | ||||
|         val tags = seriesBody?.select("div.series-tags > a")?.mapNotNull { it?.text()?.trim() ?: return@mapNotNull null } | ||||
|         val recs = body?.select("ul.series > li")?.mapNotNull { | ||||
|             val a = it.select("a.series-img") ?: return@mapNotNull null | ||||
|             val aUrl = fixUrlNull(a.attr("href")) ?: return@mapNotNull null | ||||
|             val aImg = fixUrlNull(a.select("img")?.attr("src")) | ||||
|             val aName = a.select("img")?.attr("alt") ?: return@mapNotNull null | ||||
|             val aYear = aName.trim().takeLast(5).removeSuffix(")").toIntOrNull() | ||||
|             MovieSearchResponse( | ||||
|                 url = aUrl, | ||||
|                 name = aName, | ||||
|                 type = TvType.Movie, | ||||
|                 posterUrl = aImg, | ||||
|                 year = aYear, | ||||
|                 apiName = this.name | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         // Episodes Links | ||||
|         val episodeList = ArrayList<TvSeriesEpisode>() | ||||
|  | @ -101,7 +117,7 @@ class DramaSeeProvider : MainAPI() { | |||
|             val count = innerA.select("span.episode")?.text()?.toIntOrNull() ?: 0 | ||||
|             val epLink = fixUrlNull(innerA.attr("href")) ?: return@forEach | ||||
|             //Log.i(this.name, "Result => (epLink) ${epLink}") | ||||
|             if (epLink.isNotEmpty()) { | ||||
|             if (epLink.isNotBlank()) { | ||||
|                 // Fetch video links | ||||
|                 val epVidLinkEl = app.get(epLink, referer = mainUrl).document | ||||
|                 val ajaxUrl = epVidLinkEl.select("div#js-player")?.attr("embed") | ||||
|  | @ -111,7 +127,7 @@ class DramaSeeProvider : MainAPI() { | |||
|                     val listOfLinks = mutableListOf<String>() | ||||
|                     innerPage.select("div.player.active > main > div")?.forEach { em -> | ||||
|                         val href = fixUrlNull(em.attr("src")) ?: "" | ||||
|                         if (href.isNotEmpty()) { | ||||
|                         if (href.isNotBlank()) { | ||||
|                             listOfLinks.add(href) | ||||
|                         } | ||||
|                     } | ||||
|  | @ -133,20 +149,30 @@ class DramaSeeProvider : MainAPI() { | |||
| 
 | ||||
|         //If there's only 1 episode, consider it a movie. | ||||
|         if (episodeList.size == 1) { | ||||
|             return MovieLoadResponse(title, url, this.name, TvType.Movie, episodeList[0].data, poster, year, descript, null, null) | ||||
|             return MovieLoadResponse( | ||||
|                 name = title, | ||||
|                 url = url, | ||||
|                 apiName = this.name, | ||||
|                 type = TvType.Movie, | ||||
|                 dataUrl = episodeList[0].data, | ||||
|                 posterUrl = poster, | ||||
|                 year = year, | ||||
|                 plot = descript, | ||||
|                 recommendations = recs, | ||||
|                 tags = tags | ||||
|             ) | ||||
|         } | ||||
|         return TvSeriesLoadResponse( | ||||
|             title, | ||||
|             url, | ||||
|             this.name, | ||||
|             TvType.TvSeries, | ||||
|             episodeList.reversed(), | ||||
|             poster, | ||||
|             year, | ||||
|             descript, | ||||
|             null, | ||||
|             null, | ||||
|             null | ||||
|             name = title, | ||||
|             url = url, | ||||
|             apiName = this.name, | ||||
|             type = TvType.TvSeries, | ||||
|             episodes = episodeList.reversed(), | ||||
|             posterUrl = poster, | ||||
|             year = year, | ||||
|             plot = descript, | ||||
|             recommendations = recs, | ||||
|             tags = tags | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -110,6 +110,24 @@ class KdramaHoodProvider : MainAPI() { | |||
|             res | ||||
|         } catch (e: Exception) { null } | ||||
| 
 | ||||
|         val recs = doc.select("div.sidebartv > div.tvitemrel")?.mapNotNull { | ||||
|             val a = it?.select("a") ?: return@mapNotNull null | ||||
|             val aUrl = fixUrlNull(a.attr("href")) ?: return@mapNotNull null | ||||
|             val aImg = a.select("img") | ||||
|             val aCover = fixUrlNull(aImg?.attr("src")) ?: fixUrlNull(aImg?.attr("data-src")) | ||||
|             val aNameYear = a.select("div.datatvrel") ?: return@mapNotNull null | ||||
|             val aName = aNameYear.select("h4")?.text() ?: aImg?.attr("alt") ?: return@mapNotNull null | ||||
|             val aYear = aName.trim().takeLast(5).removeSuffix(")").toIntOrNull() | ||||
|             MovieSearchResponse( | ||||
|                 url = aUrl, | ||||
|                 name = aName, | ||||
|                 type = TvType.Movie, | ||||
|                 posterUrl = aCover, | ||||
|                 year = aYear, | ||||
|                 apiName = this.name | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         // Episodes Links | ||||
|         val episodeList = inner?.select("ul.episodios > li")?.mapNotNull { ep -> | ||||
|             //Log.i(this.name, "Result => (ep) ${ep}") | ||||
|  | @ -119,7 +137,7 @@ class KdramaHoodProvider : MainAPI() { | |||
|             //Log.i(this.name, "Result => (innerA) ${innerA}") | ||||
|             val epLink = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null | ||||
|             //Log.i(this.name, "Result => (epLink) ${epLink}") | ||||
|             if (epLink.isNotEmpty()) { | ||||
|             if (epLink.isNotBlank()) { | ||||
|                 // Fetch video links | ||||
|                 val epVidLinkEl = app.get(epLink, referer = mainUrl).document | ||||
|                 val epLinksContent = epVidLinkEl.selectFirst("div.player_nav > script")?.html() | ||||
|  | @ -131,20 +149,10 @@ class KdramaHoodProvider : MainAPI() { | |||
|                     Jsoup.parse(epLinksContent)?.select("div")?.forEach { em -> | ||||
|                         val href = em?.html()?.trim()?.removePrefix("'") ?: return@forEach | ||||
|                         //Log.i(this.name, "Result => (ep#$count link) $href") | ||||
|                         if (href.isNotEmpty()) { | ||||
|                         if (href.isNotBlank()) { | ||||
|                             listOfLinks.add(fixUrl(href)) | ||||
|                         } | ||||
|                     } | ||||
|                     /* Doesn't get all links for some reasons | ||||
|                     val rex = Regex("(?<=ifr_target.src =)(.*)(?=';)") | ||||
|                     rex.find(epLinksContent)?.groupValues?.forEach { em -> | ||||
|                         val href = em.trim() | ||||
|                         Log.i(this.name, "Result => (ep #$count href) $href") | ||||
|                         if (href.isNotEmpty()) { | ||||
|                             listOfLinks.add(href) | ||||
|                         } | ||||
|                     } | ||||
|                      */ | ||||
|                 } | ||||
|             } | ||||
|             TvSeriesEpisode( | ||||
|  | @ -159,20 +167,28 @@ class KdramaHoodProvider : MainAPI() { | |||
| 
 | ||||
|         //If there's only 1 episode, consider it a movie. | ||||
|         if (episodeList.size == 1) { | ||||
|             return MovieLoadResponse(title, url, this.name, TvType.Movie, episodeList[0].data, poster, year, descript, null, null) | ||||
|             return MovieLoadResponse( | ||||
|                 name = title, | ||||
|                 url = url, | ||||
|                 apiName = this.name, | ||||
|                 type = TvType.Movie, | ||||
|                 dataUrl = episodeList[0].data, | ||||
|                 posterUrl = poster, | ||||
|                 year = year, | ||||
|                 plot = descript, | ||||
|                 recommendations = recs | ||||
|             ) | ||||
|         } | ||||
|         return TvSeriesLoadResponse( | ||||
|             title, | ||||
|             url, | ||||
|             this.name, | ||||
|             TvType.TvSeries, | ||||
|             episodeList.reversed(), | ||||
|             poster, | ||||
|             year, | ||||
|             descript, | ||||
|             null, | ||||
|             null, | ||||
|             null | ||||
|             name = title, | ||||
|             url = url, | ||||
|             apiName = this.name, | ||||
|             type = TvType.TvSeries, | ||||
|             episodes = episodeList.reversed(), | ||||
|             posterUrl = poster, | ||||
|             year = year, | ||||
|             plot = descript, | ||||
|             recommendations = recs | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|  | @ -184,7 +200,7 @@ class KdramaHoodProvider : MainAPI() { | |||
|     ): Boolean { | ||||
|         var count = 0 | ||||
|         mapper.readValue<List<String>>(data).apmap { item -> | ||||
|             if (item.isNotEmpty()) { | ||||
|             if (item.isNotBlank()) { | ||||
|                 count++ | ||||
|                 var url = item.trim() | ||||
|                 if (url.startsWith("//")) { | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| package com.lagradost.cloudstream3.movieproviders | ||||
| 
 | ||||
| import android.util.Log | ||||
| import com.fasterxml.jackson.module.kotlin.readValue | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||
|  | @ -23,38 +24,31 @@ class PinoyHDXyzProvider : MainAPI() { | |||
| 
 | ||||
|         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 | ||||
|             val elements = row?.select("li.img_frame.preview-tumb7")?.mapNotNull { | ||||
|                 // Get inner div from article | ||||
|                 val innerBody = it?.selectFirst("a") ?: return@mapNotNull null | ||||
|                 // Fetch details | ||||
|                 val name = it.text() | ||||
|                 if (name.isNullOrBlank()) { return@mapNotNull null } | ||||
| 
 | ||||
|                 val link = innerBody.attr("href") ?: return@mapNotNull null | ||||
|                 val image = fixUrlNull(innerBody.select("img")?.attr("src")) | ||||
|                 //Log.i(this.name, "Result => (innerBody, image) ${innerBody} / ${image}") | ||||
|                 // Get Year from Link | ||||
|                 val rex = Regex("_(\\d+)_") | ||||
|                 val year = rex.find(link)?.value?.replace("_", "")?.toIntOrNull() | ||||
|                 //Log.i(this.name, "Result => (yearRes, year) ${yearRes} / ${year}") | ||||
|                 MovieSearchResponse( | ||||
|                     name = name, | ||||
|                     url = link, | ||||
|                     apiName = this.name, | ||||
|                     type = TvType.Movie, | ||||
|                     posterUrl = image, | ||||
|                     year = year | ||||
|                 ) | ||||
|             }?.distinctBy { c -> c.url } ?: listOf() | ||||
|             // Add to Homepage | ||||
|             if (elements.isNotEmpty()) { | ||||
|                 all.add( | ||||
|                     HomePageList( | ||||
|                         title, elements | ||||
|  | @ -78,12 +72,12 @@ class PinoyHDXyzProvider : MainAPI() { | |||
|             val image = null // site provides no image on search page | ||||
| 
 | ||||
|             MovieSearchResponse( | ||||
|                 title, | ||||
|                 link, | ||||
|                 this.name, | ||||
|                 TvType.Movie, | ||||
|                 image, | ||||
|                 year | ||||
|                 name = title, | ||||
|                 url = link, | ||||
|                 apiName = this.name, | ||||
|                 type = TvType.Movie, | ||||
|                 posterUrl = image, | ||||
|                 year = year | ||||
|             ) | ||||
|         }?.distinctBy { c -> c.url } ?: listOf() | ||||
|     } | ||||
|  | @ -93,29 +87,57 @@ class PinoyHDXyzProvider : MainAPI() { | |||
|         val body = doc.getElementsByTag("body") | ||||
|         val inner = body?.select("div.info") | ||||
| 
 | ||||
|         // Video links | ||||
|         val listOfLinks: MutableList<String> = mutableListOf() | ||||
| 
 | ||||
|         // Video details | ||||
|         val imgLinkCode = inner?.select("div.portfolio-tumb.ph-link > img")?.attr("src") | ||||
|         val poster = if (!imgLinkCode.isNullOrEmpty()) { "${mainUrl}${imgLinkCode}" } else { null } | ||||
|         var title = "" | ||||
|         var year: Int? = null | ||||
|         var tags: List<String>? = null | ||||
|         val poster = fixUrlNull(inner?.select("div.portfolio-tumb.ph-link > img")?.attr("src")) | ||||
|         //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}") | ||||
|         val title = inner?.select("td.trFon2.entt")?.firstOrNull()?.text() ?: "<Untitled>" | ||||
|         var yearRes = inner?.select("td.trFon2")?.toString() | ||||
|         val year = if (!yearRes.isNullOrEmpty()) { | ||||
|             if (yearRes.contains("var year =")) { | ||||
|                 yearRes = yearRes.substring(yearRes.indexOf("var year =") + "var year =".length) | ||||
|                 //Log.i(this.name, "Result => (yearRes) $yearRes") | ||||
|                 yearRes = yearRes.substring(0, yearRes.indexOf(';')) | ||||
|                     .trim().removeSurrounding("'") | ||||
|         inner?.select("table")?.select("tr")?.forEach { | ||||
|             val td = it?.select("td") ?: return@forEach | ||||
|             val caption = td[0].text()?.lowercase() | ||||
|             //Log.i(this.name, "Result => (caption) $caption") | ||||
|             when (caption) { | ||||
|                 "name" -> { | ||||
|                     title = td[1].text() | ||||
|                 } | ||||
|                 "year" -> { | ||||
|                     var yearRes = td[1].toString() | ||||
|                     year = if (yearRes.isNotBlank()) { | ||||
|                         if (yearRes.contains("var year =")) { | ||||
|                             yearRes = yearRes.substring(yearRes.indexOf("var year =") + "var year =".length) | ||||
|                             //Log.i(this.name, "Result => (yearRes) $yearRes") | ||||
|                             yearRes = yearRes.substring(0, yearRes.indexOf(';')) | ||||
|                                 .trim().removeSurrounding("'") | ||||
|                         } | ||||
|                         yearRes.toIntOrNull() | ||||
|                     } else { null } | ||||
|                 } | ||||
|                 "genre" -> { | ||||
|                     tags = td[1].select("a")?.mapNotNull { tag -> | ||||
|                         tag?.text()?.trim() ?: return@mapNotNull null | ||||
|                     }?.filter { a -> a.isNotBlank() } | ||||
|                 } | ||||
|             } | ||||
|             yearRes.toIntOrNull() | ||||
|         } else { null } | ||||
|         } | ||||
| 
 | ||||
|         var descript = body?.select("div.eText")?.text() | ||||
|         if (!descript.isNullOrEmpty()) { | ||||
|             try { | ||||
|                 descript = descript.substring(0, descript.indexOf("_x_Polus1")) | ||||
|                     .replace("_x_Polus1", "") | ||||
|                 descript = "(undefined_x_Polus+[.\\d+])".toRegex().replace(descript, "") | ||||
|                 descript = "(_x_Polus+[.\\d+])".toRegex().replace(descript, "") | ||||
|                 descript = descript.trim().removeSuffix("undefined").trim() | ||||
|             } catch (e: java.lang.Exception) {  } | ||||
|         } | ||||
|         // Add links hidden in description | ||||
|         listOfLinks.addAll(fetchUrls(descript)) | ||||
|         listOfLinks.forEach { link -> | ||||
|             //Log.i(this.name, "Result => (hidden link) $link") | ||||
|             descript = descript?.replace(link, "") | ||||
|         } | ||||
| 
 | ||||
|         // Try looking for episodes, for series | ||||
|         val episodeList = ArrayList<TvSeriesEpisode>() | ||||
|  | @ -145,22 +167,19 @@ class PinoyHDXyzProvider : MainAPI() { | |||
|         } | ||||
|         if (episodeList.size > 0) { | ||||
|             return TvSeriesLoadResponse( | ||||
|                 title, | ||||
|                 url, | ||||
|                 this.name, | ||||
|                 TvType.TvSeries, | ||||
|                 episodeList, | ||||
|                 poster, | ||||
|                 year, | ||||
|                 descript, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null | ||||
|                 name = title, | ||||
|                 url = url, | ||||
|                 apiName = this.name, | ||||
|                 type = TvType.TvSeries, | ||||
|                 episodes = episodeList, | ||||
|                 posterUrl = poster, | ||||
|                 year = year, | ||||
|                 plot = descript, | ||||
|                 tags = tags | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         // Video links for Movie | ||||
|         val listOfLinks: MutableList<String> = mutableListOf() | ||||
|         body?.select("div.tabcontent > iframe")?.forEach { | ||||
|             val linkMain = it?.attr("src") | ||||
|             if (!linkMain.isNullOrEmpty()) { | ||||
|  | @ -181,7 +200,17 @@ class PinoyHDXyzProvider : MainAPI() { | |||
| 
 | ||||
|         val streamLinks = listOfLinks.distinct().toJson() | ||||
|         //Log.i(this.name, "Result => (streamLinks) streamLinks") | ||||
|         return MovieLoadResponse(title, url, this.name, TvType.Movie, streamLinks, poster, year, descript, null, null) | ||||
|         return MovieLoadResponse( | ||||
|             name = title, | ||||
|             url = url, | ||||
|             apiName = this.name, | ||||
|             type = TvType.Movie, | ||||
|             dataUrl = streamLinks, | ||||
|             posterUrl = poster, | ||||
|             year = year, | ||||
|             plot = descript, | ||||
|             tags = tags | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun loadLinks( | ||||
|  | @ -191,11 +220,12 @@ class PinoyHDXyzProvider : MainAPI() { | |||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         var count = 0 | ||||
|         mapper.readValue<List<String>>(data).apmap { item -> | ||||
|             if (item.isNotEmpty()) { | ||||
|                 val url = item.trim() | ||||
|                 loadExtractor(url, mainUrl, callback) | ||||
|                 count++ | ||||
|         mapper.readValue<List<String>>(data).forEach { item -> | ||||
|             val url = item.trim() | ||||
|             if (url.isNotBlank()) { | ||||
|                 if (loadExtractor(url, mainUrl, callback)) { | ||||
|                     count++ | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return count > 0 | ||||
|  |  | |||
|  | @ -113,13 +113,33 @@ class PinoyMoviePediaProvider : MainAPI() { | |||
|         val isTvSeries = doc.select("title")?.text()?.lowercase()?.contains("full episode -") ?: false | ||||
| 
 | ||||
|         // Video details | ||||
|         val data = inner?.select("div.data") | ||||
|         val poster = inner?.select("div.poster > img")?.attr("src") | ||||
|         val title = inner?.select("div.data > h1")?.firstOrNull()?.text() ?: "" | ||||
|         val descript = body?.select("div#info > div.wp-content")?.text() | ||||
|         val title = data?.select("h1")?.firstOrNull()?.text() ?: "" | ||||
|         val descript = body?.select("div#info > div.wp-content") | ||||
|             ?.select("p")?.get(0)?.text() | ||||
|         val rex = Regex("\\((\\d+)") | ||||
|         val yearRes = rex.find(title)?.value ?: "" | ||||
|         //Log.i(this.name, "Result => (yearRes) ${yearRes}") | ||||
|         val year = yearRes.replace("(", "").toIntOrNull() | ||||
|         val tags = data?.select("div.sgeneros > a")?.mapNotNull { tag -> | ||||
|             tag?.text()?.trim() ?: return@mapNotNull null | ||||
|         }?.toList() | ||||
|         val recList = body?.select("div#single_relacionados > article")?.mapNotNull { | ||||
|             val a = it.select("a") ?: return@mapNotNull null | ||||
|             val aUrl = a.attr("href") ?: return@mapNotNull null | ||||
|             val aImg = a.select("img")?.attr("src") | ||||
|             val aName = a.select("img")?.attr("alt") ?: return@mapNotNull null | ||||
|             val aYear = aName.trim().takeLast(5).removeSuffix(")").toIntOrNull() | ||||
|             MovieSearchResponse( | ||||
|                 url = aUrl, | ||||
|                 name = aName, | ||||
|                 type = TvType.Movie, | ||||
|                 posterUrl = aImg, | ||||
|                 year = aYear, | ||||
|                 apiName = this.name | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         // Video links | ||||
|         val playcontainer = body?.select("div#playcontainer") | ||||
|  | @ -162,21 +182,31 @@ class PinoyMoviePediaProvider : MainAPI() { | |||
|                 } | ||||
|             } | ||||
|             return TvSeriesLoadResponse( | ||||
|                 title, | ||||
|                 url, | ||||
|                 this.name, | ||||
|                 TvType.TvSeries, | ||||
|                 episodeList, | ||||
|                 poster, | ||||
|                 year, | ||||
|                 descript, | ||||
|                 null, | ||||
|                 null, | ||||
|                 null | ||||
|                 name = title, | ||||
|                 url = url, | ||||
|                 apiName = this.name, | ||||
|                 type = TvType.TvSeries, | ||||
|                 episodes = episodeList, | ||||
|                 posterUrl = poster, | ||||
|                 year = year, | ||||
|                 plot = descript, | ||||
|                 tags = tags, | ||||
|                 recommendations = recList | ||||
|             ) | ||||
|         } | ||||
|         val streamlinks = listOfLinks.distinct().toJson() | ||||
|         return MovieLoadResponse(title, url, this.name, TvType.Movie, streamlinks, poster, year, descript, null, null) | ||||
|         return MovieLoadResponse( | ||||
|             name = title, | ||||
|             url = url, | ||||
|             apiName = this.name, | ||||
|             type = TvType.Movie, | ||||
|             dataUrl = streamlinks, | ||||
|             posterUrl = poster, | ||||
|             year = year, | ||||
|             plot = descript, | ||||
|             tags = tags, | ||||
|             recommendations = recList | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun loadLinks( | ||||
|  |  | |||
|  | @ -29,45 +29,49 @@ class PinoyMoviesEsProvider : MainAPI() { | |||
|         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 image = it?.select("div.poster > img")?.attr("data-src") | ||||
| 
 | ||||
|                     // Get Title and Year | ||||
|                     val name = urlTitle?.select("h3")?.text() ?: "" | ||||
|                     var year = urlTitle?.select("span")?.text()?.toIntOrNull() | ||||
| 
 | ||||
|                     if (year == null) { | ||||
|                         // Get year from name | ||||
|                         val rex = Regex("\\((\\d+)") | ||||
|                         year = rex.find(name)?.value?.replace("(", "")?.toIntOrNull() | ||||
|                     } | ||||
| 
 | ||||
|                     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 | ||||
|                     )) | ||||
|             val elements = mainbody.select("div${sep}${item.second} > article")?.mapNotNull { | ||||
|                 // Get inner div from article | ||||
|                 var urlTitle = it?.select("div.data.dfeatur") | ||||
|                 if (urlTitle.isNullOrEmpty()) { | ||||
|                     urlTitle = it?.select("div.data") | ||||
|                 } | ||||
|                 if (urlTitle.isNullOrEmpty()) { return@mapNotNull null } | ||||
|                 // Fetch details | ||||
|                 val link = fixUrlNull(urlTitle.select("a")?.attr("href")) | ||||
|                 if (link.isNullOrBlank()) { return@mapNotNull null } | ||||
| 
 | ||||
|                 val image = it?.select("div.poster > img")?.attr("data-src") | ||||
| 
 | ||||
|                 // Get Title and Year | ||||
|                 val name = urlTitle.select("h3")?.text() | ||||
|                     ?: urlTitle.select("h2")?.text() | ||||
|                     ?: urlTitle.select("h1")?.text() | ||||
|                 if (name.isNullOrBlank()) { return@mapNotNull null } | ||||
| 
 | ||||
|                 var year = urlTitle.select("span")?.text()?.toIntOrNull() | ||||
| 
 | ||||
|                 if (year == null) { | ||||
|                     // Get year from name | ||||
|                     val rex = Regex("\\((\\d+)") | ||||
|                     year = rex.find(name)?.value?.replace("(", "")?.toIntOrNull() | ||||
|                 } | ||||
| 
 | ||||
|                 MovieSearchResponse( | ||||
|                     name = name, | ||||
|                     url = link, | ||||
|                     apiName = this.name, | ||||
|                     type = TvType.Movie, | ||||
|                     posterUrl = image, | ||||
|                     year = year | ||||
|                 ) | ||||
|             }?.distinctBy { c -> c.url } ?: listOf() | ||||
|             //Add to list of homepages | ||||
|             if (!elements.isNullOrEmpty()) { | ||||
|                 all.add( | ||||
|                     HomePageList( | ||||
|                         title, elements | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|         return all | ||||
|  | @ -136,12 +140,30 @@ class PinoyMoviesEsProvider : MainAPI() { | |||
| 
 | ||||
|         val descript = body?.select("div#info > div.wp-content")?.text() | ||||
|         val poster = body?.select("div.poster > img")?.attr("src") | ||||
|         val tags = data?.select("div.sgeneros > a")?.mapNotNull { tag -> | ||||
|             tag?.text() ?: return@mapNotNull null | ||||
|         }?.toList() | ||||
|         val recList = body?.select("div#single_relacionados > article")?.mapNotNull { | ||||
|             val a = it.select("a") ?: return@mapNotNull null | ||||
|             val aUrl = a.attr("href") ?: return@mapNotNull null | ||||
|             val aImg = a.select("img")?.attr("data-src") | ||||
|             val aName = a.select("img")?.attr("alt") ?: return@mapNotNull null | ||||
|             val aYear = aName.trim().takeLast(5).removeSuffix(")").toIntOrNull() | ||||
|             MovieSearchResponse( | ||||
|                 url = aUrl, | ||||
|                 name = aName, | ||||
|                 type = TvType.Movie, | ||||
|                 posterUrl = aImg, | ||||
|                 year = aYear, | ||||
|                 apiName = this.name | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         // Video links | ||||
|         val listOfLinks: MutableList<String> = mutableListOf() | ||||
|         val postlist = body?.select("div#playeroptions > ul > li")?.mapNotNull { | ||||
|             it?.attr("data-post") ?: return@mapNotNull null | ||||
|         }?.filter { it.isNotEmpty() }?.distinct() ?: listOf() | ||||
|         }?.filter { it.isNotBlank() }?.distinct() ?: listOf() | ||||
| 
 | ||||
|         postlist.apmap { datapost -> | ||||
|             //Log.i(this.name, "Result => (datapost) ${datapost}") | ||||
|  | @ -159,7 +181,18 @@ class PinoyMoviesEsProvider : MainAPI() { | |||
|                 listOfLinks.add(embedData.embed_url) | ||||
|             } | ||||
|         } | ||||
|         return MovieLoadResponse(title, url, this.name, TvType.Movie, listOfLinks.toJson(), poster, year, descript, null, null) | ||||
|         return MovieLoadResponse( | ||||
|             name = title, | ||||
|             url = url, | ||||
|             apiName = this.name, | ||||
|             type = TvType.Movie, | ||||
|             dataUrl = listOfLinks.toJson(), | ||||
|             posterUrl = poster, | ||||
|             year = year, | ||||
|             plot = descript, | ||||
|             tags = tags, | ||||
|             recommendations = recList | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun loadLinks( | ||||
|  | @ -170,19 +203,22 @@ class PinoyMoviesEsProvider : MainAPI() { | |||
|     ): Boolean { | ||||
|         // parse movie servers | ||||
|         var count = 0 | ||||
|         mapper.readValue<List<String>>(data).apmap { link -> | ||||
|             count++ | ||||
|         mapper.readValue<List<String>>(data).forEach { link -> | ||||
|             //Log.i(this.name, "Result => (link) $link") | ||||
|             if (link.startsWith("https://vstreamhub.com")) { | ||||
|                 VstreamhubHelper.getUrls(link, callback) | ||||
|                 count++ | ||||
|             } else if (link.contains("fembed.com")) { | ||||
|                 val extractor = FEmbed() | ||||
|                 extractor.domainUrl = "diasfem.com" | ||||
|                 extractor.getUrl(data).forEach { | ||||
|                     callback.invoke(it) | ||||
|                     count++ | ||||
|                 } | ||||
|             } else { | ||||
|                 loadExtractor(link, mainUrl, callback) | ||||
|                 if (loadExtractor(link, mainUrl, callback)) { | ||||
|                     count++ | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return count > 0 | ||||
|  |  | |||
|  | @ -98,6 +98,7 @@ class WatchAsianProvider : MainAPI() { | |||
|         var title = "" | ||||
|         var descript : String? = null | ||||
|         var year : Int? = null | ||||
|         var tags : List<String>? = null | ||||
|         if (isDramaDetail) { | ||||
|             val main = body.select("div.details") | ||||
|             val inner = main?.select("div.info") | ||||
|  | @ -105,14 +106,20 @@ class WatchAsianProvider : MainAPI() { | |||
|             poster = fixUrlNull(main?.select("div.img > img")?.attr("src")) ?: "" | ||||
|             //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}") | ||||
|             title = inner?.select("h1")?.firstOrNull()?.text() ?: "" | ||||
|             year = if (title.length > 5) { | ||||
|                 title.replace(")", "").replace("(", "").substring(title.length - 5) | ||||
|                     .trim().trimEnd(')').toIntOrNull() | ||||
|             } else { | ||||
|                 null | ||||
|             } | ||||
|             //Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}") | ||||
|             descript = inner?.text() | ||||
| 
 | ||||
|             inner?.select("p")?.forEach { p -> | ||||
|                 val caption = p?.selectFirst("span")?.text()?.trim()?.lowercase()?.removeSuffix(":")?.trim() ?: return@forEach | ||||
|                 when (caption) { | ||||
|                     "genre" -> { | ||||
|                         tags = p.select("a")?.mapNotNull { it?.text()?.trim() } | ||||
|                     } | ||||
|                     "released" -> { | ||||
|                         year = p.select("a")?.text()?.trim()?.toIntOrNull() | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             poster = body.select("meta[itemprop=\"image\"]")?.attr("content") ?: "" | ||||
|             title = body.selectFirst("div.block.watch-drama")?.selectFirst("h1") | ||||
|  | @ -120,6 +127,13 @@ class WatchAsianProvider : MainAPI() { | |||
|             year = null | ||||
|             descript = body.select("meta[name=\"description\"]")?.attr("content") | ||||
|         } | ||||
|         //Fallback year from title | ||||
|         if (year == null) { | ||||
|             year = if (title.length > 5) { | ||||
|                 title.replace(")", "").replace("(", "").substring(title.length - 5) | ||||
|                     .trim().trimEnd(')').toIntOrNull() | ||||
|             } else { null } | ||||
|         } | ||||
| 
 | ||||
|         // Episodes Links | ||||
|         //Log.i(this.name, "Result => (all eps) ${body.select("ul.list-episode-item-2.all-episode > li")}") | ||||
|  | @ -147,20 +161,28 @@ class WatchAsianProvider : MainAPI() { | |||
|             title = title.trim().removeSuffix("Episode 1") | ||||
|             val streamlink = getServerLinks(episodeList[0].data) | ||||
|             //Log.i(this.name, "Result => (streamlink) $streamlink") | ||||
|             return MovieLoadResponse(title, url, this.name, TvType.Movie, streamlink, poster, year, descript, null, null) | ||||
|             return MovieLoadResponse( | ||||
|                 name = title, | ||||
|                 url = url, | ||||
|                 apiName = this.name, | ||||
|                 type = TvType.Movie, | ||||
|                 dataUrl = streamlink, | ||||
|                 posterUrl = poster, | ||||
|                 year = year, | ||||
|                 plot = descript, | ||||
|                 tags = tags | ||||
|             ) | ||||
|         } | ||||
|         return TvSeriesLoadResponse( | ||||
|             title, | ||||
|             url, | ||||
|             this.name, | ||||
|             TvType.TvSeries, | ||||
|             episodeList.reversed(), | ||||
|             poster, | ||||
|             year, | ||||
|             descript, | ||||
|             null, | ||||
|             null, | ||||
|             null | ||||
|             name = title, | ||||
|             url = url, | ||||
|             apiName = this.name, | ||||
|             type = TvType.TvSeries, | ||||
|             episodes = episodeList.reversed(), | ||||
|             posterUrl = poster, | ||||
|             year = year, | ||||
|             plot = descript, | ||||
|             tags = tags | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue