[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:
Jace 2022-02-06 19:43:12 +08:00 committed by GitHub
parent 11e10a9bd8
commit 765aa7c5af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 350 additions and 190 deletions

View file

@ -15,7 +15,7 @@ class UpstreamExtractor: ExtractorApi() {
//Log.i(this.name, "Result => (no extractor) ${url}") //Log.i(this.name, "Result => (no extractor) ${url}")
val sources: MutableList<ExtractorLink> = mutableListOf() val sources: MutableList<ExtractorLink> = mutableListOf()
val doc = app.get(url, referer = referer).text val doc = app.get(url, referer = referer).text
if (doc.isNotEmpty()) { if (doc.isNotBlank()) {
var reg = Regex("(?<=master)(.*)(?=hls)") var reg = Regex("(?<=master)(.*)(?=hls)")
val result = reg.find(doc)?.groupValues?.map { val result = reg.find(doc)?.groupValues?.map {
it.trim('|') it.trim('|')

View file

@ -21,7 +21,7 @@ open class VoeExtractor : ExtractorApi() {
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> { override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf() val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
val doc = app.get(url).text val doc = app.get(url).text
if (doc.isNotEmpty()) { if (doc.isNotBlank()) {
val start = "const sources =" val start = "const sources ="
var src = doc.substring(doc.indexOf(start)) var src = doc.substring(doc.indexOf(start))
src = src.substring(start.length, src.indexOf(";")) src = src.substring(start.length, src.indexOf(";"))

View file

@ -16,7 +16,7 @@ class AsianEmbedHelper {
links.apmap { links.apmap {
val datavid = it.attr("data-video") ?: "" val datavid = it.attr("data-video") ?: ""
//Log.i("AsianEmbed", "Result => (datavid) ${datavid}") //Log.i("AsianEmbed", "Result => (datavid) ${datavid}")
if (datavid.isNotEmpty()) { if (datavid.isNotBlank()) {
val res = loadExtractor(datavid, url, callback) val res = loadExtractor(datavid, url, callback)
Log.i("AsianEmbed", "Result => ($res) (datavid) $datavid") Log.i("AsianEmbed", "Result => ($res) (datavid) $datavid")
} }

View file

@ -37,7 +37,7 @@ class VstreamhubHelper {
val startString = "window.open([" val startString = "window.open(["
val bb = aa.substring(aa.indexOf(startString)) val bb = aa.substring(aa.indexOf(startString))
val datavid = bb.substring(startString.length, bb.indexOf("]")).removeSurrounding("\"") val datavid = bb.substring(startString.length, bb.indexOf("]")).removeSurrounding("\"")
if (datavid.isNotEmpty()) { if (datavid.isNotBlank()) {
loadExtractor(datavid, url, callback) loadExtractor(datavid, url, callback)
//Log.i(baseName, "Result => (datavid) ${datavid}") //Log.i(baseName, "Result => (datavid) ${datavid}")
} }

View file

@ -91,8 +91,24 @@ class DramaSeeProvider : MainAPI() {
val year = if (title.length > 5) { title.substring(title.length - 5) val year = if (title.length > 5) { title.substring(title.length - 5)
.trim().trimEnd(')').toIntOrNull() } else { null } .trim().trimEnd(')').toIntOrNull() } else { null }
//Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}") //Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}")
val descript = body?.select("div.series-body")?.firstOrNull() val seriesBody = body?.select("div.series-body")
?.select("div.js-content")?.text() 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 // Episodes Links
val episodeList = ArrayList<TvSeriesEpisode>() val episodeList = ArrayList<TvSeriesEpisode>()
@ -101,7 +117,7 @@ class DramaSeeProvider : MainAPI() {
val count = innerA.select("span.episode")?.text()?.toIntOrNull() ?: 0 val count = innerA.select("span.episode")?.text()?.toIntOrNull() ?: 0
val epLink = fixUrlNull(innerA.attr("href")) ?: return@forEach val epLink = fixUrlNull(innerA.attr("href")) ?: return@forEach
//Log.i(this.name, "Result => (epLink) ${epLink}") //Log.i(this.name, "Result => (epLink) ${epLink}")
if (epLink.isNotEmpty()) { if (epLink.isNotBlank()) {
// Fetch video links // Fetch video links
val epVidLinkEl = app.get(epLink, referer = mainUrl).document val epVidLinkEl = app.get(epLink, referer = mainUrl).document
val ajaxUrl = epVidLinkEl.select("div#js-player")?.attr("embed") val ajaxUrl = epVidLinkEl.select("div#js-player")?.attr("embed")
@ -111,7 +127,7 @@ class DramaSeeProvider : MainAPI() {
val listOfLinks = mutableListOf<String>() val listOfLinks = mutableListOf<String>()
innerPage.select("div.player.active > main > div")?.forEach { em -> innerPage.select("div.player.active > main > div")?.forEach { em ->
val href = fixUrlNull(em.attr("src")) ?: "" val href = fixUrlNull(em.attr("src")) ?: ""
if (href.isNotEmpty()) { if (href.isNotBlank()) {
listOfLinks.add(href) listOfLinks.add(href)
} }
} }
@ -133,20 +149,30 @@ class DramaSeeProvider : MainAPI() {
//If there's only 1 episode, consider it a movie. //If there's only 1 episode, consider it a movie.
if (episodeList.size == 1) { 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( return TvSeriesLoadResponse(
title, name = title,
url, url = url,
this.name, apiName = this.name,
TvType.TvSeries, type = TvType.TvSeries,
episodeList.reversed(), episodes = episodeList.reversed(),
poster, posterUrl = poster,
year, year = year,
descript, plot = descript,
null, recommendations = recs,
null, tags = tags
null
) )
} }

View file

@ -110,6 +110,24 @@ class KdramaHoodProvider : MainAPI() {
res res
} catch (e: Exception) { null } } 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 // Episodes Links
val episodeList = inner?.select("ul.episodios > li")?.mapNotNull { ep -> val episodeList = inner?.select("ul.episodios > li")?.mapNotNull { ep ->
//Log.i(this.name, "Result => (ep) ${ep}") //Log.i(this.name, "Result => (ep) ${ep}")
@ -119,7 +137,7 @@ class KdramaHoodProvider : MainAPI() {
//Log.i(this.name, "Result => (innerA) ${innerA}") //Log.i(this.name, "Result => (innerA) ${innerA}")
val epLink = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null val epLink = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null
//Log.i(this.name, "Result => (epLink) ${epLink}") //Log.i(this.name, "Result => (epLink) ${epLink}")
if (epLink.isNotEmpty()) { if (epLink.isNotBlank()) {
// Fetch video links // Fetch video links
val epVidLinkEl = app.get(epLink, referer = mainUrl).document val epVidLinkEl = app.get(epLink, referer = mainUrl).document
val epLinksContent = epVidLinkEl.selectFirst("div.player_nav > script")?.html() val epLinksContent = epVidLinkEl.selectFirst("div.player_nav > script")?.html()
@ -131,20 +149,10 @@ class KdramaHoodProvider : MainAPI() {
Jsoup.parse(epLinksContent)?.select("div")?.forEach { em -> Jsoup.parse(epLinksContent)?.select("div")?.forEach { em ->
val href = em?.html()?.trim()?.removePrefix("'") ?: return@forEach val href = em?.html()?.trim()?.removePrefix("'") ?: return@forEach
//Log.i(this.name, "Result => (ep#$count link) $href") //Log.i(this.name, "Result => (ep#$count link) $href")
if (href.isNotEmpty()) { if (href.isNotBlank()) {
listOfLinks.add(fixUrl(href)) 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( TvSeriesEpisode(
@ -159,20 +167,28 @@ class KdramaHoodProvider : MainAPI() {
//If there's only 1 episode, consider it a movie. //If there's only 1 episode, consider it a movie.
if (episodeList.size == 1) { 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( return TvSeriesLoadResponse(
title, name = title,
url, url = url,
this.name, apiName = this.name,
TvType.TvSeries, type = TvType.TvSeries,
episodeList.reversed(), episodes = episodeList.reversed(),
poster, posterUrl = poster,
year, year = year,
descript, plot = descript,
null, recommendations = recs
null,
null
) )
} }
@ -184,7 +200,7 @@ class KdramaHoodProvider : MainAPI() {
): Boolean { ): Boolean {
var count = 0 var count = 0
mapper.readValue<List<String>>(data).apmap { item -> mapper.readValue<List<String>>(data).apmap { item ->
if (item.isNotEmpty()) { if (item.isNotBlank()) {
count++ count++
var url = item.trim() var url = item.trim()
if (url.startsWith("//")) { if (url.startsWith("//")) {

View file

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import android.util.Log
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson 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 -> mainbody?.select("div.section-cotent.col-md-12.bordert")?.forEach { row ->
val title = row?.select("div.title-section.tt")?.text() ?: "<Row>" val title = row?.select("div.title-section.tt")?.text() ?: "<Row>"
val inner = row?.select("li.img_frame.preview-tumb7") val elements = row?.select("li.img_frame.preview-tumb7")?.mapNotNull {
if (inner != null) { // Get inner div from article
val elements: List<SearchResponse> = inner.map { val innerBody = it?.selectFirst("a") ?: return@mapNotNull null
// Get inner div from article // Fetch details
val innerBody = it?.select("a")?.firstOrNull() val name = it.text()
// Fetch details if (name.isNullOrBlank()) { return@mapNotNull null }
val name = it?.text() ?: ""
val link = innerBody?.attr("href") ?: "" val link = innerBody.attr("href") ?: return@mapNotNull null
val imgsrc = innerBody?.select("img")?.attr("src") val image = fixUrlNull(innerBody.select("img")?.attr("src"))
val image = when (!imgsrc.isNullOrEmpty()) { //Log.i(this.name, "Result => (innerBody, image) ${innerBody} / ${image}")
true -> "${mainUrl}${imgsrc}" // Get Year from Link
false -> null val rex = Regex("_(\\d+)_")
} val year = rex.find(link)?.value?.replace("_", "")?.toIntOrNull()
//Log.i(this.name, "Result => (innerBody, image) ${innerBody} / ${image}") //Log.i(this.name, "Result => (yearRes, year) ${yearRes} / ${year}")
// Get Year from Link MovieSearchResponse(
val rex = Regex("_(\\d+)_") name = name,
val yearRes = rex.find(link)?.value ?: "" url = link,
val year = yearRes.replace("_", "").toIntOrNull() apiName = this.name,
//Log.i(this.name, "Result => (yearRes, year) ${yearRes} / ${year}") type = TvType.Movie,
MovieSearchResponse( posterUrl = image,
name, year = year
link, )
this.name, }?.distinctBy { c -> c.url } ?: listOf()
TvType.Movie, // Add to Homepage
image, if (elements.isNotEmpty()) {
year,
null,
)
}.filter { a -> a.url.isNotEmpty() }
.filter { b -> b.name.isNotEmpty() }
.distinctBy { c -> c.url }
// Add
all.add( all.add(
HomePageList( HomePageList(
title, elements title, elements
@ -78,12 +72,12 @@ class PinoyHDXyzProvider : MainAPI() {
val image = null // site provides no image on search page val image = null // site provides no image on search page
MovieSearchResponse( MovieSearchResponse(
title, name = title,
link, url = link,
this.name, apiName = this.name,
TvType.Movie, type = TvType.Movie,
image, posterUrl = image,
year year = year
) )
}?.distinctBy { c -> c.url } ?: listOf() }?.distinctBy { c -> c.url } ?: listOf()
} }
@ -93,29 +87,57 @@ class PinoyHDXyzProvider : MainAPI() {
val body = doc.getElementsByTag("body") val body = doc.getElementsByTag("body")
val inner = body?.select("div.info") val inner = body?.select("div.info")
// Video links
val listOfLinks: MutableList<String> = mutableListOf()
// Video details // Video details
val imgLinkCode = inner?.select("div.portfolio-tumb.ph-link > img")?.attr("src") var title = ""
val poster = if (!imgLinkCode.isNullOrEmpty()) { "${mainUrl}${imgLinkCode}" } else { null } 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}") //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}")
val title = inner?.select("td.trFon2.entt")?.firstOrNull()?.text() ?: "<Untitled>" inner?.select("table")?.select("tr")?.forEach {
var yearRes = inner?.select("td.trFon2")?.toString() val td = it?.select("td") ?: return@forEach
val year = if (!yearRes.isNullOrEmpty()) { val caption = td[0].text()?.lowercase()
if (yearRes.contains("var year =")) { //Log.i(this.name, "Result => (caption) $caption")
yearRes = yearRes.substring(yearRes.indexOf("var year =") + "var year =".length) when (caption) {
//Log.i(this.name, "Result => (yearRes) $yearRes") "name" -> {
yearRes = yearRes.substring(0, yearRes.indexOf(';')) title = td[1].text()
.trim().removeSurrounding("'") }
"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() var descript = body?.select("div.eText")?.text()
if (!descript.isNullOrEmpty()) { if (!descript.isNullOrEmpty()) {
try { try {
descript = descript.substring(0, descript.indexOf("_x_Polus1")) descript = "(undefined_x_Polus+[.\\d+])".toRegex().replace(descript, "")
.replace("_x_Polus1", "") descript = "(_x_Polus+[.\\d+])".toRegex().replace(descript, "")
descript = descript.trim().removeSuffix("undefined").trim()
} catch (e: java.lang.Exception) { } } 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 // Try looking for episodes, for series
val episodeList = ArrayList<TvSeriesEpisode>() val episodeList = ArrayList<TvSeriesEpisode>()
@ -145,22 +167,19 @@ class PinoyHDXyzProvider : MainAPI() {
} }
if (episodeList.size > 0) { if (episodeList.size > 0) {
return TvSeriesLoadResponse( return TvSeriesLoadResponse(
title, name = title,
url, url = url,
this.name, apiName = this.name,
TvType.TvSeries, type = TvType.TvSeries,
episodeList, episodes = episodeList,
poster, posterUrl = poster,
year, year = year,
descript, plot = descript,
null, tags = tags
null,
null
) )
} }
// Video links for Movie // Video links for Movie
val listOfLinks: MutableList<String> = mutableListOf()
body?.select("div.tabcontent > iframe")?.forEach { body?.select("div.tabcontent > iframe")?.forEach {
val linkMain = it?.attr("src") val linkMain = it?.attr("src")
if (!linkMain.isNullOrEmpty()) { if (!linkMain.isNullOrEmpty()) {
@ -181,7 +200,17 @@ class PinoyHDXyzProvider : MainAPI() {
val streamLinks = listOfLinks.distinct().toJson() val streamLinks = listOfLinks.distinct().toJson()
//Log.i(this.name, "Result => (streamLinks) streamLinks") //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( override suspend fun loadLinks(
@ -191,11 +220,12 @@ class PinoyHDXyzProvider : MainAPI() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
var count = 0 var count = 0
mapper.readValue<List<String>>(data).apmap { item -> mapper.readValue<List<String>>(data).forEach { item ->
if (item.isNotEmpty()) { val url = item.trim()
val url = item.trim() if (url.isNotBlank()) {
loadExtractor(url, mainUrl, callback) if (loadExtractor(url, mainUrl, callback)) {
count++ count++
}
} }
} }
return count > 0 return count > 0

View file

@ -113,13 +113,33 @@ class PinoyMoviePediaProvider : MainAPI() {
val isTvSeries = doc.select("title")?.text()?.lowercase()?.contains("full episode -") ?: false val isTvSeries = doc.select("title")?.text()?.lowercase()?.contains("full episode -") ?: false
// Video details // Video details
val data = inner?.select("div.data")
val poster = inner?.select("div.poster > img")?.attr("src") val poster = inner?.select("div.poster > img")?.attr("src")
val title = inner?.select("div.data > h1")?.firstOrNull()?.text() ?: "" val title = data?.select("h1")?.firstOrNull()?.text() ?: ""
val descript = body?.select("div#info > div.wp-content")?.text() val descript = body?.select("div#info > div.wp-content")
?.select("p")?.get(0)?.text()
val rex = Regex("\\((\\d+)") val rex = Regex("\\((\\d+)")
val yearRes = rex.find(title)?.value ?: "" val yearRes = rex.find(title)?.value ?: ""
//Log.i(this.name, "Result => (yearRes) ${yearRes}") //Log.i(this.name, "Result => (yearRes) ${yearRes}")
val year = yearRes.replace("(", "").toIntOrNull() 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 // Video links
val playcontainer = body?.select("div#playcontainer") val playcontainer = body?.select("div#playcontainer")
@ -162,21 +182,31 @@ class PinoyMoviePediaProvider : MainAPI() {
} }
} }
return TvSeriesLoadResponse( return TvSeriesLoadResponse(
title, name = title,
url, url = url,
this.name, apiName = this.name,
TvType.TvSeries, type = TvType.TvSeries,
episodeList, episodes = episodeList,
poster, posterUrl = poster,
year, year = year,
descript, plot = descript,
null, tags = tags,
null, recommendations = recList
null
) )
} }
val streamlinks = listOfLinks.distinct().toJson() 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( override suspend fun loadLinks(

View file

@ -29,45 +29,49 @@ class PinoyMoviesEsProvider : MainAPI() {
val all = mutableListOf<HomePageList>() val all = mutableListOf<HomePageList>()
for (item in rows) { for (item in rows) {
val title = item.first val title = item.first
val inner = mainbody.select("div${sep}${item.second} > article") val elements = mainbody.select("div${sep}${item.second} > article")?.mapNotNull {
if (inner != null) { // Get inner div from article
val elements: List<SearchResponse> = inner.map { var urlTitle = it?.select("div.data.dfeatur")
// Get inner div from article if (urlTitle.isNullOrEmpty()) {
var urlTitle = it?.select("div.data.dfeatur") urlTitle = it?.select("div.data")
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
))
} }
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 return all
@ -136,12 +140,30 @@ class PinoyMoviesEsProvider : MainAPI() {
val descript = body?.select("div#info > div.wp-content")?.text() val descript = body?.select("div#info > div.wp-content")?.text()
val poster = body?.select("div.poster > img")?.attr("src") 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 // Video links
val listOfLinks: MutableList<String> = mutableListOf() val listOfLinks: MutableList<String> = mutableListOf()
val postlist = body?.select("div#playeroptions > ul > li")?.mapNotNull { val postlist = body?.select("div#playeroptions > ul > li")?.mapNotNull {
it?.attr("data-post") ?: return@mapNotNull null it?.attr("data-post") ?: return@mapNotNull null
}?.filter { it.isNotEmpty() }?.distinct() ?: listOf() }?.filter { it.isNotBlank() }?.distinct() ?: listOf()
postlist.apmap { datapost -> postlist.apmap { datapost ->
//Log.i(this.name, "Result => (datapost) ${datapost}") //Log.i(this.name, "Result => (datapost) ${datapost}")
@ -159,7 +181,18 @@ class PinoyMoviesEsProvider : MainAPI() {
listOfLinks.add(embedData.embed_url) 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( override suspend fun loadLinks(
@ -170,19 +203,22 @@ class PinoyMoviesEsProvider : MainAPI() {
): Boolean { ): Boolean {
// parse movie servers // parse movie servers
var count = 0 var count = 0
mapper.readValue<List<String>>(data).apmap { link -> mapper.readValue<List<String>>(data).forEach { link ->
count++
//Log.i(this.name, "Result => (link) $link") //Log.i(this.name, "Result => (link) $link")
if (link.startsWith("https://vstreamhub.com")) { if (link.startsWith("https://vstreamhub.com")) {
VstreamhubHelper.getUrls(link, callback) VstreamhubHelper.getUrls(link, callback)
count++
} else if (link.contains("fembed.com")) { } else if (link.contains("fembed.com")) {
val extractor = FEmbed() val extractor = FEmbed()
extractor.domainUrl = "diasfem.com" extractor.domainUrl = "diasfem.com"
extractor.getUrl(data).forEach { extractor.getUrl(data).forEach {
callback.invoke(it) callback.invoke(it)
count++
} }
} else { } else {
loadExtractor(link, mainUrl, callback) if (loadExtractor(link, mainUrl, callback)) {
count++
}
} }
} }
return count > 0 return count > 0

View file

@ -98,6 +98,7 @@ class WatchAsianProvider : MainAPI() {
var title = "" var title = ""
var descript : String? = null var descript : String? = null
var year : Int? = null var year : Int? = null
var tags : List<String>? = null
if (isDramaDetail) { if (isDramaDetail) {
val main = body.select("div.details") val main = body.select("div.details")
val inner = main?.select("div.info") val inner = main?.select("div.info")
@ -105,14 +106,20 @@ class WatchAsianProvider : MainAPI() {
poster = fixUrlNull(main?.select("div.img > img")?.attr("src")) ?: "" poster = fixUrlNull(main?.select("div.img > img")?.attr("src")) ?: ""
//Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}") //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}")
title = inner?.select("h1")?.firstOrNull()?.text() ?: "" 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)}") //Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}")
descript = inner?.text() 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 { } else {
poster = body.select("meta[itemprop=\"image\"]")?.attr("content") ?: "" poster = body.select("meta[itemprop=\"image\"]")?.attr("content") ?: ""
title = body.selectFirst("div.block.watch-drama")?.selectFirst("h1") title = body.selectFirst("div.block.watch-drama")?.selectFirst("h1")
@ -120,6 +127,13 @@ class WatchAsianProvider : MainAPI() {
year = null year = null
descript = body.select("meta[name=\"description\"]")?.attr("content") 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 // Episodes Links
//Log.i(this.name, "Result => (all eps) ${body.select("ul.list-episode-item-2.all-episode > li")}") //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") title = title.trim().removeSuffix("Episode 1")
val streamlink = getServerLinks(episodeList[0].data) val streamlink = getServerLinks(episodeList[0].data)
//Log.i(this.name, "Result => (streamlink) $streamlink") //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( return TvSeriesLoadResponse(
title, name = title,
url, url = url,
this.name, apiName = this.name,
TvType.TvSeries, type = TvType.TvSeries,
episodeList.reversed(), episodes = episodeList.reversed(),
poster, posterUrl = poster,
year, year = year,
descript, plot = descript,
null, tags = tags
null,
null
) )
} }