Fixed French Stream Providers
This commit is contained in:
parent
cf62f5267a
commit
d55beb8c6c
|
@ -1,20 +1,25 @@
|
|||
package com.lagradost
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
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.extractorApis
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
|
||||
class FrenchStreamProvider : MainAPI() {
|
||||
override var mainUrl = "https://french-stream.cx" //re ou ac ou city
|
||||
override var mainUrl = "https://streem.re" //re ou ac ou city
|
||||
override var name = "FrenchStream"
|
||||
override val hasQuickSearch = false
|
||||
override val hasMainPage = true
|
||||
override var lang = "fr"
|
||||
override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries)
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val link = "$mainUrl/?do=search&subaction=search&story=$query" // search'
|
||||
val document =
|
||||
|
@ -22,21 +27,60 @@ class FrenchStreamProvider : MainAPI() {
|
|||
val results = document.select("div#dle-content > > div.short")
|
||||
|
||||
val allresultshome =
|
||||
results.apmap { article -> // avec mapnotnull si un élément est null, il sera automatiquement enlevé de la liste
|
||||
results.mapNotNull { article -> // avec mapnotnull si un élément est null, il sera automatiquement enlevé de la liste
|
||||
article.toSearchResponse()
|
||||
}
|
||||
return allresultshome
|
||||
}
|
||||
|
||||
private fun Element.takeEpisode(
|
||||
url: String,
|
||||
): List<Episode> {
|
||||
return this.select("a").map { a ->
|
||||
val epNum =
|
||||
Regex("""pisode[\s]+(\d+)""").find(a.text().lowercase())?.groupValues?.get(1)
|
||||
?.toIntOrNull()
|
||||
val epTitle = if (a.text().contains("Episode")) {
|
||||
val type = if ("honey" in a.attr("id")) {
|
||||
"VF"
|
||||
} else {
|
||||
"Vostfr"
|
||||
}
|
||||
"Episode $type"
|
||||
} else {
|
||||
a.text()
|
||||
}
|
||||
|
||||
Episode(
|
||||
loadLinkData(
|
||||
fixUrl(url),
|
||||
epTitle.contains("Vostfr"),
|
||||
epNum,
|
||||
).toJson(),
|
||||
epTitle,
|
||||
null,
|
||||
epNum,
|
||||
a.selectFirst("div.fposter > img")?.attr("src"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class loadLinkData(
|
||||
val embedUrl: String,
|
||||
val isVostFr: Boolean? = null,
|
||||
val episodenumber: Int? = null,
|
||||
)
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val soup = app.get(url).document
|
||||
|
||||
var subEpisodes = listOf<Episode>()
|
||||
var dubEpisodes = listOf<Episode>()
|
||||
val title = soup.selectFirst("h1#s-title")!!.text().toString()
|
||||
val isMovie = !title.contains("saison", ignoreCase = true)
|
||||
val isMovie = !url.contains("/serie/", ignoreCase = true)
|
||||
val description =
|
||||
soup.selectFirst("div.fdesc")!!.text().toString()
|
||||
.split("streaming", ignoreCase = true)[1].replace(":", "")
|
||||
var poster = soup.selectFirst("div.fposter > img")?.attr("src")
|
||||
val poster = soup.selectFirst("div.fposter > img")?.attr("src")
|
||||
val listEpisode = soup.select("div.elink")
|
||||
val tags = soup.select("ul.flist-col > li").getOrNull(1)
|
||||
//val rating = soup.select("span[id^=vote-num-id]")?.getOrNull(1)?.text()?.toInt()
|
||||
|
@ -48,7 +92,7 @@ class FrenchStreamProvider : MainAPI() {
|
|||
?.mapNotNull { // all the tags like action, thriller ...; unused variable
|
||||
it?.text()
|
||||
}
|
||||
return newMovieLoadResponse(title, url, TvType.Movie, url) {
|
||||
return newMovieLoadResponse(title, url, TvType.Movie, loadLinkData(url)) {
|
||||
this.posterUrl = poster
|
||||
this.year = year?.toIntOrNull()
|
||||
this.tags = tagsList
|
||||
|
@ -56,56 +100,26 @@ class FrenchStreamProvider : MainAPI() {
|
|||
//this.rating = rating
|
||||
addTrailer(soup.selectFirst("button#myBtn > a")?.attr("href"))
|
||||
}
|
||||
} else // a tv serie
|
||||
{
|
||||
|
||||
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
|
||||
} else {
|
||||
if ("<a" in listEpisode[1].toString()) { // check if VF is empty
|
||||
subEpisodes = listEpisode[1].takeEpisode(url)// return vostfr
|
||||
}
|
||||
|
||||
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 " + 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
|
||||
)
|
||||
if ("<a" in listEpisode[0].toString()) {
|
||||
dubEpisodes = listEpisode[0].takeEpisode(url)// return vf
|
||||
}
|
||||
|
||||
// val tagsList = tags?.text()?.replace("Genre :","")
|
||||
val yearRegex = Regex("""Titre .* \/ (\d*)""")
|
||||
val year = yearRegex.find(soup.text())?.groupValues?.get(1)
|
||||
return newTvSeriesLoadResponse(
|
||||
return newAnimeLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.TvSeries,
|
||||
episodes,
|
||||
) {
|
||||
this.posterUrl = poster
|
||||
this.plot = description
|
||||
this.year = year?.toInt()
|
||||
//this.rating = rating
|
||||
//this.showStatus = ShowStatus.Ongoing
|
||||
//this.tags = tagsList
|
||||
addTrailer(soup.selectFirst("button#myBtn > a")?.attr("href"))
|
||||
if (subEpisodes.isNotEmpty()) addEpisodes(DubStatus.Subbed, subEpisodes)
|
||||
if (dubEpisodes.isNotEmpty()) addEpisodes(DubStatus.Dubbed, dubEpisodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,23 +140,26 @@ class FrenchStreamProvider : MainAPI() {
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
|
||||
override suspend fun loadLinks( // TODO FIX *Garbage* data transmission betwenn function
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
): Boolean {
|
||||
val parsedData = tryParseJson<loadLinkData>(data)
|
||||
val url = parsedData?.embedUrl ?: return false
|
||||
val servers =
|
||||
if (data.contains("-episodenumber:"))// It's a serie:
|
||||
if (parsedData.episodenumber != null)// 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 isvostfr = parsedData.isVostFr == true
|
||||
|
||||
|
||||
val wantedEpisode =
|
||||
if (split[1] == "2") { // the episode number 2 has id of ABCDE, don't ask any question
|
||||
if (parsedData.episodenumber.toString() == "2") { // the episode number 2 has id of ABCDE, don't ask any question
|
||||
"ABCDE"
|
||||
} else {
|
||||
"episode" + split[1]
|
||||
"episode" + parsedData.episodenumber.toString()
|
||||
}
|
||||
|
||||
|
||||
|
@ -160,7 +177,7 @@ class FrenchStreamProvider : MainAPI() {
|
|||
// val litext = li.text()
|
||||
if (serverUrl.isNotBlank()) {
|
||||
if (li.text().replace(" ", "").replace(" ", "").isNotBlank()) {
|
||||
Pair(li.text().replace(" ", ""), "vf" + fixUrl(serverUrl))
|
||||
Pair(li.text().replace(" ", ""), fixUrl(serverUrl))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
@ -169,14 +186,14 @@ class FrenchStreamProvider : MainAPI() {
|
|||
}
|
||||
}
|
||||
|
||||
val translated = translate(split[1], serversvf.isNotEmpty())
|
||||
val translated = translate(parsedData.episodenumber.toString(), 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))
|
||||
Pair(li.text().replace(" ", ""), fixUrl(serverUrl))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
@ -184,10 +201,14 @@ class FrenchStreamProvider : MainAPI() {
|
|||
null
|
||||
}
|
||||
}
|
||||
serversvf + serversvo
|
||||
if (isvostfr) {
|
||||
serversvo
|
||||
} else {
|
||||
serversvf
|
||||
}
|
||||
} else { // it's a movie
|
||||
val movieServers =
|
||||
app.get(fixUrl(data)).document.select("nav#primary_nav_wrap > ul > li > ul > li > a")
|
||||
app.get(fixUrl(url)).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]
|
||||
|
@ -200,33 +221,19 @@ class FrenchStreamProvider : MainAPI() {
|
|||
}
|
||||
movieServers
|
||||
}
|
||||
|
||||
servers.apmap {
|
||||
for (extractor in extractorApis) {
|
||||
var playerName = it.first
|
||||
val urlplayer = it.second
|
||||
|
||||
if (playerName.contains("Stream.B")) {
|
||||
playerName = it.first.replace("Stream.B", "StreamSB")
|
||||
}
|
||||
if (it.second.contains("streamlare")) {
|
||||
playerName = "Streamlare"
|
||||
}
|
||||
if (playerName.contains(extractor.name, ignoreCase = true)) {
|
||||
val header = app.get(
|
||||
"https" + it.second.split("https").get(1),
|
||||
allowRedirects = false
|
||||
).headers
|
||||
val urlplayer = it.second
|
||||
var playerUrl = when (!urlplayer.isNullOrEmpty()) {
|
||||
urlplayer.contains("opsktp.com") -> header.get("location")
|
||||
.toString() // case where there is redirection to opsktp
|
||||
|
||||
else -> it.second
|
||||
}
|
||||
extractor.getSafeUrl(playerUrl, playerUrl, subtitleCallback, callback)
|
||||
break
|
||||
}
|
||||
}
|
||||
val playerUrl = if (urlplayer.contains("opsktp.com") || urlplayer.contains("flixeo.xyz")) {
|
||||
val header = app.get(
|
||||
"https" + it.second.split("https")[1],
|
||||
allowRedirects = false
|
||||
).headers
|
||||
header["location"].toString()
|
||||
} else {
|
||||
urlplayer
|
||||
}.replace("https://doodstream.com", "https://dood.yt")
|
||||
loadExtractor(playerUrl, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -237,19 +244,20 @@ class FrenchStreamProvider : MainAPI() {
|
|||
|
||||
val posterUrl = fixUrl(select("a.short-poster > img").attr("src"))
|
||||
val qualityExtracted = select("span.film-ripz > a").text()
|
||||
val type = select("span.mli-eps").text()
|
||||
val type = select("span.mli-eps").text().lowercase()
|
||||
val title = select("div.short-title").text()
|
||||
val link = select("a.short-poster").attr("href").replace("wvw.", "") //wvw is an issue
|
||||
var quality = when (!qualityExtracted.isNullOrBlank()) {
|
||||
qualityExtracted.contains("HDLight") -> getQualityFromString("HD")
|
||||
qualityExtracted.contains("Bdrip") -> getQualityFromString("BlueRay")
|
||||
qualityExtracted.contains("DVD") -> getQualityFromString("DVD")
|
||||
qualityExtracted.contains("CAM") -> getQualityFromString("Cam")
|
||||
val quality = getQualityFromString(
|
||||
when (!qualityExtracted.isNullOrBlank()) {
|
||||
qualityExtracted.contains("HDLight") -> "HD"
|
||||
qualityExtracted.contains("Bdrip") -> "BlueRay"
|
||||
qualityExtracted.contains("DVD") -> "DVD"
|
||||
qualityExtracted.contains("CAM") -> "Cam"
|
||||
else -> null
|
||||
}
|
||||
)
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (type.contains("Eps", false)) {
|
||||
if (!type.contains("eps")) {
|
||||
return MovieSearchResponse(
|
||||
name = title,
|
||||
url = link,
|
||||
|
@ -261,35 +269,43 @@ class FrenchStreamProvider : MainAPI() {
|
|||
)
|
||||
|
||||
|
||||
} else // an Serie
|
||||
} else // a Serie
|
||||
{
|
||||
|
||||
return TvSeriesSearchResponse(
|
||||
return newAnimeSearchResponse(
|
||||
name = title,
|
||||
url = link,
|
||||
apiName = title,
|
||||
type = TvType.TvSeries,
|
||||
posterUrl = posterUrl,
|
||||
quality = quality,
|
||||
//
|
||||
)
|
||||
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
addDubStatus(
|
||||
isDub = select("span.film-verz").text().uppercase().contains("VF"),
|
||||
episodes = select("span.mli-eps>i").text().toIntOrNull()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
data class mediaData(
|
||||
@JsonProperty("title") var title: String,
|
||||
@JsonProperty("url") val url: String,
|
||||
)
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
Pair("$mainUrl/xfsearch/version-film/page/", "Derniers films"),
|
||||
Pair("$mainUrl/xfsearch/version-serie/page/", "Derniers séries"),
|
||||
Pair("$mainUrl/film/arts-martiaux/page/", "Films za m'ringué (Arts martiaux)"),
|
||||
Pair("$mainUrl/film/action/page/", "Films Actions"),
|
||||
Pair("$mainUrl/film/romance/page/", "Films za malomo (Romance)"),
|
||||
Pair("$mainUrl/serie/aventure-serie/page/", "Série aventure"),
|
||||
Pair("$mainUrl/film/documentaire/page/", "Documentaire")
|
||||
Pair("/xfsearch/version-film/page/", "Derniers Films"),
|
||||
Pair("/xfsearch/version-serie/page/", "Dernieres Séries"),
|
||||
Pair("/film/arts-martiaux/page/", "Films Arts martiaux"),
|
||||
Pair("/film/action/page/", "Films Action"),
|
||||
Pair("/film/romance/page/", "Films Romance"),
|
||||
Pair("/serie/aventure-serie/page/", "Séries aventure"),
|
||||
Pair("/film/documentaire/page/", "Documentaires")
|
||||
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||
val url = request.data + page
|
||||
val url = mainUrl + request.data + page
|
||||
val document = app.get(url).document
|
||||
val movies = document.select("div#dle-content > div.short")
|
||||
|
||||
|
@ -299,5 +315,5 @@ class FrenchStreamProvider : MainAPI() {
|
|||
}
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue