mirror of
https://github.com/recloudstream/cloudstream-extensions.git
synced 2024-08-15 03:03:54 +00:00
Ported over all movie providers (some disabled)
This commit is contained in:
parent
c0509c5db9
commit
5c5a8d142f
283 changed files with 17532 additions and 76 deletions
|
@ -5,8 +5,8 @@ version = 1
|
|||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
description = "Lorem Ipsum"
|
||||
authors = listOf("Cloudburst")
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
|
@ -1,2 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.example"/>
|
||||
<manifest package="com.lagradost"/>
|
224
AkwamProvider/src/main/kotlin/com/lagradost/AkwamProvider.kt
Normal file
224
AkwamProvider/src/main/kotlin/com/lagradost/AkwamProvider.kt
Normal file
|
@ -0,0 +1,224 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class AkwamProvider : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://akwam.to"
|
||||
override var name = "Akwam"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime, TvType.Cartoon)
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = select("a.box").attr("href") ?: return null
|
||||
if (url.contains("/games/") || url.contains("/programs/")) return null
|
||||
val poster = select("picture > img")
|
||||
val title = poster.attr("alt")
|
||||
val posterUrl = poster.attr("data-src")
|
||||
val year = select(".badge-secondary").text().toIntOrNull()
|
||||
|
||||
// If you need to differentiate use the url.
|
||||
return MovieSearchResponse(
|
||||
title,
|
||||
url,
|
||||
this@AkwamProvider.name,
|
||||
TvType.TvSeries,
|
||||
posterUrl,
|
||||
year,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
// Title, Url
|
||||
val moviesUrl = listOf(
|
||||
"Movies" to "$mainUrl/movies",
|
||||
"Series" to "$mainUrl/series",
|
||||
"Shows" to "$mainUrl/shows"
|
||||
)
|
||||
val pages = moviesUrl.apmap {
|
||||
val doc = app.get(it.second).document
|
||||
val list = doc.select("div.col-lg-auto.col-md-4.col-6.mb-12").mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
HomePageList(it.first, list)
|
||||
}.sortedBy { it.name }
|
||||
return HomePageResponse(pages)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/search?q=$query"
|
||||
val doc = app.get(url).document
|
||||
return doc.select("div.col-lg-auto").mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
private fun Element.toEpisode(): Episode {
|
||||
val a = select("a.text-white")
|
||||
val url = a.attr("href")
|
||||
val title = a.text()
|
||||
val thumbUrl = select("picture > img").attr("src")
|
||||
val date = select("p.entry-date").text()
|
||||
return newEpisode(url) {
|
||||
name = title
|
||||
episode = title.getIntFromText()
|
||||
posterUrl = thumbUrl
|
||||
addDate(date)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val isMovie = url.contains("/movie/")
|
||||
val title = doc.select("h1.entry-title").text()
|
||||
val posterUrl = doc.select("picture > img").attr("src")
|
||||
|
||||
val year =
|
||||
doc.select("div.font-size-16.text-white.mt-2").firstOrNull {
|
||||
it.text().contains("السنة")
|
||||
}?.text()?.getIntFromText()
|
||||
|
||||
// A bit iffy to parse twice like this, but it'll do.
|
||||
val duration =
|
||||
doc.select("div.font-size-16.text-white.mt-2").firstOrNull {
|
||||
it.text().contains("مدة الفيلم")
|
||||
}?.text()?.getIntFromText()
|
||||
|
||||
val synopsis = doc.select("div.widget-body p:first-child").text()
|
||||
|
||||
val rating = doc.select("span.mx-2").text().split("/").lastOrNull()?.toRatingInt()
|
||||
|
||||
val tags = doc.select("div.font-size-16.d-flex.align-items-center.mt-3 > a").map {
|
||||
it.text()
|
||||
}
|
||||
|
||||
val actors = doc.select("div.widget-body > div > div.entry-box > a").mapNotNull {
|
||||
val name = it?.selectFirst("div > .entry-title")?.text() ?: return@mapNotNull null
|
||||
val image = it.selectFirst("div > img")?.attr("src") ?: return@mapNotNull null
|
||||
Actor(name, image)
|
||||
}
|
||||
|
||||
val recommendations =
|
||||
doc.select("div > div.widget-body > div.row > div > div.entry-box").mapNotNull {
|
||||
val recTitle = it?.selectFirst("div.entry-body > .entry-title > .text-white")
|
||||
?: return@mapNotNull null
|
||||
val href = recTitle.attr("href") ?: return@mapNotNull null
|
||||
val name = recTitle.text() ?: return@mapNotNull null
|
||||
val poster = it.selectFirst(".entry-image > a > picture > img")?.attr("data-src")
|
||||
?: return@mapNotNull null
|
||||
MovieSearchResponse(name, href, this.name, TvType.Movie, fixUrl(poster))
|
||||
}
|
||||
|
||||
return if (isMovie) {
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.rating = rating
|
||||
this.tags = tags
|
||||
this.duration = duration
|
||||
this.recommendations = recommendations
|
||||
addActors(actors)
|
||||
}
|
||||
} else {
|
||||
val episodes = doc.select("div.bg-primary2.p-4.col-lg-4.col-md-6.col-12").map {
|
||||
it.toEpisode()
|
||||
}.let {
|
||||
val isReversed = (it.lastOrNull()?.episode ?: 1) < (it.firstOrNull()?.episode ?: 0)
|
||||
if (isReversed)
|
||||
it.reversed()
|
||||
else it
|
||||
}
|
||||
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
|
||||
this.duration = duration
|
||||
this.posterUrl = posterUrl
|
||||
this.tags = tags.filterNotNull()
|
||||
this.rating = rating
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.recommendations = recommendations
|
||||
addActors(actors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// // Maybe possible to not use the url shortener but cba investigating that.
|
||||
// private suspend fun skipUrlShortener(url: String): AppResponse {
|
||||
// return app.get(app.get(url).document.select("a.download-link").attr("href"))
|
||||
// }
|
||||
|
||||
private fun getQualityFromId(id: Int?): Qualities {
|
||||
return when (id) {
|
||||
2 -> Qualities.P360 // Extrapolated
|
||||
3 -> Qualities.P480
|
||||
4 -> Qualities.P720
|
||||
5 -> Qualities.P1080
|
||||
else -> Qualities.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val doc = app.get(data).document
|
||||
|
||||
val links = doc.select("div.tab-content.quality").map { element ->
|
||||
val quality = getQualityFromId(element.attr("id").getIntFromText())
|
||||
element.select(".col-lg-6 > a:contains(تحميل)").map { linkElement ->
|
||||
if (linkElement.attr("href").contains("/download/")) {
|
||||
Pair(
|
||||
linkElement.attr("href"),
|
||||
quality,
|
||||
)
|
||||
} else {
|
||||
val url = "$mainUrl/download${
|
||||
linkElement.attr("href").split("/link")[1]
|
||||
}${data.split("/movie|/episode|/show/episode".toRegex())[1]}"
|
||||
Pair(
|
||||
url,
|
||||
quality,
|
||||
)
|
||||
// just in case if they add the shorts urls again
|
||||
}
|
||||
}
|
||||
}.flatten()
|
||||
|
||||
links.map {
|
||||
val linkDoc = app.get(it.first).document
|
||||
val button = linkDoc.select("div.btn-loader > a")
|
||||
val url = button.attr("href")
|
||||
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
url,
|
||||
this.mainUrl,
|
||||
it.second.value
|
||||
)
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class AkwamProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(AkwamProvider())
|
||||
}
|
||||
}
|
22
AllMoviesForYouProvider/build.gradle.kts
Normal file
22
AllMoviesForYouProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
AllMoviesForYouProvider/src/main/AndroidManifest.xml
Normal file
2
AllMoviesForYouProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,206 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
class AllMoviesForYouProvider : MainAPI() {
|
||||
companion object {
|
||||
fun getType(t: String): TvType {
|
||||
return when {
|
||||
t.contains("series") -> TvType.TvSeries
|
||||
t.contains("movies") -> TvType.Movie
|
||||
else -> TvType.Movie
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetching movies will not work if this link is outdated.
|
||||
override var mainUrl = "https://allmoviesforyou.net"
|
||||
override var name = "AllMoviesForYou"
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val items = ArrayList<HomePageList>()
|
||||
val soup = app.get(mainUrl).document
|
||||
val urls = listOf(
|
||||
Pair("Movies", "section[data-id=movies] article.TPost.B"),
|
||||
Pair("TV Series", "section[data-id=series] article.TPost.B"),
|
||||
)
|
||||
for ((name, element) in urls) {
|
||||
try {
|
||||
val home = soup.select(element).map {
|
||||
val title = it.selectFirst("h2.title")!!.text()
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
fixUrl(it.selectFirst("figure img")!!.attr("data-src")),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
items.add(HomePageList(name, home))
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
if (items.size <= 0) throw ErrorLoadingException()
|
||||
return HomePageResponse(items)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/?s=$query"
|
||||
val document = app.get(url).document
|
||||
|
||||
val items = document.select("ul.MovieList > li > article > a")
|
||||
return items.map { item ->
|
||||
val href = item.attr("href")
|
||||
val title = item.selectFirst("> h2.Title")!!.text()
|
||||
val img = fixUrl(item.selectFirst("> div.Image > figure > img")!!.attr("data-src"))
|
||||
val type = getType(href)
|
||||
if (type == TvType.Movie) {
|
||||
MovieSearchResponse(title, href, this.name, type, img, null)
|
||||
} else {
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
type,
|
||||
img,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private fun getLink(document: Document): List<String>? {
|
||||
// val list = ArrayList<String>()
|
||||
// Regex("iframe src=\"(.*?)\"").find(document.html())?.groupValues?.get(1)?.let {
|
||||
// list.add(it)
|
||||
// }
|
||||
// document.select("div.OptionBx")?.forEach { element ->
|
||||
// val baseElement = element.selectFirst("> a.Button")
|
||||
// val elementText = element.selectFirst("> p.AAIco-dns")?.text()
|
||||
// if (elementText == "Streamhub" || elementText == "Dood") {
|
||||
// baseElement?.attr("href")?.let { href ->
|
||||
// list.add(href)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return if (list.isEmpty()) null else list
|
||||
// }
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val type = getType(url)
|
||||
|
||||
val document = app.get(url).document
|
||||
|
||||
val title = document.selectFirst("h1.Title")!!.text()
|
||||
val descipt = document.selectFirst("div.Description > p")!!.text()
|
||||
val rating =
|
||||
document.selectFirst("div.Vote > div.post-ratings > span")?.text()?.toRatingInt()
|
||||
val year = document.selectFirst("span.Date")?.text()
|
||||
val duration = document.selectFirst("span.Time")!!.text()
|
||||
val backgroundPoster =
|
||||
fixUrlNull(document.selectFirst("div.Image > figure > img")?.attr("data-src"))
|
||||
|
||||
if (type == TvType.TvSeries) {
|
||||
val list = ArrayList<Pair<Int, String>>()
|
||||
|
||||
document.select("main > section.SeasonBx > div > div.Title > a").forEach { element ->
|
||||
val season = element.selectFirst("> span")?.text()?.toIntOrNull()
|
||||
val href = element.attr("href")
|
||||
if (season != null && season > 0 && !href.isNullOrBlank()) {
|
||||
list.add(Pair(season, fixUrl(href)))
|
||||
}
|
||||
}
|
||||
if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found")
|
||||
|
||||
val episodeList = ArrayList<Episode>()
|
||||
|
||||
for (season in list) {
|
||||
val seasonResponse = app.get(season.second).text
|
||||
val seasonDocument = Jsoup.parse(seasonResponse)
|
||||
val episodes = seasonDocument.select("table > tbody > tr")
|
||||
if (episodes.isNotEmpty()) {
|
||||
episodes.forEach { episode ->
|
||||
val epNum = episode.selectFirst("> td > span.Num")?.text()?.toIntOrNull()
|
||||
val poster = episode.selectFirst("> td.MvTbImg > a > img")?.attr("data-src")
|
||||
val aName = episode.selectFirst("> td.MvTbTtl > a")
|
||||
val name = aName!!.text()
|
||||
val href = aName.attr("href")
|
||||
val date = episode.selectFirst("> td.MvTbTtl > span")?.text()
|
||||
|
||||
episodeList.add(
|
||||
newEpisode(href) {
|
||||
this.name = name
|
||||
this.season = season.first
|
||||
this.episode = epNum
|
||||
this.posterUrl = fixUrlNull(poster)
|
||||
addDate(date)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
type,
|
||||
episodeList,
|
||||
backgroundPoster,
|
||||
year?.toIntOrNull(),
|
||||
descipt,
|
||||
null,
|
||||
rating
|
||||
)
|
||||
} else {
|
||||
return newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
type,
|
||||
fixUrl(url)
|
||||
) {
|
||||
posterUrl = backgroundPoster
|
||||
this.year = year?.toIntOrNull()
|
||||
this.plot = descipt
|
||||
this.rating = rating
|
||||
addDuration(duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val doc = app.get(data).document
|
||||
val iframe = doc.select("body iframe").map { fixUrl(it.attr("src")) }
|
||||
iframe.apmap { id ->
|
||||
if (id.contains("trembed")) {
|
||||
val soup = app.get(id).document
|
||||
soup.select("body iframe").map {
|
||||
val link = fixUrl(it.attr("src").replace("streamhub.to/d/", "streamhub.to/e/"))
|
||||
loadExtractor(link, data, subtitleCallback, callback)
|
||||
}
|
||||
} else loadExtractor(id, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class AllMoviesForYouProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(AllMoviesForYouProvider())
|
||||
}
|
||||
}
|
22
AltadefinizioneProvider/build.gradle.kts
Normal file
22
AltadefinizioneProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
AltadefinizioneProvider/src/main/AndroidManifest.xml
Normal file
2
AltadefinizioneProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,160 @@
|
|||
package com.lagradost
|
||||
|
||||
//import androidx.core.text.parseAsHtml
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
|
||||
|
||||
class AltadefinizioneProvider : MainAPI() {
|
||||
override var lang = "it"
|
||||
override var mainUrl = "https://altadefinizione.tienda"
|
||||
override var name = "Altadefinizione"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie
|
||||
)
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
Pair("$mainUrl/cerca/anno/2022/page/", "Ultimi Film"),
|
||||
Pair("$mainUrl/cerca/openload-quality/HD/page/", "Film in HD"),
|
||||
Pair("$mainUrl/cinema/page/", "Ora al cinema")
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||
val url = request.data + page
|
||||
|
||||
val soup = app.get(url).document
|
||||
val home = soup.select("div.box").map {
|
||||
val title = it.selectFirst("img")!!.attr("alt")
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
val image = mainUrl + it.selectFirst("img")!!.attr("src")
|
||||
val quality = getQualityFromString(it.selectFirst("span")!!.text())
|
||||
|
||||
MovieSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image,
|
||||
null,
|
||||
null,
|
||||
quality,
|
||||
)
|
||||
}
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val doc = app.post(
|
||||
"$mainUrl/index.php", data = mapOf(
|
||||
"do" to "search",
|
||||
"subaction" to "search",
|
||||
"story" to query,
|
||||
"sortby" to "news_read"
|
||||
)
|
||||
).document
|
||||
return doc.select("div.box").map {
|
||||
val title = it.selectFirst("img")!!.attr("alt")
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
val image = mainUrl + it.selectFirst("img")!!.attr("src")
|
||||
val quality = getQualityFromString(it.selectFirst("span")!!.text())
|
||||
|
||||
MovieSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image,
|
||||
null,
|
||||
null,
|
||||
quality,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val page = app.get(url)
|
||||
val document = page.document
|
||||
val title = document.selectFirst(" h1 > a")!!.text().replace("streaming", "")
|
||||
val description = document.select("#sfull").toString().substringAfter("altadefinizione")
|
||||
.substringBeforeLast("fonte trama").html().toString()
|
||||
val rating = null
|
||||
|
||||
val year = document.selectFirst("#details > li:nth-child(2)")!!.childNode(2).toString()
|
||||
.filter { it.isDigit() }.toInt()
|
||||
|
||||
val poster = fixUrl(document.selectFirst("div.thumbphoto > img")!!.attr("src"))
|
||||
|
||||
val recomm = document.select("ul.related-list > li").map {
|
||||
val href = it.selectFirst("a")!!.attr("href")
|
||||
val posterUrl = mainUrl + it.selectFirst("img")!!.attr("src")
|
||||
val name = it.selectFirst("img")!!.attr("alt")
|
||||
MovieSearchResponse(
|
||||
name,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
posterUrl,
|
||||
null
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
val actors: List<ActorData> =
|
||||
document.select("#staring > a").map {
|
||||
ActorData(actor = Actor(it.text()))
|
||||
}
|
||||
|
||||
val tags: List<String> = document.select("#details > li:nth-child(1) > a").map { it.text() }
|
||||
|
||||
val trailerurl = document.selectFirst("#showtrailer > div > div > iframe")?.attr("src")
|
||||
|
||||
return newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
posterUrl = fixUrlNull(poster)
|
||||
this.year = year
|
||||
this.plot = description
|
||||
this.rating = rating
|
||||
this.recommendations = recomm
|
||||
this.duration = null
|
||||
this.actors = actors
|
||||
this.tags = tags
|
||||
addTrailer(trailerurl)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val doc = app.get(data).document
|
||||
if (doc.select("div.guardahd-player").isNullOrEmpty()) {
|
||||
val videoUrl =
|
||||
doc.select("input").last { it.hasAttr("data-mirror") }.attr("value")
|
||||
loadExtractor(videoUrl, data, subtitleCallback, callback)
|
||||
doc.select("#mirrors > li > a").forEach {
|
||||
loadExtractor(fixUrl(it.attr("data-target")), data, subtitleCallback, callback)
|
||||
}
|
||||
} else {
|
||||
val pagelinks = doc.select("div.guardahd-player").select("iframe").attr("src")
|
||||
val docLinks = app.get(pagelinks).document
|
||||
docLinks.select("body > div > ul > li").forEach {
|
||||
loadExtractor(fixUrl(it.attr("data-link")), data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class AltadefinizioneProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(AltadefinizioneProvider())
|
||||
}
|
||||
}
|
22
AsiaFlixProvider/build.gradle.kts
Normal file
22
AsiaFlixProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
AsiaFlixProvider/src/main/AndroidManifest.xml
Normal file
2
AsiaFlixProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,198 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.*
|
||||
//import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider.Companion.getStatus
|
||||
import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import java.net.URI
|
||||
|
||||
class AsiaFlixProvider : MainAPI() {
|
||||
companion object {
|
||||
fun getType(t: String): TvType {
|
||||
return if (t.contains("OVA") || t.contains("Special")) TvType.OVA
|
||||
else if (t.contains("Movie")) TvType.AnimeMovie
|
||||
else TvType.Anime
|
||||
}
|
||||
|
||||
fun getStatus(t: String): ShowStatus {
|
||||
return when (t) {
|
||||
"Completed" -> ShowStatus.Completed
|
||||
"Ongoing" -> ShowStatus.Ongoing
|
||||
else -> ShowStatus.Completed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override var mainUrl = "https://asiaflix.app"
|
||||
override var name = "AsiaFlix"
|
||||
override val hasQuickSearch = false
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = false
|
||||
override val supportedTypes = setOf(TvType.AsianDrama)
|
||||
|
||||
private val apiUrl = "https://api.asiaflix.app/api/v2"
|
||||
|
||||
data class DashBoardObject(
|
||||
@JsonProperty("sectionName") val sectionName: String,
|
||||
@JsonProperty("type") val type: String?,
|
||||
@JsonProperty("data") val data: List<Data>?
|
||||
)
|
||||
|
||||
data class Episodes(
|
||||
@JsonProperty("_id") val _id: String,
|
||||
@JsonProperty("epUrl") val epUrl: String?,
|
||||
@JsonProperty("number") val number: Int?,
|
||||
@JsonProperty("type") val type: String?,
|
||||
@JsonProperty("extracted") val extracted: String?,
|
||||
@JsonProperty("videoUrl") val videoUrl: String?
|
||||
)
|
||||
|
||||
|
||||
data class Data(
|
||||
@JsonProperty("_id") val _id: String,
|
||||
@JsonProperty("name") val name: String,
|
||||
@JsonProperty("altNames") val altNames: String?,
|
||||
@JsonProperty("image") val image: String?,
|
||||
@JsonProperty("tvStatus") val tvStatus: String?,
|
||||
@JsonProperty("genre") val genre: String?,
|
||||
@JsonProperty("releaseYear") val releaseYear: Int?,
|
||||
@JsonProperty("createdAt") val createdAt: Long?,
|
||||
@JsonProperty("episodes") val episodes: List<Episodes>?,
|
||||
@JsonProperty("views") val views: Int?
|
||||
)
|
||||
|
||||
|
||||
data class DramaPage(
|
||||
@JsonProperty("_id") val _id: String,
|
||||
@JsonProperty("name") val name: String,
|
||||
@JsonProperty("altNames") val altNames: String?,
|
||||
@JsonProperty("synopsis") val synopsis: String?,
|
||||
@JsonProperty("image") val image: String?,
|
||||
@JsonProperty("language") val language: String?,
|
||||
@JsonProperty("dramaUrl") val dramaUrl: String?,
|
||||
@JsonProperty("published") val published: Boolean?,
|
||||
@JsonProperty("tvStatus") val tvStatus: String?,
|
||||
@JsonProperty("firstAirDate") val firstAirDate: String?,
|
||||
@JsonProperty("genre") val genre: String?,
|
||||
@JsonProperty("releaseYear") val releaseYear: Int?,
|
||||
@JsonProperty("createdAt") val createdAt: Long?,
|
||||
@JsonProperty("modifiedAt") val modifiedAt: Long?,
|
||||
@JsonProperty("episodes") val episodes: List<Episodes>,
|
||||
@JsonProperty("__v") val __v: Int?,
|
||||
@JsonProperty("cdnImage") val cdnImage: String?,
|
||||
@JsonProperty("views") val views: Int?
|
||||
)
|
||||
|
||||
private fun Data.toSearchResponse(): TvSeriesSearchResponse {
|
||||
return TvSeriesSearchResponse(
|
||||
name,
|
||||
_id,
|
||||
this@AsiaFlixProvider.name,
|
||||
TvType.AsianDrama,
|
||||
image,
|
||||
releaseYear,
|
||||
episodes?.size,
|
||||
)
|
||||
}
|
||||
|
||||
private fun Episodes.toEpisode(): Episode? {
|
||||
if (videoUrl != null && videoUrl.contains("watch/null") || number == null) return null
|
||||
return videoUrl?.let {
|
||||
Episode(
|
||||
it,
|
||||
null,
|
||||
number,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DramaPage.toLoadResponse(): TvSeriesLoadResponse {
|
||||
return TvSeriesLoadResponse(
|
||||
name,
|
||||
"$mainUrl$dramaUrl/$_id".replace("drama-detail", "show-details"),
|
||||
this@AsiaFlixProvider.name,
|
||||
TvType.AsianDrama,
|
||||
episodes.mapNotNull { it.toEpisode() }.sortedBy { it.episode },
|
||||
image,
|
||||
releaseYear,
|
||||
synopsis,
|
||||
getStatus(tvStatus ?: ""),
|
||||
null,
|
||||
genre?.split(",")?.map { it.trim() }
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||
val headers = mapOf("X-Requested-By" to "asiaflix-web")
|
||||
val response = app.get("$apiUrl/dashboard", headers = headers).text
|
||||
|
||||
val customMapper =
|
||||
mapper.copy().configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
|
||||
// Hack, because it can either be object or a list
|
||||
val cleanedResponse = Regex(""""data":(\{.*?),\{"sectionName"""").replace(response) {
|
||||
""""data":null},{"sectionName""""
|
||||
}
|
||||
|
||||
val dashBoard = customMapper.readValue<List<DashBoardObject>?>(cleanedResponse)
|
||||
|
||||
val listItems = dashBoard?.mapNotNull {
|
||||
it.data?.map { data ->
|
||||
data.toSearchResponse()
|
||||
}?.let { searchResponse ->
|
||||
HomePageList(it.sectionName, searchResponse)
|
||||
}
|
||||
}
|
||||
return HomePageResponse(listItems ?: listOf())
|
||||
}
|
||||
|
||||
data class Link(
|
||||
@JsonProperty("url") val url: String?,
|
||||
)
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
if (isCasting) return false
|
||||
val headers = mapOf("X-Requested-By" to "asiaflix-web")
|
||||
app.get(
|
||||
"$apiUrl/utility/get-stream-links?url=$data",
|
||||
headers = headers
|
||||
).text.toKotlinObject<Link>().url?.let {
|
||||
// val fixedUrl = "https://api.asiaflix.app/api/v2/utility/cors-proxy/playlist/${URLEncoder.encode(it, StandardCharsets.UTF_8.toString())}"
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
it,
|
||||
"https://asianload1.com/",
|
||||
/** <------ This provider should be added instead */
|
||||
getQualityFromName(it),
|
||||
URI(it).path.endsWith(".m3u8")
|
||||
)
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse>? {
|
||||
val headers = mapOf("X-Requested-By" to "asiaflix-web")
|
||||
val url = "$apiUrl/drama/search?q=$query"
|
||||
val response = app.get(url, headers = headers).text
|
||||
return mapper.readValue<List<Data>?>(response)?.map { it.toSearchResponse() }
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val headers = mapOf("X-Requested-By" to "asiaflix-web")
|
||||
val requestUrl = "$apiUrl/drama?id=${url.split("/").lastOrNull()}"
|
||||
val response = app.get(requestUrl, headers = headers).text
|
||||
val dramaPage = response.toKotlinObject<DramaPage>()
|
||||
return dramaPage.toLoadResponse()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class AsiaFlixProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(AsiaFlixProvider())
|
||||
}
|
||||
}
|
25
AsianLoadProvider/build.gradle.kts
Normal file
25
AsianLoadProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,25 @@
|
|||
dependencies {
|
||||
implementation(project(mapOf("path" to ":VidstreamProviderTemplate")))
|
||||
}
|
||||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
AsianLoadProvider/src/main/AndroidManifest.xml
Normal file
2
AsianLoadProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,25 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
|
||||
/** Needs to inherit from MainAPI() to
|
||||
* make the app know what functions to call
|
||||
*/
|
||||
class AsianLoadProvider : VidstreamProviderTemplate() {
|
||||
override var name = "AsianLoad"
|
||||
override var mainUrl = "https://asianembed.io"
|
||||
override val homePageUrlList = listOf(
|
||||
mainUrl,
|
||||
"$mainUrl/recently-added-raw",
|
||||
"$mainUrl/movies",
|
||||
"$mainUrl/kshow",
|
||||
"$mainUrl/popular",
|
||||
"$mainUrl/ongoing-series"
|
||||
)
|
||||
|
||||
override val iv = "9262859232435825"
|
||||
override val secretKey = "93422192433952489752342908585752"
|
||||
override val secretDecryptKey = secretKey
|
||||
|
||||
override val supportedTypes = setOf(TvType.AsianDrama)
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class AsianLoadProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(AsianLoadProvider())
|
||||
}
|
||||
}
|
22
BflixProvider/build.gradle.kts
Normal file
22
BflixProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
BflixProvider/src/main/AndroidManifest.xml
Normal file
2
BflixProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
300
BflixProvider/src/main/kotlin/com/lagradost/BflixProvider.kt
Normal file
300
BflixProvider/src/main/kotlin/com/lagradost/BflixProvider.kt
Normal file
|
@ -0,0 +1,300 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.decodeVrf
|
||||
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.encode
|
||||
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.encodeVrf
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
open class BflixProvider : MainAPI() {
|
||||
override var mainUrl = "https://bflix.ru"
|
||||
override var name = "Bflix"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries,
|
||||
)
|
||||
|
||||
//override val uniqueId: Int by lazy { "BflixProvider".hashCode() }
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val items = ArrayList<HomePageList>()
|
||||
val soup = app.get("$mainUrl/home").document
|
||||
val testa = listOf(
|
||||
Pair("Movies", "div.tab-content[data-name=movies] div.filmlist div.item"),
|
||||
Pair("Shows", "div.tab-content[data-name=shows] div.filmlist div.item"),
|
||||
Pair("Trending", "div.tab-content[data-name=trending] div.filmlist div.item"),
|
||||
Pair(
|
||||
"Latest Movies",
|
||||
"div.container section.bl:contains(Latest Movies) div.filmlist div.item"
|
||||
),
|
||||
Pair(
|
||||
"Latest TV-Series",
|
||||
"div.container section.bl:contains(Latest TV-Series) div.filmlist div.item"
|
||||
),
|
||||
)
|
||||
for ((name, element) in testa) try {
|
||||
val test = soup.select(element).map {
|
||||
val title = it.selectFirst("h3 a")!!.text()
|
||||
val link = fixUrl(it.selectFirst("a")!!.attr("href"))
|
||||
val qualityInfo = it.selectFirst("div.quality")!!.text()
|
||||
val quality = getQualityFromString(qualityInfo)
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
if (link.contains("/movie/")) TvType.Movie else TvType.TvSeries,
|
||||
it.selectFirst("a.poster img")!!.attr("src"),
|
||||
null,
|
||||
null,
|
||||
quality = quality
|
||||
)
|
||||
}
|
||||
items.add(HomePageList(name, test))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
if (items.size <= 0) throw ErrorLoadingException()
|
||||
return HomePageResponse(items)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse>? {
|
||||
val encodedquery = encodeVrf(query, mainKey)
|
||||
val url = "$mainUrl/search?keyword=$query&vrf=$encodedquery"
|
||||
val html = app.get(url).text
|
||||
val document = Jsoup.parse(html)
|
||||
|
||||
return document.select(".filmlist div.item").map {
|
||||
val title = it.selectFirst("h3 a")!!.text()
|
||||
val href = fixUrl(it.selectFirst("a")!!.attr("href"))
|
||||
val image = it.selectFirst("a.poster img")!!.attr("src")
|
||||
val isMovie = href.contains("/movie/")
|
||||
val qualityInfo = it.selectFirst("div.quality")!!.text()
|
||||
val quality = getQualityFromString(qualityInfo)
|
||||
|
||||
if (isMovie) {
|
||||
MovieSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image,
|
||||
null,
|
||||
quality = quality
|
||||
)
|
||||
} else {
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
image,
|
||||
null,
|
||||
null,
|
||||
quality = quality
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Response(
|
||||
@JsonProperty("html") val html: String
|
||||
)
|
||||
|
||||
companion object {
|
||||
val mainKey = "OrAimkpzm6phmN3j"
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val soup = app.get(url).document
|
||||
val movieid = soup.selectFirst("div#watch")!!.attr("data-id")
|
||||
val movieidencoded = encodeVrf(movieid, mainKey)
|
||||
val title = soup.selectFirst("div.info h1")!!.text()
|
||||
val description = soup.selectFirst(".info .desc")?.text()?.trim()
|
||||
val poster: String? = try {
|
||||
soup.selectFirst("img.poster")!!.attr("src")
|
||||
} catch (e: Exception) {
|
||||
soup.selectFirst(".info .poster img")!!.attr("src")
|
||||
}
|
||||
|
||||
val tags = soup.select("div.info .meta div:contains(Genre) a").map { it.text() }
|
||||
val vrfUrl = "$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
|
||||
println("VRF___ $vrfUrl")
|
||||
val episodes = Jsoup.parse(
|
||||
app.get(
|
||||
vrfUrl
|
||||
).parsed<Response>().html
|
||||
).select("div.episode").map {
|
||||
val a = it.selectFirst("a")
|
||||
val href = fixUrl(a!!.attr("href"))
|
||||
val extraData = a.attr("data-kname").let { str ->
|
||||
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
|
||||
}
|
||||
val isValid = extraData.size == 2
|
||||
val episode = if (isValid) extraData.getOrNull(1) else null
|
||||
val season = if (isValid) extraData.getOrNull(0) else null
|
||||
|
||||
val eptitle = it.selectFirst(".episode a span.name")!!.text()
|
||||
val secondtitle = it.selectFirst(".episode a span")!!.text()
|
||||
.replace(Regex("(Episode (\\d+):|Episode (\\d+)-|Episode (\\d+))"), "") ?: ""
|
||||
Episode(
|
||||
href,
|
||||
secondtitle + eptitle,
|
||||
season,
|
||||
episode,
|
||||
)
|
||||
}
|
||||
val tvType =
|
||||
if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries
|
||||
val recommendations =
|
||||
soup.select("div.bl-2 section.bl div.content div.filmlist div.item")
|
||||
.mapNotNull { element ->
|
||||
val recTitle = element.select("h3 a").text() ?: return@mapNotNull null
|
||||
val image = element.select("a.poster img")?.attr("src")
|
||||
val recUrl = fixUrl(element.select("a").attr("href"))
|
||||
MovieSearchResponse(
|
||||
recTitle,
|
||||
recUrl,
|
||||
this.name,
|
||||
if (recUrl.contains("/movie/")) TvType.Movie else TvType.TvSeries,
|
||||
image,
|
||||
year = null
|
||||
)
|
||||
}
|
||||
val rating = soup.selectFirst(".info span.imdb")?.text()?.toRatingInt()
|
||||
val durationdoc = soup.selectFirst("div.info div.meta").toString()
|
||||
val durationregex = Regex("((\\d+) min)")
|
||||
val yearegex = Regex("<span>(\\d+)</span>")
|
||||
val duration = if (durationdoc.contains("na min")) null
|
||||
else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min", "")
|
||||
?.toIntOrNull()
|
||||
val year = if (mainUrl == "https://bflix.ru") {
|
||||
yearegex.find(durationdoc)?.destructured?.component1()
|
||||
?.replace(Regex("<span>|</span>"), "")
|
||||
} else null
|
||||
return when (tvType) {
|
||||
TvType.TvSeries -> {
|
||||
TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
tvType,
|
||||
episodes,
|
||||
poster,
|
||||
year?.toIntOrNull(),
|
||||
description,
|
||||
null,
|
||||
rating,
|
||||
tags,
|
||||
recommendations = recommendations,
|
||||
duration = duration,
|
||||
)
|
||||
}
|
||||
TvType.Movie -> {
|
||||
MovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
tvType,
|
||||
url,
|
||||
poster,
|
||||
year?.toIntOrNull(),
|
||||
description,
|
||||
rating,
|
||||
tags,
|
||||
recommendations = recommendations,
|
||||
duration = duration
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class Subtitles(
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("label") val label: String,
|
||||
@JsonProperty("kind") val kind: String
|
||||
)
|
||||
|
||||
data class Links(
|
||||
@JsonProperty("url") val url: String
|
||||
)
|
||||
|
||||
data class Servers(
|
||||
@JsonProperty("28") val mcloud: String?,
|
||||
@JsonProperty("35") val mp4upload: String?,
|
||||
@JsonProperty("40") val streamtape: String?,
|
||||
@JsonProperty("41") val vidstream: String?,
|
||||
@JsonProperty("43") val videovard: String?
|
||||
)
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val soup = app.get(data).document
|
||||
|
||||
val movieid = encode(soup.selectFirst("div#watch")?.attr("data-id") ?: return false)
|
||||
val movieidencoded = encodeVrf(movieid, mainKey)
|
||||
Jsoup.parse(
|
||||
parseJson<Response>(
|
||||
app.get(
|
||||
"$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
|
||||
).text
|
||||
).html
|
||||
)
|
||||
.select("html body #episodes").map {
|
||||
val cleandata = data.replace(mainUrl, "")
|
||||
val a = it.select("a").map {
|
||||
it.attr("data-kname")
|
||||
}
|
||||
val tvType =
|
||||
if (data.contains("movie/") && a.size == 1) TvType.Movie else TvType.TvSeries
|
||||
val servers = if (tvType == TvType.Movie) it.select(".episode a").attr("data-ep")
|
||||
else
|
||||
it.select(".episode a[href=$cleandata]").attr("data-ep")
|
||||
?: it.select(".episode a[href=${cleandata.replace("/1-full", "")}]")
|
||||
.attr("data-ep")
|
||||
val jsonservers = parseJson<Servers?>(servers) ?: return@map
|
||||
listOfNotNull(
|
||||
jsonservers.vidstream,
|
||||
jsonservers.mcloud,
|
||||
jsonservers.mp4upload,
|
||||
jsonservers.streamtape,
|
||||
jsonservers.videovard,
|
||||
).mapNotNull {
|
||||
val epserver = app.get("$mainUrl/ajax/episode/info?id=$it").text
|
||||
(if (epserver.contains("url")) {
|
||||
parseJson<Links>(epserver)
|
||||
} else null)?.url?.let {
|
||||
decodeVrf(it, mainKey)
|
||||
}
|
||||
}.apmap { url ->
|
||||
loadExtractor(
|
||||
url, data, subtitleCallback, callback
|
||||
)
|
||||
}
|
||||
//Apparently any server works, I haven't found any diference
|
||||
val sublink =
|
||||
app.get("$mainUrl/ajax/episode/subtitles/${jsonservers.mcloud}").text
|
||||
val jsonsub = parseJson<List<Subtitles>>(sublink)
|
||||
jsonsub.forEach { subtitle ->
|
||||
subtitleCallback(
|
||||
SubtitleFile(subtitle.label, subtitle.file)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class BflixProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(BflixProvider())
|
||||
}
|
||||
}
|
22
CinecalidadProvider/build.gradle.kts
Normal file
22
CinecalidadProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
CinecalidadProvider/src/main/AndroidManifest.xml
Normal file
2
CinecalidadProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,258 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
// import com.lagradost.cloudstream3.extractors.Cinestart
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class CinecalidadProvider : MainAPI() {
|
||||
override var mainUrl = "https://cinecalidad.lol"
|
||||
override var name = "Cinecalidad"
|
||||
override var lang = "es"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries,
|
||||
)
|
||||
override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
Pair("$mainUrl/ver-serie/page/", "Series"),
|
||||
Pair("$mainUrl/page/", "Peliculas"),
|
||||
Pair("$mainUrl/genero-de-la-pelicula/peliculas-en-calidad-4k/page/", "4K UHD"),
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(
|
||||
page: Int,
|
||||
request : MainPageRequest
|
||||
): HomePageResponse {
|
||||
val url = request.data + page
|
||||
|
||||
val soup = app.get(url).document
|
||||
val home = soup.select(".item.movies").map {
|
||||
val title = it.selectFirst("div.in_title")!!.text()
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
if (link.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries,
|
||||
it.selectFirst(".poster.custom img")!!.attr("data-src"),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/?s=${query}"
|
||||
val document = app.get(url).document
|
||||
|
||||
return document.select("article").map {
|
||||
val title = it.selectFirst("div.in_title")!!.text()
|
||||
val href = it.selectFirst("a")!!.attr("href")
|
||||
val image = it.selectFirst(".poster.custom img")!!.attr("data-src")
|
||||
val isMovie = href.contains("/ver-pelicula/")
|
||||
|
||||
if (isMovie) {
|
||||
MovieSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image,
|
||||
null
|
||||
)
|
||||
} else {
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
image,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val soup = app.get(url, timeout = 120).document
|
||||
|
||||
val title = soup.selectFirst(".single_left h1")!!.text()
|
||||
val description = soup.selectFirst("div.single_left table tbody tr td p")?.text()?.trim()
|
||||
val poster: String? = soup.selectFirst(".alignnone")!!.attr("data-src")
|
||||
val episodes = soup.select("div.se-c div.se-a ul.episodios li").map { li ->
|
||||
val href = li.selectFirst("a")!!.attr("href")
|
||||
val epThumb = li.selectFirst("img.lazy")!!.attr("data-src")
|
||||
val name = li.selectFirst(".episodiotitle a")!!.text()
|
||||
val seasonid =
|
||||
li.selectFirst(".numerando")!!.text().replace(Regex("(S|E)"), "").let { str ->
|
||||
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
|
||||
}
|
||||
val isValid = seasonid.size == 2
|
||||
val episode = if (isValid) seasonid.getOrNull(1) else null
|
||||
val season = if (isValid) seasonid.getOrNull(0) else null
|
||||
Episode(
|
||||
href,
|
||||
name,
|
||||
season,
|
||||
episode,
|
||||
if (epThumb.contains("svg")) null else epThumb
|
||||
)
|
||||
}
|
||||
return when (val tvType =
|
||||
if (url.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries) {
|
||||
TvType.TvSeries -> {
|
||||
TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
tvType,
|
||||
episodes,
|
||||
poster,
|
||||
null,
|
||||
description,
|
||||
)
|
||||
}
|
||||
TvType.Movie -> {
|
||||
MovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
tvType,
|
||||
url,
|
||||
poster,
|
||||
null,
|
||||
description,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
|
||||
val datam = app.get(data)
|
||||
val doc = datam.document
|
||||
val datatext = datam.text
|
||||
|
||||
doc.select(".dooplay_player_option").apmap {
|
||||
val url = it.attr("data-option")
|
||||
// if (url.startsWith("https://cinestart.net")) {
|
||||
// val extractor = Cinestart()
|
||||
// extractor.getSafeUrl(url, null, subtitleCallback, callback)
|
||||
// } else {
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
// }
|
||||
if (url.startsWith("https://cinecalidad.lol")) {
|
||||
val cineurlregex =
|
||||
Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
cineurlregex.findAll(url).map {
|
||||
it.value.replace("/play/", "/play/r.php")
|
||||
}.toList().apmap {
|
||||
app.get(
|
||||
it,
|
||||
headers = mapOf(
|
||||
"Host" to "cinecalidad.lol",
|
||||
"User-Agent" to USER_AGENT,
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"DNT" to "1",
|
||||
"Connection" to "keep-alive",
|
||||
"Referer" to data,
|
||||
"Upgrade-Insecure-Requests" to "1",
|
||||
"Sec-Fetch-Dest" to "iframe",
|
||||
"Sec-Fetch-Mode" to "navigate",
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
"Sec-Fetch-User" to "?1",
|
||||
),
|
||||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap { extractedurl ->
|
||||
if (extractedurl.contains("cinestart")) {
|
||||
loadExtractor(extractedurl, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (datatext.contains("en castellano")) app.get("$data?ref=es").document.select(".dooplay_player_option")
|
||||
.apmap {
|
||||
val url = it.attr("data-option")
|
||||
// if (url.startsWith("https://cinestart.net")) {
|
||||
// val extractor = Cinestart()
|
||||
// extractor.getSafeUrl(url, null, subtitleCallback, callback)
|
||||
// } else {
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
// }
|
||||
|
||||
if (url.startsWith("https://cinecalidad.lol")) {
|
||||
val cineurlregex =
|
||||
Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
cineurlregex.findAll(url).map {
|
||||
it.value.replace("/play/", "/play/r.php")
|
||||
}.toList().apmap {
|
||||
app.get(
|
||||
it,
|
||||
headers = mapOf(
|
||||
"Host" to "cinecalidad.lol",
|
||||
"User-Agent" to USER_AGENT,
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"DNT" to "1",
|
||||
"Connection" to "keep-alive",
|
||||
"Referer" to data,
|
||||
"Upgrade-Insecure-Requests" to "1",
|
||||
"Sec-Fetch-Dest" to "iframe",
|
||||
"Sec-Fetch-Mode" to "navigate",
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
"Sec-Fetch-User" to "?1",
|
||||
),
|
||||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap { extractedurl ->
|
||||
if (extractedurl.contains("cinestart")) {
|
||||
loadExtractor(extractedurl, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (datatext.contains("Subtítulo LAT") || datatext.contains("Forzados LAT")) {
|
||||
doc.select("#panel_descarga.pane a").apmap {
|
||||
val link =
|
||||
if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"
|
||||
else it.attr("href")
|
||||
val docsub = app.get(link)
|
||||
val linksub = docsub.document
|
||||
val validsub = docsub.text
|
||||
if (validsub.contains("Subtítulo") || validsub.contains("Forzados")) {
|
||||
val langregex = Regex("(Subtítulo.*\$|Forzados.*\$)")
|
||||
val langdoc = linksub.selectFirst("div.titulo h3")!!.text()
|
||||
val reallang = langregex.find(langdoc)?.destructured?.component1()
|
||||
linksub.select("a.link").apmap {
|
||||
val sublink =
|
||||
if (data.contains("serie") || data.contains("episodio")) "${data}${
|
||||
it.attr("href")
|
||||
}"
|
||||
else it.attr("href")
|
||||
subtitleCallback(
|
||||
SubtitleFile(reallang!!, sublink)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class CinecalidadProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(CinecalidadProvider())
|
||||
}
|
||||
}
|
22
CuevanaProvider/build.gradle.kts
Normal file
22
CuevanaProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
CuevanaProvider/src/main/AndroidManifest.xml
Normal file
2
CuevanaProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
324
CuevanaProvider/src/main/kotlin/com/lagradost/CuevanaProvider.kt
Normal file
324
CuevanaProvider/src/main/kotlin/com/lagradost/CuevanaProvider.kt
Normal file
|
@ -0,0 +1,324 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class CuevanaProvider : MainAPI() {
|
||||
override var mainUrl = "https://cuevana3.me"
|
||||
override var name = "Cuevana"
|
||||
override var lang = "es"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries,
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val items = ArrayList<HomePageList>()
|
||||
val urls = listOf(
|
||||
Pair(mainUrl, "Recientemente actualizadas"),
|
||||
Pair("$mainUrl/estrenos/", "Estrenos"),
|
||||
)
|
||||
items.add(
|
||||
HomePageList(
|
||||
"Series",
|
||||
app.get("$mainUrl/serie", timeout = 120).document.select("section.home-series li")
|
||||
.map {
|
||||
val title = it.selectFirst("h2.Title")!!.text()
|
||||
val poster = it.selectFirst("img.lazy")!!.attr("data-src")
|
||||
val url = it.selectFirst("a")!!.attr("href")
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.Anime,
|
||||
poster,
|
||||
null,
|
||||
null,
|
||||
)
|
||||
})
|
||||
)
|
||||
for ((url, name) in urls) {
|
||||
try {
|
||||
val soup = app.get(url).document
|
||||
val home = soup.select("section li.xxx.TPostMv").map {
|
||||
val title = it.selectFirst("h2.Title")!!.text()
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries,
|
||||
it.selectFirst("img.lazy")!!.attr("data-src"),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
items.add(HomePageList(name, home))
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
if (items.size <= 0) throw ErrorLoadingException()
|
||||
return HomePageResponse(items)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/?s=${query}"
|
||||
val document = app.get(url).document
|
||||
|
||||
return document.select("li.xxx.TPostMv").map {
|
||||
val title = it.selectFirst("h2.Title")!!.text()
|
||||
val href = it.selectFirst("a")!!.attr("href")
|
||||
val image = it.selectFirst("img.lazy")!!.attr("data-src")
|
||||
val isSerie = href.contains("/serie/")
|
||||
|
||||
if (isSerie) {
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
image,
|
||||
null,
|
||||
null
|
||||
)
|
||||
} else {
|
||||
MovieSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val soup = app.get(url, timeout = 120).document
|
||||
val title = soup.selectFirst("h1.Title")!!.text()
|
||||
val description = soup.selectFirst(".Description p")?.text()?.trim()
|
||||
val poster: String? = soup.selectFirst(".movtv-info div.Image img")!!.attr("data-src")
|
||||
val year1 = soup.selectFirst("footer p.meta").toString()
|
||||
val yearRegex = Regex("<span>(\\d+)</span>")
|
||||
val yearf =
|
||||
yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("<span>|</span>"), "")
|
||||
val year = if (yearf.isNullOrBlank()) null else yearf.toIntOrNull()
|
||||
val episodes = soup.select(".all-episodes li.TPostMv article").map { li ->
|
||||
val href = li.select("a").attr("href")
|
||||
val epThumb =
|
||||
li.selectFirst("div.Image img")?.attr("data-src") ?: li.selectFirst("img.lazy")!!
|
||||
.attr("data-srcc")
|
||||
val seasonid = li.selectFirst("span.Year")!!.text().let { str ->
|
||||
str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() }
|
||||
}
|
||||
val isValid = seasonid.size == 2
|
||||
val episode = if (isValid) seasonid.getOrNull(1) else null
|
||||
val season = if (isValid) seasonid.getOrNull(0) else null
|
||||
Episode(
|
||||
href,
|
||||
null,
|
||||
season,
|
||||
episode,
|
||||
fixUrl(epThumb)
|
||||
)
|
||||
}
|
||||
val tags = soup.select("ul.InfoList li.AAIco-adjust:contains(Genero) a").map { it.text() }
|
||||
val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries
|
||||
val recelement =
|
||||
if (tvType == TvType.TvSeries) "main section div.series_listado.series div.xxx"
|
||||
else "main section ul.MovieList li"
|
||||
val recommendations =
|
||||
soup.select(recelement).mapNotNull { element ->
|
||||
val recTitle = element.select("h2.Title").text() ?: return@mapNotNull null
|
||||
val image = element.select("figure img")?.attr("data-src")
|
||||
val recUrl = fixUrl(element.select("a").attr("href"))
|
||||
MovieSearchResponse(
|
||||
recTitle,
|
||||
recUrl,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image,
|
||||
year = null
|
||||
)
|
||||
}
|
||||
|
||||
return when (tvType) {
|
||||
TvType.TvSeries -> {
|
||||
TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
tvType,
|
||||
episodes,
|
||||
poster,
|
||||
year,
|
||||
description,
|
||||
tags = tags,
|
||||
recommendations = recommendations
|
||||
)
|
||||
}
|
||||
TvType.Movie -> {
|
||||
MovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
tvType,
|
||||
url,
|
||||
poster,
|
||||
year,
|
||||
description,
|
||||
tags = tags,
|
||||
recommendations = recommendations
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
data class Femcuevana(
|
||||
@JsonProperty("url") val url: String,
|
||||
)
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
app.get(data).document.select("div.TPlayer.embed_div iframe").apmap {
|
||||
val iframe = fixUrl(it.attr("data-src"))
|
||||
if (iframe.contains("api.cuevana3.me/fembed/")) {
|
||||
val femregex =
|
||||
Regex("(https.\\/\\/api\\.cuevana3\\.me\\/fembed\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
femregex.findAll(iframe).map { femreg ->
|
||||
femreg.value
|
||||
}.toList().apmap { fem ->
|
||||
val key = fem.replace("https://api.cuevana3.me/fembed/?h=", "")
|
||||
val url = app.post(
|
||||
"https://api.cuevana3.me/fembed/api.php",
|
||||
allowRedirects = false,
|
||||
headers = mapOf(
|
||||
"Host" to "api.cuevana3.me",
|
||||
"User-Agent" to USER_AGENT,
|
||||
"Accept" to "application/json, text/javascript, */*; q=0.01",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"X-Requested-With" to "XMLHttpRequest",
|
||||
"Origin" to "https://api.cuevana3.me",
|
||||
"DNT" to "1",
|
||||
"Connection" to "keep-alive",
|
||||
"Sec-Fetch-Dest" to "empty",
|
||||
"Sec-Fetch-Mode" to "cors",
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
),
|
||||
data = mapOf(Pair("h", key))
|
||||
).text
|
||||
val json = parseJson<Femcuevana>(url)
|
||||
val link = json.url
|
||||
if (link.contains("fembed")) {
|
||||
loadExtractor(link, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (iframe.contains("tomatomatela")) {
|
||||
val tomatoRegex =
|
||||
Regex("(\\/\\/apialfa.tomatomatela.com\\/ir\\/player.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
tomatoRegex.findAll(iframe).map { tomreg ->
|
||||
tomreg.value
|
||||
}.toList().apmap { tom ->
|
||||
val tomkey = tom.replace("//apialfa.tomatomatela.com/ir/player.php?h=", "")
|
||||
app.post(
|
||||
"https://apialfa.tomatomatela.com/ir/rd.php", allowRedirects = false,
|
||||
headers = mapOf(
|
||||
"Host" to "apialfa.tomatomatela.com",
|
||||
"User-Agent" to USER_AGENT,
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"Content-Type" to "application/x-www-form-urlencoded",
|
||||
"Origin" to "null",
|
||||
"DNT" to "1",
|
||||
"Connection" to "keep-alive",
|
||||
"Upgrade-Insecure-Requests" to "1",
|
||||
"Sec-Fetch-Dest" to "iframe",
|
||||
"Sec-Fetch-Mode" to "navigate",
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
),
|
||||
data = mapOf(Pair("url", tomkey))
|
||||
).okhttpResponse.headers.values("location").apmap { loc ->
|
||||
if (loc.contains("goto_ddh.php")) {
|
||||
val gotoregex =
|
||||
Regex("(\\/\\/api.cuevana3.me\\/ir\\/goto_ddh.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
gotoregex.findAll(loc).map { goreg ->
|
||||
goreg.value.replace("//api.cuevana3.me/ir/goto_ddh.php?h=", "")
|
||||
}.toList().apmap { gotolink ->
|
||||
app.post(
|
||||
"https://api.cuevana3.me/ir/redirect_ddh.php",
|
||||
allowRedirects = false,
|
||||
headers = mapOf(
|
||||
"Host" to "api.cuevana3.me",
|
||||
"User-Agent" to USER_AGENT,
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"Content-Type" to "application/x-www-form-urlencoded",
|
||||
"Origin" to "null",
|
||||
"DNT" to "1",
|
||||
"Connection" to "keep-alive",
|
||||
"Upgrade-Insecure-Requests" to "1",
|
||||
"Sec-Fetch-Dest" to "iframe",
|
||||
"Sec-Fetch-Mode" to "navigate",
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
),
|
||||
data = mapOf(Pair("url", gotolink))
|
||||
).okhttpResponse.headers.values("location").apmap { golink ->
|
||||
loadExtractor(golink, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (loc.contains("index.php?h=")) {
|
||||
val indexRegex =
|
||||
Regex("(\\/\\/api.cuevana3.me\\/sc\\/index.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
indexRegex.findAll(loc).map { indreg ->
|
||||
indreg.value.replace("//api.cuevana3.me/sc/index.php?h=", "")
|
||||
}.toList().apmap { inlink ->
|
||||
app.post(
|
||||
"https://api.cuevana3.me/sc/r.php", allowRedirects = false,
|
||||
headers = mapOf(
|
||||
"Host" to "api.cuevana3.me",
|
||||
"User-Agent" to USER_AGENT,
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"Accept-Encoding" to "gzip, deflate, br",
|
||||
"Content-Type" to "application/x-www-form-urlencoded",
|
||||
"Origin" to "null",
|
||||
"DNT" to "1",
|
||||
"Connection" to "keep-alive",
|
||||
"Upgrade-Insecure-Requests" to "1",
|
||||
"Sec-Fetch-Dest" to "iframe",
|
||||
"Sec-Fetch-Mode" to "navigate",
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
"Sec-Fetch-User" to "?1",
|
||||
),
|
||||
data = mapOf(Pair("h", inlink))
|
||||
).okhttpResponse.headers.values("location").apmap { link ->
|
||||
loadExtractor(link, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class CuevanaProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(CuevanaProvider())
|
||||
}
|
||||
}
|
25
DopeboxProvider/build.gradle.kts
Normal file
25
DopeboxProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,25 @@
|
|||
dependencies {
|
||||
// implementation(project(mapOf("path" to ":SflixProvider")))
|
||||
}
|
||||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
DopeboxProvider/src/main/AndroidManifest.xml
Normal file
2
DopeboxProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,6 @@
|
|||
package com.lagradost
|
||||
|
||||
class DopeboxProvider : SflixProvider() {
|
||||
override var mainUrl = "https://dopebox.to"
|
||||
override var name = "Dopebox"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class DopeboxProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(DopeboxProvider())
|
||||
}
|
||||
}
|
22
DoramasYTProvider/build.gradle.kts
Normal file
22
DoramasYTProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
DoramasYTProvider/src/main/AndroidManifest.xml
Normal file
2
DoramasYTProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,155 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
//import com.lagradost.cloudstream3.extractors.FEmbed
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import java.util.*
|
||||
|
||||
|
||||
class DoramasYTProvider : MainAPI() {
|
||||
companion object {
|
||||
fun getType(t: String): TvType {
|
||||
return if (t.contains("OVA") || t.contains("Especial")) TvType.OVA
|
||||
else if (t.contains("Pelicula")) TvType.Movie
|
||||
else TvType.TvSeries
|
||||
}
|
||||
fun getDubStatus(title: String): DubStatus {
|
||||
return if (title.contains("Latino") || title.contains("Castellano"))
|
||||
DubStatus.Dubbed
|
||||
else DubStatus.Subbed
|
||||
}
|
||||
}
|
||||
|
||||
override var mainUrl = "https://doramasyt.com"
|
||||
override var name = "DoramasYT"
|
||||
override var lang = "es"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.AsianDrama,
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val urls = listOf(
|
||||
Pair("$mainUrl/emision", "En emisión"),
|
||||
Pair(
|
||||
"$mainUrl/doramas?categoria=pelicula&genero=false&fecha=false&letra=false",
|
||||
"Peliculas"
|
||||
),
|
||||
Pair("$mainUrl/doramas", "Doramas"),
|
||||
Pair(
|
||||
"$mainUrl/doramas?categoria=live-action&genero=false&fecha=false&letra=false",
|
||||
"Live Action"
|
||||
),
|
||||
)
|
||||
|
||||
val items = ArrayList<HomePageList>()
|
||||
|
||||
items.add(
|
||||
HomePageList(
|
||||
"Capítulos actualizados",
|
||||
app.get(mainUrl, timeout = 120).document.select(".col-6").map {
|
||||
val title = it.selectFirst("p")!!.text()
|
||||
val poster = it.selectFirst(".chapter img")!!.attr("src")
|
||||
val epRegex = Regex("episodio-(\\d+)")
|
||||
val url = it.selectFirst("a")!!.attr("href").replace("ver/", "dorama/")
|
||||
.replace(epRegex, "sub-espanol")
|
||||
val epNum = it.selectFirst("h3")!!.text().toIntOrNull()
|
||||
newAnimeSearchResponse(title,url) {
|
||||
this.posterUrl = fixUrl(poster)
|
||||
addDubStatus(getDubStatus(title), epNum)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
for (i in urls) {
|
||||
try {
|
||||
val home = app.get(i.first, timeout = 120).document.select(".col-6").map {
|
||||
val title = it.selectFirst(".animedtls p")!!.text()
|
||||
val poster = it.selectFirst(".anithumb img")!!.attr("src")
|
||||
newAnimeSearchResponse(title, fixUrl(it.selectFirst("a")!!.attr("href"))) {
|
||||
this.posterUrl = fixUrl(poster)
|
||||
addDubStatus(getDubStatus(title))
|
||||
}
|
||||
}
|
||||
|
||||
items.add(HomePageList(i.second, home))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
if (items.size <= 0) throw ErrorLoadingException()
|
||||
return HomePageResponse(items)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
return app.get("$mainUrl/buscar?q=$query", timeout = 120).document.select(".col-6").map {
|
||||
val title = it.selectFirst(".animedtls p")!!.text()
|
||||
val href = it.selectFirst("a")!!.attr("href")
|
||||
val image = it.selectFirst(".animes img")!!.attr("src")
|
||||
AnimeSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Anime,
|
||||
image,
|
||||
null,
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
|
||||
DubStatus.Dubbed
|
||||
) else EnumSet.of(DubStatus.Subbed),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url, timeout = 120).document
|
||||
val poster = doc.selectFirst("div.flimimg img.img1")!!.attr("src")
|
||||
val title = doc.selectFirst("h1")!!.text()
|
||||
val type = doc.selectFirst("h4")!!.text()
|
||||
val description = doc.selectFirst("p.textComplete")!!.text().replace("Ver menos", "")
|
||||
val genres = doc.select(".nobel a").map { it.text() }
|
||||
val status = when (doc.selectFirst(".state h6")?.text()) {
|
||||
"Estreno" -> ShowStatus.Ongoing
|
||||
"Finalizado" -> ShowStatus.Completed
|
||||
else -> null
|
||||
}
|
||||
val episodes = doc.select(".heromain .col-item").map {
|
||||
val name = it.selectFirst(".dtlsflim p")!!.text()
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
val epThumb = it.selectFirst(".flimimg img.img1")!!.attr("src")
|
||||
Episode(link, name, posterUrl = epThumb)
|
||||
}
|
||||
return newAnimeLoadResponse(title, url, getType(type)) {
|
||||
posterUrl = poster
|
||||
addEpisodes(DubStatus.Subbed, episodes)
|
||||
showStatus = status
|
||||
plot = description
|
||||
tags = genres
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
app.get(data).document.select("div.playother p").apmap {
|
||||
val encodedurl = it.select("p").attr("data-player")
|
||||
val urlDecoded = base64Decode(encodedurl)
|
||||
val url = (urlDecoded).replace("https://doramasyt.com/reproductor?url=", "")
|
||||
// if (url.startsWith("https://www.fembed.com")) {
|
||||
// val extractor = FEmbed()
|
||||
// extractor.getUrl(url).forEach { link ->
|
||||
// callback.invoke(link)
|
||||
// }
|
||||
// } else {
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
// }
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class DoramasYTProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(DoramasYTProvider())
|
||||
}
|
||||
}
|
22
DramaSeeProvider/build.gradle.kts
Normal file
22
DramaSeeProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
DramaSeeProvider/src/main/AndroidManifest.xml
Normal file
2
DramaSeeProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,217 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider.Companion.extractVidstream
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class DramaSeeProvider : MainAPI() {
|
||||
override var mainUrl = "https://dramasee.net"
|
||||
override var name = "DramaSee"
|
||||
override val hasQuickSearch = false
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = false
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(TvType.AsianDrama)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val headers = mapOf("X-Requested-By" to mainUrl)
|
||||
val document = app.get(mainUrl, headers = headers).document
|
||||
val mainbody = document.getElementsByTag("body")
|
||||
|
||||
return HomePageResponse(
|
||||
mainbody.select("section.block_area.block_area_home")?.map { main ->
|
||||
val title = main.select("h2.cat-heading").text() ?: "Main"
|
||||
val inner = main.select("div.flw-item") ?: return@map null
|
||||
|
||||
HomePageList(
|
||||
title,
|
||||
inner.mapNotNull {
|
||||
val innerBody = it?.selectFirst("a")
|
||||
// Fetch details
|
||||
val link = fixUrlNull(innerBody?.attr("href")) ?: return@mapNotNull null
|
||||
val image = fixUrlNull(it.select("img").attr("data-src")) ?: ""
|
||||
val name = innerBody?.attr("title") ?: "<Untitled>"
|
||||
//Log.i(this.name, "Result => (innerBody, image) ${innerBody} / ${image}")
|
||||
MovieSearchResponse(
|
||||
name,
|
||||
link,
|
||||
this.name,
|
||||
TvType.AsianDrama,
|
||||
image,
|
||||
year = null,
|
||||
id = null,
|
||||
)
|
||||
}.distinctBy { c -> c.url })
|
||||
}?.filterNotNull() ?: listOf()
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/search?q=$query"
|
||||
val document = app.get(url).document
|
||||
val posters = document.select("div.film-poster")
|
||||
|
||||
|
||||
return posters.mapNotNull {
|
||||
val innerA = it.select("a") ?: return@mapNotNull null
|
||||
val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null
|
||||
val title = innerA.attr("title") ?: return@mapNotNull null
|
||||
val year =
|
||||
Regex(""".*\((\d{4})\)""").find(title)?.groupValues?.getOrNull(1)?.toIntOrNull()
|
||||
val imgSrc = it.select("img")?.attr("data-src") ?: return@mapNotNull null
|
||||
val image = fixUrlNull(imgSrc)
|
||||
|
||||
MovieSearchResponse(
|
||||
name = title,
|
||||
url = link,
|
||||
apiName = this.name,
|
||||
type = TvType.Movie,
|
||||
posterUrl = image,
|
||||
year = year
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val body = doc.getElementsByTag("body")
|
||||
val inner = body?.select("div.anis-content")
|
||||
|
||||
// Video details
|
||||
val poster = fixUrlNull(inner?.select("img.film-poster-img")?.attr("src")) ?: ""
|
||||
//Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}")
|
||||
val title = inner?.select("h2.film-name.dynamic-name")?.text() ?: ""
|
||||
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?.firstOrNull()?.select("div.film-description.m-hide")?.text()
|
||||
val tags = inner?.select("div.item.item-list > a")
|
||||
?.mapNotNull { it?.text()?.trim() ?: return@mapNotNull null }
|
||||
val recs = body.select("div.flw-item")?.mapNotNull {
|
||||
val a = it.select("a") ?: return@mapNotNull null
|
||||
val aUrl = fixUrlNull(a.attr("href")) ?: return@mapNotNull null
|
||||
val aImg = fixUrlNull(it.select("img")?.attr("data-src"))
|
||||
val aName = a.attr("title") ?: 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 episodeUrl = body.select("a.btn.btn-radius.btn-primary.btn-play").attr("href")
|
||||
val episodeDoc = app.get(episodeUrl).document
|
||||
|
||||
|
||||
val episodeList = episodeDoc.select("div.ss-list.ss-list-min > a").mapNotNull { ep ->
|
||||
val episodeNumber = ep.attr("data-number").toIntOrNull()
|
||||
val epLink = fixUrlNull(ep.attr("href")) ?: return@mapNotNull null
|
||||
|
||||
// if (epLink.isNotBlank()) {
|
||||
// // Fetch video links
|
||||
// val epVidLinkEl = app.get(epLink, referer = mainUrl).document
|
||||
// val ajaxUrl = epVidLinkEl.select("div#js-player")?.attr("embed")
|
||||
// //Log.i(this.name, "Result => (ajaxUrl) ${ajaxUrl}")
|
||||
// if (!ajaxUrl.isNullOrEmpty()) {
|
||||
// val innerPage = app.get(fixUrl(ajaxUrl), referer = epLink).document
|
||||
// val listOfLinks = mutableListOf<String>()
|
||||
// innerPage.select("div.player.active > main > div")?.forEach { em ->
|
||||
// val href = fixUrlNull(em.attr("src")) ?: ""
|
||||
// if (href.isNotBlank()) {
|
||||
// listOfLinks.add(href)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //Log.i(this.name, "Result => (listOfLinks) ${listOfLinks.toJson()}")
|
||||
//
|
||||
// }
|
||||
// }
|
||||
Episode(
|
||||
name = null,
|
||||
season = null,
|
||||
episode = episodeNumber,
|
||||
data = epLink,
|
||||
posterUrl = null,
|
||||
date = null
|
||||
)
|
||||
}
|
||||
|
||||
//If there's only 1 episode, consider it a movie.
|
||||
if (episodeList.size == 1) {
|
||||
return MovieLoadResponse(
|
||||
name = title,
|
||||
url = url,
|
||||
apiName = this.name,
|
||||
type = TvType.Movie,
|
||||
dataUrl = episodeList.first().data,
|
||||
posterUrl = poster,
|
||||
year = year,
|
||||
plot = descript,
|
||||
recommendations = recs,
|
||||
tags = tags
|
||||
)
|
||||
}
|
||||
return TvSeriesLoadResponse(
|
||||
name = title,
|
||||
url = url,
|
||||
apiName = this.name,
|
||||
type = TvType.AsianDrama,
|
||||
episodes = episodeList,
|
||||
posterUrl = poster,
|
||||
year = year,
|
||||
plot = descript,
|
||||
recommendations = recs,
|
||||
tags = tags
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
println("DATATATAT $data")
|
||||
|
||||
val document = app.get(data).document
|
||||
val iframeUrl = document.select("iframe").attr("src")
|
||||
val iframe = app.get(iframeUrl)
|
||||
val iframeDoc = iframe.document
|
||||
|
||||
argamap({
|
||||
iframeDoc.select(".list-server-items > .linkserver")
|
||||
.forEach { element ->
|
||||
val status = element.attr("data-status") ?: return@forEach
|
||||
if (status != "1") return@forEach
|
||||
val extractorData = element.attr("data-video") ?: return@forEach
|
||||
loadExtractor(extractorData, iframe.url, subtitleCallback, callback)
|
||||
}
|
||||
}, {
|
||||
val iv = "9262859232435825"
|
||||
val secretKey = "93422192433952489752342908585752"
|
||||
val secretDecryptKey = "93422192433952489752342908585752"
|
||||
extractVidstream(
|
||||
iframe.url,
|
||||
this.name,
|
||||
callback,
|
||||
iv,
|
||||
secretKey,
|
||||
secretDecryptKey,
|
||||
isUsingAdaptiveKeys = false,
|
||||
isUsingAdaptiveData = true,
|
||||
iframeDocument = iframeDoc
|
||||
)
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class DramaSeeProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(DramaSeeProvider())
|
||||
}
|
||||
}
|
22
DramaidProvider/build.gradle.kts
Normal file
22
DramaidProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
DramaidProvider/src/main/AndroidManifest.xml
Normal file
2
DramaidProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
213
DramaidProvider/src/main/kotlin/com/lagradost/DramaidProvider.kt
Normal file
213
DramaidProvider/src/main/kotlin/com/lagradost/DramaidProvider.kt
Normal file
|
@ -0,0 +1,213 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class DramaidProvider : MainAPI() {
|
||||
override var mainUrl = "https://185.224.83.103"
|
||||
override var name = "DramaId"
|
||||
override val hasQuickSearch = false
|
||||
override val hasMainPage = true
|
||||
override var lang = "id"
|
||||
override val hasDownloadSupport = true
|
||||
override val hasChromecastSupport = false
|
||||
override val supportedTypes = setOf(TvType.AsianDrama)
|
||||
|
||||
companion object {
|
||||
fun getStatus(t: String): ShowStatus {
|
||||
return when (t) {
|
||||
"Completed" -> ShowStatus.Completed
|
||||
"Ongoing" -> ShowStatus.Ongoing
|
||||
else -> ShowStatus.Completed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"&status=&type=&order=update" to "Drama Terbaru",
|
||||
"&order=latest" to "Baru Ditambahkan",
|
||||
"&status=&type=&order=popular" to "Drama Popular",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||
val document = app.get("$mainUrl/series/?page=$page${request.data}").document
|
||||
val home = document.select("article[itemscope=itemscope]").mapNotNull {
|
||||
it.toSearchResult()
|
||||
}
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
private fun getProperDramaLink(uri: String): String {
|
||||
return if (uri.contains("/series/")) {
|
||||
uri
|
||||
} else {
|
||||
"$mainUrl/series/" + Regex("$mainUrl/(.+)-ep.+").find(uri)?.groupValues?.get(1)
|
||||
.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun Element.toSearchResult(): SearchResponse? {
|
||||
val href = getProperDramaLink(this.selectFirst("a.tip")!!.attr("href"))
|
||||
val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null
|
||||
val posterUrl = fixUrlNull(this.selectFirst(".limit > noscript > img")?.attr("src"))
|
||||
|
||||
return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
|
||||
this.posterUrl = posterUrl
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val link = "$mainUrl/?s=$query"
|
||||
val document = app.get(link).document
|
||||
|
||||
return document.select("article[itemscope=itemscope]").map {
|
||||
val title = it.selectFirst("h2[itemprop=headline]")!!.text().trim()
|
||||
val poster = it.selectFirst(".limit > noscript > img")!!.attr("src")
|
||||
val href = it.selectFirst("a.tip")!!.attr("href")
|
||||
|
||||
newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
|
||||
this.posterUrl = poster
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val document = app.get(url).document
|
||||
|
||||
val title = document.selectFirst("h1.entry-title")!!.text().trim()
|
||||
val poster = document.select(".thumb > noscript > img").attr("src")
|
||||
val tags = document.select(".genxed > a").map { it.text() }
|
||||
|
||||
val year = Regex("\\d, ([0-9]*)").find(
|
||||
document.selectFirst(".info-content > .spe > span > time")!!.text().trim()
|
||||
)?.groupValues?.get(1).toString().toIntOrNull()
|
||||
val status = getStatus(
|
||||
document.select(".info-content > .spe > span:nth-child(1)")
|
||||
.text().trim().replace("Status: ", "")
|
||||
)
|
||||
val description = document.select(".entry-content > p").text().trim()
|
||||
|
||||
val episodes = document.select(".eplister > ul > li").map {
|
||||
val name = it.selectFirst("a > .epl-title")!!.text().trim()
|
||||
val link = it.select("a").attr("href")
|
||||
val epNum = it.selectFirst("a > .epl-num")!!.text().trim().toIntOrNull()
|
||||
newEpisode(link) {
|
||||
this.name = name
|
||||
this.episode = epNum
|
||||
}
|
||||
}.reversed()
|
||||
|
||||
val recommendations =
|
||||
document.select(".listupd > article[itemscope=itemscope]").map { rec ->
|
||||
val epTitle = rec.selectFirst("h2[itemprop=headline]")!!.text().trim()
|
||||
val epPoster = rec.selectFirst(".limit > noscript > img")!!.attr("src")
|
||||
val epHref = fixUrl(rec.selectFirst("a.tip")!!.attr("href"))
|
||||
|
||||
newTvSeriesSearchResponse(epTitle, epHref, TvType.AsianDrama) {
|
||||
this.posterUrl = epPoster
|
||||
}
|
||||
}
|
||||
|
||||
if (episodes.size == 1) {
|
||||
return newMovieLoadResponse(title, url, TvType.Movie, episodes[0].data) {
|
||||
posterUrl = poster
|
||||
this.year = year
|
||||
plot = description
|
||||
this.tags = tags
|
||||
this.recommendations = recommendations
|
||||
}
|
||||
} else {
|
||||
return newTvSeriesLoadResponse(title, url, TvType.AsianDrama, episodes = episodes) {
|
||||
posterUrl = poster
|
||||
this.year = year
|
||||
showStatus = status
|
||||
plot = description
|
||||
this.tags = tags
|
||||
this.recommendations = recommendations
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private data class Sources(
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("label") val label: String,
|
||||
@JsonProperty("type") val type: String,
|
||||
@JsonProperty("default") val default: Boolean?
|
||||
)
|
||||
|
||||
private data class Tracks(
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("label") val label: String,
|
||||
@JsonProperty("kind") val type: String,
|
||||
@JsonProperty("default") val default: Boolean?
|
||||
)
|
||||
|
||||
private suspend fun invokeDriveSource(
|
||||
url: String,
|
||||
name: String,
|
||||
subCallback: (SubtitleFile) -> Unit,
|
||||
sourceCallback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val server = app.get(url).document.selectFirst(".picasa")?.nextElementSibling()?.data()
|
||||
|
||||
val source = "[${server!!.substringAfter("sources: [").substringBefore("],")}]".trimIndent()
|
||||
val trackers = server.substringAfter("tracks:[").substringBefore("],")
|
||||
.replace("//language", "")
|
||||
.replace("file", "\"file\"")
|
||||
.replace("label", "\"label\"")
|
||||
.replace("kind", "\"kind\"").trimIndent()
|
||||
|
||||
tryParseJson<List<Sources>>(source)?.map {
|
||||
sourceCallback(
|
||||
ExtractorLink(
|
||||
name,
|
||||
"Drive",
|
||||
fixUrl(it.file),
|
||||
referer = "https://motonews.club/",
|
||||
quality = getQualityFromName(it.label)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
tryParseJson<Tracks>(trackers)?.let {
|
||||
subCallback.invoke(
|
||||
SubtitleFile(
|
||||
if (it.label.contains("Indonesia")) "${it.label}n" else it.label,
|
||||
it.file
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val document = app.get(data).document
|
||||
val sources = document.select(".mobius > .mirror > option").mapNotNull {
|
||||
fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src"))
|
||||
}
|
||||
|
||||
sources.map {
|
||||
it.replace("https://ndrama.xyz", "https://www.fembed.com")
|
||||
}.apmap {
|
||||
when {
|
||||
it.contains("motonews.club") -> invokeDriveSource(it, this.name, subtitleCallback, callback)
|
||||
else -> loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class DramaidProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(DramaidProvider())
|
||||
}
|
||||
}
|
22
DubokuProvider/build.gradle.kts
Normal file
22
DubokuProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
DubokuProvider/src/main/AndroidManifest.xml
Normal file
2
DubokuProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
133
DubokuProvider/src/main/kotlin/com/lagradost/DubokuProvider.kt
Normal file
133
DubokuProvider/src/main/kotlin/com/lagradost/DubokuProvider.kt
Normal file
|
@ -0,0 +1,133 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class DubokuProvider : MainAPI() {
|
||||
override var mainUrl = "https://www.duboku.tv"
|
||||
override var name = "Duboku"
|
||||
override val hasMainPage = true
|
||||
override var lang = "zh"
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries,
|
||||
TvType.AsianDrama,
|
||||
)
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/vodshow/2--time------" to "连续剧 时间",
|
||||
"$mainUrl/vodshow/2--hits------" to "连续剧 人气",
|
||||
"$mainUrl/vodshow/13--time------" to "陆剧 时间",
|
||||
"$mainUrl/vodshow/13--hits------" to "陆剧 人气",
|
||||
"$mainUrl/vodshow/15--time------" to "日韩剧 时间",
|
||||
"$mainUrl/vodshow/15--hits------" to "日韩剧 人气",
|
||||
"$mainUrl/vodshow/21--time------" to "短剧 时间",
|
||||
"$mainUrl/vodshow/21--hits------" to "短剧 人气",
|
||||
"$mainUrl/vodshow/16--time------" to "英美剧 时间",
|
||||
"$mainUrl/vodshow/16--hits------" to "英美剧 人气",
|
||||
"$mainUrl/vodshow/14--time------" to "台泰剧 时间",
|
||||
"$mainUrl/vodshow/14--hits------" to "台泰剧 人气",
|
||||
"$mainUrl/vodshow/20--time------" to "港剧 时间",
|
||||
"$mainUrl/vodshow/20--hits------" to "港剧 人气",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(
|
||||
page: Int,
|
||||
request: MainPageRequest
|
||||
): HomePageResponse {
|
||||
val document = app.get("${request.data}$page---.html").document
|
||||
val home = document.select("ul.myui-vodlist.clearfix li").mapNotNull {
|
||||
it.toSearchResult()
|
||||
}
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
private fun Element.toSearchResult(): SearchResponse? {
|
||||
val title = this.selectFirst("h4.title a")?.text()?.trim() ?: return null
|
||||
val href = fixUrl(this.selectFirst("a")?.attr("href").toString())
|
||||
val posterUrl = fixUrlNull(this.selectFirst("a")?.attr("data-original"))
|
||||
val episode = this.selectFirst("span.pic-text.text-right")?.text()?.filter { it.isDigit() }
|
||||
?.toIntOrNull()
|
||||
|
||||
return newAnimeSearchResponse(title, href, TvType.Movie) {
|
||||
this.posterUrl = posterUrl
|
||||
addSub(episode)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val document = app.get("$mainUrl/vodsearch/-------------.html?wd=$query&submit=").document
|
||||
|
||||
return document.select("ul#searchList li").mapNotNull {
|
||||
it.toSearchResult()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val document = app.get(url).document
|
||||
|
||||
val title = document.selectFirst("h1.title")?.text()?.trim() ?: return null
|
||||
val tvType = if (document.select("ul.myui-content__list li").size == 1
|
||||
) TvType.Movie else TvType.TvSeries
|
||||
val actors = document.select("p.data")[2].select("a").map { it.text() }
|
||||
|
||||
val episodes = document.select("ul.myui-content__list li").map {
|
||||
val href = fixUrl(it.select("a").attr("href"))
|
||||
val name = it.select("a").text().trim()
|
||||
Episode(
|
||||
data = href,
|
||||
name = name,
|
||||
)
|
||||
}
|
||||
return newTvSeriesLoadResponse(title, url, tvType, episodes) {
|
||||
this.posterUrl = fixUrlNull(
|
||||
document.selectFirst("a.myui-vodlist__thumb.picture img")?.attr("data-original")
|
||||
)
|
||||
this.year =
|
||||
document.select("p.data")[0].select("a").last()?.text()?.trim()?.toIntOrNull()
|
||||
this.plot = document.selectFirst("span.sketch.content")?.text()?.trim()
|
||||
this.tags = document.select("p.data")[0].select("a").map { it.text() }
|
||||
this.rating = document.select("div#rating span.branch").text().toRatingInt()
|
||||
addActors(actors)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
|
||||
app.get(data).document.select("script").map { script ->
|
||||
if (script.data().contains("var player_data={")) {
|
||||
val dataJson =
|
||||
script.data().substringAfter("var player_data={").substringBefore("}")
|
||||
tryParseJson<Sources>("{$dataJson}")?.let { source ->
|
||||
M3u8Helper.generateM3u8(
|
||||
this.name,
|
||||
source.url ?: return@map,
|
||||
referer = "https://w.duboku.io/",
|
||||
headers = mapOf("Origin" to "https://w.duboku.io")
|
||||
).forEach(callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
data class Sources(
|
||||
@JsonProperty("url") val url: String?,
|
||||
)
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class DubokuProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(DubokuProvider())
|
||||
}
|
||||
}
|
22
EgyBestProvider/build.gradle.kts
Normal file
22
EgyBestProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
EgyBestProvider/src/main/AndroidManifest.xml
Normal file
2
EgyBestProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
237
EgyBestProvider/src/main/kotlin/com/lagradost/EgyBestProvider.kt
Normal file
237
EgyBestProvider/src/main/kotlin/com/lagradost/EgyBestProvider.kt
Normal file
|
@ -0,0 +1,237 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class EgyBestProvider : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://www.egy.best"
|
||||
override var name = "EgyBest"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime)
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = this.attr("href") ?: return null
|
||||
val posterUrl = select("img")?.attr("src")
|
||||
var title = select("span.title").text()
|
||||
val year = title.getYearFromTitle()
|
||||
val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
|
||||
val tvType = if (isMovie) TvType.Movie else TvType.TvSeries
|
||||
title = if (year !== null) title else title.split(" (")[0].trim()
|
||||
val quality = select("span.ribbon span").text().replace("-", "")
|
||||
// If you need to differentiate use the url.
|
||||
return MovieSearchResponse(
|
||||
title,
|
||||
url,
|
||||
this@EgyBestProvider.name,
|
||||
tvType,
|
||||
posterUrl,
|
||||
year,
|
||||
null,
|
||||
quality = getQualityFromString(quality)
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
// url, title
|
||||
val doc = app.get(mainUrl).document
|
||||
val pages = arrayListOf<HomePageList>()
|
||||
doc.select("#mainLoad div.mbox").apmap {
|
||||
val name = it.select(".bdb.pda > strong").text()
|
||||
if (it.select(".movie").first()?.attr("href")?.contains("season-(.....)|ep-(.....)".toRegex()) == true) return@apmap
|
||||
val list = arrayListOf<SearchResponse>()
|
||||
it.select(".movie").map { element ->
|
||||
list.add(element.toSearchResponse()!!)
|
||||
}
|
||||
pages.add(HomePageList(name, list))
|
||||
}
|
||||
return HomePageResponse(pages)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val q = query.replace(" ","%20")
|
||||
val result = arrayListOf<SearchResponse>()
|
||||
listOf("$mainUrl/explore/?q=$q").apmap { url ->
|
||||
val d = app.get(url).document
|
||||
d.select("div.movies a").not("a.auto.load.btn.b").mapNotNull {
|
||||
it.toSearchResponse()?.let { it1 -> result.add(it1) }
|
||||
}
|
||||
}
|
||||
return result.distinct().sortedBy { it.name }
|
||||
}
|
||||
|
||||
private fun String.getYearFromTitle(): Int? {
|
||||
return Regex("""\(\d{4}\)""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
|
||||
val posterUrl = doc.select("div.movie_img a img")?.attr("src")
|
||||
val year = doc.select("div.movie_title h1 a")?.text()?.toIntOrNull()
|
||||
val title = doc.select("div.movie_title h1 span").text()
|
||||
val youtubeTrailer = doc.select("div.play")?.attr("url")
|
||||
|
||||
val synopsis = doc.select("div.mbox").firstOrNull {
|
||||
it.text().contains("القصة")
|
||||
}?.text()?.replace("القصة ", "")
|
||||
|
||||
val tags = doc.select("table.movieTable tbody tr").firstOrNull {
|
||||
it.text().contains("النوع")
|
||||
}?.select("a")?.map { it.text() }
|
||||
|
||||
val actors = doc.select("div.cast_list .cast_item").mapNotNull {
|
||||
val name = it.selectFirst("div > a > img")?.attr("alt") ?: return@mapNotNull null
|
||||
val image = it.selectFirst("div > a > img")?.attr("src") ?: return@mapNotNull null
|
||||
val roleString = it.selectFirst("div > span")!!.text()
|
||||
val mainActor = Actor(name, image)
|
||||
ActorData(actor = mainActor, roleString = roleString)
|
||||
}
|
||||
|
||||
return if (isMovie) {
|
||||
val recommendations = doc.select(".movies_small .movie").mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.recommendations = recommendations
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.actors = actors
|
||||
addTrailer(youtubeTrailer)
|
||||
}
|
||||
} else {
|
||||
val episodes = ArrayList<Episode>()
|
||||
doc.select("#mainLoad > div:nth-child(2) > div.h_scroll > div a").map {
|
||||
it.attr("href")
|
||||
}.apmap {
|
||||
val d = app.get(it).document
|
||||
val season = Regex("season-(.....)").find(it)?.groupValues?.getOrNull(1)?.getIntFromText()
|
||||
if(d.select("tr.published").isNotEmpty()) {
|
||||
d.select("tr.published").map { element ->
|
||||
val ep = Regex("ep-(.....)").find(element.select(".ep_title a").attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
|
||||
episodes.add(
|
||||
Episode(
|
||||
element.select(".ep_title a").attr("href"),
|
||||
name = element.select("td.ep_title").html().replace(".*</span>|</a>".toRegex(), ""),
|
||||
season,
|
||||
ep,
|
||||
rating = element.select("td.tam:not(.date, .ep_len)").text().getIntFromText()
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
d.select("#mainLoad > div:nth-child(3) > div.movies_small a").map { eit ->
|
||||
val ep = Regex("ep-(.....)").find(eit.attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
|
||||
episodes.add(
|
||||
Episode(
|
||||
eit.attr("href"),
|
||||
eit.select("span.title").text(),
|
||||
season,
|
||||
ep,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
|
||||
this.posterUrl = posterUrl
|
||||
this.tags = tags
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.actors = actors
|
||||
addTrailer(youtubeTrailer)
|
||||
}
|
||||
}
|
||||
}
|
||||
data class Sources (
|
||||
@JsonProperty("quality") val quality: Int?,
|
||||
@JsonProperty("link") val link: String
|
||||
)
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
/*val baseURL = data.split("/")[0] + "//" + data.split("/")[2]
|
||||
val episodeSoup = app.get(data).document
|
||||
|
||||
val vidstreamURL = fixUrlNull(episodeSoup.selectFirst("iframe.auto-size")?.attr("src") ) ?: throw ErrorLoadingException("No iframe")
|
||||
val videoSoup = app.get(vidstreamURL).document
|
||||
fixUrlNull( videoSoup.select("source").firstOrNull { it.hasAttr("src") }?.attr("src"))?.let {
|
||||
callback.invoke(ExtractorLink(this.name,this.name,it,"",Qualities.Unknown.value,it.contains(".m3u8")))
|
||||
} ?: run {
|
||||
var jsCode = videoSoup.select("script")[1].data()
|
||||
|
||||
val verificationToken = Regex("{'[0-9a-zA-Z_]*':'ok'}").findAll(jsCode)[0][2:-7]
|
||||
val encodedAdLinkVar = Regex("([0-9a-zA-Z_]{2,12}\[Math").findAll(jsCode)[0][1:-5]
|
||||
val encodingArraysRegEx = Regex(",[0-9a-zA-Z_]{2,12}=\[\]").findAll(jsCode)
|
||||
val firstEncodingArray = encodingArraysRegEx[1][1:-3]
|
||||
val secondEncodingArray = encodingArraysRegEx[2][1:-3]
|
||||
|
||||
jsCode = Regex("^<script type=\"text/javascript\">", "", jsCode)
|
||||
jsCode = Regex("[;,]\$\('\*'\)(.*)$", ";", jsCode)
|
||||
jsCode = Regex(",ismob=(.*)\(navigator\[(.*)\]\)[,;]", ";", jsCode)
|
||||
jsCode = Regex("var a0b=function\(\)(.*)a0a\(\);",).findAll( jsCode)
|
||||
jsCode += "var link = ''; for (var i = 0; i <= $secondEncodingArray['length']; i++) { link += $firstEncodingArray[$secondEncodingArray[i]] || ''; } return [link, $encodedAdLinkVar[0]] }"
|
||||
|
||||
val jsCodeReturn = executeJS(jsCode)()
|
||||
val verificationPath = jsCodeReturn[0]
|
||||
val encodedAdPath = jsCodeReturn[1]
|
||||
|
||||
val adLink = baseURL + "/" + str(decode(encodedAdPath + "=" * (-len(encodedAdPath) % 4)), "utf-8")
|
||||
val session.get(adLink)
|
||||
|
||||
val verificationLink = baseURL + "/tvc.php?verify=" + verificationPath
|
||||
val session.post(verificationLink, data={verificationToken: "ok"})
|
||||
|
||||
val vidstreamResponseText = session.get(vidstreamURL).text
|
||||
val videoSoup = BeautifulSoup(vidstreamResponseText, features="html.parser")
|
||||
|
||||
val qualityLinksFileURL = baseURL + videoSoup.body.find("source").get("src")
|
||||
}
|
||||
|
||||
|
||||
return true*/
|
||||
|
||||
val requestJSON = app.get("https://api.zr5.repl.co/egybest?url=$data").text
|
||||
// To solve this you need to send a verify request which is pretty hidden, see
|
||||
// https://vear.egybest.deals/tvc.php?verify=.......
|
||||
val jsonArray = parseJson<List<Sources>>(requestJSON)
|
||||
for (i in jsonArray) {
|
||||
val quality = i.quality
|
||||
val link = i.link
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
link,
|
||||
this.mainUrl,
|
||||
quality!!,
|
||||
true,
|
||||
// Does not work without these headers!
|
||||
headers = mapOf("range" to "bytes=0-"),
|
||||
)
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class EgyBestProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(EgyBestProvider())
|
||||
}
|
||||
}
|
22
ElifilmsProvider/build.gradle.kts
Normal file
22
ElifilmsProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
ElifilmsProvider/src/main/AndroidManifest.xml
Normal file
2
ElifilmsProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,94 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class ElifilmsProvider : MainAPI() {
|
||||
override var mainUrl: String = "https://elifilms.net"
|
||||
override var name: String = "Elifilms"
|
||||
override var lang = "es"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val items = ArrayList<HomePageList>()
|
||||
val newest = app.get(mainUrl).document.selectFirst("a.fav_link.premiera")?.attr("href")
|
||||
val urls = listOf(
|
||||
Pair(mainUrl, "Películas recientes"),
|
||||
Pair("$mainUrl/4k-peliculas/", "Películas en 4k"),
|
||||
Pair(newest, "Últimos estrenos"),
|
||||
)
|
||||
urls.apmap { (url, name) ->
|
||||
val soup = app.get(url ?: "").document
|
||||
val home = soup.select("article.shortstory.cf").map {
|
||||
val title = it.selectFirst(".short_header")?.text() ?: ""
|
||||
val link = it.selectFirst("div a")?.attr("href") ?: ""
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
it.selectFirst("a.ah-imagge img")?.attr("data-src"),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
}
|
||||
items.add(HomePageList(name, home))
|
||||
}
|
||||
if (items.size <= 0) throw ErrorLoadingException()
|
||||
return HomePageResponse(items)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/?s=$query"
|
||||
val doc = app.get(url).document
|
||||
return doc.select("article.cf").map {
|
||||
val href = it.selectFirst("div.short_content a")?.attr("href") ?: ""
|
||||
val poster = it.selectFirst("a.ah-imagge img")?.attr("data-src")
|
||||
val name = it.selectFirst(".short_header")?.text() ?: ""
|
||||
(MovieSearchResponse(name, href, this.name, TvType.Movie, poster, null))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val document = app.get(url, timeout = 120).document
|
||||
val title = document.selectFirst(".post_title h1")?.text() ?: ""
|
||||
val rating = document.select("span.imdb.rki").toString().toIntOrNull()
|
||||
val poster = document.selectFirst(".poster img")?.attr("src")
|
||||
val desc = document.selectFirst("div.notext .actors p")?.text()
|
||||
val tags = document.select("td.notext a")
|
||||
.map { it?.text()?.trim().toString() }
|
||||
return MovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
url,
|
||||
poster,
|
||||
null,
|
||||
desc,
|
||||
rating,
|
||||
tags
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
app.get(data).document.select("li.change-server a").apmap {
|
||||
val encodedurl = it.attr("data-id")
|
||||
val urlDecoded = base64Decode(encodedurl)
|
||||
val url = fixUrl(urlDecoded)
|
||||
loadExtractor(url, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class ElifilmsProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(ElifilmsProvider())
|
||||
}
|
||||
}
|
22
EntrepeliculasyseriesProvider/build.gradle.kts
Normal file
22
EntrepeliculasyseriesProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,177 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class EntrepeliculasyseriesProvider : MainAPI() {
|
||||
override var mainUrl = "https://entrepeliculasyseries.nu"
|
||||
override var name = "EntrePeliculasySeries"
|
||||
override var lang = "es"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries,
|
||||
)
|
||||
override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
Pair("$mainUrl/series/page/", "Series"),
|
||||
Pair("$mainUrl/peliculas/page/", "Peliculas"),
|
||||
Pair("$mainUrl/anime/page/", "Animes"),
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(
|
||||
page: Int,
|
||||
request : MainPageRequest
|
||||
): HomePageResponse {
|
||||
val url = request.data + page
|
||||
|
||||
val soup = app.get(url).document
|
||||
val home = soup.select("ul.list-movie li").map {
|
||||
val title = it.selectFirst("a.link-title h2")!!.text()
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries,
|
||||
it.selectFirst("a.poster img")!!.attr("src"),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/?s=${query}"
|
||||
val document = app.get(url).document
|
||||
|
||||
return document.select("li.xxx.TPostMv").map {
|
||||
val title = it.selectFirst("h2.Title")!!.text()
|
||||
val href = it.selectFirst("a")!!.attr("href")
|
||||
val image = it.selectFirst("img.lazy")!!.attr("data-src")
|
||||
val isMovie = href.contains("/pelicula/")
|
||||
|
||||
if (isMovie) {
|
||||
MovieSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image,
|
||||
null
|
||||
)
|
||||
} else {
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
image,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
}.toList()
|
||||
}
|
||||
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val soup = app.get(url, timeout = 120).document
|
||||
|
||||
val title = soup.selectFirst("h1.title-post")!!.text()
|
||||
val description = soup.selectFirst("p.text-content:nth-child(3)")?.text()?.trim()
|
||||
val poster: String? = soup.selectFirst("article.TPost img.lazy")!!.attr("data-src")
|
||||
val episodes = soup.select(".TPostMv article").map { li ->
|
||||
val href = (li.select("a") ?: li.select(".C a") ?: li.select("article a")).attr("href")
|
||||
val epThumb = li.selectFirst("div.Image img")!!.attr("data-src")
|
||||
val seasonid = li.selectFirst("span.Year")!!.text().let { str ->
|
||||
str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() }
|
||||
}
|
||||
val isValid = seasonid.size == 2
|
||||
val episode = if (isValid) seasonid.getOrNull(1) else null
|
||||
val season = if (isValid) seasonid.getOrNull(0) else null
|
||||
Episode(
|
||||
href,
|
||||
null,
|
||||
season,
|
||||
episode,
|
||||
fixUrl(epThumb)
|
||||
)
|
||||
}
|
||||
return when (val tvType =
|
||||
if (url.contains("/pelicula/")) TvType.Movie else TvType.TvSeries) {
|
||||
TvType.TvSeries -> {
|
||||
TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
tvType,
|
||||
episodes,
|
||||
poster,
|
||||
null,
|
||||
description,
|
||||
)
|
||||
}
|
||||
TvType.Movie -> {
|
||||
MovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
tvType,
|
||||
url,
|
||||
poster,
|
||||
null,
|
||||
description,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
app.get(data).document.select(".video ul.dropdown-menu li").apmap {
|
||||
val servers = it.attr("data-link")
|
||||
val doc = app.get(servers).document
|
||||
doc.select("input").apmap {
|
||||
val postkey = it.attr("value")
|
||||
app.post(
|
||||
"https://entrepeliculasyseries.nu/r.php",
|
||||
headers = mapOf(
|
||||
"Host" to "entrepeliculasyseries.nu",
|
||||
"User-Agent" to USER_AGENT,
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"Content-Type" to "application/x-www-form-urlencoded",
|
||||
"Origin" to "https://entrepeliculasyseries.nu",
|
||||
"DNT" to "1",
|
||||
"Connection" to "keep-alive",
|
||||
"Referer" to servers,
|
||||
"Upgrade-Insecure-Requests" to "1",
|
||||
"Sec-Fetch-Dest" to "document",
|
||||
"Sec-Fetch-Mode" to "navigate",
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
"Sec-Fetch-User" to "?1",
|
||||
),
|
||||
//params = mapOf(Pair("h", postkey)),
|
||||
data = mapOf(Pair("h", postkey)),
|
||||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap {
|
||||
loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class EntrepeliculasyseriesProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(EntrepeliculasyseriesProvider())
|
||||
}
|
||||
}
|
22
EstrenosDoramasProvider/build.gradle.kts
Normal file
22
EstrenosDoramasProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
EstrenosDoramasProvider/src/main/AndroidManifest.xml
Normal file
2
EstrenosDoramasProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,286 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
class EstrenosDoramasProvider : MainAPI() {
|
||||
companion object {
|
||||
fun getType(t: String): TvType {
|
||||
return if (t.contains("OVA") || t.contains("Especial")) TvType.OVA
|
||||
else if (t.contains("Pelicula")) TvType.Movie
|
||||
else TvType.TvSeries
|
||||
}
|
||||
}
|
||||
|
||||
override var mainUrl = "https://www23.estrenosdoramas.net"
|
||||
override var name = "EstrenosDoramas"
|
||||
override var lang = "es"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val hasDownloadSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.AsianDrama,
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val urls = listOf(
|
||||
Pair(mainUrl, "Últimas series"),
|
||||
Pair("$mainUrl/category/peliculas", "Películas"),
|
||||
)
|
||||
|
||||
val items = ArrayList<HomePageList>()
|
||||
|
||||
urls.apmap { (url, name) ->
|
||||
val home = app.get(url, timeout = 120).document.select("div.clearfix").map {
|
||||
val title = cleanTitle(it.selectFirst("h3 a")?.text()!!)
|
||||
val poster = it.selectFirst("img.cate_thumb")?.attr("src")
|
||||
AnimeSearchResponse(
|
||||
title,
|
||||
it.selectFirst("a")?.attr("href")!!,
|
||||
this.name,
|
||||
TvType.AsianDrama,
|
||||
poster,
|
||||
null,
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
|
||||
DubStatus.Dubbed
|
||||
) else EnumSet.of(DubStatus.Subbed),
|
||||
)
|
||||
}
|
||||
items.add(HomePageList(name, home))
|
||||
}
|
||||
|
||||
if (items.size <= 0) throw ErrorLoadingException()
|
||||
return HomePageResponse(items)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val searchob = ArrayList<AnimeSearchResponse>()
|
||||
val search =
|
||||
app.get("$mainUrl/?s=$query", timeout = 120).document.select("div.clearfix").map {
|
||||
val title = cleanTitle(it.selectFirst("h3 a")?.text()!!)
|
||||
val href = it.selectFirst("a")?.attr("href")
|
||||
val image = it.selectFirst("img.cate_thumb")?.attr("src")
|
||||
val lists =
|
||||
AnimeSearchResponse(
|
||||
title,
|
||||
href!!,
|
||||
this.name,
|
||||
TvType.AsianDrama,
|
||||
image,
|
||||
null,
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
|
||||
DubStatus.Dubbed
|
||||
) else EnumSet.of(DubStatus.Subbed),
|
||||
)
|
||||
if (href.contains("capitulo")) {
|
||||
//nothing
|
||||
}
|
||||
else {
|
||||
searchob.add(lists)
|
||||
}
|
||||
}
|
||||
return searchob
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val doc = app.get(url, timeout = 120).document
|
||||
val poster = doc.selectFirst("head meta[property]")?.attr("content")
|
||||
val title = doc.selectFirst("h1.titulo")?.text()
|
||||
val description = try {
|
||||
doc.selectFirst("div.post div.highlight div.font")?.text()
|
||||
} catch (e:Exception){
|
||||
null
|
||||
}
|
||||
val finaldesc = description?.substringAfter("Sinopsis")?.replace(": ", "")?.trim()
|
||||
val epi = ArrayList<Episode>()
|
||||
val episodes = doc.select("div.post .lcp_catlist a").map {
|
||||
val name = it.selectFirst("a")?.text()
|
||||
val link = it.selectFirst("a")?.attr("href")
|
||||
val test = Episode(link!!, name)
|
||||
if (!link.equals(url)) {
|
||||
epi.add(test)
|
||||
}
|
||||
}.reversed()
|
||||
return when (val type = if (episodes.isEmpty()) TvType.Movie else TvType.AsianDrama) {
|
||||
TvType.AsianDrama -> {
|
||||
return newAnimeLoadResponse(title!!, url, type) {
|
||||
japName = null
|
||||
engName = title.replace(Regex("[Pp]elicula |[Pp]elicula"),"")
|
||||
posterUrl = poster
|
||||
addEpisodes(DubStatus.Subbed, epi.reversed())
|
||||
plot = finaldesc
|
||||
}
|
||||
}
|
||||
TvType.Movie -> {
|
||||
MovieLoadResponse(
|
||||
cleanTitle(title!!),
|
||||
url,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
url,
|
||||
poster,
|
||||
null,
|
||||
finaldesc,
|
||||
null,
|
||||
null,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
data class ReproDoramas (
|
||||
@JsonProperty("link") val link: String,
|
||||
@JsonProperty("time") val time: Int
|
||||
)
|
||||
|
||||
private fun cleanTitle(title: String): String = title.replace(Regex("[Pp]elicula |[Pp]elicula"),"")
|
||||
|
||||
private fun cleanExtractor(
|
||||
source: String,
|
||||
name: String,
|
||||
url: String,
|
||||
referer: String,
|
||||
m3u8: Boolean,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
callback(
|
||||
ExtractorLink(
|
||||
source,
|
||||
name,
|
||||
url,
|
||||
referer,
|
||||
Qualities.Unknown.value,
|
||||
m3u8
|
||||
)
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val headers = mapOf("Host" to "repro3.estrenosdoramas.us",
|
||||
"User-Agent" to USER_AGENT,
|
||||
"Accept" to "*/*",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"X-Requested-With" to "XMLHttpRequest",
|
||||
"Origin" to "https://repro3.estrenosdoramas.us",
|
||||
"DNT" to "1",
|
||||
"Connection" to "keep-alive",
|
||||
"Sec-Fetch-Dest" to "empty",
|
||||
"Sec-Fetch-Mode" to "cors",
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
"Cache-Control" to "max-age=0",)
|
||||
|
||||
val document = app.get(data).document
|
||||
document.select("div.tab_container iframe").apmap { container ->
|
||||
val directlink = fixUrl(container.attr("src"))
|
||||
loadExtractor(directlink, data, subtitleCallback, callback)
|
||||
|
||||
if (directlink.contains("/repro/amz/")) {
|
||||
val amzregex = Regex("https:\\/\\/repro3\\.estrenosdoramas\\.us\\/repro\\/amz\\/examples\\/.*\\.php\\?key=.*\$")
|
||||
amzregex.findAll(directlink).map {
|
||||
it.value.replace(Regex("https:\\/\\/repro3\\.estrenosdoramas\\.us\\/repro\\/amz\\/examples\\/.*\\.php\\?key="),"")
|
||||
}.toList().apmap { key ->
|
||||
val response = app.post("https://repro3.estrenosdoramas.us/repro/amz/examples/player/api/indexDCA.php",
|
||||
headers = headers,
|
||||
data = mapOf(
|
||||
Pair("key",key),
|
||||
Pair("token","MDAwMDAwMDAwMA=="),
|
||||
),
|
||||
allowRedirects = false
|
||||
).text
|
||||
val reprojson = parseJson<ReproDoramas>(response)
|
||||
val decodeurl = base64Decode(reprojson.link)
|
||||
if (decodeurl.contains("m3u8"))
|
||||
|
||||
cleanExtractor(
|
||||
name,
|
||||
name,
|
||||
decodeurl,
|
||||
"https://repro3.estrenosdoramas.us",
|
||||
decodeurl.contains(".m3u8"),
|
||||
callback
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (directlink.contains("reproducir14")) {
|
||||
val regex = Regex("(https:\\/\\/repro.\\.estrenosdoramas\\.us\\/repro\\/reproducir14\\.php\\?key=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
regex.findAll(directlink).map {
|
||||
it.value
|
||||
}.toList().apmap {
|
||||
val doc = app.get(it).text
|
||||
val videoid = doc.substringAfter("vid=\"").substringBefore("\" n")
|
||||
val token = doc.substringAfter("name=\"").substringBefore("\" s")
|
||||
val acctkn = doc.substringAfter("{ acc: \"").substringBefore("\", id:")
|
||||
val link = app.post("https://repro3.estrenosdoramas.us/repro/proto4.php",
|
||||
headers = headers,
|
||||
data = mapOf(
|
||||
Pair("acc",acctkn),
|
||||
Pair("id",videoid),
|
||||
Pair("tk",token)),
|
||||
allowRedirects = false
|
||||
).text
|
||||
val extracteklink = link.substringAfter("\"urlremoto\":\"").substringBefore("\"}")
|
||||
.replace("\\/", "/").replace("//ok.ru/","http://ok.ru/")
|
||||
loadExtractor(extracteklink, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
||||
if (directlink.contains("reproducir120")) {
|
||||
val regex = Regex("(https:\\/\\/repro3.estrenosdoramas.us\\/repro\\/reproducir120\\.php\\?\\nkey=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
regex.findAll(directlink).map {
|
||||
it.value
|
||||
}.toList().apmap {
|
||||
val doc = app.get(it).text
|
||||
val videoid = doc.substringAfter("var videoid = '").substringBefore("';")
|
||||
val token = doc.substringAfter("var tokens = '").substringBefore("';")
|
||||
val acctkn = doc.substringAfter("{ acc: \"").substringBefore("\", id:")
|
||||
val link = app.post("https://repro3.estrenosdoramas.us/repro/api3.php",
|
||||
headers = headers,
|
||||
data = mapOf(
|
||||
Pair("acc",acctkn),
|
||||
Pair("id",videoid),
|
||||
Pair("tk",token)),
|
||||
allowRedirects = false
|
||||
).text
|
||||
val extractedlink = link.substringAfter("\"{file:'").substringBefore("',label:")
|
||||
.replace("\\/", "/")
|
||||
val quality = link.substringAfter(",label:'").substringBefore("',type:")
|
||||
val type = link.substringAfter("type: '").substringBefore("'}\"")
|
||||
if (extractedlink.isNotBlank())
|
||||
if (quality.contains("File not found", ignoreCase = true)) {
|
||||
//Nothing
|
||||
} else {
|
||||
cleanExtractor(
|
||||
"Movil",
|
||||
"Movil $quality",
|
||||
extractedlink,
|
||||
"",
|
||||
!type.contains("mp4"),
|
||||
callback
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class EstrenosDoramasProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(EstrenosDoramasProvider())
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package com.example
|
||||
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.MainAPI
|
||||
import com.lagradost.cloudstream3.SearchResponse
|
||||
|
||||
class ExampleProvider : MainAPI() { // all providers must be an instance of MainAPI
|
||||
override var mainUrl = "https://example.com/"
|
||||
override var name = "Example provider"
|
||||
override val supportedTypes = setOf(TvType.Movie)
|
||||
|
||||
override var lang = "en"
|
||||
|
||||
// enable this when your provider has a main page
|
||||
override val hasMainPage = true
|
||||
|
||||
// this function gets called when you search for something
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
return listOf<SearchResponse>()
|
||||
}
|
||||
}
|
22
FaselHDProvider/build.gradle.kts
Normal file
22
FaselHDProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
FaselHDProvider/src/main/AndroidManifest.xml
Normal file
2
FaselHDProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
163
FaselHDProvider/src/main/kotlin/com/lagradost/FaselHDProvider.kt
Normal file
163
FaselHDProvider/src/main/kotlin/com/lagradost/FaselHDProvider.kt
Normal file
|
@ -0,0 +1,163 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class FaselHDProvider : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://faselhd.io"
|
||||
override var name = "FaselHD"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.AsianDrama, TvType.Anime)
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = select("div.postDiv a").attr("href") ?: return null
|
||||
val posterUrl = select("div.postDiv a div img").attr("data-src") ?:
|
||||
select("div.postDiv a div img").attr("src")
|
||||
val title = select("div.postDiv a div img").attr("alt")
|
||||
val quality = select(".quality").first()?.text()?.replace("1080p |-".toRegex(), "")
|
||||
val type = if(title.contains("فيلم")) TvType.Movie else TvType.TvSeries
|
||||
return MovieSearchResponse(
|
||||
title.replace("الموسم الأول|برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي".toRegex(),""),
|
||||
url,
|
||||
this@FaselHDProvider.name,
|
||||
type,
|
||||
posterUrl,
|
||||
null,
|
||||
null,
|
||||
quality = getQualityFromString(quality)
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
// Title, Url
|
||||
val moviesUrl = listOf(
|
||||
Pair("Movies", "$mainUrl/all-movies/page/"+(0..10).random()),
|
||||
Pair("Series", "$mainUrl/series/page/"+(0..10).random()),
|
||||
Pair("Top Movies IMDB", "$mainUrl/movies_top_imdb"),
|
||||
)
|
||||
val pages = moviesUrl.apmap { (title, url) ->
|
||||
val doc = app.get(url).document
|
||||
val list = doc.select("div[id=\"postList\"] div[class=\"col-xl-2 col-lg-2 col-md-3 col-sm-3\"]")
|
||||
.mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
HomePageList(title, list)
|
||||
}
|
||||
return HomePageResponse(pages)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val q = query.replace(" ","+")
|
||||
val d = app.get("$mainUrl/?s=$q").document
|
||||
return d.select("div[id=\"postList\"] div[class=\"col-xl-2 col-lg-2 col-md-3 col-sm-3\"]")
|
||||
.mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val isMovie = doc.select("div.epAll").isEmpty()
|
||||
val posterUrl = doc.select("div.posterImg img").attr("src")
|
||||
.ifEmpty { doc.select("div.seasonDiv.active img").attr("data-src") }
|
||||
|
||||
val year = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]").firstOrNull {
|
||||
it.text().contains("سنة|موعد".toRegex())
|
||||
}?.text()?.getIntFromText()
|
||||
|
||||
val title =
|
||||
doc.select("title").text().replace(" - فاصل إعلاني", "")
|
||||
.replace("الموسم الأول|برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي|$year".toRegex(),"")
|
||||
// A bit iffy to parse twice like this, but it'll do.
|
||||
val duration = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]").firstOrNull {
|
||||
it.text().contains("مدة|توقيت".toRegex())
|
||||
}?.text()?.getIntFromText()
|
||||
|
||||
val tags = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]:contains(تصنيف الفيلم) a").map {
|
||||
it.text()
|
||||
}
|
||||
val recommendations = doc.select("div#postList div.postDiv").mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
val synopsis = doc.select("div.singleDesc p").text()
|
||||
return if (isMovie) {
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.duration = duration
|
||||
this.tags = tags
|
||||
this.recommendations = recommendations
|
||||
}
|
||||
} else {
|
||||
val episodes = ArrayList<Episode>()
|
||||
doc.select("div.epAll a").map {
|
||||
episodes.add(
|
||||
Episode(
|
||||
it.attr("href"),
|
||||
it.text(),
|
||||
doc.select("div.seasonDiv.active div.title").text().getIntFromText() ?: 1,
|
||||
it.text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
doc.select("div[id=\"seasonList\"] div[class=\"col-xl-2 col-lg-3 col-md-6\"] div.seasonDiv")
|
||||
.not(".active").apmap { it ->
|
||||
val s = app.get("$mainUrl/?p="+it.attr("data-href")).document
|
||||
s.select("div.epAll a").map {
|
||||
episodes.add(
|
||||
Episode(
|
||||
it.attr("href"),
|
||||
it.text(),
|
||||
s.select("div.seasonDiv.active div.title").text().getIntFromText(),
|
||||
it.text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
|
||||
this.duration = duration
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.recommendations = recommendations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val player = app.get(app.get(data).document.select("iframe[name=\"player_iframe\"]").attr("src")).document
|
||||
player.select("div.quality_change button.hd_btn").map {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
it.attr("data-url"),
|
||||
this.mainUrl,
|
||||
quality = it.text().getIntFromText() ?: 0,
|
||||
isM3u8 = true
|
||||
)
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class FaselHDProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(FaselHDProvider())
|
||||
}
|
||||
}
|
22
FilmanProvider/build.gradle.kts
Normal file
22
FilmanProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
FilmanProvider/src/main/AndroidManifest.xml
Normal file
2
FilmanProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
149
FilmanProvider/src/main/kotlin/com/lagradost/FilmanProvider.kt
Normal file
149
FilmanProvider/src/main/kotlin/com/lagradost/FilmanProvider.kt
Normal file
|
@ -0,0 +1,149 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.select.Elements
|
||||
|
||||
class FilmanProvider : MainAPI() {
|
||||
override var mainUrl = "https://filman.cc"
|
||||
override var name = "filman.cc"
|
||||
override var lang = "pl"
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val document = app.get(mainUrl).document
|
||||
val lists = document.select("#item-list,#series-list")
|
||||
val categories = ArrayList<HomePageList>()
|
||||
for (l in lists) {
|
||||
val title = capitalizeString(l.parent()!!.select("h3").text().lowercase())
|
||||
val items = l.select(".poster").map { i ->
|
||||
val name = i.select("a[href]").attr("title")
|
||||
val href = i.select("a[href]").attr("href")
|
||||
val poster = i.select("img[src]").attr("src")
|
||||
val year = l.select(".film_year").text().toIntOrNull()
|
||||
if (l.hasClass("series-list")) TvSeriesSearchResponse(
|
||||
name,
|
||||
href,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
poster,
|
||||
year,
|
||||
null
|
||||
) else MovieSearchResponse(
|
||||
name,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
poster,
|
||||
year
|
||||
)
|
||||
}
|
||||
categories.add(HomePageList(title, items))
|
||||
}
|
||||
return HomePageResponse(categories)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/wyszukiwarka?phrase=$query"
|
||||
val document = app.get(url).document
|
||||
val lists = document.select("#advanced-search > div")
|
||||
val movies = lists[1].select("#item-list > div:not(.clearfix)")
|
||||
val series = lists[3].select("#item-list > div:not(.clearfix)")
|
||||
if (movies.isEmpty() && series.isEmpty()) return ArrayList()
|
||||
fun getVideos(type: TvType, items: Elements): List<SearchResponse> {
|
||||
return items.mapNotNull { i ->
|
||||
val href = i.selectFirst(".poster > a")?.attr("href") ?: return@mapNotNull null
|
||||
val img =
|
||||
i.selectFirst(".poster > a > img")?.attr("src")?.replace("/thumb/", "/big/")
|
||||
val name = i.selectFirst(".film_title")?.text() ?: return@mapNotNull null
|
||||
val year = i.selectFirst(".film_year")?.text()?.toIntOrNull()
|
||||
if (type === TvType.TvSeries) {
|
||||
TvSeriesSearchResponse(
|
||||
name,
|
||||
href,
|
||||
this.name,
|
||||
type,
|
||||
img,
|
||||
year,
|
||||
null
|
||||
)
|
||||
} else {
|
||||
MovieSearchResponse(name, href, this.name, type, img, year)
|
||||
}
|
||||
}
|
||||
}
|
||||
return getVideos(TvType.Movie, movies) + getVideos(TvType.TvSeries, series)
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val document = app.get(url).document
|
||||
val documentTitle = document.select("title").text().trim()
|
||||
|
||||
if (documentTitle.startsWith("Logowanie")) {
|
||||
throw RuntimeException("This page seems to be locked behind a login-wall on the website, unable to scrape it. If it is not please report it.")
|
||||
}
|
||||
|
||||
var title = document.select("span[itemprop=title]").text()
|
||||
val data = document.select("#links").outerHtml()
|
||||
val posterUrl = document.select("#single-poster > img").attr("src")
|
||||
val year = document.select(".info > ul > li").getOrNull(1)?.text()?.toIntOrNull()
|
||||
val plot = document.select(".description").text()
|
||||
val episodesElements = document.select("#episode-list a[href]")
|
||||
if (episodesElements.isEmpty()) {
|
||||
return MovieLoadResponse(title, url, name, TvType.Movie, data, posterUrl, year, plot)
|
||||
}
|
||||
title = document.selectFirst(".info")?.parent()?.select("h2")?.text() ?: ""
|
||||
val episodes = episodesElements.mapNotNull { episode ->
|
||||
val e = episode.text()
|
||||
val regex = Regex("""\[s(\d{1,3})e(\d{1,3})]""").find(e) ?: return@mapNotNull null
|
||||
val eid = regex.groups
|
||||
Episode(
|
||||
episode.attr("href"),
|
||||
e.split("]")[1].trim(),
|
||||
eid[1]?.value?.toInt(),
|
||||
eid[2]?.value?.toInt(),
|
||||
)
|
||||
}.toMutableList()
|
||||
|
||||
return TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
name,
|
||||
TvType.TvSeries,
|
||||
episodes,
|
||||
posterUrl,
|
||||
year,
|
||||
plot
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val document = if (data.startsWith("http"))
|
||||
app.get(data).document.select("#links").first()
|
||||
else Jsoup.parse(data)
|
||||
|
||||
document?.select(".link-to-video")?.apmap { item ->
|
||||
val decoded = base64Decode(item.select("a").attr("data-iframe"))
|
||||
val link = tryParseJson<LinkElement>(decoded)?.src ?: return@apmap
|
||||
loadExtractor(link, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
data class LinkElement(
|
||||
@JsonProperty("src") val src: String
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class FilmanProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(FilmanProvider())
|
||||
}
|
||||
}
|
22
FilmpertuttiProvider/build.gradle.kts
Normal file
22
FilmpertuttiProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
FilmpertuttiProvider/src/main/AndroidManifest.xml
Normal file
2
FilmpertuttiProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,193 @@
|
|||
package com.lagradost
|
||||
|
||||
//import androidx.core.text.parseAsHtml
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addRating
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.ShortLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||
|
||||
|
||||
class FilmpertuttiProvider : MainAPI() {
|
||||
override var lang = "it"
|
||||
override var mainUrl = "https://filmpertutti.photo"
|
||||
override var name = "Filmpertutti"
|
||||
override val hasMainPage = true
|
||||
override val hasChromecastSupport = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries
|
||||
)
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
Pair("$mainUrl/category/film/page/", "Film Popolari"),
|
||||
Pair("$mainUrl/category/serie-tv/page/", "Serie Tv Popolari"),
|
||||
Pair("$mainUrl/prime-visioni/", "Ultime uscite"),
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(
|
||||
page: Int,
|
||||
request: MainPageRequest
|
||||
): HomePageResponse {
|
||||
val url = request.data + page
|
||||
|
||||
val soup = app.get(url).document
|
||||
val home = soup.select("ul.posts > li").map {
|
||||
val title = it.selectFirst("div.title")!!.text().substringBeforeLast("(")
|
||||
.substringBeforeLast("[")
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
val image = it.selectFirst("a")!!.attr("data-thumbnail")
|
||||
val qualitydata = it.selectFirst("div.hd")
|
||||
val quality = if (qualitydata != null) {
|
||||
getQualityFromString(qualitydata.text())
|
||||
} else {
|
||||
null
|
||||
}
|
||||
newTvSeriesSearchResponse(
|
||||
title,
|
||||
link
|
||||
) {
|
||||
this.posterUrl = image
|
||||
this.quality = quality
|
||||
}
|
||||
}
|
||||
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val queryformatted = query.replace(" ", "+")
|
||||
val url = "$mainUrl/?s=$queryformatted"
|
||||
val doc = app.get(url).document
|
||||
return doc.select("ul.posts > li").map {
|
||||
val title = it.selectFirst("div.title")!!.text().substringBeforeLast("(")
|
||||
.substringBeforeLast("[")
|
||||
val link = it.selectFirst("a")!!.attr("href")
|
||||
val image = it.selectFirst("a")!!.attr("data-thumbnail")
|
||||
val quality = getQualityFromString(it.selectFirst("div.hd")?.text())
|
||||
|
||||
MovieSearchResponse(
|
||||
title,
|
||||
link,
|
||||
this.name,
|
||||
quality = quality,
|
||||
posterUrl = image
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val document = app.get(url).document
|
||||
val type =
|
||||
if (document.selectFirst("a.taxonomy.category")!!.attr("href").contains("serie-tv")
|
||||
.not()
|
||||
) TvType.Movie else TvType.TvSeries
|
||||
val title = document.selectFirst("#content > h1")!!.text().substringBeforeLast("(")
|
||||
.substringBeforeLast("[")
|
||||
|
||||
val description =
|
||||
document.selectFirst("i.fa.fa-file-text-o.fa-fw")?.parent()?.nextSibling()?.toString()
|
||||
?.html().toString()
|
||||
|
||||
|
||||
val rating = document.selectFirst("div.rating > div.value")?.text()
|
||||
|
||||
val year =
|
||||
document.selectFirst("#content > h1")?.text()?.substringAfterLast("(")
|
||||
?.filter { it.isDigit() }?.toIntOrNull()
|
||||
?: description.substringAfter("trasmessa nel").take(6).filter { it.isDigit() }
|
||||
.toIntOrNull() ?: (document.selectFirst("i.fa.fa-calendar.fa-fw")?.parent()
|
||||
?.nextSibling() as Element?)?.text()?.substringAfterLast(" ")
|
||||
?.filter { it.isDigit() }?.toIntOrNull()
|
||||
|
||||
|
||||
val poster = document.selectFirst("div.meta > div > img")?.attr("data-src")
|
||||
|
||||
|
||||
val trailerurl =
|
||||
document.selectFirst("div.youtube-player")?.attr("data-id")?.let { urldata ->
|
||||
"https://www.youtube.com/watch?v=$urldata"
|
||||
}
|
||||
|
||||
if (type == TvType.TvSeries) {
|
||||
|
||||
val episodeList = ArrayList<Episode>()
|
||||
document.select("div.accordion-item").filter { a ->
|
||||
a.selectFirst("#season > ul > li.s_title > span")!!.text().isNotEmpty()
|
||||
}.map { element ->
|
||||
val season =
|
||||
element.selectFirst("#season > ul > li.s_title > span")!!.text().toInt()
|
||||
element.select("div.episode-wrap").map { episode ->
|
||||
val href =
|
||||
episode.select("#links > div > div > table > tbody:nth-child(2) > tr")
|
||||
.map { it.selectFirst("a")!!.attr("href") }.toJson()
|
||||
val epNum = episode.selectFirst("li.season-no")!!.text().substringAfter("x")
|
||||
.filter { it.isDigit() }.toIntOrNull()
|
||||
val epTitle = episode.selectFirst("li.other_link > a")?.text()
|
||||
|
||||
val posterUrl = episode.selectFirst("figure > img")?.attr("data-src")
|
||||
episodeList.add(
|
||||
Episode(
|
||||
href,
|
||||
epTitle,
|
||||
season,
|
||||
epNum,
|
||||
posterUrl,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return newTvSeriesLoadResponse(
|
||||
title,
|
||||
url, type, episodeList
|
||||
) {
|
||||
this.posterUrl = poster
|
||||
this.year = year
|
||||
this.plot = description
|
||||
addRating(rating)
|
||||
addTrailer(trailerurl)
|
||||
}
|
||||
} else {
|
||||
|
||||
val urls0 = document.select("div.embed-player")
|
||||
val urls = if (urls0.isNotEmpty()) {
|
||||
urls0.map { it.attr("data-id") }.toJson()
|
||||
} else {
|
||||
document.select("#info > ul > li ").mapNotNull { it.selectFirst("a")?.attr("href") }
|
||||
.toJson()
|
||||
}
|
||||
|
||||
return newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
type,
|
||||
urls
|
||||
) {
|
||||
posterUrl = fixUrlNull(poster)
|
||||
this.year = year
|
||||
this.plot = description
|
||||
addRating(rating)
|
||||
addTrailer(trailerurl)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
tryParseJson<List<String>>(data)?.apmap { id ->
|
||||
val link = ShortLink.unshorten(id).trim().replace("/v/", "/e/").replace("/f/", "/e/")
|
||||
loadExtractor(link, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class FilmpertuttiProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(FilmpertuttiProvider())
|
||||
}
|
||||
}
|
22
FmoviesToProvider/build.gradle.kts
Normal file
22
FmoviesToProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
FmoviesToProvider/src/main/AndroidManifest.xml
Normal file
2
FmoviesToProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,6 @@
|
|||
package com.lagradost
|
||||
|
||||
class FmoviesToProvider : BflixProvider() {
|
||||
override var mainUrl = "https://fmovies.to"
|
||||
override var name = "Fmovies.to"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class FmoviesToProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(FmoviesToProvider())
|
||||
}
|
||||
}
|
22
FrenchStreamProvider/build.gradle.kts
Normal file
22
FrenchStreamProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
FrenchStreamProvider/src/main/AndroidManifest.xml
Normal file
2
FrenchStreamProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,273 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addRating
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.extractorApis
|
||||
|
||||
|
||||
class FrenchStreamProvider : MainAPI() {
|
||||
override var mainUrl = "https://french-stream.re"
|
||||
override var name = "French Stream"
|
||||
override val hasQuickSearch = false
|
||||
override val hasMainPage = true
|
||||
override var lang = "fr"
|
||||
override val supportedTypes = setOf(TvType.AnimeMovie, TvType.TvSeries, TvType.Movie)
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val link = "$mainUrl/?do=search&subaction=search&story=$query"
|
||||
val soup = app.post(link).document
|
||||
|
||||
return soup.select("div.short-in.nl").map { li ->
|
||||
val href = fixUrl(li.selectFirst("a.short-poster")!!.attr("href"))
|
||||
val poster = li.selectFirst("img")?.attr("src")
|
||||
val title = li.selectFirst("> a.short-poster")!!.text().toString().replace(". ", "")
|
||||
val year = li.selectFirst(".date")?.text()?.split("-")?.get(0)?.toIntOrNull()
|
||||
if (title.contains(
|
||||
"saison",
|
||||
ignoreCase = true
|
||||
)
|
||||
) { // if saison in title ==> it's a TV serie
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
poster,
|
||||
year,
|
||||
(title.split("Eps ", " ")[1]).split(" ")[0].toIntOrNull()
|
||||
)
|
||||
} else { // it's a movie
|
||||
MovieSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
poster,
|
||||
year,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val soup = app.get(url).document
|
||||
|
||||
val title = soup.selectFirst("h1#s-title")!!.text().toString()
|
||||
val isMovie = !title.contains("saison", ignoreCase = true)
|
||||
val description =
|
||||
soup.selectFirst("div.fdesc")!!.text().toString()
|
||||
.split("streaming", ignoreCase = true)[1].replace(" : ", "")
|
||||
var poster = fixUrlNull(soup.selectFirst("div.fposter > img")?.attr("src"))
|
||||
val listEpisode = soup.select("div.elink")
|
||||
|
||||
if (isMovie) {
|
||||
val tags = soup.select("ul.flist-col > li").getOrNull(1)
|
||||
val tagsList = tags?.select("a")
|
||||
?.mapNotNull { // all the tags like action, thriller ...; unused variable
|
||||
it?.text()
|
||||
}
|
||||
return newMovieLoadResponse(title, url, TvType.Movie, url) {
|
||||
this.posterUrl = poster
|
||||
addRating(soup.select("div.fr-count > div").text())
|
||||
this.year = soup.select("ul.flist-col > li").getOrNull(2)?.text()?.toIntOrNull()
|
||||
this.tags = tagsList
|
||||
this.plot = description
|
||||
addTrailer(soup.selectFirst("div.fleft > span > a")?.attr("href"))
|
||||
}
|
||||
} else // a tv serie
|
||||
{
|
||||
//println(listEpisode)
|
||||
//println("listeEpisode:")
|
||||
val episodeList = if ("<a" !in (listEpisode[0]).toString()) { // check if VF is empty
|
||||
listEpisode[1] // no vf, return vostfr
|
||||
} else {
|
||||
listEpisode[0] // no vostfr, return vf
|
||||
}
|
||||
|
||||
//println(url)
|
||||
|
||||
val episodes = episodeList.select("a").map { a ->
|
||||
val epNum = a.text().split("Episode")[1].trim().toIntOrNull()
|
||||
val epTitle = if (a.text().contains("Episode")) {
|
||||
val type = if ("honey" in a.attr("id")) {
|
||||
"VF"
|
||||
} else {
|
||||
"VOSTFR"
|
||||
}
|
||||
"Episode " + epNum?.toString() + " en " + type
|
||||
} else {
|
||||
a.text()
|
||||
}
|
||||
if (poster == null) {
|
||||
poster = a.selectFirst("div.fposter > img")?.attr("src")
|
||||
}
|
||||
Episode(
|
||||
fixUrl(url).plus("-episodenumber:$epNum"),
|
||||
epTitle,
|
||||
null,
|
||||
epNum,
|
||||
null, // episode Thumbnail
|
||||
null // episode date
|
||||
)
|
||||
}
|
||||
return TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
episodes,
|
||||
poster,
|
||||
null,
|
||||
description,
|
||||
ShowStatus.Ongoing,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun translate(
|
||||
// the website has weird naming of series for episode 2 and 1 and original version content
|
||||
episodeNumber: String,
|
||||
is_vf_available: Boolean,
|
||||
): String {
|
||||
return if (episodeNumber == "1") {
|
||||
if (is_vf_available) { // 1 translate differently if vf is available or not
|
||||
"FGHIJK"
|
||||
} else {
|
||||
"episode033"
|
||||
}
|
||||
} else {
|
||||
"episode" + (episodeNumber.toInt() + 32).toString()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
): Boolean {
|
||||
val servers =
|
||||
if (data.contains("-episodenumber:"))// It's a serie:
|
||||
{
|
||||
val split =
|
||||
data.split("-episodenumber:") // the data contains the url and the wanted episode number (a temporary dirty fix that will last forever)
|
||||
val url = split[0]
|
||||
val wantedEpisode =
|
||||
if (split[1] == "2") { // the episode number 2 has id of ABCDE, don't ask any question
|
||||
"ABCDE"
|
||||
} else {
|
||||
"episode" + split[1]
|
||||
}
|
||||
|
||||
|
||||
val soup = app.get(fixUrl(url)).document
|
||||
val div =
|
||||
if (wantedEpisode == "episode1") {
|
||||
"> div.tabs-sel " // this element is added when the wanted episode is one (the place changes in the document)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
val serversvf =// French version servers
|
||||
soup.select("div#$wantedEpisode > div.selink > ul.btnss $div> li")
|
||||
.mapNotNull { li -> // list of all french version servers
|
||||
val serverUrl = fixUrl(li.selectFirst("a")!!.attr("href"))
|
||||
// val litext = li.text()
|
||||
if (serverUrl.isNotBlank()) {
|
||||
if (li.text().replace(" ", "").replace(" ", "").isNotBlank()) {
|
||||
Pair(li.text().replace(" ", ""), "vf" + fixUrl(serverUrl))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val translated = translate(split[1], serversvf.isNotEmpty())
|
||||
val serversvo = // Original version servers
|
||||
soup.select("div#$translated > div.selink > ul.btnss $div> li")
|
||||
.mapNotNull { li ->
|
||||
val serverUrl = fixUrlNull(li.selectFirst("a")?.attr("href"))
|
||||
if (!serverUrl.isNullOrEmpty()) {
|
||||
if (li.text().replace(" ", "").isNotBlank()) {
|
||||
Pair(li.text().replace(" ", ""), "vo" + fixUrl(serverUrl))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
serversvf + serversvo
|
||||
} else { // it's a movie
|
||||
val movieServers =
|
||||
app.get(fixUrl(data)).document.select("nav#primary_nav_wrap > ul > li > ul > li > a")
|
||||
.mapNotNull { a ->
|
||||
val serverurl = fixUrlNull(a.attr("href")) ?: return@mapNotNull null
|
||||
val parent = a.parents()[2]
|
||||
val element = parent.selectFirst("a")!!.text().plus(" ")
|
||||
if (a.text().replace(" ", "").isNotBlank()) {
|
||||
Pair(element.plus(a.text()), fixUrl(serverurl))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
movieServers
|
||||
}
|
||||
|
||||
servers.apmap {
|
||||
for (extractor in extractorApis) {
|
||||
if (it.first.contains(extractor.name, ignoreCase = true)) {
|
||||
// val name = it.first
|
||||
// print("true for $name")
|
||||
extractor.getSafeUrl(it.second, it.second, subtitleCallback, callback)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse? {
|
||||
val document = app.get(mainUrl).document
|
||||
val docs = document.select("div.sect")
|
||||
val returnList = docs.mapNotNull {
|
||||
val epList = it.selectFirst("> div.sect-c.floats.clearfix") ?: return@mapNotNull null
|
||||
val title =
|
||||
it.selectFirst("> div.sect-t.fx-row.icon-r > div.st-left > a.st-capt")!!.text()
|
||||
val list = epList.select("> div.short")
|
||||
val isMovieType = title.contains("Films") // if truen type is Movie
|
||||
val currentList = list.map { head ->
|
||||
val hrefItem = head.selectFirst("> div.short-in.nl > a")
|
||||
val href = fixUrl(hrefItem!!.attr("href"))
|
||||
val img = hrefItem.selectFirst("> img")
|
||||
val posterUrl = img!!.attr("src")
|
||||
val name = img.attr("> div.short-title").toString()
|
||||
return@map if (isMovieType) MovieSearchResponse(
|
||||
name,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
posterUrl,
|
||||
null
|
||||
) else TvSeriesSearchResponse(
|
||||
name,
|
||||
href,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
posterUrl,
|
||||
null, null
|
||||
)
|
||||
}
|
||||
if (currentList.isNotEmpty()) {
|
||||
HomePageList(title, currentList)
|
||||
} else null
|
||||
}
|
||||
if (returnList.isEmpty()) return null
|
||||
return HomePageResponse(returnList)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class FrenchStreamProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(FrenchStreamProvider())
|
||||
}
|
||||
}
|
22
HDMProvider/build.gradle.kts
Normal file
22
HDMProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
HDMProvider/src/main/AndroidManifest.xml
Normal file
2
HDMProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
116
HDMProvider/src/main/kotlin/com/lagradost/HDMProvider.kt
Normal file
116
HDMProvider/src/main/kotlin/com/lagradost/HDMProvider.kt
Normal file
|
@ -0,0 +1,116 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
class HDMProvider : MainAPI() {
|
||||
override var name = "HD Movies"
|
||||
override var mainUrl = "https://hdm.to"
|
||||
override val hasMainPage = true
|
||||
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
)
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/search/$query"
|
||||
val response = app.get(url).text
|
||||
val document = Jsoup.parse(response)
|
||||
val items = document.select("div.col-md-2 > article > a")
|
||||
if (items.isEmpty()) return emptyList()
|
||||
|
||||
return items.map { i ->
|
||||
val href = i.attr("href")
|
||||
val data = i.selectFirst("> div.item")!!
|
||||
val img = data.selectFirst("> img")!!.attr("src")
|
||||
val name = data.selectFirst("> div.movie-details")!!.text()
|
||||
MovieSearchResponse(name, href, this.name, TvType.Movie, img, null)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
if (data == "") return false
|
||||
val slug = Regex(".*/(.*?)\\.mp4").find(data)?.groupValues?.get(1) ?: return false
|
||||
val response = app.get(data).text
|
||||
val key = Regex("playlist\\.m3u8(.*?)\"").find(response)?.groupValues?.get(1) ?: return false
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
"https://hls.1o.to/vod/$slug/playlist.m3u8$key",
|
||||
"",
|
||||
Qualities.P720.value,
|
||||
true
|
||||
)
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val response = app.get(url).text
|
||||
val document = Jsoup.parse(response)
|
||||
val title = document.selectFirst("h2.movieTitle")?.text() ?: throw ErrorLoadingException("No Data Found")
|
||||
val poster = document.selectFirst("div.post-thumbnail > img")!!.attr("src")
|
||||
val descript = document.selectFirst("div.synopsis > p")!!.text()
|
||||
val year = document.select("div.movieInfoAll > div.row > div.col-md-6").getOrNull(1)?.selectFirst("> p > a")?.text()
|
||||
?.toIntOrNull()
|
||||
val data = "src/player/\\?v=(.*?)\"".toRegex().find(response)?.groupValues?.get(1) ?: return null
|
||||
|
||||
return MovieLoadResponse(
|
||||
title, url, this.name, TvType.Movie,
|
||||
"$mainUrl/src/player/?v=$data", poster, year, descript, null
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val html = app.get(mainUrl, timeout = 25).text
|
||||
val document = Jsoup.parse(html)
|
||||
val all = ArrayList<HomePageList>()
|
||||
|
||||
val mainbody = document.getElementsByTag("body")
|
||||
?.select("div.homeContentOuter > section > div.container > div")
|
||||
// Fetch row title
|
||||
val inner = mainbody?.select("div.col-md-2.col-sm-2.mrgb")
|
||||
val title = mainbody?.select("div > div")?.firstOrNull()?.select("div.title.titleBar")?.text() ?: "Unnamed Row"
|
||||
// Fetch list of items and map
|
||||
if (inner != null) {
|
||||
val elements: List<SearchResponse> = inner.map {
|
||||
|
||||
val aa = it.select("a").firstOrNull()
|
||||
val item = aa?.select("div.item")
|
||||
val href = aa?.attr("href")
|
||||
val link = when (href != null) {
|
||||
true -> fixUrl(href)
|
||||
false -> ""
|
||||
}
|
||||
val name = item?.select("div.movie-details")?.text() ?: "<No Title>"
|
||||
var image = item?.select("img")?.get(1)?.attr("src") ?: ""
|
||||
val year = null
|
||||
|
||||
MovieSearchResponse(
|
||||
name,
|
||||
link,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image,
|
||||
year,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
all.add(
|
||||
HomePageList(
|
||||
title, elements
|
||||
)
|
||||
)
|
||||
}
|
||||
return HomePageResponse(all)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class HDMProviderPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(HDMProvider())
|
||||
}
|
||||
}
|
22
HDMovie5/build.gradle.kts
Normal file
22
HDMovie5/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
HDMovie5/src/main/AndroidManifest.xml
Normal file
2
HDMovie5/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
154
HDMovie5/src/main/kotlin/com/lagradost/HDMovie5.kt
Normal file
154
HDMovie5/src/main/kotlin/com/lagradost/HDMovie5.kt
Normal file
|
@ -0,0 +1,154 @@
|
|||
package com.lagradost
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.httpsify
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class HDMovie5 : MainAPI() {
|
||||
override var mainUrl = "https://hdmovie2.click"
|
||||
override var name = "HDMovie"
|
||||
override var lang = "hi"
|
||||
|
||||
override val hasQuickSearch = true
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries,
|
||||
)
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/genre/tv-movie/page/" to "TV Movie",
|
||||
"$mainUrl/genre/tv-show/page/" to "TV- Show",
|
||||
"$mainUrl/genre/hindi-dubbed/page/" to "Hindi Dubbed",
|
||||
"$mainUrl/genre/netflix/page/" to "NETFLIX",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||
val home = app.get(request.data + page).document.select("article.item").mapNotNull {
|
||||
it.toSearchResult()
|
||||
}
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
private fun Element.toSearchResult(): SearchResponse? {
|
||||
val title = this.selectFirst("h3 > a")?.text()?.trim() ?: return null
|
||||
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
||||
val posterUrl = this.selectFirst("img")?.attr("src")
|
||||
return newMovieSearchResponse(title, href, TvType.Movie) {
|
||||
addPoster(posterUrl)
|
||||
}
|
||||
}
|
||||
|
||||
private data class QuickSearchResponse(
|
||||
val title: String,
|
||||
val url: String,
|
||||
val img: String,
|
||||
val extra: Extra
|
||||
) {
|
||||
data class Extra(
|
||||
val date: String
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun quickSearch(query: String): List<SearchResponse> {
|
||||
return app.get("$mainUrl/wp-json/dooplay/search/?keyword=$query&nonce=ddbde04d9c")
|
||||
.parsed<Map<String, QuickSearchResponse>>().map {
|
||||
val res = it.value
|
||||
MovieSearchResponse(
|
||||
res.title,
|
||||
res.url,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
res.img,
|
||||
res.extra.date.toIntOrNull()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
return app.get("$mainUrl/?s=$query").document.select(".search-page>div.result-item").map {
|
||||
val image = it.select(".image")
|
||||
MovieSearchResponse(
|
||||
image.select("img").attr("alt"),
|
||||
image.select("a").attr("href"),
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
image.select("img").attr("src"),
|
||||
it.select(".year").text().toIntOrNull()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val info = doc.select(".sheader")
|
||||
val links = doc.select("#playeroptionsul>li")
|
||||
val data = links.joinToString(",") { it.attr("data-post") }
|
||||
return MovieLoadResponse(
|
||||
info.select(".data>h1").text(),
|
||||
url,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
data,
|
||||
info.select(".poster>img").attr("src"),
|
||||
info.select(".date").text().substringAfter(", ").toIntOrNull(),
|
||||
doc.select(".wp-content>p").let { it.getOrNull(it.size - 1)?.text() },
|
||||
(doc.select("#repimdb>strong").text().toFloatOrNull()?.times(1000))?.toInt(),
|
||||
info.select(".sgeneros>a").map { it.text() },
|
||||
info.select(".runtime").text().substringBefore(" Min.").toIntOrNull(),
|
||||
mutableListOf(),
|
||||
doc.select("#single_relacionados>article>a").map {
|
||||
val img = it.select("img")
|
||||
MovieSearchResponse(
|
||||
img.attr("alt"),
|
||||
it.attr("href"),
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
img.attr("src")
|
||||
)
|
||||
},
|
||||
doc.select("#cast>.persons>.person").mapNotNull {
|
||||
if (it.attr("itemprop") != "director") {
|
||||
ActorData(
|
||||
Actor(
|
||||
it.select("meta").attr("content"),
|
||||
it.select("img").attr("src")
|
||||
)
|
||||
)
|
||||
} else null
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private data class PlayerAjaxResponse(
|
||||
@JsonProperty("embed_url")
|
||||
val embedURL: String? = null
|
||||
)
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
return data.split(",").apmapIndexed { index, it ->
|
||||
val p = app.post(
|
||||
"$mainUrl/wp-admin/admin-ajax.php",
|
||||
data = mapOf(
|
||||
"action" to "doo_player_ajax",
|
||||
"post" to it,
|
||||
"nume" to "${index + 1}",
|
||||
"type" to "movie"
|
||||
)
|
||||
)
|
||||
val html = p.parsedSafe<PlayerAjaxResponse>()?.embedURL ?: return@apmapIndexed false
|
||||
val doc = Jsoup.parse(html)
|
||||
val link = doc.select("iframe").attr("src")
|
||||
loadExtractor(httpsify(link), "$mainUrl/", subtitleCallback, callback)
|
||||
}.contains(true)
|
||||
}
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
package com.example
|
||||
|
||||
package com.lagradost
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class TestPlugin: Plugin() {
|
||||
class HDMovie5Plugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(ExampleProvider())
|
||||
registerMainAPI(HDMovie5())
|
||||
}
|
||||
}
|
22
HDTodayProvider/build.gradle.kts
Normal file
22
HDTodayProvider/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
|
||||
cloudstream {
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
// description = "Lorem Ipsum"
|
||||
// authors = listOf("Cloudburst")
|
||||
|
||||
/**
|
||||
* Status int as the following:
|
||||
* 0: Down
|
||||
* 1: Ok
|
||||
* 2: Slow
|
||||
* 3: Beta only
|
||||
* */
|
||||
status = 1 // will be 3 if unspecified
|
||||
|
||||
// Set to true to get an 18+ symbol next to the plugin
|
||||
adult = false // will be false if unspecified
|
||||
}
|
2
HDTodayProvider/src/main/AndroidManifest.xml
Normal file
2
HDTodayProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.lagradost"/>
|
|
@ -0,0 +1,6 @@
|
|||
package com.lagradost
|
||||
|
||||
class HDTodayProvider : SflixProvider() {
|
||||
override var mainUrl = "https://hdtoday.cc"
|
||||
override var name = "HDToday"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue