Merge remote-tracking branch 'origin/master'

This commit is contained in:
Blatzar 2022-03-17 16:06:20 +01:00
commit f055b55e89
96 changed files with 1084 additions and 492 deletions

View file

@ -6,14 +6,14 @@ from typing import List, Dict
# Globals
URL_REGEX = compile(
"override val mainUrl(?:\:\s?String)?[^\"']+[\"'](https?://[a-zA-Z0-9\.-]+)[\"']")
"override\sva[lr]\smainUrl[^\"']+[\"'](https?://[a-zA-Z0-9\.-]+)[\"']")
NAME_REGEX = compile("class (.+?) ?: \w+\(\)\s\{")
START_MARKER = "<!--SITE LIST START-->"
END_MARKER = "<!--SITE LIST END-->"
GLOB = "app/src/main/java/com/lagradost/cloudstream3/*providers/*Provider.kt"
MAIN_API = "app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt"
API_REGEX = compile(
"val (?:restrictedA|a)pis = arrayListOf\((.+?)\)(?=\n\n)", DOTALL)
"val\s*allProviders.*?{\s.*?arrayListOf\(([\W\w]*?)\)\s*\n*\s*}", DOTALL)
sites: Dict[str, str] = {}
enabled_sites: List[str] = []

View file

@ -98,4 +98,6 @@ It merely scrapes 3rd-party websites that are publicly accessable via any regula
- [9anime.center](https://9anime.center)
- [animeworld.tv](https://www.animeworld.tv)
- [asiaflix.app](https://asiaflix.app)
- [kawaiifu.com](https://kawaiifu.com)
- [hdm.to](https://hdm.to)
<!--SITE LIST END-->

View file

@ -6,6 +6,7 @@ import android.net.Uri
import android.util.Base64.encodeToString
import androidx.annotation.WorkerThread
import androidx.preference.PreferenceManager
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
@ -31,21 +32,13 @@ object APIHolder {
private const val defProvider = 0
val apis = arrayListOf(
val allProviders by lazy {
arrayListOf(
// Movie providers
PelisplusProvider(),
PelisplusHDProvider(),
PeliSmartProvider(),
GogoanimeProvider(),
AllAnimeProvider(),
AnimekisaProvider(),
//ShiroProvider(), // v2 fucked me
AnimeFlickProvider(),
AnimeflvnetProvider(),
TenshiProvider(),
WcoProvider(),
// MeloMovieProvider(), // Captcha for links
DubbedAnimeProvider(),
MeloMovieProvider(), // Captcha for links
DoramasYTProvider(),
CinecalidadProvider(),
CuevanaProvider(),
@ -53,34 +46,22 @@ object APIHolder {
PelisflixProvider(),
SeriesflixProvider(),
IHaveNoTvProvider(), // Documentaries provider
//LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
VMoveeProvider(),
WatchCartoonOnlineProvider(),
AllMoviesForYouProvider(),
ApiMDBProvider(),
MonoschinosProvider(),
VidEmbedProvider(),
VfFilmProvider(),
VfSerieProvider(),
FrenchStreamProvider(),
AsianLoadProvider(),
BflixProvider("https://bflix.ru","Bflix"),
BflixProvider("https://fmovies.to","Fmovies.to"),
BflixProvider("https://sflix.pro","Sflix.pro"),
SflixProvider("https://sflix.to", "Sflix.to"),
SflixProvider("https://dopebox.to", "Dopebox"),
SflixProvider("https://solarmovie.pe", "Solarmovie"),
//TmdbProvider(),
AsiaFlixProvider(), // restricted
BflixProvider(),
FmoviesToProvider(),
SflixProProvider(),
FilmanProvider(),
ZoroProvider(),
SflixProvider(),
DopeboxProvider(),
SolarmovieProvider(),
PinoyMoviePediaProvider(),
PinoyHDXyzProvider(),
PinoyMoviesEsProvider(),
@ -92,25 +73,35 @@ object APIHolder {
AkwamProvider(),
MyCimaProvider(),
EgyBestProvider(),
SoaptwoDayProvider(),
HDMProvider(),// disabled due to cloudflare
// Metadata providers
//TmdbProvider(),
CrossTmdbProvider(),
ApiMDBProvider(),
// Anime providers
WatchCartoonOnlineProvider(),
GogoanimeProvider(),
AllAnimeProvider(),
AnimekisaProvider(),
//ShiroProvider(), // v2 fucked me
AnimeFlickProvider(),
AnimeflvnetProvider(),
TenshiProvider(),
WcoProvider(),
AnimePaheProvider(),
NineAnimeProvider(),
AnimeWorldProvider(),
SoaptwoDayProvider(),
CrossTmdbProvider(),
ZoroProvider(),
DubbedAnimeProvider(),
MonoschinosProvider(),
KawaiifuProvider(), // disabled due to cloudflare
)
}
val restrictedApis = arrayListOf(
// TrailersToProvider(), // be aware that this is fuckery
// NyaaProvider(), // torrents in cs3 is wack
// ThenosProvider(), // ddos protection and wacked links
AsiaFlixProvider(),
)
private val backwardsCompatibleProviders = arrayListOf(
KawaiifuProvider(), // removed due to cloudflare
HDMProvider(),// removed due to cloudflare
)
var apis : List<MainAPI> = arrayListOf()
fun getApiFromName(apiName: String?): MainAPI {
return getApiFromNameNull(apiName) ?: apis[defProvider]
@ -118,15 +109,7 @@ object APIHolder {
fun getApiFromNameNull(apiName: String?): MainAPI? {
if (apiName == null) return null
for (api in apis) {
if (apiName == api.name)
return api
}
for (api in restrictedApis) {
if (apiName == api.name)
return api
}
for (api in backwardsCompatibleProviders) {
for (api in allProviders) {
if (apiName == api.name)
return api
}
@ -281,10 +264,45 @@ object APIHolder {
}
}
/*
0 = Site not good
1 = All good
2 = Slow, heavy traffic
3 = restricted, must donate 30 benenes to use
*/
const val PROVIDER_STATUS_KEY = "PROVIDER_STATUS_KEY"
const val PROVIDER_STATUS_URL = "https://raw.githubusercontent.com/LagradOst/CloudStream-3/master/providers.json"
const val PROVIDER_STATUS_BETA_ONLY = 3
const val PROVIDER_STATUS_SLOW = 2
const val PROVIDER_STATUS_OK = 1
const val PROVIDER_STATUS_DOWN = 0
data class ProvidersInfoJson(
@JsonProperty("name") var name: String,
@JsonProperty("url") var url: String,
@JsonProperty("status") var status: Int,
)
/**Every provider will **not** have try catch built in, so handle exceptions when calling these functions*/
abstract class MainAPI {
open val name = "NONE"
open val mainUrl = "NONE"
companion object {
var overrideData : HashMap<String, ProvidersInfoJson>? = null
}
public fun overrideWithNewData(data : ProvidersInfoJson) {
this.name = data.name
this.mainUrl = data.url
}
init {
overrideData?.get(this.javaClass.simpleName)?.let { data ->
overrideWithNewData(data)
}
}
open var name = "NONE"
open var mainUrl = "NONE"
//open val uniqueId : Int by lazy { this.name.hashCode() } // in case of duplicate providers you can have a shared id
@ -317,17 +335,17 @@ abstract class MainAPI {
open val providerType = ProviderType.DirectProvider
@WorkerThread
suspend open fun getMainPage(): HomePageResponse? {
open suspend fun getMainPage(): HomePageResponse? {
throw NotImplementedError()
}
@WorkerThread
suspend open fun search(query: String): List<SearchResponse>? {
open suspend fun search(query: String): List<SearchResponse>? {
throw NotImplementedError()
}
@WorkerThread
suspend open fun quickSearch(query: String): List<SearchResponse>? {
open suspend fun quickSearch(query: String): List<SearchResponse>? {
throw NotImplementedError()
}
@ -336,7 +354,7 @@ abstract class MainAPI {
* Based on data from search() or getMainPage() it generates a LoadResponse,
* basically opening the info page from a link.
* */
suspend open fun load(url: String): LoadResponse? {
open suspend fun load(url: String): LoadResponse? {
throw NotImplementedError()
}
@ -350,13 +368,13 @@ abstract class MainAPI {
* if the need arises.
* */
@WorkerThread
suspend open fun extractorVerifierJob(extractorData: String?) {
open suspend fun extractorVerifierJob(extractorData: String?) {
throw NotImplementedError()
}
/**Callback is fired once a link is found, will return true if method is executed successfully*/
@WorkerThread
suspend open fun loadLinks(
open suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,

View file

@ -23,9 +23,9 @@ import androidx.preference.PreferenceManager
import com.google.android.gms.cast.framework.*
import com.google.android.material.navigationrail.NavigationRailView
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import com.lagradost.cloudstream3.APIHolder.allProviders
import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
import com.lagradost.cloudstream3.APIHolder.restrictedApis
import com.lagradost.cloudstream3.CommonActivity.backEvent
import com.lagradost.cloudstream3.CommonActivity.loadThemes
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
@ -46,9 +46,12 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSet
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.removeKey
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState
@ -60,6 +63,9 @@ import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_result_swipe.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.File
import kotlin.concurrent.thread
@ -308,6 +314,88 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
for (api in OAuth2accountApis) {
api.init()
}
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val downloadFromGithub = try {
settingsManager.getBoolean(getString(R.string.killswitch_key), true)
} catch (e: Exception) {
logError(e)
false
}
// must give benenes to get beta providers
val hasBenene = try {
val count = settingsManager.getInt(getString(R.string.benene_count), 0)
count > 30
} catch (e: Exception) {
e.printStackTrace()
false
}
// this pulls the latest data so ppl don't have to update to simply change provider url
if(downloadFromGithub) {
try {
runBlocking {
withContext(Dispatchers.IO) {
try {
val cacheStr: String? = getKey(PROVIDER_STATUS_KEY)
val cache: HashMap<String, ProvidersInfoJson>? =
cacheStr?.let { tryParseJson(cacheStr) }
if (cache != null) {
// if cache is found then spin up a new request, but dont wait
main {
try {
val txt = app.get(PROVIDER_STATUS_URL).text
val newCache =
tryParseJson<HashMap<String, ProvidersInfoJson>>(txt)
setKey(PROVIDER_STATUS_KEY, txt)
MainAPI.overrideData = newCache // update all new providers
for (api in apis) { // update current providers
newCache?.get(api.javaClass.simpleName)?.let { data ->
api.overrideWithNewData(data)
}
}
} catch (e: Exception) {
logError(e)
}
}
cache
} else {
// if it is the first time the user has used the app then wait for a request to update all providers
val txt = app.get(PROVIDER_STATUS_URL).text
setKey(PROVIDER_STATUS_KEY, txt)
val newCache = tryParseJson<HashMap<String, ProvidersInfoJson>>(txt)
newCache
}?.let { providersJsonMap ->
MainAPI.overrideData = providersJsonMap
val acceptableProviders =
providersJsonMap.filter { it.value.status == PROVIDER_STATUS_OK || it.value.status == PROVIDER_STATUS_SLOW }
.map { it.key }.toSet()
val restrictedApis =
if (hasBenene) providersJsonMap.filter { it.value.status == PROVIDER_STATUS_BETA_ONLY }
.map { it.key }.toSet() else emptySet()
apis = allProviders.filter { api ->
val name = api.javaClass.simpleName
// if the provider does not exist in the json file, then it is shown by default
!providersJsonMap.containsKey(name) || acceptableProviders.contains(name) || restrictedApis.contains(name)
}
}
} catch (e : Exception) {
logError(e)
}
}
}
} catch (e: Exception) {
apis = allProviders
e.printStackTrace()
logError(e)
}
} else {
apis = allProviders
}
loadThemes(this)
updateLocale()
app.initClient(this)
@ -458,10 +546,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
createISO()
}*/
var providersString = "Current providers are:\n"
var providersAndroidManifestString = "Current androidmanifest should be:\n"
for (api in apis) {
providersString += "+ ${api.mainUrl}\n"
for (api in allProviders) {
providersAndroidManifestString += "<data android:scheme=\"https\" android:host=\"${
api.mainUrl.removePrefix(
"https://"
@ -469,17 +555,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
}\" android:pathPrefix=\"/\"/>\n"
}
for (api in restrictedApis) {
providersString += "+ ${api.mainUrl}\n"
providersAndroidManifestString += "<data android:scheme=\"https\" android:host=\"${
api.mainUrl.removePrefix(
"https://"
)
}\" android:pathPrefix=\"/\"/>\n"
}
println(providersString)
println(providersAndroidManifestString)
handleAppIntent(intent)
@ -488,15 +563,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
runAutoUpdate()
}
// must give benenes to get beta providers
try {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val count = settingsManager.getInt(getString(R.string.benene_count), 0)
if (count > 30 && restrictedApis.size > 0 && !apis.contains(restrictedApis.first()))
apis.addAll(restrictedApis)
} catch (e: Exception) {
e.printStackTrace()
}
APIRepository.dubStatusActive = getApiDubstatusSettings()
try {
@ -507,7 +573,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
} catch (e: Exception) {
logError(e)
}
println("Loaded everything")
/*
val relativePath = (Environment.DIRECTORY_DOWNLOADS) + File.separatorChar
val displayName = "output.dex" //""output.dex"

View file

@ -17,8 +17,8 @@ import java.util.*
class AllAnimeProvider : MainAPI() {
override val mainUrl = "https://allanime.site"
override val name = "AllAnime"
override var mainUrl = "https://allanime.site"
override var name = "AllAnime"
override val hasQuickSearch = false
override val hasMainPage = false

View file

@ -16,8 +16,8 @@ class AnimeFlickProvider : MainAPI() {
}
}
override val mainUrl = "https://animeflick.net"
override val name = "AnimeFlick"
override var mainUrl = "https://animeflick.net"
override var name = "AnimeFlick"
override val hasQuickSearch = false
override val hasMainPage = false

View file

@ -44,8 +44,8 @@ class AnimePaheProvider : MainAPI() {
Regex("""(^(?:https?:)?(?://)?(?:www\.)?(?:youtu\.be/|youtube(?:-nocookie)?\.(?:[A-Za-z]{2,4}|[A-Za-z]{2,3}\.[A-Za-z]{2})/)(?:watch|embed/|vi?/)*(?:\?[\w=&]*vi?=)?[^#&?/]{11}.*${'$'})""")
}
override val mainUrl = MAIN_URL
override val name = "AnimePahe"
override var mainUrl = MAIN_URL
override var name = "AnimePahe"
override val hasQuickSearch = false
override val hasMainPage = true

View file

@ -8,8 +8,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
class AnimeWorldProvider : MainAPI() {
override val mainUrl = "https://www.animeworld.tv"
override val name = "AnimeWorld"
override var mainUrl = "https://www.animeworld.tv"
override var name = "AnimeWorld"
override val lang = "it"
override val hasMainPage = true

View file

@ -14,8 +14,8 @@ class AnimeflvnetProvider:MainAPI() {
else TvType.Anime
}
}
override val mainUrl = "https://www3.animeflv.net"
override val name = "Animeflv.net"
override var mainUrl = "https://www3.animeflv.net"
override var name = "Animeflv.net"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -12,8 +12,8 @@ import kotlin.collections.ArrayList
class AnimekisaProvider : MainAPI() {
override val mainUrl = "https://animekisa.in"
override val name = "Animekisa"
override var mainUrl = "https://animekisa.in"
override var name = "Animekisa"
override val hasMainPage = true
override val hasChromecastSupport = true
override val hasDownloadSupport = true

View file

@ -11,8 +11,8 @@ import org.jsoup.Jsoup
import java.util.*
class DubbedAnimeProvider : MainAPI() {
override val mainUrl = "https://bestdubbedanime.com"
override val name = "DubbedAnime"
override var mainUrl = "https://bestdubbedanime.com"
override var name = "DubbedAnime"
override val hasQuickSearch = true
override val hasMainPage = true

View file

@ -155,8 +155,8 @@ class GogoanimeProvider : MainAPI() {
}
}
override val mainUrl = "https://gogoanime.film"
override val name = "GogoAnime"
override var mainUrl = "https://gogoanime.film"
override var name = "GogoAnime"
override val hasQuickSearch = false
override val hasMainPage = true

View file

@ -7,8 +7,8 @@ import org.jsoup.Jsoup
import java.util.*
class KawaiifuProvider : MainAPI() {
override val mainUrl = "https://kawaiifu.com"
override val name = "Kawaiifu"
override var mainUrl = "https://kawaiifu.com"
override var name = "Kawaiifu"
override val hasQuickSearch = false
override val hasMainPage = true

View file

@ -17,8 +17,8 @@ class MonoschinosProvider : MainAPI() {
}
}
override val mainUrl = "https://monoschinos2.com"
override val name = "Monoschinos"
override var mainUrl = "https://monoschinos2.com"
override var name = "Monoschinos"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -10,8 +10,8 @@ import org.jsoup.Jsoup
import java.util.*
class NineAnimeProvider : MainAPI() {
override val mainUrl = "https://9anime.center"
override val name = "9Anime"
override var mainUrl = "https://9anime.center"
override var name = "9Anime"
override val hasMainPage = true
override val hasChromecastSupport = true
override val hasDownloadSupport = true

View file

@ -25,8 +25,8 @@ class TenshiProvider : MainAPI() {
}
}
override val mainUrl = "https://tenshi.moe"
override val name = "Tenshi.moe"
override var mainUrl = "https://tenshi.moe"
override var name = "Tenshi.moe"
override val hasQuickSearch = false
override val hasMainPage = true
override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie, TvType.OVA)

View file

@ -12,8 +12,8 @@ import java.util.*
class WatchCartoonOnlineProvider : MainAPI() {
override val name = "WatchCartoonOnline"
override val mainUrl = "https://www.wcostream.com"
override var name = "WatchCartoonOnline"
override var mainUrl = "https://www.wcostream.com"
override val supportedTypes = setOf(
TvType.Cartoon,

View file

@ -19,8 +19,8 @@ class WcoProvider : MainAPI() {
}
}
override val mainUrl = "https://wcostream.cc"
override val name = "WCO Stream"
override var mainUrl = "https://wcostream.cc"
override var name = "WCO Stream"
override val hasQuickSearch = true
override val hasMainPage = true

View file

@ -18,8 +18,8 @@ import java.net.URI
import java.util.*
class ZoroProvider : MainAPI() {
override val mainUrl = "https://zoro.to"
override val name = "Zoro"
override var mainUrl = "https://zoro.to"
override var name = "Zoro"
override val hasQuickSearch = false
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -5,8 +5,8 @@ import com.lagradost.cloudstream3.utils.*
import java.net.URI
class AsianLoad : ExtractorApi() {
override val name = "AsianLoad"
override val mainUrl = "https://asianembed.io"
override var name = "AsianLoad"
override var mainUrl = "https://asianembed.io"
override val requiresReferer = true
private val sourceRegex = Regex("""sources:[\W\w]*?file:\s*?["'](.*?)["']""")

View file

@ -7,21 +7,21 @@ import com.lagradost.cloudstream3.utils.Qualities
import kotlinx.coroutines.delay
class DoodToExtractor : DoodLaExtractor() {
override val mainUrl = "https://dood.to"
override var mainUrl = "https://dood.to"
}
class DoodSoExtractor : DoodLaExtractor() {
override val mainUrl = "https://dood.so"
override var mainUrl = "https://dood.so"
}
class DoodWsExtractor : DoodLaExtractor() {
override val mainUrl = "https://dood.ws"
override var mainUrl = "https://dood.ws"
}
open class DoodLaExtractor : ExtractorApi() {
override val name = "DoodStream"
override val mainUrl = "https://dood.la"
override var name = "DoodStream"
override var mainUrl = "https://dood.la"
override val requiresReferer = false
override fun getExtractorUrl(id: String): String {

View file

@ -4,7 +4,7 @@ import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.app
class Evoload1 : Evoload() {
override val mainUrl = "https://evoload.io"
override var mainUrl = "https://evoload.io"
}
open class Evoload : ExtractorApi() {

View file

@ -12,8 +12,8 @@ import com.lagradost.cloudstream3.utils.getQualityFromName
open class GenericM3U8 : ExtractorApi() {
override val name = "Upstream"
override val mainUrl = "https://upstream.to"
override var name = "Upstream"
override var mainUrl = "https://upstream.to"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {

View file

@ -6,8 +6,8 @@ import com.lagradost.cloudstream3.app
open class Jawcloud : ExtractorApi() {
override val name = "Jawcloud"
override val mainUrl = "https://jawcloud.co"
override var name = "Jawcloud"
override var mainUrl = "https://jawcloud.co"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {

View file

@ -11,8 +11,8 @@ import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.getQualityFromName
open class Mcloud : ExtractorApi() {
override val name = "Mcloud"
override val mainUrl = "https://mcloud.to"
override var name = "Mcloud"
override var mainUrl = "https://mcloud.to"
override val requiresReferer = true
val headers = mapOf(
"Host" to "mcloud.to",

View file

@ -4,8 +4,8 @@ import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
class MixDrop : ExtractorApi() {
override val name = "MixDrop"
override val mainUrl = "https://mixdrop.co"
override var name = "MixDrop"
override var mainUrl = "https://mixdrop.co"
private val srcRegex = Regex("""wurl.*?=.*?"(.*?)";""")
override val requiresReferer = false

View file

@ -7,8 +7,8 @@ import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.getAndUnpack
class Mp4Upload : ExtractorApi() {
override val name = "Mp4Upload"
override val mainUrl = "https://www.mp4upload.com"
override var name = "Mp4Upload"
override var mainUrl = "https://www.mp4upload.com"
private val srcRegex = Regex("""player\.src\("(.*?)"""")
override val requiresReferer = true

View file

@ -8,8 +8,8 @@ import com.lagradost.cloudstream3.utils.getQualityFromName
import java.net.URI
class MultiQuality : ExtractorApi() {
override val name = "MultiQuality"
override val mainUrl = "https://gogo-play.net"
override var name = "MultiQuality"
override var mainUrl = "https://gogo-play.net"
private val sourceRegex = Regex("""file:\s*['"](.*?)['"],label:\s*['"](.*?)['"]""")
private val m3u8Regex = Regex(""".*?(\d*).m3u8""")
private val urlRegex = Regex("""(.*?)([^/]+$)""")

View file

@ -1,35 +1,63 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
data class DataOptionsJson (
@JsonProperty("flashvars") var flashvars : Flashvars? = Flashvars(),
)
data class Flashvars (
@JsonProperty("metadata") var metadata : String? = null,
@JsonProperty("hlsManifestUrl") var hlsManifestUrl : String? = null, //m3u8
)
data class MetadataOkru (
@JsonProperty("videos") var videos: ArrayList<Videos> = arrayListOf(),
)
data class Videos (
@JsonProperty("name") var name : String,
@JsonProperty("url") var url : String,
@JsonProperty("seekSchema") var seekSchema : Int? = null,
@JsonProperty("disallowed") var disallowed : Boolean? = null
)
open class OkRu : ExtractorApi() {
override val name = "Okru"
override val mainUrl = "http://ok.ru"
override var name = "Okru"
override var mainUrl = "http://ok.ru"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val doc = app.get(url).document
val urlString = doc.select("div[data-options]").attr("data-options")
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
.substringBefore("]")
urlString.split("{\\\"name\\\":\\\"").reversed().forEach {
val extractedUrl = it.substringAfter("url\\\":\\\"")
.substringBefore("\\\"")
.replace("\\\\u0026", "&")
val Quality = it.uppercase().substringBefore("\\\"")
if (extractedUrl.isNotBlank()) return listOf(
ExtractorLink(
val sources = ArrayList<ExtractorLink>()
val datajson = doc.select("div[data-options]").attr("data-options")
if (datajson.isNotBlank()) {
val main = parseJson<DataOptionsJson>(datajson)
val metadatajson = parseJson<MetadataOkru>(main.flashvars?.metadata!!)
val servers = metadatajson.videos
servers.forEach {
val quality = it.name.uppercase()
.replace("MOBILE","144p")
.replace("LOWEST","240p")
.replace("LOW","360p")
.replace("SD","480p")
.replace("HD","720p")
.replace("FULL","1080p")
.replace("QUAD","1440p")
.replace("ULTRA","4k")
val extractedurl = it.url.replace("\\\\u0026", "&")
sources.add(ExtractorLink(
name,
"$name ${Quality}",
extractedUrl,
"$name $quality",
extractedurl,
url,
Qualities.Unknown.value,
getQualityFromName(quality),
isM3u8 = false
)
)
}
return null
))
}
}
return sources
}
}

View file

@ -6,8 +6,8 @@ import com.lagradost.cloudstream3.app
open class PlayerVoxzer : ExtractorApi() {
override val name = "Voxzer"
override val mainUrl = "https://player.voxzer.org"
override var name = "Voxzer"
override var mainUrl = "https://player.voxzer.org"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {

View file

@ -10,16 +10,16 @@ import com.lagradost.cloudstream3.utils.getPostForm
import org.jsoup.Jsoup
//class SBPlay1 : SBPlay() {
// override val mainUrl = "https://sbplay1.com"
// override var mainUrl = "https://sbplay1.com"
//}
//class SBPlay2 : SBPlay() {
// override val mainUrl = "https://sbplay2.com"
// override var mainUrl = "https://sbplay2.com"
//}
open class SBPlay : ExtractorApi() {
override val mainUrl = "https://sbplay.one"
override val name = "SBPlay"
override var mainUrl = "https://sbplay.one"
override var name = "SBPlay"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {

View file

@ -9,46 +9,50 @@ import com.lagradost.cloudstream3.utils.AppUtils.parseJson
class StreamSB1 : StreamSB() {
override val mainUrl = "https://sbplay1.com"
override var mainUrl = "https://sbplay1.com"
}
class StreamSB2 : StreamSB() {
override val mainUrl = "https://sbplay2.com"
override var mainUrl = "https://sbplay2.com"
}
class StreamSB3 : StreamSB() {
override val mainUrl = "https://sbplay3.com"
override var mainUrl = "https://sbplay3.com"
}
class StreamSB4 : StreamSB() {
override val mainUrl = "https://cloudemb.com"
override var mainUrl = "https://cloudemb.com"
}
class StreamSB5 : StreamSB() {
override val mainUrl = "https://sbplay.org"
override var mainUrl = "https://sbplay.org"
}
class StreamSB6 : StreamSB() {
override val mainUrl = "https://embedsb.com"
override var mainUrl = "https://embedsb.com"
}
class StreamSB7 : StreamSB() {
override val mainUrl = "https://pelistop.co"
override var mainUrl = "https://pelistop.co"
}
class StreamSB8 : StreamSB() {
override val mainUrl = "https://streamsb.net"
override var mainUrl = "https://streamsb.net"
}
class StreamSB9 : StreamSB() {
override val mainUrl = "https://sbplay.one"
override var mainUrl = "https://sbplay.one"
}
class StreamSB10 : StreamSB() {
override var mainUrl = "https://sbplay2.xyz"
}
// This is a modified version of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/genoanime/src/eu/kanade/tachiyomi/animeextension/en/genoanime/extractors/StreamSBExtractor.kt
// The following code is under the Apache License 2.0 https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE
open class StreamSB : ExtractorApi() {
override val name = "StreamSB"
override val mainUrl = "https://watchsb.com"
override var name = "StreamSB"
override var mainUrl = "https://watchsb.com"
override val requiresReferer = false
private val hexArray = "0123456789ABCDEF".toCharArray()
@ -88,53 +92,30 @@ open class StreamSB : ExtractorApi() {
}.first()
val bytes = id.toByteArray()
val bytesToHex = bytesToHex(bytes)
val master = "$mainUrl/sources41/566d337678566f743674494a7c7c${bytesToHex}7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362"
val master = "$mainUrl/sources41/6d6144797752744a454267617c7c${bytesToHex.lowercase()}7c7c4e61755a56456f34385243727c7c73747265616d7362/6b4a33767968506e4e71374f7c7c343837323439333133333462353935333633373836643638376337633462333634663539343137373761333635313533333835333763376333393636363133393635366136323733343435323332376137633763373337343732363536313664373336327c7c504d754478413835306633797c7c73747265616d7362"
val headers = mapOf(
"Host" to url.substringAfter("https://").substringBefore("/"),
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0",
"Accept" to "application/json, text/plain, */*",
"Accept-Language" to "en-US,en;q=0.5",
"Referer" to url,
"watchsb" to "streamsb",
"DNT" to "1",
"Connection" to "keep-alive",
"Sec-Fetch-Dest" to "empty",
"Sec-Fetch-Mode" to "no-cors",
"Sec-Fetch-Site" to "same-origin",
"TE" to "trailers",
"Pragma" to "no-cache",
"Cache-Control" to "no-cache",)
)
val urltext = app.get(master,
headers = headers,
allowRedirects = false
).text
val mapped = urltext.let { parseJson<Main>(it) }
val testurl = app.get(mapped.streamData.file, headers = headers).text
val urlmain = mapped.streamData.file.substringBefore("/hls/")
// val urlmain = mapped.streamData.file.substringBefore("/hls/")
if (urltext.contains("m3u8") && testurl.contains("EXTM3U")) return M3u8Helper().m3u8Generation(
M3u8Helper.M3u8Stream(
mapped.streamData.file,
headers = mapOf(
"User-Agent" to USER_AGENT,
"Accept" to "*/*",
"Accept-Language" to "en-US,en;q=0.5",
"Accept-Encoding" to "gzip, deflate, br",
"Origin" to mainUrl,
"DNT" to "1",
"Connection" to "keep-alive",
"Referer" to "$mainUrl/",
"Sec-Fetch-Dest" to "empty",
"Sec-Fetch-Mode" to "cors",
"Sec-Fetch-Site" to "cross-site",),
headers = headers
), true
)
.map { stream ->
val cleanstreamurl = stream.streamUrl.replace(Regex("https://.*/hls/"), "$urlmain/hls/")
// val cleanstreamurl = stream.streamUrl.replace(Regex("https://.*/hls/"), "$urlmain/hls/")
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
ExtractorLink(
name,
"$name $qualityString",
cleanstreamurl,
stream.streamUrl,
url,
getQualityFromName(stream.quality.toString()),
true

View file

@ -6,8 +6,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
class StreamTape : ExtractorApi() {
override val name = "StreamTape"
override val mainUrl = "https://streamtape.com"
override var name = "StreamTape"
override var mainUrl = "https://streamtape.com"
override val requiresReferer = false
private val linkRegex =

View file

@ -8,8 +8,8 @@ import com.lagradost.cloudstream3.utils.Qualities
import java.net.URI
class Streamhub : ExtractorApi() {
override val mainUrl = "https://streamhub.to"
override val name = "Streamhub"
override var mainUrl = "https://streamhub.to"
override var name = "Streamhub"
override val requiresReferer = false
override fun getExtractorUrl(id: String): String {

View file

@ -1,19 +1,21 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.app
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
class Cinestart: Tomatomatela() {
override val name: String = "Cinestart"
override val mainUrl: String = "https://cinestart.net"
override var name = "Cinestart"
override var mainUrl = "https://cinestart.net"
override val details = "vr.php?v="
}
open class Tomatomatela : ExtractorApi() {
override val name = "Tomatomatela"
override val mainUrl = "https://tomatomatela.com"
override var name = "Tomatomatela"
override var mainUrl = "https://tomatomatela.com"
override val requiresReferer = false
private data class Tomato (
@JsonProperty("status") val status: Int,

View file

@ -4,7 +4,7 @@ import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.app
class Uqload1 : Uqload() {
override val mainUrl = "https://uqload.com"
override var mainUrl = "https://uqload.com"
}
open class Uqload : ExtractorApi() {

View file

@ -8,8 +8,8 @@ import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.getQualityFromName
open class WatchSB : ExtractorApi() {
override val name = "WatchSB"
override val mainUrl = "https://watchsb.com"
override var name = "WatchSB"
override var mainUrl = "https://watchsb.com"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {

View file

@ -8,19 +8,19 @@ import com.lagradost.cloudstream3.mapper
import com.lagradost.cloudstream3.utils.*
class Vidstreamz : WcoStream() {
override val mainUrl: String = "https://vidstreamz.online"
override var mainUrl = "https://vidstreamz.online"
}
class Vizcloud : WcoStream() {
override val mainUrl: String = "https://vizcloud2.ru"
override var mainUrl = "https://vizcloud2.ru"
}
class Vizcloud2 : WcoStream() {
override val mainUrl: String = "https://vizcloud2.online"
override var mainUrl = "https://vizcloud2.online"
}
open class WcoStream : ExtractorApi() {
override val name = "VidStream" //Cause works for animekisa and wco
override val mainUrl = "https://vidstream.pro"
override var name = "VidStream" //Cause works for animekisa and wco
override var mainUrl = "https://vidstream.pro"
override val requiresReferer = false
private val hlsHelper = M3u8Helper()

View file

@ -5,23 +5,23 @@ import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
class Zplayer: ZplayerV2() {
override val name: String = "Zplayer"
override val mainUrl: String = "https://zplayer.live"
override var name: String = "Zplayer"
override var mainUrl: String = "https://zplayer.live"
}
class Upstream: ZplayerV2() {
override val name: String = "Upstream" //Here 'cause works
override val mainUrl: String = "https://upstream.to"
override var name: String = "Upstream" //Here 'cause works
override var mainUrl: String = "https://upstream.to"
}
class Streamhub2: ZplayerV2() {
override val name: String = "Streamhub" //Here 'cause works
override val mainUrl: String = "https://streamhub.to"
override var name = "Streamhub" //Here 'cause works
override var mainUrl = "https://streamhub.to"
}
open class ZplayerV2 : ExtractorApi() {
override val name = "Zplayer V2"
override val mainUrl = "https://v2.zplayer.live"
override var name = "Zplayer V2"
override var mainUrl = "https://v2.zplayer.live"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {

View file

@ -10,7 +10,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
class CrossTmdbProvider : TmdbProvider() {
override val name = "MultiMovie"
override var name = "MultiMovie"
override val apiName = "MultiMovie"
override val lang = "en"
override val useMetaLoadResponse = true

View file

@ -9,8 +9,8 @@ import org.jsoup.nodes.Element
class AkwamProvider : MainAPI() {
override val lang = "ar"
override val mainUrl = "https://akwam.to"
override val name = "Akwam"
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)

View file

@ -19,8 +19,8 @@ class AllMoviesForYouProvider : MainAPI() {
}
// Fetching movies will not work if this link is outdated.
override val mainUrl = "https://allmoviesforyou.net"
override val name = "AllMoviesForYou"
override var mainUrl = "https://allmoviesforyou.net"
override var name = "AllMoviesForYou"
override val hasMainPage = true
override val supportedTypes = setOf(
TvType.Movie,
@ -149,7 +149,7 @@ class AllMoviesForYouProvider : MainAPI() {
name,
season.first,
epNum,
href,
fixUrl(href),
fixUrlNull(poster),
date
)
@ -175,7 +175,7 @@ class AllMoviesForYouProvider : MainAPI() {
title,
url,
type,
url
fixUrl(url)
) {
posterUrl = backgroundPoster
this.year = year?.toIntOrNull()
@ -193,12 +193,12 @@ class AllMoviesForYouProvider : MainAPI() {
callback: (ExtractorLink) -> Unit
): Boolean {
val doc = app.get(data).document
val iframe = doc.select("body iframe").map { it.attr("src") }
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 = it.attr("src").replace("streamhub.to/d/","streamhub.to/e/")
val link = fixUrl(it.attr("src").replace("streamhub.to/d/","streamhub.to/e/"))
loadExtractor(link, data, callback)
}
} else loadExtractor(id, data, callback)

View file

@ -10,8 +10,8 @@ import com.lagradost.cloudstream3.utils.loadExtractor
class ApiMDBProvider : TmdbProvider() {
override val apiName = "ApiMDB"
override val name = "ApiMDB"
override val mainUrl = "https://v2.apimdb.net"
override var name = "ApiMDB"
override var mainUrl = "https://v2.apimdb.net"
override val useMetaLoadResponse = true
override val instantLinkLoading = false
override val supportedTypes = setOf(

View file

@ -11,8 +11,8 @@ import com.lagradost.cloudstream3.utils.getQualityFromName
import java.net.URI
class AsiaFlixProvider : MainAPI() {
override val mainUrl = "https://asiaflix.app"
override val name = "AsiaFlix"
override var mainUrl = "https://asiaflix.app"
override var name = "AsiaFlix"
override val hasQuickSearch = false
override val hasMainPage = true
override val hasChromecastSupport = false

View file

@ -6,8 +6,8 @@ import com.lagradost.cloudstream3.TvType
* make the app know what functions to call
*/
class AsianLoadProvider : VidstreamProviderTemplate() {
override val name = "AsianLoad"
override val mainUrl = "https://asianembed.io"
override var name = "AsianLoad"
override var mainUrl = "https://asianembed.io"
override val homePageUrlList = listOf(
mainUrl,
"$mainUrl/recently-added-raw",

View file

@ -7,9 +7,18 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
override val mainUrl = providerUrl
override val name = providerName
class FmoviesToProvider : BflixProvider() {
override var mainUrl = "https://fmovies.to"
override var name = "Fmovies.to"
}
class SflixProProvider : BflixProvider() {
override var mainUrl = "https://sflix.pro"
override var name = "Sflix.pro"
}
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

View file

@ -1,17 +1,14 @@
package com.lagradost.cloudstream3.movieproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Cinestart
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.*
import java.util.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class CinecalidadProvider:MainAPI() {
override val mainUrl: String
get() = "https://cinecalidad.lol"
override val name: String
get() = "Cinecalidad"
override var mainUrl = "https://cinecalidad.lol"
override var name = "Cinecalidad"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -9,8 +9,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import java.util.*
class CuevanaProvider:MainAPI() {
override val mainUrl = "https://cuevana3.io"
override val name = "Cuevana"
override var mainUrl = "https://cuevana3.me"
override var name = "Cuevana"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true
@ -191,19 +191,19 @@ class CuevanaProvider:MainAPI() {
): Boolean {
app.get(data).document.select("div.TPlayer.embed_div iframe").apmap {
val iframe = fixUrl(it.attr("data-src"))
if (iframe.contains("api.cuevana3.io/fembed/")) {
val femregex = Regex("(https.\\/\\/api\\.cuevana3\\.io\\/fembed\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
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.io/fembed/?h=","")
val url = app.post("https://api.cuevana3.io/fembed/api.php", allowRedirects = false, headers = mapOf("Host" to "api.cuevana3.io",
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.io",
"Origin" to "https://api.cuevana3.me",
"DNT" to "1",
"Connection" to "keep-alive",
"Sec-Fetch-Dest" to "empty",
@ -239,12 +239,12 @@ class CuevanaProvider:MainAPI() {
data = mapOf(Pair("url",tomkey))
).response.headers.values("location").apmap { loc ->
if (loc.contains("goto_ddh.php")) {
val gotoregex = Regex("(\\/\\/api.cuevana3.io\\/ir\\/goto_ddh.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
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.io/ir/goto_ddh.php?h=","")
goreg.value.replace("//api.cuevana3.me/ir/goto_ddh.php?h=","")
}.toList().apmap { gotolink ->
app.post("https://api.cuevana3.io/ir/redirect_ddh.php", allowRedirects = false,
headers = mapOf("Host" to "api.cuevana3.io",
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",
@ -263,12 +263,12 @@ class CuevanaProvider:MainAPI() {
}
}
if (loc.contains("index.php?h=")) {
val indexRegex = Regex("(\\/\\/api.cuevana3.io\\/sc\\/index.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
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.io/sc/index.php?h=","")
indreg.value.replace("//api.cuevana3.me/sc/index.php?h=","")
}.toList().apmap { inlink ->
app.post("https://api.cuevana3.io/sc/r.php", allowRedirects = false,
headers = mapOf("Host" to "api.cuevana3.io",
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",

View file

@ -16,8 +16,8 @@ class DoramasYTProvider : MainAPI() {
}
}
override val mainUrl = "https://doramasyt.com"
override val name = "DoramasYT"
override var mainUrl = "https://doramasyt.com"
override var name = "DoramasYT"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -10,8 +10,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class DramaSeeProvider : MainAPI() {
override val mainUrl = "https://dramasee.net"
override val name = "DramaSee"
override var mainUrl = "https://dramasee.net"
override var name = "DramaSee"
override val hasQuickSearch = false
override val hasMainPage = true
override val hasChromecastSupport = false

View file

@ -8,8 +8,8 @@ import org.jsoup.nodes.Element
class EgyBestProvider : MainAPI() {
override val lang = "ar"
override val mainUrl = "https://egy.best"
override val name = "EgyBest"
override var mainUrl = "https://egy.best"
override var name = "EgyBest"
override val usesWebView = false
override val hasMainPage = true
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)

View file

@ -6,8 +6,8 @@ import com.lagradost.cloudstream3.utils.*
import java.util.*
class EntrepeliculasyseriesProvider:MainAPI() {
override val mainUrl = "https://entrepeliculasyseries.nu"
override val name = "EntrePeliculasySeries"
override var mainUrl = "https://entrepeliculasyseries.nu"
override var name = "EntrePeliculasySeries"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -9,8 +9,8 @@ import org.jsoup.Jsoup
import org.jsoup.select.Elements
class FilmanProvider : MainAPI() {
override val mainUrl = "https://filman.cc"
override val name = "filman.cc"
override var mainUrl = "https://filman.cc"
override var name = "filman.cc"
override val lang = "pl"
override val hasMainPage = true
override val supportedTypes = setOf(

View file

@ -6,8 +6,8 @@ import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.Jsoup
class HDMProvider : MainAPI() {
override val name = "HD Movies"
override val mainUrl = "https://hdm.to"
override var name = "HD Movies"
override var mainUrl = "https://hdm.to"
override val hasMainPage = true
override val supportedTypes = setOf(

View file

@ -7,8 +7,8 @@ import org.jsoup.Jsoup
import java.net.URLEncoder
class IHaveNoTvProvider : MainAPI() {
override val mainUrl = "https://ihavenotv.com"
override val name = "I Have No TV"
override var mainUrl = "https://ihavenotv.com"
override var name = "I Have No TV"
override val hasQuickSearch = false
override val hasMainPage = true

View file

@ -14,8 +14,8 @@ import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
class KdramaHoodProvider : MainAPI() {
override val mainUrl = "https://kdramahood.com"
override val name = "KDramaHood"
override var mainUrl = "https://kdramahood.com"
override var name = "KDramaHood"
override val hasQuickSearch = false
override val hasMainPage = true
override val hasChromecastSupport = false

View file

@ -13,8 +13,8 @@ import org.jsoup.Jsoup
//BE AWARE THAT weboas.is is a clone of lookmovie
class LookMovieProvider : MainAPI() {
override val hasQuickSearch = true
override val name = "LookMovie"
override val mainUrl = "https://lookmovie.io"
override var name = "LookMovie"
override var mainUrl = "https://lookmovie.io"
override val supportedTypes = setOf(
TvType.Movie,

View file

@ -11,8 +11,8 @@ import org.jsoup.Jsoup
import org.jsoup.nodes.Element
class MeloMovieProvider : MainAPI() {
override val name = "MeloMovie"
override val mainUrl = "https://melomovie.com"
override var name = "MeloMovie"
override var mainUrl = "https://melomovie.com"
override val instantLinkLoading = true
override val hasQuickSearch = true
override val hasChromecastSupport = false // MKV FILES CANT BE PLAYED ON A CHROMECAST

View file

@ -9,8 +9,8 @@ import org.jsoup.nodes.Element
class MyCimaProvider : MainAPI() {
override val lang = "ar"
override val mainUrl = "https://mycima.tv"
override val name = "MyCima"
override var mainUrl = "https://mycima.tv"
override var name = "MyCima"
override val usesWebView = false
override val hasMainPage = true
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)

View file

@ -7,8 +7,8 @@ import com.lagradost.cloudstream3.utils.loadExtractor
import kotlin.collections.ArrayList
class PeliSmartProvider: MainAPI() {
override val mainUrl = "https://pelismart.com"
override val name = "PeliSmart"
override var mainUrl = "https://pelismart.com"
override var name = "PeliSmart"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -7,8 +7,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class PelisflixProvider : MainAPI() {
override val mainUrl = "https://pelisflix.li"
override val name = "Pelisflix"
override var mainUrl = "https://pelisflix.li"
override var name = "Pelisflix"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -6,8 +6,8 @@ import org.jsoup.nodes.Element
import java.util.*
class PelisplusHDProvider:MainAPI() {
override val mainUrl = "https://pelisplushd.net"
override val name = "PelisplusHD"
override var mainUrl = "https://pelisplushd.net"
override var name = "PelisplusHD"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -7,10 +7,10 @@ import com.lagradost.cloudstream3.TvType
*/
class PelisplusProvider : PelisplusProviderTemplate() {
// mainUrl is good to have as a holder for the url to make future changes easier.
override val mainUrl = "https://pelisplus.icu"
override var mainUrl = "https://pelisplus.icu"
// name is for how the provider will be named which is visible in the UI, no real rules for this.
override val name = "Pelisplus"
override var name = "Pelisplus"
override val homePageUrlList = listOf(
mainUrl,

View file

@ -1,11 +1,8 @@
package com.lagradost.cloudstream3.movieproviders
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Pelisplus
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.*
import org.jsoup.Jsoup
import java.net.URI
/** Needs to inherit from MainAPI() to
* make the app know what functions to call
@ -14,7 +11,6 @@ import java.net.URI
open class PelisplusProviderTemplate : MainAPI() {
override val lang = "es"
open val homePageUrlList = listOf<String>()
open val pelisplusExtractorUrl: String? = null
// // mainUrl is good to have as a holder for the url to make future changes easier.
// override val mainUrl: String
@ -35,6 +31,7 @@ open class PelisplusProviderTemplate : MainAPI() {
// Searching returns a SearchResponse, which can be one of the following: AnimeSearchResponse, MovieSearchResponse, TorrentSearchResponse, TvSeriesSearchResponse
// Each of the classes requires some different data, but always has some critical things like name, poster and url.
override suspend fun search(query: String): ArrayList<SearchResponse> {
// Simply looking at devtools network is enough to spot a request like:
// https://vidembed.cc/search.html?keyword=neverland where neverland is the query, can be written as below.
@ -48,7 +45,7 @@ open class PelisplusProviderTemplate : MainAPI() {
val poster = fixUrl(li.selectFirst("img").attr("src"))
// .text() selects all the text in the element, be careful about doing this while too high up in the html hierarchy
val title = li.selectFirst(".name").text()
val title = cleanName(li.selectFirst(".name").text())
// Use get(0) and toIntOrNull() to prevent any possible crashes, [0] or toInt() will error the search on unexpected values.
val year = li.selectFirst(".date")?.text()?.split("-")?.get(0)?.toIntOrNull()
@ -73,33 +70,29 @@ open class PelisplusProviderTemplate : MainAPI() {
val html = app.get(url).text
val soup = Jsoup.parse(html)
var title = soup.selectFirst("h1,h2,h3").text()
title = if (!title.contains("Episode")) title else title.split("Episode")[0].trim()
val title = cleanName(soup.selectFirst("h1,h2,h3").text())
val description = soup.selectFirst(".post-entry")?.text()?.trim()
var poster: String? = null
val poster = soup.selectFirst("head meta[property=og:image]").attr("content")
val episodes = soup.select(".listing.items.lists > .video-block").map { li ->
val epTitle = if (li.selectFirst(".name") != null)
if (li.selectFirst(".name").text().contains("Episode"))
"Episode " + li.selectFirst(".name").text().split("Episode")[1].trim()
else
li.selectFirst(".name").text()
else ""
val href = fixUrl(li.selectFirst("a").attr("href"))
val regexseason = Regex("(-[Tt]emporada-(\\d+)-[Cc]apitulo-(\\d+))")
val aaa = regexseason.find(href)?.destructured?.component1()?.replace(Regex("(-[Tt]emporada-|[Cc]apitulo-)"),"")
val seasonid = aaa.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
val epThumb = fixUrl(li.selectFirst("img").attr("src"))
val epDate = li.selectFirst(".meta > .date").text()
if (poster == null) {
poster = li.selectFirst("img")?.attr("onerror")?.replace("//img", "https://img")?.split("=")?.get(1)
?.replace(Regex("[';]"), "")
}
val epNum = Regex("""Episode (\d+)""").find(epTitle)?.destructured?.component1()?.toIntOrNull()
TvSeriesEpisode(
epTitle,
null,
epNum,
season,
episode,
fixUrl(li.selectFirst("a").attr("href")),
epThumb,
epDate
@ -119,10 +112,10 @@ open class PelisplusProviderTemplate : MainAPI() {
this.name,
tvType,
episodes,
poster,
fixUrl(poster),
year,
description,
ShowStatus.Ongoing,
null,
null,
null
)
@ -134,7 +127,7 @@ open class PelisplusProviderTemplate : MainAPI() {
this.name,
tvType,
episodes[0].data,
poster,
fixUrl(poster),
year,
description,
null,
@ -156,12 +149,12 @@ open class PelisplusProviderTemplate : MainAPI() {
val document = Jsoup.parse(response)
document.select("div.main-inner")?.forEach { inner ->
// Always trim your text unless you want the risk of spaces at the start or end.
val title = inner.select(".widget-title").text().trim()
val title = cleanName(inner.select(".widget-title").text())
val elements = inner.select(".video-block").map {
val link = fixUrl(it.select("a").attr("href"))
val image = it.select(".picture > img").attr("src").replace("//img", "https://img")
val name = it.select("div.name").text().trim().replace(Regex("""[Ee]pisode \d+"""), "")
val isSeries = (name.contains("Season") || name.contains("Episode"))
val name = cleanName(it.select("div.name").text())
val isSeries = (name.contains("Temporada") || name.contains("Capítulo"))
if (isSeries) {
TvSeriesSearchResponse(
@ -198,6 +191,38 @@ open class PelisplusProviderTemplate : MainAPI() {
return HomePageResponse(homePageList)
}
private fun cleanName(input: String): String = input.replace(Regex("([Tt]emporada (\\d+)|[Cc]apítulo (\\d+))|[Tt]emporada|[Cc]apítulo"),"").trim()
private suspend fun getPelisStream(
link: String,
callback: (ExtractorLink) -> Unit) : Boolean {
val soup = app.get(link).text
val m3u8regex = Regex("((https:|http:)\\/\\/.*m3u8.*expiry=(\\d+))")
val m3u8 = m3u8regex.find(soup)?.value ?: return false
M3u8Helper().m3u8Generation(
M3u8Helper.M3u8Stream(
m3u8,
headers = mapOf("Referer" to mainUrl)
), true
)
.map { stream ->
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
callback(
ExtractorLink(
name,
"$name $qualityString",
stream.streamUrl,
mainUrl,
getQualityFromName(stream.quality.toString()),
true
)
)
}
return true
}
// loadLinks gets the raw .mp4 or .m3u8 urls from the data parameter in the episodes class generated in load()
// See TvSeriesEpisode(...) in this provider.
// The data are usually links, but can be any other string to help aid loading the links.
@ -208,67 +233,37 @@ open class PelisplusProviderTemplate : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
// "?: return" is a very useful statement which returns if the iframe link isn't found.
val iframeLink = Jsoup.parse(app.get(data).text).selectFirst(".tab-video")?.attr("data-video") ?: return false
// In this case the video player is a vidstream clone and can be handled by the vidstream extractor.
// This case is a both unorthodox and you normally do not call extractors as they detect the url returned and does the rest.
val vidstreamObject = Pelisplus(pelisplusExtractorUrl ?: mainUrl)
// https://vidembed.cc/streaming.php?id=MzUwNTY2&... -> MzUwNTY2
val id = Regex("""id=([^?]*)""").find(iframeLink)?.groupValues?.get(1)
if (id != null) {
vidstreamObject.getUrl(id, isCasting, callback)
}
val html = app.get(fixUrl(iframeLink)).text
val soup = Jsoup.parse(html)
val servers = soup.select(".list-server-items > .linkserver").mapNotNull { li ->
if (!li?.attr("data-video").isNullOrEmpty()) {
Pair(li.text(), fixUrl(li.attr("data-video")))
} else {
null
}
}
servers.apmap {
// When checking strings make sure to make them lowercase and trimmed because edgecases like "beta server " wouldn't work otherwise.
if (it.first.trim().equals("beta server", ignoreCase = true)) {
// Group 1: link, Group 2: Label
// Regex can be used to effectively parse small amounts of json without bothering with writing a json class.
val sourceRegex = Regex("""sources:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""")
val trackRegex = Regex("""tracks:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""")
// Having a referer is often required. It's a basic security check most providers have.
// Try to replicate what your browser does.
val serverHtml = app.get(it.second, headers = mapOf("referer" to iframeLink)).text
sourceRegex.findAll(serverHtml).forEach { match ->
callback.invoke(
ExtractorLink(
this.name,
match.groupValues.getOrNull(2)?.let { "${this.name} $it" } ?: this.name,
match.groupValues[1],
it.second,
// Useful function to turn something like "1080p" to an app quality.
getQualityFromName(match.groupValues.getOrNull(2) ?: ""),
// Kinda risky
// isM3u8 makes the player pick the correct extractor for the source.
// If isM3u8 is wrong the player will error on that source.
URI(match.groupValues[1]).path.endsWith(".m3u8"),
)
)
}
trackRegex.findAll(serverHtml).forEach { match ->
subtitleCallback.invoke(
SubtitleFile(
match.groupValues.getOrNull(2) ?: "Unknown",
match.groupValues[1]
)
)
val doc = app.get(data).document
val info = doc.select("div.tabs-video li").text()
if (info.contains("Latino")) {
doc.select(".server-item-1 li").apmap {
val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play")
loadExtractor(serverid, data, callback)
if (serverid.contains("pelisplus.icu")) {
getPelisStream(serverid, callback)
}
}
}
if (info.contains("Subtitulado")) {
doc.select(".server-item-0 li").apmap {
val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play")
loadExtractor(serverid, data, callback)
if (serverid.contains("pelisplus.icu")) {
getPelisStream(serverid, callback)
}
}
}
if (info.contains("Castellano")) {
doc.select(".server-item-2 li").apmap {
val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play")
loadExtractor(serverid, data, callback)
if (serverid.contains("pelisplus.icu")) {
getPelisStream(serverid, callback)
}
}
}
return true
}
}

View file

@ -8,8 +8,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class PinoyHDXyzProvider : MainAPI() {
override val name = "Pinoy-HD"
override val mainUrl = "https://www.pinoy-hd.xyz"
override var name = "Pinoy-HD"
override var mainUrl = "https://www.pinoy-hd.xyz"
override val lang = "tl"
override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries)
override val hasDownloadSupport = true

View file

@ -9,8 +9,8 @@ import com.lagradost.cloudstream3.utils.loadExtractor
import java.lang.Exception
class PinoyMoviePediaProvider : MainAPI() {
override val name = "Pinoy Moviepedia"
override val mainUrl = "https://pinoymoviepedia.ru"
override var name = "Pinoy Moviepedia"
override var mainUrl = "https://pinoymoviepedia.ru"
override val lang = "tl"
override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries)
override val hasDownloadSupport = true

View file

@ -13,8 +13,8 @@ import org.jsoup.select.Elements
import java.lang.Exception
class PinoyMoviesEsProvider : MainAPI() {
override val name = "Pinoy Movies"
override val mainUrl = "https://pinoymovies.es"
override var name = "Pinoy Movies"
override var mainUrl = "https://pinoymovies.es"
override val lang = "tl"
override val supportedTypes = setOf(TvType.Movie)
override val hasDownloadSupport = false

View file

@ -7,8 +7,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class SeriesflixProvider : MainAPI() {
override val mainUrl = "https://seriesflix.video"
override val name = "Seriesflix"
override var mainUrl = "https://seriesflix.video"
override var name = "Seriesflix"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true

View file

@ -21,9 +21,18 @@ import org.jsoup.nodes.Element
import java.net.URI
import kotlin.system.measureTimeMillis
class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
override val mainUrl = providerUrl
override val name = providerName
class DopeboxProvider : SflixProvider() {
override var mainUrl = "https://dopebox.to"
override var name = "Dopebox"
}
class SolarmovieProvider : SflixProvider() {
override var mainUrl = "https://solarmovie.pe"
override var name = "Solarmovie"
}
open class SflixProvider() : MainAPI() {
override var mainUrl = "https://sflix.to"
override var name = "Sflix.to"
override val hasQuickSearch = false
override val hasMainPage = true

View file

@ -8,8 +8,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import java.util.*
class SoaptwoDayProvider:MainAPI() {
override val mainUrl = "https://secretlink.xyz" //Probably a rip off, but it has no captcha
override val name = "Soap2Day"
override var mainUrl = "https://secretlink.xyz" //Probably a rip off, but it has no captcha
override var name = "Soap2Day"
override val hasMainPage = true
override val hasChromecastSupport = true
override val hasDownloadSupport = true

View file

@ -12,8 +12,8 @@ import com.lagradost.cloudstream3.utils.SubtitleHelper
class TrailersTwoProvider : TmdbProvider() {
val user = "cloudstream"
override val apiName = "Trailers.to"
override val name = "Trailers.to"
override val mainUrl = "https://trailers.to"
override var name = "Trailers.to"
override var mainUrl = "https://trailers.to"
override val useMetaLoadResponse = true
override val instantLinkLoading = true

View file

@ -12,8 +12,8 @@ import com.lagradost.cloudstream3.utils.loadExtractor
class TwoEmbedProvider : TmdbProvider() {
override val apiName = "2Embed"
override val name = "2Embed"
override val mainUrl = "https://www.2embed.ru"
override var name = "2Embed"
override var mainUrl = "https://www.2embed.ru"
override val useMetaLoadResponse = true
override val instantLinkLoading = false
override val supportedTypes = setOf(

View file

@ -8,8 +8,8 @@ import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.Jsoup
class VMoveeProvider : MainAPI() {
override val name = "VMovee"
override val mainUrl = "https://www.vmovee.watch"
override var name = "VMovee"
override var mainUrl = "https://www.vmovee.watch"
override val supportedTypes = setOf(TvType.Movie)

View file

@ -7,8 +7,8 @@ import org.jsoup.Jsoup
// referer = https://vf-film.org, USERAGENT ALSO REQUIRED
class VfFilmProvider : MainAPI() {
override val mainUrl = "https://vf-film.me"
override val name = "vf-film.me"
override var mainUrl = "https://vf-film.me"
override var name = "vf-film.me"
override val lang = "fr"
override val hasQuickSearch = false
override val hasMainPage = false

View file

@ -7,8 +7,8 @@ import org.jsoup.Jsoup
// referer = https://vf-serie.org, USERAGENT ALSO REQUIRED
class VfSerieProvider : MainAPI() {
override val mainUrl = "https://vf-serie.org"
override val name = "vf-serie.org"
override var mainUrl = "https://vf-serie.org"
override var name = "vf-serie.org"
override val lang = "fr"
override val hasQuickSearch = false

View file

@ -7,10 +7,10 @@ import com.lagradost.cloudstream3.TvType
*/
class VidEmbedProvider : VidstreamProviderTemplate() {
// mainUrl is good to have as a holder for the url to make future changes easier.
override val mainUrl = "https://vidembed.cc"
override var mainUrl = "https://vidembed.cc"
// name is for how the provider will be named which is visible in the UI, no real rules for this.
override val name = "VidEmbed"
override var name = "VidEmbed"
override val homePageUrlList: List<String> = listOf(
mainUrl,

View file

@ -10,8 +10,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class WatchAsianProvider : MainAPI() {
override val mainUrl = "https://watchasian.sh"
override val name = "WatchAsian"
override var mainUrl = "https://watchasian.sh"
override var name = "WatchAsian"
override val hasQuickSearch = false
override val hasMainPage = true
override val hasChromecastSupport = false

View file

@ -6,8 +6,8 @@ import com.lagradost.cloudstream3.utils.extractorApis
class FrenchStreamProvider : MainAPI() {
override val mainUrl = "https://french-stream.re"
override val name = "French Stream"
override var mainUrl = "https://french-stream.re"
override var name = "French Stream"
override val hasQuickSearch = false
override val hasMainPage = true
override val lang = "fr"

View file

@ -26,11 +26,11 @@ import java.net.URL
import java.util.*
class AniListApi(index: Int) : AccountManager(index), SyncAPI {
override val name = "AniList"
override var name = "AniList"
override val key = "6871"
override val redirectUrl = "anilistlogin"
override val idPrefix = "anilist"
override val mainUrl = "https://anilist.co"
override var mainUrl = "https://anilist.co"
override val icon = R.drawable.ic_anilist_icon
override fun loginInfo(): OAuth2API.LoginInfo? {

View file

@ -5,7 +5,7 @@ import com.lagradost.cloudstream3.syncproviders.OAuth2API
//TODO dropbox sync
class Dropbox : OAuth2API {
override val idPrefix = "dropbox"
override val name = "Dropbox"
override var name = "Dropbox"
override val key = "zlqsamadlwydvb2"
override val redirectUrl = "dropboxlogin"

View file

@ -31,11 +31,11 @@ import java.util.*
const val MAL_MAX_SEARCH_LIMIT = 25
class MALApi(index: Int) : AccountManager(index), SyncAPI {
override val name = "MAL"
override var name = "MAL"
override val key = "1714d6f2f4f7cc19644384f8c4629910"
override val redirectUrl = "mallogin"
override val idPrefix = "mal"
override val mainUrl = "https://myanimelist.net"
override var mainUrl = "https://myanimelist.net"
override val icon = R.drawable.mal_logo
override fun logOut() {

View file

@ -6,10 +6,10 @@ import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.Jsoup
class NyaaProvider : MainAPI() {
override val name = "Nyaa"
override var name = "Nyaa"
override val hasChromecastSupport = false
override val mainUrl = "https://nyaa.si"
override var mainUrl = "https://nyaa.si"
override val supportedTypes = setOf(TvType.Torrent)
override val vpnStatus = VPNStatus.Torrent
override val instantLinkLoading = true

View file

@ -11,11 +11,11 @@ class APIRepository(val api: MainAPI) {
var dubStatusActive = HashSet<DubStatus>()
val noneApi = object : MainAPI() {
override val name = "None"
override var name = "None"
override val supportedTypes = emptySet<TvType>()
}
val randomApi = object : MainAPI() {
override val name = "Random"
override var name = "Random"
override val supportedTypes = emptySet<TvType>()
}

View file

@ -339,14 +339,21 @@ abstract class AbstractPlayerFragment(
SubtitlesFragment.applyStyleEvent += ::onSubStyleChanged
try {
context?.let {
context?.let { ctx ->
val settingsManager = PreferenceManager.getDefaultSharedPreferences(
it
ctx
)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_cache_key), 300)
player.cacheSize = currentPrefSize * 1024L * 1024L
val currentPrefCacheSize =
settingsManager.getInt(getString(R.string.video_buffer_size_key), 0)
val currentPrefDiskSize =
settingsManager.getInt(getString(R.string.video_buffer_disk_key), 0)
val currentPrefBufferSec =
settingsManager.getInt(getString(R.string.video_buffer_length_key), 0)
player.cacheSize = currentPrefCacheSize * 1024L * 1024L
player.simpleCacheSize = currentPrefDiskSize * 1024L * 1024L
player.videoBufferMs = currentPrefBufferSec * 1000L
}
} catch (e: Exception) {
logError(e)

View file

@ -39,8 +39,9 @@ const val TAG = "CS3ExoPlayer"
class CS3IPlayer : IPlayer {
private var isPlaying = false
private var exoPlayer: ExoPlayer? = null
var cacheSize = 300L * 1024L * 1024L // 300 mb
private val simpleCacheSize : Long get() = cacheSize / 2 // idk chosen at random kinda
var cacheSize = 0L
var simpleCacheSize = 0L
var videoBufferMs = 0L
private val seekActionTime = 30000L
@ -423,6 +424,7 @@ class CS3IPlayer : IPlayer {
playBackSpeed: Float,
subtitleOffset: Long,
cacheSize: Long,
videoBufferMs: Long,
playWhenReady: Boolean = true,
cacheFactory: CacheDataSource.Factory? = null,
trackSelector: TrackSelector? = null,
@ -460,10 +462,11 @@ class CS3IPlayer : IPlayer {
)
.setBufferDurationsMs(
DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
maxOf(
DefaultLoadControl.DEFAULT_MAX_BUFFER_MS,
((cacheSize * 75L) / 32768L).toInt()
), // 500mb = 20min
if(videoBufferMs <= 0) {
DefaultLoadControl.DEFAULT_MAX_BUFFER_MS
} else {
videoBufferMs.toInt()
},
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
).build()
@ -574,6 +577,7 @@ class CS3IPlayer : IPlayer {
playbackPosition,
playBackSpeed,
cacheSize = cacheSize,
videoBufferMs = videoBufferMs,
playWhenReady = isPlaying, // this keep the current state of the player
cacheFactory = cacheFactory,
subtitleOffset = currentSubtitleOffset

View file

@ -22,7 +22,6 @@ import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
import com.lagradost.cloudstream3.APIHolder.restrictedApis
import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.CommonActivity.setLocale
@ -205,26 +204,105 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}
fun getFolderSize(dir: File): Long {
var size: Long = 0
dir.listFiles()?.let {
for (file in it) {
size += if (file.isFile) {
// System.out.println(file.getName() + " " + file.length());
file.length()
} else getFolderSize(file)
}
}
return size
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard()
setPreferencesFromResource(R.xml.settings, rootKey)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.video_cache_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_cache_size_names)
val prefValues = resources.getIntArray(R.array.video_cache_size_values)
getPref(R.string.video_buffer_length_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_length_names)
val prefValues = resources.getIntArray(R.array.video_buffer_length_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_cache_key), 300)
settingsManager.getInt(getString(R.string.video_buffer_length_key), 0)
activity?.showBottomDialog(
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_cache_settings),
getString(R.string.video_buffer_length_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_cache_key), prefValues[it])
.putInt(getString(R.string.video_buffer_length_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
}
getPref(R.string.video_buffer_size_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_size_names)
val prefValues = resources.getIntArray(R.array.video_buffer_size_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_buffer_size_key), 0)
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_buffer_size_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_buffer_size_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
}
getPref(R.string.video_buffer_clear_key)?.let { pref ->
val cacheDir = context?.cacheDir ?: return@let
fun updateSummery() {
try {
pref.summary =
getString(R.string.mb_format).format(getFolderSize(cacheDir) / (1024L * 1024L))
} catch (e: Exception) {
logError(e)
}
}
updateSummery()
pref.setOnPreferenceClickListener {
try {
cacheDir.deleteRecursively()
updateSummery()
} catch (e: Exception) {
logError(e)
}
return@setOnPreferenceClickListener true
}
}
getPref(R.string.video_buffer_disk_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_size_names)
val prefValues = resources.getIntArray(R.array.video_buffer_size_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_buffer_disk_key), 0)
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_buffer_disk_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_buffer_disk_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
@ -301,9 +379,6 @@ class SettingsFragment : PreferenceFragmentCompat() {
for (api in apis) {
allLangs.add(api.lang)
}
for (api in restrictedApis) {
allLangs.add(api.lang)
}
val currentList = ArrayList<Int>()
for (i in current) {

View file

@ -323,18 +323,25 @@ class SubtitlesFragment : Fragment() {
val fontSizes = listOf(
Pair(null, textView.context.getString(R.string.normal)),
Pair(6f, "6$suffix"),
Pair(7f, "7$suffix"),
Pair(8f, "8$suffix"),
Pair(9f, "9$suffix"),
Pair(10f, "10$suffix"),
Pair(11f, "11$suffix"),
Pair(12f, "12$suffix"),
Pair(13f, "13$suffix"),
Pair(14f, "14$suffix"),
Pair(15f, "15$suffix"),
Pair(16f, "16$suffix"),
Pair(17f, "17$suffix"),
Pair(18f, "18$suffix"),
Pair(19f, "19$suffix"),
Pair(20f, "20$suffix"),
Pair(21f, "21$suffix"),
Pair(22f, "22$suffix"),
Pair(23f, "23$suffix"),
Pair(24f, "24$suffix"),
Pair(25f, "25$suffix"),
Pair(26f, "26$suffix"),
Pair(28f, "28$suffix"),
Pair(30f, "30$suffix"),

View file

@ -112,6 +112,7 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
StreamSB7(),
StreamSB8(),
StreamSB9(),
StreamSB10(),
// Streamhub(), cause Streamhub2() works
Streamhub2(),

View file

@ -232,7 +232,7 @@
<string name="dont_show_again">لا تظهر مرة أخرى</string>
<string name="update">تحديث</string>
<string name="watch_quality_pref">جودة المشاهدة المفضلة</string>
<string name="video_cache_settings">حجم ذاكرة التخزين المؤقت للفيديو</string>
<string name="video_buffer_size_settings">حجم ذاكرة التخزين المؤقت للفيديو</string>
<string name="dns_pref">DNS فوق HTTPS</string>
<string name="dns_pref_summary">مفيد لتجاوز كتل مزود خدمة الإنترنت</string>

View file

@ -186,7 +186,7 @@
\n%s -&gt; %s</string>
<string name="filler" formatted="true">Épisode spécial</string>
<string name="watch_quality_pref">Qualité de visionnage préférée</string>
<string name="video_cache_settings">Taille de la mémoire cache</string>
<string name="video_buffer_size_settings">Taille de la mémoire cache</string>
<string name="resize_fill">Étendre</string>
<string name="legal_notice">Non-responsabilité</string>
<string name="primary_color_settings">Couleur principale</string>

View file

@ -269,7 +269,7 @@
<string name="dont_show_again">Non mostrare di nuovo</string>
<string name="update">Aggiorna</string>
<string name="watch_quality_pref">Risoluzione preferita</string>
<string name="video_cache_settings">Dimensione cache video</string>
<string name="video_buffer_size_settings">Dimensione cache video</string>
<string name="dns_pref">DNS over HTTPS</string>
<string name="dns_pref_summary">Utile per bypassare i blocchi ISP</string>

View file

@ -232,7 +232,7 @@
<string name="dont_show_again">Không hiển thị lại</string>
<string name="update">Cập nhật</string>
<string name="watch_quality_pref">Tự động chọn chất lượng phim</string>
<string name="video_cache_settings">Kích thước video cache</string>
<string name="video_buffer_size_settings">Kích thước video cache</string>
<string name="dns_pref_summary">Rất hữu ích để bỏ chặn ISP</string>
<string name="download_path_pref">Đường dẫn tải xuống</string>

View file

@ -56,20 +56,88 @@
<item>1</item>
<item>2</item>
</array>
<array name="video_cache_size_names">
<item>@string/none</item>
<array name="video_buffer_length_names">
<item>@string/automatic</item>
<item>1min</item>
<item>1min 30s</item>
<item>2min</item>
<item>2min 30s</item>
<item>3min</item>
<item>3min 30s</item>
<item>4min</item>
<item>5min</item>
<item>6min</item>
<item>7min</item>
<item>8min</item>
<item>9min</item>
<item>10min</item>
<item>15min</item>
<item>20min</item>
<item>30min</item>
</array>
<array name="video_buffer_length_values">
<item>0</item>
<item>60</item>
<item>90</item>
<item>120</item>
<item>150</item>
<item>180</item>
<item>210</item>
<item>240</item>
<item>300</item>
<item>360</item>
<item>420</item>
<item>480</item>
<item>540</item>
<item>600</item>
<item>900</item>
<item>1200</item>
<item>1800</item>
</array>
<array name="video_buffer_size_names">
<item>@string/automatic</item>
<item>10MB</item>
<item>20MB</item>
<item>30MB</item>
<item>40MB</item>
<item>50MB</item>
<item>60MB</item>
<item>70MB</item>
<item>80MB</item>
<item>90MB</item>
<item>100MB</item>
<item>150MB</item>
<item>200MB</item>
<item>250MB</item>
<item>300MB</item>
<item>350MB</item>
<item>400MB</item>
<item>450MB</item>
<item>500MB</item>
</array>
<array name="video_cache_size_values">
<array name="video_buffer_size_values">
<item>0</item>
<item>10</item>
<item>20</item>
<item>30</item>
<item>40</item>
<item>50</item>
<item>60</item>
<item>70</item>
<item>80</item>
<item>90</item>
<item>100</item>
<item>150</item>
<item>200</item>
<item>250</item>
<item>300</item>
<item>350</item>
<item>400</item>
<item>450</item>
<item>500</item>
</array>

View file

@ -13,7 +13,10 @@
<string name="subtitle_settings_key" translatable="false">subtitle_settings_key</string>
<string name="subtitle_settings_chromecast_key" translatable="false">subtitle_settings_chromecast_key</string>
<string name="quality_pref_key" translatable="false">quality_pref_key</string>
<string name="video_cache_key" translatable="false">video_cache_key</string>
<string name="video_buffer_size_key" translatable="false">video_buffer_size_key</string>
<string name="video_buffer_length_key" translatable="false">video_buffer_length_key</string>
<string name="video_buffer_clear_key" translatable="false">video_buffer_clear_key</string>
<string name="video_buffer_disk_key" translatable="false">video_buffer_disk_key</string>
<string name="prerelease_commit_hash" translatable="false">unknown_prerelease</string>
<string name="use_system_brightness_key" translatable="false">use_system_brightness_key</string>
<string name="swipe_enabled_key" translatable="false">swipe_enabled_key</string>
@ -32,6 +35,7 @@
<string name="app_layout_key" translatable="false">app_layout_key</string>
<string name="primary_color_key" translatable="false">primary_color_key</string>
<string name="restore_key" translatable="false">restore_key</string>
<string name="killswitch_key" translatable="false">killswitch_key</string>
<string name="backup_key" translatable="false">backup_key</string>
<string name="prefer_media_type_key" translatable="false">prefer_media_type_key</string>
<string name="app_theme_key" translatable="false">app_theme_key</string>
@ -41,6 +45,7 @@
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
<string name="mb_format" translatable="false" formatted="true">%dMB</string>
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
@ -198,6 +203,9 @@
</string>
<string name="restore_settings">Restore data from backup</string>
<string name="killswitch_settings">Download latest metadata from github</string>
<string name="killswitch_settings_des">If you want access to all providers (even broken ones) turn this off</string>
<string name="backup_settings">Backup data</string>
<string name="restore_success">Loaded backup file</string>
<string name="restore_failed_format" formatted="true">Failed to restore data from file %s</string>
@ -315,7 +323,14 @@
<string name="dont_show_again">Don\'t show again</string>
<string name="update">Update</string>
<string name="watch_quality_pref">Preferred watch quality</string>
<string name="video_cache_settings">Video cache size</string>
<string name="video_buffer_size_settings">Video buffer size</string>
<string name="video_buffer_length_settings">Video buffer length</string>
<string name="video_buffer_disk_settings">Video cache on disk</string>
<string name="video_buffer_clear_settings">Clear video and image cache</string>
<string name="video_ram_description">May cause problems on systems with low ram such as Android TV devices or old phones if you set it too high</string>
<string name="video_disk_description">May cause problems on systems with low storage space such as Android TV devices if you set it too high</string>
<string name="dns_pref">DNS over HTTPS</string>
<string name="dns_pref_summary">Useful for bypassing ISP blocks</string>

View file

@ -20,10 +20,7 @@
android:key="@string/quality_pref_key"
android:title="@string/watch_quality_pref"
android:icon="@drawable/ic_baseline_hd_24" />
<Preference
android:key="@string/video_cache_key"
android:title="@string/video_cache_settings"
android:icon="@drawable/ic_baseline_storage_24" />
<SwitchPreference
android:icon="@drawable/ic_baseline_picture_in_picture_alt_24"
app:key="@string/pip_enabled_key"
@ -66,6 +63,28 @@
android:title="@string/double_tap_to_pause_settings"
android:summary="@string/double_tap_to_pause_settings_des"
app:defaultValue="false" />
<Preference
android:key="@string/video_buffer_disk_key"
android:title="@string/video_buffer_disk_settings"
android:summary="@string/video_disk_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_size_key"
android:title="@string/video_buffer_size_settings"
android:summary="@string/video_ram_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_length_key"
android:title="@string/video_buffer_length_settings"
android:summary="@string/video_ram_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_clear_key"
android:title="@string/video_buffer_clear_settings"
android:icon="@drawable/ic_baseline_delete_outline_24" />
<!--
<SwitchPreference
android:icon="@drawable/ic_baseline_brightness_7_24"
@ -179,6 +198,13 @@
android:key="@string/restore_key"
android:title="@string/restore_settings" />
<SwitchPreference
android:icon="@drawable/netflix_download"
android:key="@string/killswitch_key"
android:defaultValue="true"
android:summary="@string/killswitch_settings_des"
android:title="@string/killswitch_settings" />
<Preference
android:key="@string/mal_key"
android:icon="@drawable/mal_logo" />

282
providers.json Normal file
View file

@ -0,0 +1,282 @@
{
"AkwamProvider": {
"name": "Akwam",
"url": "https://akwam.to",
"status": 1
},
"AllAnimeProvider": {
"name": "AllAnime",
"url": "https://allanime.site",
"status": 1
},
"AllMoviesForYouProvider": {
"name": "AllMoviesForYou",
"url": "https://allmoviesforyou.net",
"status": 1
},
"AnimeFlickProvider": {
"name": "AnimeFlick",
"url": "https://animeflick.net",
"status": 1
},
"AnimePaheProvider": {
"name": "AnimePahe",
"url": "https://animepahe.com",
"status": 1
},
"AnimeWorldProvider": {
"name": "AnimeWorld",
"url": "https://www.animeworld.tv",
"status": 1
},
"AnimeflvnetProvider": {
"name": "Animeflv.net",
"url": "https://www3.animeflv.net",
"status": 1
},
"AnimekisaProvider": {
"name": "Animekisa",
"url": "https://animekisa.in",
"status": 1
},
"AsianLoadProvider": {
"name": "AsianLoad",
"url": "https://asianembed.io",
"status": 1
},
"AsiaFlixProvider": {
"name": "AsiaFlix",
"url": "https://asiaflix.app",
"status": 3
},
"BflixProvider": {
"name": "Bflix",
"url": "https://bflix.ru",
"status": 1
},
"FmoviesToProvider": {
"name": "Fmovies.to",
"url": "https://fmovies.to",
"status": 1
},
"SflixProProvider": {
"name": "Sflix.pro",
"url": "https://sflix.pro",
"status": 1
},
"CinecalidadProvider": {
"name": "Cinecalidad",
"url": "https://cinecalidad.lol",
"status": 1
},
"CrossTmdbProvider": {
"name": "MultiMovie",
"url": "NONE",
"status": 1
},
"CuevanaProvider": {
"name": "Cuevana",
"url": "https://cuevana3.me",
"status": 1
},
"DoramasYTProvider": {
"name": "DoramasYT",
"url": "https://doramasyt.com",
"status": 1
},
"DramaSeeProvider": {
"name": "DramaSee",
"url": "https://dramasee.net",
"status": 1
},
"DubbedAnimeProvider": {
"name": "DubbedAnime",
"url": "https://bestdubbedanime.com",
"status": 1
},
"EgyBestProvider": {
"name": "EgyBest",
"url": "https://egy.best",
"status": 1
},
"EntrepeliculasyseriesProvider": {
"name": "EntrePeliculasySeries",
"url": "https://entrepeliculasyseries.nu",
"status": 1
},
"FilmanProvider": {
"name": "filman.cc",
"url": "https://filman.cc",
"status": 1
},
"FrenchStreamProvider": {
"name": "French Stream",
"url": "https://french-stream.re",
"status": 1
},
"GogoanimeProvider": {
"name": "GogoAnime",
"url": "https://gogoanime.film",
"status": 1
},
"KawaiifuProvider": {
"name": "Kawaiifu",
"url": "https://kawaiifu.com",
"status": 0
},
"HDMProvider": {
"name": "HD Movies",
"url": "https://hdm.to",
"status": 0
},
"IHaveNoTvProvider": {
"name": "I Have No TV",
"url": "https://ihavenotv.com",
"status": 1
},
"KdramaHoodProvider": {
"name": "KDramaHood",
"url": "https://kdramahood.com",
"status": 1
},
"LookMovieProvider": {
"name": "LookMovie",
"url": "https://lookmovie.io",
"status": 0
},
"MeloMovieProvider": {
"name": "MeloMovie",
"url": "https://melomovie.com",
"status": 0
},
"MonoschinosProvider": {
"name": "Monoschinos",
"url": "https://monoschinos2.com",
"status": 1
},
"MyCimaProvider": {
"name": "MyCima",
"url": "https://mycima.tv",
"status": 1
},
"NineAnimeProvider": {
"name": "9Anime",
"url": "https://9anime.center",
"status": 1
},
"PeliSmartProvider": {
"name": "PeliSmart",
"url": "https://pelismart.com",
"status": 1
},
"PelisflixProvider": {
"name": "Pelisflix",
"url": "https://pelisflix.li",
"status": 1
},
"PelisplusHDProvider": {
"name": "PelisplusHD",
"url": "https://pelisplushd.net",
"status": 1
},
"PelisplusProvider": {
"name": "Pelisplus",
"url": "https://pelisplus.icu",
"status": 1
},
"PinoyHDXyzProvider": {
"name": "Pinoy-HD",
"url": "https://www.pinoy-hd.xyz",
"status": 1
},
"PinoyMoviePediaProvider": {
"name": "Pinoy Moviepedia",
"url": "https://pinoymoviepedia.ru",
"status": 1
},
"PinoyMoviesEsProvider": {
"name": "Pinoy Movies",
"url": "https://pinoymovies.es",
"status": 1
},
"SflixProvider": {
"name": "Sflix.to",
"url": "https://sflix.to",
"status": 1
},
"DopeboxProvider": {
"name": "Dopebox",
"url": "https://dopebox.to",
"status": 1
},
"SolarmovieProvider": {
"name": "Solarmovie",
"url": "https://solarmovie.pe",
"status": 1
},
"SeriesflixProvider": {
"name": "Seriesflix",
"url": "https://seriesflix.video",
"status": 1
},
"SoaptwoDayProvider": {
"name": "Soap2Day",
"url": "https://secretlink.xyz",
"status": 1
},
"TenshiProvider": {
"name": "Tenshi.moe",
"url": "https://tenshi.moe",
"status": 1
},
"TrailersTwoProvider": {
"name": "Trailers.to",
"url": "https://trailers.to",
"status": 1
},
"TwoEmbedProvider": {
"name": "2Embed",
"url": "https://www.2embed.ru",
"status": 1
},
"VMoveeProvider": {
"name": "VMovee",
"url": "https://www.vmovee.watch",
"status": 1
},
"VfFilmProvider": {
"name": "vf-film.me",
"url": "https://vf-film.me",
"status": 1
},
"VfSerieProvider": {
"name": "vf-serie.org",
"url": "https://vf-serie.org",
"status": 1
},
"VidEmbedProvider": {
"name": "VidEmbed",
"url": "https://vidembed.cc",
"status": 1
},
"WatchAsianProvider": {
"name": "WatchAsian",
"url": "https://watchasian.sh",
"status": 1
},
"WatchCartoonOnlineProvider": {
"name": "WatchCartoonOnline",
"url": "https://www.wcostream.com",
"status": 1
},
"WcoProvider": {
"name": "WCO Stream",
"url": "https://wcostream.cc",
"status": 1
},
"ZoroProvider": {
"name": "Zoro",
"url": "https://zoro.to",
"status": 1
}
}