clone site feature don't work with witflix, add alternative for wiflix and french stream

in mainpage see episode number nekosama
This commit is contained in:
Eddy 2022-11-08 10:41:21 +01:00
parent 50b934a0cf
commit 9bd6623187
3 changed files with 267 additions and 146 deletions

View file

@ -1,10 +1,13 @@
package com.lagradost package com.lagradost
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.extractorApis import com.lagradost.cloudstream3.utils.extractorApis
import kotlinx.coroutines.runBlocking
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
@ -16,6 +19,35 @@ class FrenchStreamProvider : MainAPI() {
override var lang = "fr" override var lang = "fr"
override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries) override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries)
init {
runBlocking {
try {
val document = app.get(mainUrl).document
val newMainUrl = document.select("link[rel*=\"canonical\"]").attr("href")
if (!newMainUrl.isNullOrBlank() && newMainUrl.contains("french-stream")) {
mainUrl = newMainUrl
} else {
val data =
AppUtils.tryParseJson<ArrayList<mediaData>>(app.get("https://raw.githubusercontent.com/Eddy976/cloudstream-extensions-eddy/ressources/fetchwebsite.json").text)!!
data.forEach {
if (it.title.lowercase().contains("french-stream")) {
mainUrl = it.url
}
}
}
} catch (e: Exception) { // url changed
val data =
AppUtils.tryParseJson<ArrayList<mediaData>>(app.get("https://raw.githubusercontent.com/Eddy976/cloudstream-extensions-eddy/ressources/fetchwebsite.json").text)!!
data.forEach {
if (it.title.lowercase().contains("french-stream")) {
mainUrl = it.url
}
}
}
}
}
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/?do=search&subaction=search&story=$query" // search' val link = "$mainUrl/?do=search&subaction=search&story=$query" // search'
val document = val document =
@ -29,20 +61,57 @@ class FrenchStreamProvider : MainAPI() {
return allresultshome return allresultshome
} }
private fun Element.takeEpisode(
url: String,
): MutableList<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(
fixUrl(url).plus("-episodenumber:$epNum") + if (epTitle.contains("Vostfr")) {
"*vostfr*"
} else {
""
},
epTitle,
null,
epNum,
a.selectFirst("div.fposter > img")?.attr("src"),
)
}.toMutableList()
}
override suspend fun load(url: String): LoadResponse { override suspend fun load(url: String): LoadResponse {
val soup = app.get(url).document val soup = app.get(url).document
var subEpisodes = mutableListOf<Episode>()
var dubEpisodes = mutableListOf<Episode>()
val title = soup.selectFirst("h1#s-title")!!.text().toString() val title = soup.selectFirst("h1#s-title")!!.text().toString()
val isMovie = !title.contains("saison", ignoreCase = true)
val description = val description =
soup.selectFirst("div.fdesc")!!.text().toString() soup.selectFirst("div.fdesc")!!.text().toString()
.split("streaming", ignoreCase = true)[1].replace(":", "") .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 listEpisode = soup.select("div.elink")
val tags = soup.select("ul.flist-col > li").getOrNull(1) val tags = soup.select("ul.flist-col > li").getOrNull(1)
//val rating = soup.select("span[id^=vote-num-id]")?.getOrNull(1)?.text()?.toInt() //val rating = soup.select("span[id^=vote-num-id]")?.getOrNull(1)?.text()?.toInt()
if ("<a" in (listEpisode[1]).toString()) { // check if VF is empty
if (isMovie) { subEpisodes = listEpisode[1].takeEpisode(url) // return vostfr
}
if ("<a" in (listEpisode[0]).toString()) {
dubEpisodes = listEpisode[0].takeEpisode(url)// return vf
}
if (subEpisodes.isEmpty() && dubEpisodes.isEmpty()) {
val yearRegex = Regex("""ate de sortie\: (\d*)""") val yearRegex = Regex("""ate de sortie\: (\d*)""")
val year = yearRegex.find(soup.text())?.groupValues?.get(1) val year = yearRegex.find(soup.text())?.groupValues?.get(1)
val tagsList = tags?.select("a") val tagsList = tags?.select("a")
@ -57,56 +126,21 @@ class FrenchStreamProvider : MainAPI() {
//this.rating = rating //this.rating = rating
addTrailer(soup.selectFirst("button#myBtn > a")?.attr("href")) addTrailer(soup.selectFirst("button#myBtn > a")?.attr("href"))
} }
} else // a tv serie } else {
{
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
}
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
)
}
// val tagsList = tags?.text()?.replace("Genre :","")
val yearRegex = Regex("""Titre .* \/ (\d*)""") val yearRegex = Regex("""Titre .* \/ (\d*)""")
val year = yearRegex.find(soup.text())?.groupValues?.get(1) val year = yearRegex.find(soup.text())?.groupValues?.get(1)
return newTvSeriesLoadResponse( return newAnimeLoadResponse(
title, title,
url, url,
TvType.TvSeries, TvType.TvSeries,
episodes,
) { ) {
this.posterUrl = poster this.posterUrl = poster
this.plot = description this.plot = description
this.year = year?.toInt() this.year = year?.toInt()
//this.rating = rating
//this.showStatus = ShowStatus.Ongoing
//this.tags = tagsList
addTrailer(soup.selectFirst("button#myBtn > a")?.attr("href")) addTrailer(soup.selectFirst("button#myBtn > a")?.attr("href"))
if (subEpisodes.isNotEmpty()) addEpisodes(DubStatus.Subbed, subEpisodes)
if (dubEpisodes.isNotEmpty()) addEpisodes(DubStatus.Dubbed, dubEpisodes)
} }
} }
} }
@ -127,6 +161,7 @@ class FrenchStreamProvider : MainAPI() {
} }
} }
override suspend fun loadLinks( override suspend fun loadLinks(
data: String, data: String,
isCasting: Boolean, isCasting: Boolean,
@ -136,8 +171,14 @@ class FrenchStreamProvider : MainAPI() {
val servers = val servers =
if (data.contains("-episodenumber:"))// It's a serie: if (data.contains("-episodenumber:"))// It's a serie:
{ {
val isvostfr = data.takeLast(8) == "*vostfr*"
val split = val split =
data.split("-episodenumber:") // the data contains the url and the wanted episode number (a temporary dirty fix that will last forever) if (isvostfr) {
data.dropLast(8).split("-episodenumber:")
} else {
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 url = split[0]
val wantedEpisode = val wantedEpisode =
if (split[1] == "2") { // the episode number 2 has id of ABCDE, don't ask any question if (split[1] == "2") { // the episode number 2 has id of ABCDE, don't ask any question
@ -185,7 +226,11 @@ class FrenchStreamProvider : MainAPI() {
null null
} }
} }
serversvf + serversvo if (isvostfr) {
serversvo
} else {
serversvf
}
} else { // it's a movie } else { // it's a movie
val movieServers = val movieServers =
app.get(fixUrl(data)).document.select("nav#primary_nav_wrap > ul > li > ul > li > a") app.get(fixUrl(data)).document.select("nav#primary_nav_wrap > ul > li > ul > li > a")
@ -218,7 +263,7 @@ class FrenchStreamProvider : MainAPI() {
allowRedirects = false allowRedirects = false
).headers ).headers
val urlplayer = it.second val urlplayer = it.second
var playerUrl = when (!urlplayer.isNullOrEmpty()) { val playerUrl = when (!urlplayer.isNullOrEmpty()) {
urlplayer.contains("opsktp.com") -> header.get("location") urlplayer.contains("opsktp.com") -> header.get("location")
.toString() // case where there is redirection to opsktp .toString() // case where there is redirection to opsktp
@ -238,19 +283,20 @@ class FrenchStreamProvider : MainAPI() {
val posterUrl = fixUrl(select("a.short-poster > img").attr("src")) val posterUrl = fixUrl(select("a.short-poster > img").attr("src"))
val qualityExtracted = select("span.film-ripz > a").text() 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 title = select("div.short-title").text()
val link = select("a.short-poster").attr("href").replace("wvw.", "") //wvw is an issue val link = select("a.short-poster").attr("href").replace("wvw.", "") //wvw is an issue
var quality = when (!qualityExtracted.isNullOrBlank()) { val quality = getQualityFromString(
qualityExtracted.contains("HDLight") -> getQualityFromString("HD") when (!qualityExtracted.isNullOrBlank()) {
qualityExtracted.contains("Bdrip") -> getQualityFromString("BlueRay") qualityExtracted.contains("HDLight") -> "HD"
qualityExtracted.contains("DVD") -> getQualityFromString("DVD") qualityExtracted.contains("Bdrip") -> "BlueRay"
qualityExtracted.contains("CAM") -> getQualityFromString("Cam") qualityExtracted.contains("DVD") -> "DVD"
qualityExtracted.contains("CAM") -> "Cam"
else -> null
}
)
else -> null if (!type.contains("eps")) {
}
if (type.contains("Eps", false)) {
return MovieSearchResponse( return MovieSearchResponse(
name = title, name = title,
url = link, url = link,
@ -264,20 +310,28 @@ class FrenchStreamProvider : MainAPI() {
} else // an Serie } else // an Serie
{ {
return newAnimeSearchResponse(
return TvSeriesSearchResponse(
name = title, name = title,
url = link, url = link,
apiName = title,
type = TvType.TvSeries, 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( override val mainPage = mainPageOf(
Pair("$mainUrl/xfsearch/version-film/page/", "Derniers films"), Pair("$mainUrl/xfsearch/version-film/page/", "Derniers films"),
Pair("$mainUrl/xfsearch/version-serie/page/", "Derniers séries"), Pair("$mainUrl/xfsearch/version-serie/page/", "Derniers séries"),
@ -288,17 +342,9 @@ class FrenchStreamProvider : MainAPI() {
Pair("$mainUrl/film/documentaire/page/", "Documentaire") Pair("$mainUrl/film/documentaire/page/", "Documentaire")
) )
private var ismainUrlChecked = false
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val url = request.data + page val url = request.data + page
if (!ismainUrlChecked) {
ismainUrlChecked = true
val document = app.get(mainUrl).document
val newMainUrl = document.select("link[rel*=\"canonical\"]").attr("href")
if (!newMainUrl.isNullOrBlank() && newMainUrl.contains("french-stream")) {
mainUrl = newMainUrl
}
}
val document = app.get(url).document val document = app.get(url).document
val movies = document.select("div#dle-content > div.short") val movies = document.select("div#dle-content > div.short")
@ -308,5 +354,6 @@ class FrenchStreamProvider : MainAPI() {
} }
return newHomePageResponse(request.name, home) return newHomePageResponse(request.name, home)
} }
} }

View file

@ -4,8 +4,6 @@ package com.lagradost
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
@ -59,7 +57,7 @@ class NekosamaProvider : MainAPI() {
if (query == null) { if (query == null) {
// No shorting so return the first title // No shorting so return the first title
var title = this.title val title = this.title
return title return title
} else { } else {
@ -333,7 +331,7 @@ class NekosamaProvider : MainAPI() {
val type = select("div.info > p.year").text() val type = select("div.info > p.year").text()
val title = select("div.info > a.title > div.limit").text() val title = select("div.info > a.title > div.limit").text()
val link = fixUrl(select("div.cover > a").attr("href")) val link = fixUrl(select("div.cover > a").attr("href"))
if (type.contains("Film")) { if (type.uppercase().contains("FILM")) {
return newMovieSearchResponse( return newMovieSearchResponse(
title, title,
link, link,
@ -341,6 +339,7 @@ class NekosamaProvider : MainAPI() {
false, false,
) { ) {
this.posterUrl = posterUrl this.posterUrl = posterUrl
} }
} else // an Anime } else // an Anime
@ -352,6 +351,11 @@ class NekosamaProvider : MainAPI() {
false, false,
) { ) {
this.posterUrl = posterUrl this.posterUrl = posterUrl
addDubStatus(
isDub = link.contains("-vf"),
episodes = Regex("""(\d*) Eps""").find(type)?.groupValues?.get(1)
?.toIntOrNull()
)
} }
} }
} }
@ -371,17 +375,13 @@ class NekosamaProvider : MainAPI() {
private fun LastEpisodeData.tomainHome(): SearchResponse { private fun LastEpisodeData.tomainHome(): SearchResponse {
var posterUrl = this.url_image?.replace("""\""", "") val posterUrl = this.url_image?.replace("""\""", "")
val link = this.anime_url?.replace("""\""", "")?.let { fixUrl(it) } val link = this.anime_url?.replace("""\""", "")?.let { fixUrl(it) }
?: throw error("Error parsing") ?: throw error("Error parsing")
val title = this.title ?: throw error("Error parsing") val title = this.title ?: throw error("Error parsing")
val type = this.episode ?: "" val type = this.episode ?: ""
var lang = this.lang val lang = this.lang
val dubStatus = if (lang?.contains("vf") == true) {
DubStatus.Dubbed
} else {
DubStatus.Subbed
}
if (type.contains("Ep")) { if (type.contains("Ep")) {
return newAnimeSearchResponse( return newAnimeSearchResponse(
@ -391,8 +391,11 @@ class NekosamaProvider : MainAPI() {
false, false,
) { ) {
this.posterUrl = posterUrl this.posterUrl = posterUrl
this.dubStatus = EnumSet.of(dubStatus) addDubStatus(
isDub = lang?.contains("vf")==true,
episodes = Regex("""Ep[\.][\s]+(\d*)""").find(type)?.groupValues?.get(1)
?.toIntOrNull()
)
} }
} else // a movie } else // a movie
@ -404,8 +407,11 @@ class NekosamaProvider : MainAPI() {
false, false,
) { ) {
this.posterUrl = posterUrl this.posterUrl = posterUrl
this.dubStatus = EnumSet.of(dubStatus) addDubStatus(
} isDub = lang?.contains("vf")==true,
episodes = Regex("""(\d*) Eps""").find(type)?.groupValues?.get(1)
?.toIntOrNull()
) }
} }
} }

View file

@ -8,18 +8,39 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import com.lagradost.cloudstream3.network.CloudflareKiller
import com.lagradost.nicehttp.NiceResponse
import kotlinx.coroutines.runBlocking
class WiflixProvider : MainAPI() { class WiflixProvider : MainAPI() {
override var mainUrl = "https://wiflix.zone" override var mainUrl = "https://wiflix.cafe"
override var name = "Wiflix" override var name = "Wiflix"
override val hasQuickSearch = false // recherche rapide (optionel, pas vraimet utile) override val hasQuickSearch = false // recherche rapide (optionel, pas vraimet utile)
override val hasMainPage = true // page d'accueil (optionel mais encoragé) override val hasMainPage = true // page d'accueil (optionel mais encoragé)
override var lang = "fr" // fournisseur est en francais override var lang = "fr" // fournisseur est en francais
override val supportedTypes = override val supportedTypes =
setOf(TvType.Movie, TvType.TvSeries) // series, films setOf(TvType.Movie, TvType.TvSeries) // series, films
// liste des types: https://recloudstream.github.io/dokka/app/com.lagradost.cloudstream3/-tv-type/index.html private val interceptor = CloudflareKiller()
init {
runBlocking {
try {
app.get(mainUrl)
} catch (e: Exception) { // url changed
val data =
tryParseJson<ArrayList<mediaData>>(app.get("https://raw.githubusercontent.com/Eddy976/cloudstream-extensions-eddy/ressources/fetchwebsite.json").text)!!
data.forEach {
if (it.title.lowercase().contains("wiflix")) {
mainUrl = it.url
}
}
}
}
}
/** /**
Cherche le site pour un titre spécifique Cherche le site pour un titre spécifique
@ -29,7 +50,7 @@ class WiflixProvider : MainAPI() {
**/ **/
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse> {
val link = val link =
"$mainUrl/index.php?do=search&subaction=search&search_start=0&full_search=1&result_from=1&story=$query&titleonly=3&searchuser=&replyless=0&replylimit=0&searchdate=0&beforeafter=after&sortby=date&resorder=desc&showposts=0&catlist%5B%5D=0" // search' "$mainUrl/index.php?do=search&subaction=search&search_start=0&full_search=1&result_from=1&story=$query&titleonly=3&searchuser=&replyless=0&replylimit=0&searchdate=0&beforeafter=after&sortby=date&resorder=desc&showposts=0&catlist%5B%5D=0" // search'
val document = val document =
app.post(link).document // app.get() permet de télécharger la page html avec une requete HTTP (get) app.post(link).document // app.get() permet de télécharger la page html avec une requete HTTP (get)
val results = document.select("div#dle-content > div.clearfix") val results = document.select("div#dle-content > div.clearfix")
@ -50,13 +71,17 @@ class WiflixProvider : MainAPI() {
@JsonProperty("episodeNumber") val episodeNumber: String, @JsonProperty("episodeNumber") val episodeNumber: String,
) )
private fun Elements.takeEpisode(url: String, duborSub: String?): ArrayList<Episode> { private fun Elements.takeEpisode(
url: String,
posterUrl: String?,
duborSub: String?
): ArrayList<Episode> {
val episodes = ArrayList<Episode>() val episodes = ArrayList<Episode>()
this.select("ul.eplist > li").forEach { this.select("ul.eplist > li").forEach {
val strEpisode = it.text() val strEpisodeN =
val strEpisodeN = strEpisode.replace("Episode ", "") Regex("""pisode[\s]+(\d+)""").find(it.text())?.groupValues?.get(1).toString()
val link = val link =
EpisodeData( EpisodeData(
url, url,
@ -66,9 +91,14 @@ class WiflixProvider : MainAPI() {
episodes.add( episodes.add(
Episode( Episode(
link, link + if (duborSub=="vostfr") {
name = duborSub, "*$duborSub*"
episode = strEpisodeN.toInt(), } else {
""
},
name = "Episode en " + duborSub,
episode = strEpisodeN.toIntOrNull(),
posterUrl = posterUrl
) )
) )
} }
@ -77,11 +107,11 @@ class WiflixProvider : MainAPI() {
} }
override suspend fun load(url: String): LoadResponse { override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document // val document = avoidCloudflare(url).document //
// url est le lien retourné par la fonction search (la variable href) ou la fonction getMainPage // url est le lien retourné par la fonction search (la variable href) ou la fonction getMainPage
var subEpisodes = ArrayList<Episode>()
var episodes = ArrayList<Episode>() var dubEpisodes = ArrayList<Episode>()
var mediaType: TvType val mediaType: TvType
val episodeFrfound = val episodeFrfound =
document.select("div.blocfr") document.select("div.blocfr")
@ -97,27 +127,23 @@ class WiflixProvider : MainAPI() {
val tags = document.select("[itemprop=genre] > a") val tags = document.select("[itemprop=genre] > a")
.map { it.text() } // séléctione tous les tags et les ajoutes à une liste .map { it.text() } // séléctione tous les tags et les ajoutes à une liste
mediaType = TvType.TvSeries
if (episodeFrfound.text().contains("Episode")) { if (episodeFrfound.text().lowercase().contains("episode")) {
mediaType = TvType.TvSeries val duborSub = "\uD83C\uDDE8\uD83C\uDDF5"
val duborSub = "Episode en VF" dubEpisodes = episodeFrfound.takeEpisode(url, fixUrl(posterUrl), duborSub)
episodes = episodeFrfound.takeEpisode(url, duborSub) }
} else if (episodeVostfrfound.text().contains("Episode")) { if (episodeVostfrfound.text().lowercase().contains("episode")) {
mediaType = TvType.TvSeries val duborSub = "vostfr"
val duborSub = "Episode sous-titré" subEpisodes = episodeVostfrfound.takeEpisode(url, fixUrl(posterUrl), duborSub)
episodes = episodeVostfrfound.takeEpisode(url, duborSub)
} else {
mediaType = TvType.Movie
} }
/////////////////////////////////////////// ///////////////////////////////////////////
/////////////////////////////////////////// ///////////////////////////////////////////
var type_rec: TvType var type_rec: TvType
val recommendations = val recommendations =
document.select("div.clearfixme > div > div")?.mapNotNull { element -> document.select("div.clearfixme > div > div").mapNotNull { element ->
val recTitle = val recTitle =
element.select("a").text() ?: return@mapNotNull null element.select("a").text() ?: return@mapNotNull null
val image = element.select("a >img")?.attr("src") val image = element.select("a >img").attr("src")
val recUrl = element.select("a").attr("href") val recUrl = element.select("a").attr("href")
type_rec = TvType.TvSeries type_rec = TvType.TvSeries
if (recUrl.contains("film")) type_rec = TvType.Movie if (recUrl.contains("film")) type_rec = TvType.Movie
@ -138,15 +164,14 @@ class WiflixProvider : MainAPI() {
this.name, this.name,
TvType.Movie, TvType.Movie,
image?.let { fixUrl(it) }, image?.let { fixUrl(it) },
)
)
} }
var comingSoon = url.contains("films-prochainement") val comingSoon = url.contains("films-prochainement")
if (mediaType == TvType.Movie) { if (subEpisodes.isEmpty() && dubEpisodes.isEmpty()) {
val description = document.selectFirst("div.screenshots-full")?.text() val description = document.selectFirst("div.screenshots-full")?.text()
?.replace("(.* .ynopsis)".toRegex(), "") ?.replace("(.* .ynopsis)".toRegex(), "")
return newMovieLoadResponse( return newMovieLoadResponse(
@ -165,11 +190,10 @@ class WiflixProvider : MainAPI() {
} }
} else { } else {
val description = document.selectFirst("span[itemprop=description]")?.text() val description = document.selectFirst("span[itemprop=description]")?.text()
return newTvSeriesLoadResponse( return newAnimeLoadResponse(
title, title,
url, url,
mediaType, mediaType,
episodes
) { ) {
this.posterUrl = fixUrl(posterUrl) this.posterUrl = fixUrl(posterUrl)
this.plot = description this.plot = description
@ -177,6 +201,8 @@ class WiflixProvider : MainAPI() {
this.year = year?.toIntOrNull() this.year = year?.toIntOrNull()
this.comingSoon = comingSoon this.comingSoon = comingSoon
this.tags = tags this.tags = tags
if (subEpisodes.isNotEmpty()) addEpisodes(DubStatus.Subbed, subEpisodes)
if (dubEpisodes.isNotEmpty()) addEpisodes(DubStatus.Dubbed, dubEpisodes)
} }
} }
@ -190,30 +216,43 @@ class WiflixProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
): Boolean { ): Boolean {
val parsedInfo = var isvostfr = false
val parsedInfo = if (data.takeLast(8) == "*vostfr*") {
isvostfr = true
tryParseJson<EpisodeData>(data.dropLast(6))
} else {
tryParseJson<EpisodeData>(data) tryParseJson<EpisodeData>(data)
}
val url = parsedInfo?.url ?: data val url = parsedInfo?.url ?: data
val numeroEpisode = parsedInfo?.episodeNumber ?: null val numeroEpisode = parsedInfo?.episodeNumber
val document = app.get(url).document val document = avoidCloudflare(url).document
val episodeFrfound = val episodeFrfound =
document.select("div.blocfr") document.select("div.blocfr")
val episodeVostfrfound = val episodeVostfrfound =
document.select("div.blocvostfr") document.select("div.blocvostfr")
var flag = "\uD83C\uDDE8\uD83C\uDDF5"
val cssCodeForPlayer = if (episodeFrfound.text().contains("Episode")) { val cssCodeForPlayer = if (episodeFrfound.text().contains("Episode") && !isvostfr) {
"div.ep${numeroEpisode}vf > a" "div.ep${numeroEpisode}vf > a"
} else if (episodeVostfrfound.text().contains("Episode")) { } else if (episodeVostfrfound.text().contains("Episode")) {
"div.ep${numeroEpisode}vs > a" "div.ep${numeroEpisode}vs > a"
} else { } else {
"div.linkstab > a" "div.linkstab > a"
} }
if (cssCodeForPlayer.contains("vs")) {
flag = " \uD83D\uDCDC \uD83C\uDDEC\uD83C\uDDE7"
}
document.select("$cssCodeForPlayer").apmap { player -> // séléctione tous les players
var playerUrl = "https"+player.attr("href").replace("(.*)https".toRegex(), "") document.select(cssCodeForPlayer).apmap { player -> // séléctione tous les players
if (!playerUrl.isNullOrBlank()) var playerUrl = "https" + player.attr("href").replace("(.*)https".toRegex(), "")
if (!playerUrl.isBlank())
if (playerUrl.contains("dood")) { if (playerUrl.contains("dood")) {
playerUrl = playerUrl.replace("doodstream.com", "dood.wf") playerUrl = playerUrl.replace("doodstream.com", "dood.wf")
} }
@ -225,7 +264,7 @@ class WiflixProvider : MainAPI() {
callback.invoke( callback.invoke(
ExtractorLink( // ici je modifie le callback pour ajouter des informations, normalement ce n'est pas nécessaire ExtractorLink( // ici je modifie le callback pour ajouter des informations, normalement ce n'est pas nécessaire
link.source, link.source,
link.name + "", link.name + flag,
link.url, link.url,
link.referer, link.referer,
getQualityFromName("HD"), getQualityFromName("HD"),
@ -245,18 +284,20 @@ class WiflixProvider : MainAPI() {
val posterUrl = fixUrl(select("div.img-box > img").attr("src")) val posterUrl = fixUrl(select("div.img-box > img").attr("src"))
val qualityExtracted = select("div.nbloc1-2 >span").text() val qualityExtracted = select("div.nbloc1-2 >span").text()
val type = select("div.nbloc3").text() val type = select("div.nbloc3").text().lowercase()
val title = select("a.nowrap").text() val title = select("a.nowrap").text()
val link = select("a.nowrap").attr("href") val link = select("a.nowrap").attr("href")
var quality = when (!qualityExtracted.isNullOrBlank()) { val quality = getQualityFromString(
qualityExtracted.contains("HDLight") -> getQualityFromString("HD") when (!qualityExtracted.isNullOrBlank()) {
qualityExtracted.contains("Bdrip") -> getQualityFromString("BlueRay") qualityExtracted.contains("HDLight") -> "HD"
qualityExtracted.contains("DVD") -> getQualityFromString("DVD") qualityExtracted.contains("Bdrip") -> "BlueRay"
qualityExtracted.contains("CAM") -> getQualityFromString("Cam") qualityExtracted.contains("DVD") -> "DVD"
qualityExtracted.contains("CAM") -> "Cam"
else -> null else -> null
} }
if (type.contains("Film")) { )
if (type.contains("film")) {
return MovieSearchResponse( return MovieSearchResponse(
name = title, name = title,
url = link, url = link,
@ -271,19 +312,40 @@ class WiflixProvider : MainAPI() {
} else // an Serie } else // an Serie
{ {
return TvSeriesSearchResponse( return newAnimeSearchResponse(
name = title, name = title,
url = link, url = link,
apiName = title,
type = TvType.TvSeries, type = TvType.TvSeries,
posterUrl = posterUrl,
quality = quality, ) {
// this.posterUrl = posterUrl
) this.quality = quality
addDubStatus(
isDub = !select("span.block-sai").text().uppercase().contains("VOSTFR"),
episodes = Regex("""pisode[\s]+(\d+)""").find(select("div.block-ep").text())?.groupValues?.get(
1
)?.toIntOrNull()
)
}
} }
} }
suspend fun avoidCloudflare(url: String): NiceResponse {
if (!app.get(url).isSuccessful) {
return app.get(url, interceptor = interceptor)
} else {
return app.get(url)
}
}
data class mediaData(
@JsonProperty("title") var title: String,
@JsonProperty("url") val url: String,
)
override val mainPage = mainPageOf( override val mainPage = mainPageOf(
Pair("$mainUrl/films-prochainement/page/", "Film Prochainement en Streaming"), Pair("$mainUrl/films-prochainement/page/", "Film Prochainement en Streaming"),
Pair("$mainUrl/film-en-streaming/page/", "Top Films cette année"), Pair("$mainUrl/film-en-streaming/page/", "Top Films cette année"),
@ -294,7 +356,11 @@ class WiflixProvider : MainAPI() {
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val url = request.data + page val url = request.data + page
val document = app.get(url).document val document =
avoidCloudflare(url).document
//posterHeaders = interceptor.getCookieHeaders(url).toMap()
val movies = document.select("div#dle-content > div.clearfix") val movies = document.select("div#dle-content > div.clearfix")
val home = val home =
@ -305,3 +371,5 @@ class WiflixProvider : MainAPI() {
} }
} }