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