mirror of
https://github.com/recloudstream/cloudstream-extensions-multilingual.git
synced 2024-08-15 03:15:14 +00:00
added webflix
This commit is contained in:
parent
f446545188
commit
d8ed50157c
5 changed files with 269 additions and 0 deletions
26
WebFlix/build.gradle.kts
Normal file
26
WebFlix/build.gradle.kts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// use an integer for version numbers
|
||||||
|
version = 1
|
||||||
|
|
||||||
|
|
||||||
|
cloudstream {
|
||||||
|
// All of these properties are optional, you can safely remove them
|
||||||
|
|
||||||
|
description = "Adds multiple sites using WebFlix. This includes sites in English, Polish, Portuguese and Arabic"
|
||||||
|
authors = listOf("Cloudburst")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status int as the following:
|
||||||
|
* 0: Down
|
||||||
|
* 1: Ok
|
||||||
|
* 2: Slow
|
||||||
|
* 3: Beta only
|
||||||
|
* */
|
||||||
|
status = 1 // will be 3 if unspecified
|
||||||
|
tvTypes = listOf(
|
||||||
|
"Movies",
|
||||||
|
"TvSeries",
|
||||||
|
"Live"
|
||||||
|
)
|
||||||
|
|
||||||
|
iconUrl = "https://raw.githubusercontent.com/recloudstream/cloudstream-extensions-multilinugal/master/WebFlix/icon.png"
|
||||||
|
}
|
BIN
WebFlix/icon.png
Normal file
BIN
WebFlix/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
2
WebFlix/src/main/AndroidManifest.xml
Normal file
2
WebFlix/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="com.lagradost"/>
|
222
WebFlix/src/main/kotlin/com/lagradost/WebFlixProvider.kt
Normal file
222
WebFlix/src/main/kotlin/com/lagradost/WebFlixProvider.kt
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
package com.lagradost
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
|
import android.util.Log
|
||||||
|
import com.lagradost.WebFlixProvider.Companion.toHomePageList
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
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.Qualities
|
||||||
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
|
import java.net.URLEncoder
|
||||||
|
|
||||||
|
|
||||||
|
class WebFlixProvider(override var lang: String, override var mainUrl: String, override var name: String, override val supportedTypes: Set<TvType>) : MainAPI() {
|
||||||
|
val magicPath = base64Decode("NEY1QTlDM0Q5QTg2RkE1NEVBQ0VEREQ2MzUxODUvZDUwNmFiZmQtOWZlMi00YjcxLWI5NzktZmVmZjIxYmNhZDEzLw==")
|
||||||
|
override val hasMainPage = true
|
||||||
|
override val hasChromecastSupport = true
|
||||||
|
|
||||||
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
|
request : MainPageRequest
|
||||||
|
): HomePageResponse? {
|
||||||
|
val res = tryParseJson<HomeResponse>(app.get("$mainUrl/api/first/$magicPath").text) ?: return null
|
||||||
|
return HomePageResponse(
|
||||||
|
res.getHomePageLists(this),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun search(query: String): List<SearchResponse>? {
|
||||||
|
val res = tryParseJson<ApiSearchResponse>(app.get("$mainUrl/api/search/${query.encodeUri()}/$magicPath").text) ?: return null
|
||||||
|
return res.posters.map { it.toSearchResponse(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun load(url: String): LoadResponse? {
|
||||||
|
val data = tryParseJson<Entry>(app.get(url).text) ?: return null
|
||||||
|
return data.toLoadResponse(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
val sources = tryParseJson<List<Source>>(data) ?: return false
|
||||||
|
sources.forEach {
|
||||||
|
it.load(subtitleCallback, callback)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class ApiSearchResponse(
|
||||||
|
val posters: List<Entry>
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class HomeResponse(val genres: List<HomeReponseGenre>, val channels: List<Entry>, val slides: List<Entry>) {
|
||||||
|
fun getHomePageLists(provider: WebFlixProvider): List<HomePageList> {
|
||||||
|
val lists = mutableListOf<HomePageList>()
|
||||||
|
if (channels.isNotEmpty()) {
|
||||||
|
channels.forEach {
|
||||||
|
if (it.type == null) it.type = "channel"
|
||||||
|
}
|
||||||
|
lists.add(channels.toHomePageList("Channels", provider))
|
||||||
|
}
|
||||||
|
if (slides.isNotEmpty()) lists.add(slides.toHomePageList("Slides", provider))
|
||||||
|
lists.addAll(genres.map { it.toHomePageList(provider) })
|
||||||
|
return lists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private data class HomeReponseGenre(
|
||||||
|
val title: String,
|
||||||
|
val posters: List<Entry>
|
||||||
|
) {
|
||||||
|
fun toHomePageList(provider: WebFlixProvider) = posters.toHomePageList(title, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Source(
|
||||||
|
val title: String?,
|
||||||
|
val url: String?,
|
||||||
|
val quality: String?,
|
||||||
|
) {
|
||||||
|
suspend fun load(subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
|
||||||
|
if (url == null) return;
|
||||||
|
when (url.split(".").last()) {
|
||||||
|
"mp4", "m3u8", "mov" -> callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
quality ?: "",
|
||||||
|
title ?: "",
|
||||||
|
url,
|
||||||
|
"",
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
isM3u8 = (url.endsWith("m3u8"))
|
||||||
|
))
|
||||||
|
else -> loadExtractor(url, subtitleCallback, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class ApiEpisode(
|
||||||
|
val id: Int,
|
||||||
|
val title: String?,
|
||||||
|
val description: String?,
|
||||||
|
val sources: List<Source> = emptyList()
|
||||||
|
) {
|
||||||
|
fun toEpisode(season: Int, episode: Int) = Episode(
|
||||||
|
sources.toJson(),
|
||||||
|
title,
|
||||||
|
season,
|
||||||
|
episode,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
description
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class ApiSeason(
|
||||||
|
val title: String?,
|
||||||
|
val episodes: List<ApiEpisode> = emptyList()
|
||||||
|
) {
|
||||||
|
fun getEpisodes(season: Int): List<Episode> = episodes.mapIndexed { idx, episode -> episode.toEpisode(season, idx + 1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Entry(
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
val label: String?,
|
||||||
|
val sublabel: String?,
|
||||||
|
val image: String?,
|
||||||
|
val description: String?,
|
||||||
|
var type: String?,
|
||||||
|
val year: String?,
|
||||||
|
val imdb: Double?,
|
||||||
|
val sources: List<Source> = emptyList()
|
||||||
|
) {
|
||||||
|
fun getTvType() = when (type) {
|
||||||
|
"serie" -> TvType.TvSeries
|
||||||
|
"movie" -> TvType.Movie
|
||||||
|
"channel", "4" -> TvType.Live
|
||||||
|
else -> {
|
||||||
|
Log.d("WebFlix", "other: $type")
|
||||||
|
TvType.Others
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toSearchResponse(provider: WebFlixProvider): SearchResponse {
|
||||||
|
val entry = this
|
||||||
|
return when(getTvType()) {
|
||||||
|
TvType.Movie -> provider.newMovieSearchResponse(
|
||||||
|
title,
|
||||||
|
"${provider.mainUrl}/api/movie/by/$id/${provider.magicPath}",
|
||||||
|
getTvType(),
|
||||||
|
) {
|
||||||
|
posterUrl = image
|
||||||
|
year = entry.year?.toIntOrNull()
|
||||||
|
}
|
||||||
|
TvType.TvSeries -> provider.newTvSeriesSearchResponse(
|
||||||
|
title,
|
||||||
|
"${provider.mainUrl}/api/series/by/$id/${provider.magicPath}",
|
||||||
|
TvType.TvSeries
|
||||||
|
) {
|
||||||
|
posterUrl = image
|
||||||
|
//year = entry.year?.toIntOrNull()
|
||||||
|
}
|
||||||
|
TvType.Live -> provider.newMovieSearchResponse(
|
||||||
|
title,
|
||||||
|
"${provider.mainUrl}/api/channel/by/$id/${provider.magicPath}",
|
||||||
|
getTvType(),
|
||||||
|
) {
|
||||||
|
posterUrl = image
|
||||||
|
year = entry.year?.toIntOrNull()
|
||||||
|
}
|
||||||
|
else -> provider.newMovieSearchResponse(
|
||||||
|
title,
|
||||||
|
"${provider.mainUrl}/api/$type/by/$id/${provider.magicPath}",
|
||||||
|
getTvType(),
|
||||||
|
) {
|
||||||
|
posterUrl = image
|
||||||
|
year = entry.year?.toIntOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun toLoadResponse(provider: WebFlixProvider): LoadResponse? {
|
||||||
|
val entry = this
|
||||||
|
return when(getTvType()) {
|
||||||
|
TvType.TvSeries -> {
|
||||||
|
val res = tryParseJson<List<ApiSeason>>(app.get("${provider.mainUrl}/api/season/by/serie/${id}/${provider.magicPath}").text) ?: return null
|
||||||
|
provider.newTvSeriesLoadResponse(
|
||||||
|
title,
|
||||||
|
"",
|
||||||
|
TvType.TvSeries,
|
||||||
|
res.mapIndexed { idx, season -> season.getEpisodes(idx + 1) }
|
||||||
|
.flatten()
|
||||||
|
) {
|
||||||
|
this.posterUrl = entry.image
|
||||||
|
this.year = entry.year?.toIntOrNull()
|
||||||
|
this.plot = description
|
||||||
|
this.rating = if (entry.imdb != null) (entry.imdb*10).toInt() else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> provider.newMovieLoadResponse(
|
||||||
|
title,
|
||||||
|
"",
|
||||||
|
getTvType(),
|
||||||
|
sources.toJson()
|
||||||
|
) {
|
||||||
|
this.posterUrl = entry.image
|
||||||
|
this.year = entry.year?.toIntOrNull()
|
||||||
|
this.plot = description
|
||||||
|
this.rating = if (entry.imdb != null) (entry.imdb*10).toInt() else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun String.encodeUri() = URLEncoder.encode(this, "utf8")
|
||||||
|
fun List<Entry>.toHomePageList(name: String, provider: WebFlixProvider) = HomePageList(name, this.map { it.toSearchResponse(provider) })
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
package com.lagradost
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||||
|
import com.lagradost.cloudstream3.plugins.Plugin
|
||||||
|
import android.content.Context
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
|
|
||||||
|
@CloudstreamPlugin
|
||||||
|
class WebFlixProviderPlugin: Plugin() {
|
||||||
|
override fun load(context: Context) {
|
||||||
|
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||||
|
registerMainAPI(WebFlixProvider("en", "https://dhfilmtv.com", "DHFilmTv", setOf(TvType.Movie, TvType.TvSeries)))
|
||||||
|
registerMainAPI(WebFlixProvider("pl", "https://app.vodi.cc", "Vodi.cc", setOf(TvType.Movie, TvType.TvSeries)))
|
||||||
|
registerMainAPI(WebFlixProvider("fr", "http://www.vanflix.cm", "Vanflix", setOf(TvType.Movie, TvType.TvSeries, TvType.Live)))
|
||||||
|
registerMainAPI(WebFlixProvider("pt-pt", "https://www.brflix.xyz", "BrFlix", setOf(TvType.Movie, TvType.TvSeries, TvType.Live)))
|
||||||
|
registerMainAPI(WebFlixProvider("ar", "https://ifilm.live", "ifilm.live", setOf(TvType.Movie, TvType.TvSeries)))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue