mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
add kdramahood provider. minor cleanups. (#440)
This commit is contained in:
parent
9ed55d6d82
commit
153b164cec
4 changed files with 233 additions and 3 deletions
|
@ -68,7 +68,8 @@ object APIHolder {
|
||||||
PinoyMoviesEsProvider(),
|
PinoyMoviesEsProvider(),
|
||||||
TrailersTwoProvider(),
|
TrailersTwoProvider(),
|
||||||
DramaSeeProvider(),
|
DramaSeeProvider(),
|
||||||
WatchAsianProvider()
|
WatchAsianProvider(),
|
||||||
|
KdramaHoodProvider()
|
||||||
)
|
)
|
||||||
|
|
||||||
val restrictedApis = arrayListOf(
|
val restrictedApis = arrayListOf(
|
||||||
|
@ -278,7 +279,7 @@ fun MainAPI.fixUrlNull(url : String?) : String? {
|
||||||
if (url.isNullOrEmpty()) {
|
if (url.isNullOrEmpty()) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return fixUrl(url ?: return null)
|
return fixUrl(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MainAPI.fixUrl(url: String): String {
|
fun MainAPI.fixUrl(url: String): String {
|
||||||
|
|
|
@ -10,4 +10,5 @@ import com.lagradost.cloudstream3.mapper
|
||||||
class FeHD: XStreamCdn() {
|
class FeHD: XStreamCdn() {
|
||||||
override val name: String = "FeHD"
|
override val name: String = "FeHD"
|
||||||
override val mainUrl: String = "https://fembed-hd.com"
|
override val mainUrl: String = "https://fembed-hd.com"
|
||||||
|
override var domainUrl: String = "fembed-hd.com"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ open class XStreamCdn : ExtractorApi() {
|
||||||
override val name: String = "XStreamCdn"
|
override val name: String = "XStreamCdn"
|
||||||
override val mainUrl: String = "https://embedsito.com"
|
override val mainUrl: String = "https://embedsito.com"
|
||||||
override val requiresReferer = false
|
override val requiresReferer = false
|
||||||
var domainUrl: String = "embedsito.com"
|
open var domainUrl: String = "embedsito.com"
|
||||||
|
|
||||||
private data class ResponseData(
|
private data class ResponseData(
|
||||||
@JsonProperty("file") val file: String,
|
@JsonProperty("file") val file: String,
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
package com.lagradost.cloudstream3.movieproviders
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.extractors.*
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import kotlin.Exception
|
||||||
|
|
||||||
|
class KdramaHoodProvider : MainAPI() {
|
||||||
|
override val mainUrl = "https://kdramahood.com"
|
||||||
|
override val name = "KDramaHood"
|
||||||
|
override val hasQuickSearch = false
|
||||||
|
override val hasMainPage = true
|
||||||
|
override val hasChromecastSupport = false
|
||||||
|
override val hasDownloadSupport = true
|
||||||
|
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)
|
||||||
|
|
||||||
|
override fun getMainPage(): HomePageResponse {
|
||||||
|
val doc = app.get("$mainUrl/home2").document
|
||||||
|
val home = ArrayList<HomePageList>()
|
||||||
|
|
||||||
|
// Hardcoded homepage cause of site implementation
|
||||||
|
// Recently added
|
||||||
|
val recentlyInner = doc.selectFirst("div.peliculas")
|
||||||
|
val recentlyAddedTitle = recentlyInner.selectFirst("h1")?.text() ?: "Recently Added"
|
||||||
|
val recentlyAdded = recentlyInner.select("div.item_2.items > div.fit.item")?.mapNotNull {
|
||||||
|
if (it == null) {
|
||||||
|
return@mapNotNull null
|
||||||
|
}
|
||||||
|
val innerA = it.select("div.image > a") ?: return@mapNotNull null
|
||||||
|
val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null
|
||||||
|
val image = fixUrlNull(innerA.select("img")?.attr("src"))
|
||||||
|
|
||||||
|
val innerData = it.selectFirst("div.data")
|
||||||
|
val title = innerData.selectFirst("h1")?.text() ?: return@mapNotNull null
|
||||||
|
val year = try {
|
||||||
|
val yearText = innerData.selectFirst("span.titulo_o")
|
||||||
|
?.text()?.takeLast(11)?.trim()?.take(4) ?: ""
|
||||||
|
//Log.i(this.name, "Result => (yearText) $yearText")
|
||||||
|
val rex = Regex("\\((\\d+)")
|
||||||
|
//Log.i(this.name, "Result => (rex value) ${rex.find(yearText)?.value}")
|
||||||
|
rex.find(yearText)?.value?.toIntOrNull()
|
||||||
|
} catch (e: Exception) { null }
|
||||||
|
|
||||||
|
MovieSearchResponse(
|
||||||
|
name = title,
|
||||||
|
url = link,
|
||||||
|
apiName = this.name,
|
||||||
|
type = TvType.TvSeries,
|
||||||
|
posterUrl = image,
|
||||||
|
year = year
|
||||||
|
)
|
||||||
|
}?.distinctBy { it.url } ?: listOf()
|
||||||
|
home.add(HomePageList(recentlyAddedTitle, recentlyAdded))
|
||||||
|
return HomePageResponse(home.filter { it.list.isNotEmpty() })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun search(query: String): List<SearchResponse> {
|
||||||
|
val url = "$mainUrl/?s=$query"
|
||||||
|
val html = app.get(url).document
|
||||||
|
val document = html.getElementsByTag("body")
|
||||||
|
.select("div.item_1.items > div.item") ?: return listOf()
|
||||||
|
|
||||||
|
return document.mapNotNull {
|
||||||
|
if (it == null) {
|
||||||
|
return@mapNotNull null
|
||||||
|
}
|
||||||
|
val innerA = it.selectFirst("div.boxinfo > a") ?: return@mapNotNull null
|
||||||
|
val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null
|
||||||
|
val title = innerA.select("span.tt")?.text() ?: return@mapNotNull null
|
||||||
|
|
||||||
|
val year = it.selectFirst("span.year")?.text()?.toIntOrNull()
|
||||||
|
val image = fixUrlNull(it.selectFirst("div.image > img")?.attr("src"))
|
||||||
|
|
||||||
|
MovieSearchResponse(
|
||||||
|
name = title,
|
||||||
|
url = link,
|
||||||
|
apiName = this.name,
|
||||||
|
type = TvType.Movie,
|
||||||
|
posterUrl = image,
|
||||||
|
year = year
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun load(url: String): LoadResponse {
|
||||||
|
val doc = app.get(url).document
|
||||||
|
val inner = doc.selectFirst("div.central")
|
||||||
|
|
||||||
|
// Video details
|
||||||
|
val title = inner?.selectFirst("h1")?.text() ?: ""
|
||||||
|
val poster = fixUrlNull(doc.selectFirst("meta[property=og:image]")?.attr("content")) ?: ""
|
||||||
|
//Log.i(this.name, "Result => (poster) ${poster}")
|
||||||
|
val info = inner.selectFirst("div#info")
|
||||||
|
val descript = inner?.selectFirst("div.contenidotv > div > p")?.text()
|
||||||
|
val year = try {
|
||||||
|
val startLink = "https://kdramahood.com/drama-release-year/"
|
||||||
|
var res: Int? = null
|
||||||
|
info.select("div.metadatac")?.forEach {
|
||||||
|
if (res != null) { return@forEach }
|
||||||
|
if (it == null) { return@forEach }
|
||||||
|
val yearLink = it.select("a")?.attr("href") ?: return@forEach
|
||||||
|
if (yearLink.startsWith(startLink)) {
|
||||||
|
res = yearLink.substring(startLink.length).replace("/", "").toIntOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
} catch (e: Exception) { null }
|
||||||
|
|
||||||
|
// Episodes Links
|
||||||
|
val episodeList = inner?.select("ul.episodios > li")?.mapNotNull { ep ->
|
||||||
|
//Log.i(this.name, "Result => (ep) ${ep}")
|
||||||
|
val listOfLinks = mutableListOf<String>()
|
||||||
|
val count = ep.select("div.numerando")?.text()?.toIntOrNull() ?: 0
|
||||||
|
val innerA = ep.select("div.episodiotitle > a") ?: return@mapNotNull null
|
||||||
|
//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()) {
|
||||||
|
// Fetch video links
|
||||||
|
val epVidLinkEl = app.get(epLink, referer = mainUrl).document
|
||||||
|
val epLinksContent = epVidLinkEl.selectFirst("div.player_nav > script")?.html()
|
||||||
|
?.replace("ifr_target.src =", "<div>")
|
||||||
|
?.replace("';", "</div>")
|
||||||
|
//Log.i(this.name, "Result => (epLinksContent) $epLinksContent")
|
||||||
|
if (!epLinksContent.isNullOrEmpty()) {
|
||||||
|
//Log.i(this.name, "Result => (epLinksContent) ${Jsoup.parse(epLinksContent)?.select("div")}")
|
||||||
|
Jsoup.parse(epLinksContent)?.select("div")?.forEach { em ->
|
||||||
|
var href = em?.html()?.trim()?.removePrefix("'") ?: return@forEach
|
||||||
|
if (href.startsWith("//")) {
|
||||||
|
href = "https:$href"
|
||||||
|
}
|
||||||
|
//Log.i(this.name, "Result => (ep#$count link) $href")
|
||||||
|
if (href.isNotEmpty()) {
|
||||||
|
listOfLinks.add(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(
|
||||||
|
name = null,
|
||||||
|
season = null,
|
||||||
|
episode = count,
|
||||||
|
data = listOfLinks.distinct().toJson(),
|
||||||
|
posterUrl = poster,
|
||||||
|
date = null
|
||||||
|
)
|
||||||
|
} ?: listOf()
|
||||||
|
|
||||||
|
//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 TvSeriesLoadResponse(
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
this.name,
|
||||||
|
TvType.TvSeries,
|
||||||
|
episodeList,
|
||||||
|
poster,
|
||||||
|
year,
|
||||||
|
descript,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
if (data.isEmpty()) return false
|
||||||
|
if (data == "[]") return false
|
||||||
|
if (data == "about:blank") return false
|
||||||
|
|
||||||
|
var count = 0
|
||||||
|
mapper.readValue<List<String>>(data).forEach { item ->
|
||||||
|
if (item.isNotEmpty()) {
|
||||||
|
count++
|
||||||
|
var url = item.trim()
|
||||||
|
if (url.startsWith("//")) {
|
||||||
|
url = "https:$url"
|
||||||
|
}
|
||||||
|
//Log.i(this.name, "Result => (url) ${url}")
|
||||||
|
if (url.startsWith("https://asianembed.io")) {
|
||||||
|
// Fetch links
|
||||||
|
val doc = app.get(url).document
|
||||||
|
val links = doc.select("div#list-server-more > ul > li.linkserver")
|
||||||
|
if (!links.isNullOrEmpty()) {
|
||||||
|
links.forEach {
|
||||||
|
val datavid = it.attr("data-video") ?: ""
|
||||||
|
//Log.i(this.name, "Result => (datavid) ${datavid}")
|
||||||
|
if (datavid.isNotEmpty()) {
|
||||||
|
loadExtractor(datavid, url, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (url.startsWith("https://embedsito.com")) {
|
||||||
|
val extractor = XStreamCdn()
|
||||||
|
extractor.domainUrl = "embedsito.com"
|
||||||
|
extractor.getUrl(url).forEach { link ->
|
||||||
|
callback.invoke(link)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loadExtractor(url, mainUrl, callback)
|
||||||
|
} // end if
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count > 0
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue