mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
e5515b575c
22 changed files with 1010 additions and 437 deletions
77
.github/site-list.py
vendored
77
.github/site-list.py
vendored
|
@ -1,63 +1,54 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from re import findall, compile, sub, DOTALL
|
from re import findall, compile, DOTALL
|
||||||
|
from json import dump, load
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
|
|
||||||
# Globals
|
# Globals
|
||||||
URL_REGEX = compile(
|
URL_REGEX = compile(
|
||||||
"override\sva[lr]\smainUrl[^\"']+[\"'](https?://[a-zA-Z0-9\.-]+)[\"']")
|
"override\sva[lr]\smainUrl[^\"']+[\"'](https?://[a-zA-Z0-9\.-]+)[\"']")
|
||||||
NAME_REGEX = compile("class (.+?) ?: \w+\(\)\s\{")
|
NAME_REGEX = compile("([A-Za-z0-9]+)(?:.kt)$")
|
||||||
START_MARKER = "<!--SITE LIST START-->"
|
JSON_PATH = "docs/providers.json"
|
||||||
END_MARKER = "<!--SITE LIST END-->"
|
|
||||||
GLOB = "app/src/main/java/com/lagradost/cloudstream3/*providers/*Provider.kt"
|
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\s*allProviders.*?{\s.*?arrayListOf\(([\W\w]*?)\)\s*\n*\s*}", DOTALL)
|
|
||||||
|
|
||||||
sites: Dict[str, str] = {}
|
old_sites: Dict[str, Dict] = load(open(JSON_PATH, "r", encoding="utf-8"))
|
||||||
enabled_sites: List[str] = []
|
sites: Dict[str, Dict] = {}
|
||||||
|
|
||||||
|
|
||||||
with open(MAIN_API, "r", encoding="utf-8") as f:
|
|
||||||
apis = findall(API_REGEX, f.read())
|
|
||||||
for api_list in apis:
|
|
||||||
for api in api_list.split("\n"):
|
|
||||||
if not api.strip() or api.strip().startswith("/"):
|
|
||||||
continue
|
|
||||||
enabled_sites.append(api.strip().split("(")[0])
|
|
||||||
|
|
||||||
|
# parse all *Provider.kt files
|
||||||
for path in glob(GLOB):
|
for path in glob(GLOB):
|
||||||
with open(path, "r", encoding='utf-8') as file:
|
with open(path, "r", encoding='utf-8') as file:
|
||||||
try:
|
try:
|
||||||
site_text: str = file.read()
|
site_text: str = file.read()
|
||||||
name: List[str] = findall(NAME_REGEX, site_text)
|
name: str = findall(NAME_REGEX, path)[0]
|
||||||
provider_text: str = findall(URL_REGEX, site_text)
|
provider_url: str = [*findall(URL_REGEX, site_text), ""][0]
|
||||||
|
|
||||||
if name:
|
if name in old_sites.keys(): # if already in previous list use old status and name
|
||||||
if name[0] not in enabled_sites:
|
sites[name] = {
|
||||||
continue
|
"name": old_sites[name]['name'],
|
||||||
sites[name[0]] = provider_text[0]
|
"url": provider_url if provider_url else old_sites[name]['url'],
|
||||||
|
"status": old_sites[name]['status']
|
||||||
|
}
|
||||||
|
else: # if not in previous list add with new data
|
||||||
|
display_name = name
|
||||||
|
if display_name.endswith("Provider"):
|
||||||
|
display_name = display_name[:-len("Provider")]
|
||||||
|
sites[name] = {
|
||||||
|
"name": display_name,
|
||||||
|
"url": provider_url if provider_url else "",
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("{0}: {1}".format(path, ex))
|
print("{0}: {1}".format(path, ex))
|
||||||
|
|
||||||
|
# add sites from old_sites that are missing in new list
|
||||||
|
for name in old_sites.keys():
|
||||||
|
if name not in sites.keys():
|
||||||
|
sites[name] = {
|
||||||
|
"name": old_sites[name]['name'],
|
||||||
|
"url": old_sites[name]['url'],
|
||||||
|
"status": old_sites[name]['status']
|
||||||
|
}
|
||||||
|
|
||||||
|
dump(sites, open(JSON_PATH, "w+", encoding="utf-8"), indent=4, sort_keys=True)
|
||||||
with open("README.md", "r+", encoding='utf-8') as readme:
|
|
||||||
raw = readme.read()
|
|
||||||
if START_MARKER not in raw or END_MARKER not in raw:
|
|
||||||
raise RuntimeError("Missing start and end markers")
|
|
||||||
readme.seek(0)
|
|
||||||
|
|
||||||
readme.write(raw.split(START_MARKER)[0])
|
|
||||||
readme.write(START_MARKER+"\n")
|
|
||||||
|
|
||||||
for site in enabled_sites:
|
|
||||||
if site in sites:
|
|
||||||
readme.write(
|
|
||||||
"- [{0}]({1}) \n".format(sub("^https?://(?:www\.)?", "", sites[site]), sites[site]))
|
|
||||||
|
|
||||||
readme.write(END_MARKER)
|
|
||||||
readme.write(raw.split(END_MARKER)[-1])
|
|
||||||
|
|
||||||
readme.truncate()
|
|
||||||
|
|
4
.github/workflows/site_list.yml
vendored
4
.github/workflows/site_list.yml
vendored
|
@ -4,10 +4,10 @@ on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
paths:
|
paths:
|
||||||
- 'README.md'
|
|
||||||
- 'app/src/main/java/com/lagradost/cloudstream3/*providers/*Provider.kt'
|
- 'app/src/main/java/com/lagradost/cloudstream3/*providers/*Provider.kt'
|
||||||
- '.github/workflows/site_list.yml'
|
- '.github/workflows/site_list.yml'
|
||||||
- '.github/site-list.py'
|
- '.github/site-list.py'
|
||||||
|
- 'docs/providers.json'
|
||||||
- 'app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt'
|
- 'app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt'
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
@ -19,7 +19,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Edit README.md
|
- name: Edit providers.json
|
||||||
run: |
|
run: |
|
||||||
python3 .github/site-list.py
|
python3 .github/site-list.py
|
||||||
- name: Commit to the repo
|
- name: Commit to the repo
|
||||||
|
|
52
README.md
52
README.md
|
@ -58,53 +58,5 @@ It merely scrapes 3rd-party websites that are publicly accessable via any regula
|
||||||
|
|
||||||
|
|
||||||
***Sites used:***
|
***Sites used:***
|
||||||
https://lagradost.github.io/CloudStream-3/
|
|
||||||
<!-- Do not remove those two comments -->
|
Look [here](https://lagradost.github.io/CloudStream-3/) for a comprehensive list
|
||||||
<!--SITE LIST START-->
|
|
||||||
- [pelisplus.icu](https://pelisplus.icu)
|
|
||||||
- [pelismart.com](https://pelismart.com)
|
|
||||||
- [melomovie.com](https://melomovie.com)
|
|
||||||
- [doramasyt.com](https://doramasyt.com)
|
|
||||||
- [cuevana3.me](https://cuevana3.me)
|
|
||||||
- [pelisflix.li](https://pelisflix.li)
|
|
||||||
- [seriesflix.video](https://seriesflix.video)
|
|
||||||
- [ihavenotv.com](https://ihavenotv.com)
|
|
||||||
- [lookmovie.io](https://lookmovie.io)
|
|
||||||
- [vmovee.watch](https://www.vmovee.watch)
|
|
||||||
- [allmoviesforyou.net](https://allmoviesforyou.net)
|
|
||||||
- [vidembed.cc](https://vidembed.cc)
|
|
||||||
- [vf-film.me](https://vf-film.me)
|
|
||||||
- [vf-serie.org](https://vf-serie.org)
|
|
||||||
- [asianembed.io](https://asianembed.io)
|
|
||||||
- [asiaflix.app](https://asiaflix.app)
|
|
||||||
- [fmovies.to](https://fmovies.to)
|
|
||||||
- [filman.cc](https://filman.cc)
|
|
||||||
- [dopebox.to](https://dopebox.to)
|
|
||||||
- [pinoymoviepedia.ru](https://pinoymoviepedia.ru)
|
|
||||||
- [pinoy-hd.xyz](https://www.pinoy-hd.xyz)
|
|
||||||
- [pinoymovies.es](https://pinoymovies.es)
|
|
||||||
- [trailers.to](https://trailers.to)
|
|
||||||
- [2embed.ru](https://www.2embed.ru)
|
|
||||||
- [dramasee.net](https://dramasee.net)
|
|
||||||
- [watchasian.sh](https://watchasian.sh)
|
|
||||||
- [kdramahood.com](https://kdramahood.com)
|
|
||||||
- [akwam.to](https://akwam.to)
|
|
||||||
- [mycima.tv](https://mycima.tv)
|
|
||||||
- [egy.best](https://egy.best)
|
|
||||||
- [hdm.to](https://hdm.to)
|
|
||||||
- [theflix.to](https://theflix.to)
|
|
||||||
- [v2.apimdb.net](https://v2.apimdb.net)
|
|
||||||
- [wcostream.com](https://www.wcostream.com)
|
|
||||||
- [gogoanime.film](https://gogoanime.film)
|
|
||||||
- [allanime.site](https://allanime.site)
|
|
||||||
- [animekisa.in](https://animekisa.in)
|
|
||||||
- [animeflick.net](https://animeflick.net)
|
|
||||||
- [tenshi.moe](https://tenshi.moe)
|
|
||||||
- [wcostream.cc](https://wcostream.cc)
|
|
||||||
- [9anime.id](https://9anime.id)
|
|
||||||
- [animeworld.tv](https://www.animeworld.tv)
|
|
||||||
- [zoro.to](https://zoro.to)
|
|
||||||
- [bestdubbedanime.com](https://bestdubbedanime.com)
|
|
||||||
- [monoschinos2.com](https://monoschinos2.com)
|
|
||||||
- [kawaiifu.com](https://kawaiifu.com)
|
|
||||||
<!--SITE LIST END-->
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.malApi
|
||||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import okhttp3.Headers
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -107,6 +108,7 @@ object APIHolder {
|
||||||
MonoschinosProvider(),
|
MonoschinosProvider(),
|
||||||
KawaiifuProvider(), // disabled due to cloudflare
|
KawaiifuProvider(), // disabled due to cloudflare
|
||||||
//MultiAnimeProvider(),
|
//MultiAnimeProvider(),
|
||||||
|
NginxProvider(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,6 +309,7 @@ const val PROVIDER_STATUS_DOWN = 0
|
||||||
data class ProvidersInfoJson(
|
data class ProvidersInfoJson(
|
||||||
@JsonProperty("name") var name: String,
|
@JsonProperty("name") var name: String,
|
||||||
@JsonProperty("url") var url: String,
|
@JsonProperty("url") var url: String,
|
||||||
|
@JsonProperty("credentials") var credentials: String? = null,
|
||||||
@JsonProperty("status") var status: Int,
|
@JsonProperty("status") var status: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -319,6 +322,7 @@ abstract class MainAPI {
|
||||||
fun overrideWithNewData(data: ProvidersInfoJson) {
|
fun overrideWithNewData(data: ProvidersInfoJson) {
|
||||||
this.name = data.name
|
this.name = data.name
|
||||||
this.mainUrl = data.url
|
this.mainUrl = data.url
|
||||||
|
this.storedCredentials = data.credentials
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -329,6 +333,7 @@ abstract class MainAPI {
|
||||||
|
|
||||||
open var name = "NONE"
|
open var name = "NONE"
|
||||||
open var mainUrl = "NONE"
|
open var mainUrl = "NONE"
|
||||||
|
open var storedCredentials: String? = null
|
||||||
|
|
||||||
//open val uniqueId : Int by lazy { this.name.hashCode() } // in case of duplicate providers you can have a shared id
|
//open val uniqueId : Int by lazy { this.name.hashCode() } // in case of duplicate providers you can have a shared id
|
||||||
|
|
||||||
|
@ -591,17 +596,22 @@ fun getQualityFromString(string: String?): SearchQuality? {
|
||||||
"cam" -> SearchQuality.Cam
|
"cam" -> SearchQuality.Cam
|
||||||
"camrip" -> SearchQuality.CamRip
|
"camrip" -> SearchQuality.CamRip
|
||||||
"hdcam" -> SearchQuality.HdCam
|
"hdcam" -> SearchQuality.HdCam
|
||||||
|
"hdtc" -> SearchQuality.HdCam
|
||||||
|
"hdts" -> SearchQuality.HdCam
|
||||||
"highquality" -> SearchQuality.HQ
|
"highquality" -> SearchQuality.HQ
|
||||||
"hq" -> SearchQuality.HQ
|
"hq" -> SearchQuality.HQ
|
||||||
"highdefinition" -> SearchQuality.HD
|
"highdefinition" -> SearchQuality.HD
|
||||||
"hdrip" -> SearchQuality.HD
|
"hdrip" -> SearchQuality.HD
|
||||||
"hd" -> SearchQuality.HD
|
"hd" -> SearchQuality.HD
|
||||||
|
"hdtv" -> SearchQuality.HD
|
||||||
"rip" -> SearchQuality.CamRip
|
"rip" -> SearchQuality.CamRip
|
||||||
"telecine" -> SearchQuality.Telecine
|
"telecine" -> SearchQuality.Telecine
|
||||||
"tc" -> SearchQuality.Telecine
|
"tc" -> SearchQuality.Telecine
|
||||||
"telesync" -> SearchQuality.Telesync
|
"telesync" -> SearchQuality.Telesync
|
||||||
"ts" -> SearchQuality.Telesync
|
"ts" -> SearchQuality.Telesync
|
||||||
"dvd" -> SearchQuality.DVD
|
"dvd" -> SearchQuality.DVD
|
||||||
|
"dvdrip" -> SearchQuality.DVD
|
||||||
|
"dvdscr" -> SearchQuality.DVD
|
||||||
"blueray" -> SearchQuality.BlueRay
|
"blueray" -> SearchQuality.BlueRay
|
||||||
"bluray" -> SearchQuality.BlueRay
|
"bluray" -> SearchQuality.BlueRay
|
||||||
"br" -> SearchQuality.BlueRay
|
"br" -> SearchQuality.BlueRay
|
||||||
|
@ -613,6 +623,7 @@ fun getQualityFromString(string: String?): SearchQuality? {
|
||||||
"wp" -> SearchQuality.WorkPrint
|
"wp" -> SearchQuality.WorkPrint
|
||||||
"workprint" -> SearchQuality.WorkPrint
|
"workprint" -> SearchQuality.WorkPrint
|
||||||
"webrip" -> SearchQuality.WebRip
|
"webrip" -> SearchQuality.WebRip
|
||||||
|
"webdl" -> SearchQuality.WebRip
|
||||||
"web" -> SearchQuality.WebRip
|
"web" -> SearchQuality.WebRip
|
||||||
"hdr" -> SearchQuality.HDR
|
"hdr" -> SearchQuality.HDR
|
||||||
"sdr" -> SearchQuality.SDR
|
"sdr" -> SearchQuality.SDR
|
||||||
|
|
|
@ -64,12 +64,14 @@ import com.lagradost.cloudstream3.utils.UIHelper.getResourceColor
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
||||||
|
import com.lagradost.cloudstream3.movieproviders.NginxProvider
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.collections.HashMap
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
|
||||||
|
@ -360,6 +362,57 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
fun addNginxToJson(data: java.util.HashMap<String, ProvidersInfoJson>): java.util.HashMap<String, ProvidersInfoJson>? {
|
||||||
|
try {
|
||||||
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
val nginxUrl =
|
||||||
|
settingsManager.getString(getString(R.string.nginx_url_key), "nginx_url_key").toString()
|
||||||
|
val nginxCredentials =
|
||||||
|
settingsManager.getString(getString(R.string.nginx_credentials), "nginx_credentials")
|
||||||
|
.toString()
|
||||||
|
val StoredNginxProvider = NginxProvider()
|
||||||
|
if (nginxUrl == "nginx_url_key" || nginxUrl == "") { // if key is default value, or empty:
|
||||||
|
data[StoredNginxProvider.javaClass.simpleName] = ProvidersInfoJson(
|
||||||
|
url = nginxUrl,
|
||||||
|
name = StoredNginxProvider.name,
|
||||||
|
status = PROVIDER_STATUS_DOWN, // the provider will not be display
|
||||||
|
credentials = nginxCredentials
|
||||||
|
)
|
||||||
|
} else { // valid url
|
||||||
|
data[StoredNginxProvider.javaClass.simpleName] = ProvidersInfoJson(
|
||||||
|
url = nginxUrl,
|
||||||
|
name = StoredNginxProvider.name,
|
||||||
|
status = PROVIDER_STATUS_OK,
|
||||||
|
credentials = nginxCredentials
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun createNginxJson() : ProvidersInfoJson? { //java.util.HashMap<String, ProvidersInfoJson>
|
||||||
|
return try {
|
||||||
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
val nginxUrl = settingsManager.getString(getString(R.string.nginx_url_key), "nginx_url_key").toString()
|
||||||
|
val nginxCredentials = settingsManager.getString(getString(R.string.nginx_credentials), "nginx_credentials").toString()
|
||||||
|
if (nginxUrl == "nginx_url_key" || nginxUrl == "") { // if key is default value or empty:
|
||||||
|
null // don't overwrite anything
|
||||||
|
} else {
|
||||||
|
ProvidersInfoJson(
|
||||||
|
url = nginxUrl,
|
||||||
|
name = NginxProvider().name,
|
||||||
|
status = PROVIDER_STATUS_OK,
|
||||||
|
credentials = nginxCredentials
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this pulls the latest data so ppl don't have to update to simply change provider url
|
// this pulls the latest data so ppl don't have to update to simply change provider url
|
||||||
if (downloadFromGithub) {
|
if (downloadFromGithub) {
|
||||||
|
@ -379,8 +432,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
tryParseJson<HashMap<String, ProvidersInfoJson>>(txt)
|
tryParseJson<HashMap<String, ProvidersInfoJson>>(txt)
|
||||||
setKey(PROVIDER_STATUS_KEY, txt)
|
setKey(PROVIDER_STATUS_KEY, txt)
|
||||||
MainAPI.overrideData = newCache // update all new providers
|
MainAPI.overrideData = newCache // update all new providers
|
||||||
for (api in apis) { // update current providers
|
|
||||||
newCache?.get(api.javaClass.simpleName)?.let { data ->
|
val newUpdatedCache = newCache?.let { addNginxToJson(it) ?: it }
|
||||||
|
|
||||||
|
for (api in apis) { // update current providers
|
||||||
|
newUpdatedCache?.get(api.javaClass.simpleName)?.let { data ->
|
||||||
api.overrideWithNewData(data)
|
api.overrideWithNewData(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,12 +453,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
newCache
|
newCache
|
||||||
}?.let { providersJsonMap ->
|
}?.let { providersJsonMap ->
|
||||||
MainAPI.overrideData = providersJsonMap
|
MainAPI.overrideData = providersJsonMap
|
||||||
|
val providersJsonMapUpdated = addNginxToJson(providersJsonMap)?: providersJsonMap // if return null, use unchanged one
|
||||||
val acceptableProviders =
|
val acceptableProviders =
|
||||||
providersJsonMap.filter { it.value.status == PROVIDER_STATUS_OK || it.value.status == PROVIDER_STATUS_SLOW }
|
providersJsonMapUpdated.filter { it.value.status == PROVIDER_STATUS_OK || it.value.status == PROVIDER_STATUS_SLOW }
|
||||||
.map { it.key }.toSet()
|
.map { it.key }.toSet()
|
||||||
|
|
||||||
val restrictedApis =
|
val restrictedApis =
|
||||||
if (hasBenene) providersJsonMap.filter { it.value.status == PROVIDER_STATUS_BETA_ONLY }
|
if (hasBenene) providersJsonMapUpdated.filter { it.value.status == PROVIDER_STATUS_BETA_ONLY }
|
||||||
.map { it.key }.toSet() else emptySet()
|
.map { it.key }.toSet() else emptySet()
|
||||||
|
|
||||||
apis = allProviders.filter { api ->
|
apis = allProviders.filter { api ->
|
||||||
|
@ -425,6 +482,17 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
apis = allProviders
|
apis = allProviders
|
||||||
|
try {
|
||||||
|
val nginxProviderName = NginxProvider().name
|
||||||
|
val nginxProviderIndex = apis.indexOf(APIHolder.getApiFromName(nginxProviderName))
|
||||||
|
val createdJsonProvider = createNginxJson()
|
||||||
|
if (createdJsonProvider != null) {
|
||||||
|
apis[nginxProviderIndex].overrideWithNewData(createdJsonProvider) // people will have access to it if they disable metadata check (they are not filtered)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadThemes(this)
|
loadThemes(this)
|
||||||
|
@ -619,4 +687,4 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
val output = src?.doMath()
|
val output = src?.doMath()
|
||||||
println("MASTER OUTPUT = $output")*/
|
println("MASTER OUTPUT = $output")*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,14 @@ class VizcloudLive : WcoStream() {
|
||||||
override var mainUrl = "https://vizcloud.live"
|
override var mainUrl = "https://vizcloud.live"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class VizcloudInfo : WcoStream() {
|
||||||
|
override var mainUrl = "https://vizcloud.info"
|
||||||
|
}
|
||||||
|
|
||||||
|
class MwvnVizcloudInfo : WcoStream() {
|
||||||
|
override var mainUrl = "https://mwvn.vizcloud.info"
|
||||||
|
}
|
||||||
|
|
||||||
open class WcoStream : ExtractorApi() {
|
open class WcoStream : ExtractorApi() {
|
||||||
override var name = "VidStream" //Cause works for animekisa and wco
|
override var name = "VidStream" //Cause works for animekisa and wco
|
||||||
override var mainUrl = "https://vidstream.pro"
|
override var mainUrl = "https://vidstream.pro"
|
||||||
|
@ -103,8 +111,9 @@ open class WcoStream : ExtractorApi() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mainUrl == "https://vidstream.pro" || mainUrl == "https://vidstreamz.online" || mainUrl == "https://vizcloud2.online"
|
if (mainUrl == "https://vidstream.pro" || mainUrl == "https://vidstreamz.online" || mainUrl == "https://vizcloud2.online"
|
||||||
|| mainUrl == "https://vizcloud.xyz" || mainUrl == "https://vizcloud.live") {
|
|| mainUrl == "https://vizcloud.xyz" || mainUrl == "https://vizcloud.live" || mainUrl == "https://vizcloud.info"
|
||||||
if (it.file.contains("m3u8")) {
|
|| mainUrl == "https://mwvn.vizcloud.info") {
|
||||||
|
if (it.file.contains("m3u8")) {
|
||||||
hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(it.file.replace("#.mp4",""), null,
|
hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(it.file.replace("#.mp4",""), null,
|
||||||
headers = mapOf("Referer" to url)), true)
|
headers = mapOf("Referer" to url)), true)
|
||||||
.forEach { stream ->
|
.forEach { stream ->
|
||||||
|
|
|
@ -8,7 +8,7 @@ import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class EgyBestProvider : MainAPI() {
|
class EgyBestProvider : MainAPI() {
|
||||||
override val lang = "ar"
|
override val lang = "ar"
|
||||||
override var mainUrl = "https://egy.best"
|
override var mainUrl = "https://www.egy.best"
|
||||||
override var name = "EgyBest"
|
override var name = "EgyBest"
|
||||||
override val usesWebView = false
|
override val usesWebView = false
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
|
@ -26,6 +26,7 @@ class EgyBestProvider : MainAPI() {
|
||||||
val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
|
val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
|
||||||
val tvType = if (isMovie) TvType.Movie else TvType.TvSeries
|
val tvType = if (isMovie) TvType.Movie else TvType.TvSeries
|
||||||
title = if (year !== null) title else title.split(" (")[0].trim()
|
title = if (year !== null) title else title.split(" (")[0].trim()
|
||||||
|
val quality = select("span.ribbon span").text().replace("-", "")
|
||||||
// If you need to differentiate use the url.
|
// If you need to differentiate use the url.
|
||||||
return MovieSearchResponse(
|
return MovieSearchResponse(
|
||||||
title,
|
title,
|
||||||
|
@ -35,18 +36,22 @@ class EgyBestProvider : MainAPI() {
|
||||||
posterUrl,
|
posterUrl,
|
||||||
year,
|
year,
|
||||||
null,
|
null,
|
||||||
|
quality = getQualityFromString(quality)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(): HomePageResponse {
|
||||||
// url, title
|
// url, title
|
||||||
val doc = app.get(mainUrl).document
|
val doc = app.get(mainUrl).document
|
||||||
val pages = doc.select("#mainLoad div.mbox").apmap {
|
val pages = arrayListOf<HomePageList>()
|
||||||
|
doc.select("#mainLoad div.mbox").apmap {
|
||||||
val name = it.select(".bdb.pda > strong").text()
|
val name = it.select(".bdb.pda > strong").text()
|
||||||
val list = it.select(".movie").mapNotNull { element ->
|
if (it.select(".movie").first().attr("href").contains("season-(.....)|ep-(.....)".toRegex())) return@apmap
|
||||||
element.toSearchResponse()
|
val list = arrayListOf<SearchResponse>()
|
||||||
|
it.select(".movie").map { element ->
|
||||||
|
list.add(element.toSearchResponse()!!)
|
||||||
}
|
}
|
||||||
HomePageList(name, list)
|
pages.add(HomePageList(name, list))
|
||||||
}
|
}
|
||||||
return HomePageResponse(pages)
|
return HomePageResponse(pages)
|
||||||
}
|
}
|
||||||
|
@ -72,7 +77,7 @@ class EgyBestProvider : MainAPI() {
|
||||||
val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
|
val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
|
||||||
val posterUrl = doc.select("div.movie_img a img")?.attr("src")
|
val posterUrl = doc.select("div.movie_img a img")?.attr("src")
|
||||||
val year = doc.select("div.movie_title h1 a")?.text()?.toIntOrNull()
|
val year = doc.select("div.movie_title h1 a")?.text()?.toIntOrNull()
|
||||||
val title = doc.select("div.movie_title h1 span[itemprop=\"name\"]").text()
|
val title = doc.select("div.movie_title h1 span").text()
|
||||||
|
|
||||||
val synopsis = doc.select("div.mbox").firstOrNull {
|
val synopsis = doc.select("div.mbox").firstOrNull {
|
||||||
it.text().contains("القصة")
|
it.text().contains("القصة")
|
||||||
|
|
|
@ -0,0 +1,268 @@
|
||||||
|
package com.lagradost.cloudstream3.movieproviders
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addRating
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
class NginxProvider : MainAPI() {
|
||||||
|
override var name = "Nginx"
|
||||||
|
override val hasQuickSearch = false
|
||||||
|
override val hasMainPage = true
|
||||||
|
override val supportedTypes = setOf(TvType.AnimeMovie, TvType.TvSeries, TvType.Movie)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun getAuthHeader(storedCredentials: String?): Map<String, String> {
|
||||||
|
if (storedCredentials == null) {
|
||||||
|
return mapOf(Pair("Authorization", "Basic ")) // no Authorization headers
|
||||||
|
}
|
||||||
|
val basicAuthToken = base64Encode(storedCredentials.toByteArray()) // will this be loaded when not using the provider ??? can increase load
|
||||||
|
return mapOf(Pair("Authorization", "Basic $basicAuthToken"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun load(url: String): LoadResponse {
|
||||||
|
val authHeader = getAuthHeader(storedCredentials) // call again because it isn't reloaded if in main class and storedCredentials loads after
|
||||||
|
// url can be tvshow.nfo for series or mediaRootUrl for movies
|
||||||
|
|
||||||
|
val mediaRootDocument = app.get(url, authHeader).document
|
||||||
|
|
||||||
|
val nfoUrl = url + mediaRootDocument.getElementsByAttributeValueContaining("href", ".nfo").attr("href") // metadata url file
|
||||||
|
|
||||||
|
val metadataDocument = app.get(nfoUrl, authHeader).document // get the metadata nfo file
|
||||||
|
|
||||||
|
val isMovie = !nfoUrl.contains("tvshow.nfo")
|
||||||
|
|
||||||
|
val title = metadataDocument.selectFirst("title").text()
|
||||||
|
|
||||||
|
val description = metadataDocument.selectFirst("plot").text()
|
||||||
|
|
||||||
|
if (isMovie) {
|
||||||
|
val poster = metadataDocument.selectFirst("thumb").text()
|
||||||
|
val trailer = metadataDocument.select("trailer")?.mapNotNull {
|
||||||
|
it?.text()?.replace(
|
||||||
|
"plugin://plugin.video.youtube/play/?video_id=",
|
||||||
|
"https://www.youtube.com/watch?v="
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val partialUrl = mediaRootDocument.getElementsByAttributeValueContaining("href", ".nfo").attr("href").replace(".nfo", ".")
|
||||||
|
val date = metadataDocument.selectFirst("year")?.text()?.toIntOrNull()
|
||||||
|
val ratingAverage = metadataDocument.selectFirst("value")?.text()?.toIntOrNull()
|
||||||
|
val tagsList = metadataDocument.select("genre")
|
||||||
|
?.mapNotNull { // all the tags like action, thriller ...
|
||||||
|
it?.text()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val dataList = mediaRootDocument.getElementsByAttributeValueContaining( // list of all urls of the webpage
|
||||||
|
"href",
|
||||||
|
partialUrl
|
||||||
|
)
|
||||||
|
|
||||||
|
val data = url + dataList.firstNotNullOf { item -> item.takeIf { (!it.attr("href").contains(".nfo") && !it.attr("href").contains(".jpg"))} }.attr("href").toString() // exclude poster and nfo (metadata) file
|
||||||
|
|
||||||
|
|
||||||
|
return MovieLoadResponse(
|
||||||
|
title,
|
||||||
|
data,
|
||||||
|
this.name,
|
||||||
|
TvType.Movie,
|
||||||
|
data,
|
||||||
|
poster,
|
||||||
|
date,
|
||||||
|
description,
|
||||||
|
ratingAverage,
|
||||||
|
tagsList,
|
||||||
|
null,
|
||||||
|
trailer,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
} else // a tv serie
|
||||||
|
{
|
||||||
|
|
||||||
|
val list = ArrayList<Pair<Int, String>>()
|
||||||
|
val mediaRootUrl = url.replace("tvshow.nfo", "")
|
||||||
|
val posterUrl = mediaRootUrl + "poster.jpg"
|
||||||
|
val mediaRootDocument = app.get(mediaRootUrl, authHeader).document
|
||||||
|
val seasons =
|
||||||
|
mediaRootDocument.getElementsByAttributeValueContaining("href", "Season%20")
|
||||||
|
|
||||||
|
|
||||||
|
val tagsList = metadataDocument.select("genre")
|
||||||
|
?.mapNotNull { // all the tags like action, thriller ...; unused variable
|
||||||
|
it?.text()
|
||||||
|
}
|
||||||
|
|
||||||
|
//val actorsList = document.select("actor")
|
||||||
|
// ?.mapNotNull { // all the tags like action, thriller ...; unused variable
|
||||||
|
// it?.text()
|
||||||
|
// }
|
||||||
|
|
||||||
|
seasons.forEach { element ->
|
||||||
|
val season =
|
||||||
|
element.attr("href")?.replace("Season%20", "")?.replace("/", "")?.toIntOrNull()
|
||||||
|
val href = mediaRootUrl + element.attr("href")
|
||||||
|
if (season != null && season > 0 && href.isNotBlank()) {
|
||||||
|
list.add(Pair(season, href))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found")
|
||||||
|
|
||||||
|
val episodeList = ArrayList<Episode>()
|
||||||
|
|
||||||
|
|
||||||
|
list.apmap { (seasonInt, seasonString) ->
|
||||||
|
val seasonDocument = app.get(seasonString, authHeader).document
|
||||||
|
val episodes = seasonDocument.getElementsByAttributeValueContaining(
|
||||||
|
"href",
|
||||||
|
".nfo"
|
||||||
|
) // get metadata
|
||||||
|
episodes.forEach { episode ->
|
||||||
|
val nfoDocument = app.get(seasonString + episode.attr("href"), authHeader).document // get episode metadata file
|
||||||
|
val epNum = nfoDocument.selectFirst("episode")?.text()?.toIntOrNull()
|
||||||
|
val poster =
|
||||||
|
seasonString + episode.attr("href").replace(".nfo", "-thumb.jpg")
|
||||||
|
val name = nfoDocument.selectFirst("title").text()
|
||||||
|
// val seasonInt = nfoDocument.selectFirst("season").text().toIntOrNull()
|
||||||
|
val date = nfoDocument.selectFirst("aired")?.text()
|
||||||
|
val plot = nfoDocument.selectFirst("plot")?.text()
|
||||||
|
|
||||||
|
val dataList = seasonDocument.getElementsByAttributeValueContaining(
|
||||||
|
"href",
|
||||||
|
episode.attr("href").replace(".nfo", "")
|
||||||
|
)
|
||||||
|
val data = seasonString + dataList.firstNotNullOf { item -> item.takeIf { (!it.attr("href").contains(".nfo") && !it.attr("href").contains(".jpg"))} }.attr("href").toString() // exclude poster and nfo (metadata) file
|
||||||
|
|
||||||
|
episodeList.add(
|
||||||
|
newEpisode(data) {
|
||||||
|
this.name = name
|
||||||
|
this.season = seasonInt
|
||||||
|
this.episode = epNum
|
||||||
|
this.posterUrl = poster
|
||||||
|
addDate(date)
|
||||||
|
this.description = plot
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodeList) {
|
||||||
|
this.name = title
|
||||||
|
this.url = url
|
||||||
|
this.posterUrl = posterUrl
|
||||||
|
this.episodes = episodeList
|
||||||
|
this.plot = description
|
||||||
|
this.tags = tagsList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override suspend fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
// loadExtractor(data, null) { callback(it.copy(headers=authHeader)) }
|
||||||
|
val authHeader = getAuthHeader(storedCredentials) // call again because it isn't reloaded if in main class and storedCredentials loads after
|
||||||
|
callback.invoke (
|
||||||
|
ExtractorLink(
|
||||||
|
name,
|
||||||
|
name,
|
||||||
|
data,
|
||||||
|
data, // referer not needed
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
false,
|
||||||
|
authHeader,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override suspend fun getMainPage(): HomePageResponse? {
|
||||||
|
val authHeader = getAuthHeader(storedCredentials) // call again because it isn't reloaded if in main class and storedCredentials loads after
|
||||||
|
if (mainUrl == "NONE"){
|
||||||
|
throw ErrorLoadingException("No nginx url specified in the settings: Nginx Settigns > Nginx server url, try again in a few seconds")
|
||||||
|
}
|
||||||
|
val document = app.get(mainUrl, authHeader).document
|
||||||
|
val categories = document.select("a")
|
||||||
|
val returnList = categories.mapNotNull {
|
||||||
|
val categoryPath = mainUrl + it.attr("href") ?: return@mapNotNull null // get the url of the category; like http://192.168.1.10/media/Movies/
|
||||||
|
val categoryTitle = it.text() // get the category title like Movies or Series
|
||||||
|
if (categoryTitle != "../" && categoryTitle != "Music/") { // exclude parent dir and Music dir
|
||||||
|
val categoryDocument = app.get(categoryPath, authHeader).document // queries the page http://192.168.1.10/media/Movies/
|
||||||
|
val contentLinks = categoryDocument.select("a")
|
||||||
|
val currentList = contentLinks.mapNotNull { head ->
|
||||||
|
if (head.attr("href") != "../") {
|
||||||
|
try {
|
||||||
|
val mediaRootUrl =
|
||||||
|
categoryPath + head.attr("href")// like http://192.168.1.10/media/Series/Chernobyl/
|
||||||
|
val mediaDocument = app.get(mediaRootUrl, authHeader).document
|
||||||
|
val nfoFilename = mediaDocument.getElementsByAttributeValueContaining(
|
||||||
|
"href",
|
||||||
|
".nfo"
|
||||||
|
)[0].attr("href")
|
||||||
|
val isMovieType = nfoFilename != "tvshow.nfo"
|
||||||
|
val nfoPath =
|
||||||
|
mediaRootUrl + nfoFilename // must exist or will raise errors, only the first one is taken
|
||||||
|
val nfoContent =
|
||||||
|
app.get(nfoPath, authHeader).document // all the metadata
|
||||||
|
|
||||||
|
|
||||||
|
if (isMovieType) {
|
||||||
|
val movieName = nfoContent.select("title").text()
|
||||||
|
|
||||||
|
val posterUrl = mediaRootUrl + "poster.jpg"
|
||||||
|
|
||||||
|
return@mapNotNull MovieSearchResponse(
|
||||||
|
movieName,
|
||||||
|
mediaRootUrl,
|
||||||
|
this.name,
|
||||||
|
TvType.Movie,
|
||||||
|
posterUrl,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
} else { // tv serie
|
||||||
|
val serieName = nfoContent.select("title").text()
|
||||||
|
|
||||||
|
val posterUrl = mediaRootUrl + "poster.jpg"
|
||||||
|
|
||||||
|
TvSeriesSearchResponse(
|
||||||
|
serieName,
|
||||||
|
nfoPath,
|
||||||
|
this.name,
|
||||||
|
TvType.TvSeries,
|
||||||
|
posterUrl,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (e: Exception) { // can cause issues invisible errors
|
||||||
|
null
|
||||||
|
//logError(e) // not working because it changes the return type of currentList to Any
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
if (currentList.isNotEmpty() && categoryTitle != "../") { // exclude upper dir
|
||||||
|
HomePageList(categoryTitle, currentList)
|
||||||
|
} else null
|
||||||
|
} else null // the path is ../ which is parent directory
|
||||||
|
}
|
||||||
|
// if (returnList.isEmpty()) return null // maybe doing nothing idk
|
||||||
|
return HomePageResponse(returnList)
|
||||||
|
}
|
||||||
|
}
|
|
@ -663,7 +663,7 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI {
|
||||||
@JsonProperty("name") val name: String,
|
@JsonProperty("name") val name: String,
|
||||||
@JsonProperty("location") val location: String,
|
@JsonProperty("location") val location: String,
|
||||||
@JsonProperty("joined_at") val joined_at: String,
|
@JsonProperty("joined_at") val joined_at: String,
|
||||||
@JsonProperty("picture") val picture: String,
|
@JsonProperty("picture") val picture: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class MalMainPicture(
|
data class MalMainPicture(
|
||||||
|
@ -694,4 +694,4 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI {
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val name: String,
|
val name: String,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -545,10 +545,14 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
tvType = meta.tvType
|
tvType = meta.tvType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Get limit of characters on Video Title
|
||||||
player_episode_filler_holder?.isVisible = isFiller ?: false
|
var limitTitle = 0
|
||||||
|
context?.let {
|
||||||
player_video_title?.text = if (headerName != null) {
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)
|
||||||
|
limitTitle = settingsManager.getInt(getString(R.string.prefer_limit_title_key), 0)
|
||||||
|
}
|
||||||
|
//Generate video title
|
||||||
|
var playerVideoTitle = if (headerName != null) {
|
||||||
(headerName +
|
(headerName +
|
||||||
if (tvType.isEpisodeBased() && episode != null)
|
if (tvType.isEpisodeBased() && episode != null)
|
||||||
if (season == null)
|
if (season == null)
|
||||||
|
@ -559,6 +563,15 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
//Truncate video title if it exceeds limit
|
||||||
|
val differenceInLength = playerVideoTitle.length - limitTitle
|
||||||
|
val margin = 3 //If the difference is smaller than or equal to this value, ignore it
|
||||||
|
if (limitTitle > 0 && differenceInLength > margin) {
|
||||||
|
playerVideoTitle = playerVideoTitle.substring(0, limitTitle-1) + "..."
|
||||||
|
}
|
||||||
|
|
||||||
|
player_episode_filler_holder?.isVisible = isFiller ?: false
|
||||||
|
player_video_title?.text = playerVideoTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
|
|
|
@ -47,6 +47,7 @@ import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||||
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showNginxTextInputDialog
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
|
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
|
||||||
|
@ -485,6 +486,32 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPref(R.string.nginx_url_key)?.setOnPreferenceClickListener {
|
||||||
|
|
||||||
|
activity?.showNginxTextInputDialog(
|
||||||
|
settingsManager.getString(getString(R.string.nginx_url_pref), "Nginx server url").toString(),
|
||||||
|
settingsManager.getString(getString(R.string.nginx_url_key), "").toString(), // key: the actual you use rn
|
||||||
|
android.text.InputType.TYPE_TEXT_VARIATION_URI, // uri
|
||||||
|
{}) {
|
||||||
|
settingsManager.edit()
|
||||||
|
.putString(getString(R.string.nginx_url_key), it).apply() // change the stored url in nginx_url_key to it
|
||||||
|
}
|
||||||
|
return@setOnPreferenceClickListener true
|
||||||
|
}
|
||||||
|
|
||||||
|
getPref(R.string.nginx_credentials)?.setOnPreferenceClickListener {
|
||||||
|
|
||||||
|
activity?.showNginxTextInputDialog(
|
||||||
|
settingsManager.getString(getString(R.string.nginx_credentials_title), "Nginx Credentials").toString(),
|
||||||
|
settingsManager.getString(getString(R.string.nginx_credentials), "").toString(), // key: the actual you use rn
|
||||||
|
android.text.InputType.TYPE_TEXT_VARIATION_URI,
|
||||||
|
{}) {
|
||||||
|
settingsManager.edit()
|
||||||
|
.putString(getString(R.string.nginx_credentials), it).apply() // change the stored url in nginx_url_key to it
|
||||||
|
}
|
||||||
|
return@setOnPreferenceClickListener true
|
||||||
|
}
|
||||||
|
|
||||||
getPref(R.string.prefer_media_type_key)?.setOnPreferenceClickListener {
|
getPref(R.string.prefer_media_type_key)?.setOnPreferenceClickListener {
|
||||||
val prefNames = resources.getStringArray(R.array.media_type_pref)
|
val prefNames = resources.getStringArray(R.array.media_type_pref)
|
||||||
val prefValues = resources.getIntArray(R.array.media_type_pref_values)
|
val prefValues = resources.getIntArray(R.array.media_type_pref_values)
|
||||||
|
@ -678,6 +705,24 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPref(R.string.prefer_limit_title_key)?.setOnPreferenceClickListener {
|
||||||
|
val prefNames = resources.getStringArray(R.array.limit_title_pref_names)
|
||||||
|
val prefValues = resources.getIntArray(R.array.limit_title_pref_values)
|
||||||
|
val current = settingsManager.getInt(getString(R.string.prefer_limit_title_key), 0)
|
||||||
|
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
prefNames.toList(),
|
||||||
|
prefValues.indexOf(current),
|
||||||
|
getString(R.string.limit_title),
|
||||||
|
true,
|
||||||
|
{}) {
|
||||||
|
settingsManager.edit()
|
||||||
|
.putInt(getString(R.string.prefer_limit_title_key), prefValues[it])
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
return@setOnPreferenceClickListener true
|
||||||
|
}
|
||||||
|
|
||||||
getPref(R.string.dns_key)?.setOnPreferenceClickListener {
|
getPref(R.string.dns_key)?.setOnPreferenceClickListener {
|
||||||
val prefNames = resources.getStringArray(R.array.dns_pref)
|
val prefNames = resources.getStringArray(R.array.dns_pref)
|
||||||
val prefValues = resources.getIntArray(R.array.dns_pref_values)
|
val prefValues = resources.getIntArray(R.array.dns_pref_values)
|
||||||
|
|
|
@ -100,6 +100,8 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
|
||||||
VizcloudOnline(),
|
VizcloudOnline(),
|
||||||
VizcloudXyz(),
|
VizcloudXyz(),
|
||||||
VizcloudLive(),
|
VizcloudLive(),
|
||||||
|
VizcloudInfo(),
|
||||||
|
MwvnVizcloudInfo(),
|
||||||
Mp4Upload(),
|
Mp4Upload(),
|
||||||
StreamTape(),
|
StreamTape(),
|
||||||
MixDrop(),
|
MixDrop(),
|
||||||
|
|
|
@ -144,6 +144,46 @@ object SingleSelectionHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun Activity.showInputDialog(
|
||||||
|
dialog: Dialog,
|
||||||
|
value: String,
|
||||||
|
name: String,
|
||||||
|
textInputType: Int?,
|
||||||
|
callback: (String) -> Unit,
|
||||||
|
dismissCallback: () -> Unit
|
||||||
|
) {
|
||||||
|
val inputView = dialog.findViewById<EditText>(R.id.nginx_text_input)!!
|
||||||
|
val textView = dialog.findViewById<TextView>(R.id.text1)!!
|
||||||
|
val applyButton = dialog.findViewById<TextView>(R.id.apply_btt)!!
|
||||||
|
val cancelButton = dialog.findViewById<TextView>(R.id.cancel_btt)!!
|
||||||
|
val applyHolder = dialog.findViewById<LinearLayout>(R.id.apply_btt_holder)!!
|
||||||
|
|
||||||
|
applyHolder.isVisible = true
|
||||||
|
textView.text = name
|
||||||
|
|
||||||
|
if (textInputType != null) {
|
||||||
|
inputView.inputType = textInputType // 16 for website url input type
|
||||||
|
}
|
||||||
|
inputView.setText(value, TextView.BufferType.EDITABLE)
|
||||||
|
|
||||||
|
|
||||||
|
applyButton.setOnClickListener {
|
||||||
|
callback.invoke(inputView.text.toString()) // try to save the setting, using callback
|
||||||
|
dialog.dismissSafe(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelButton.setOnClickListener { // just dismiss
|
||||||
|
dialog.dismissSafe(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.setOnDismissListener {
|
||||||
|
dismissCallback.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
fun Activity.showMultiDialog(
|
fun Activity.showMultiDialog(
|
||||||
items: List<String>,
|
items: List<String>,
|
||||||
selectedIndex: List<Int>,
|
selectedIndex: List<Int>,
|
||||||
|
@ -192,7 +232,7 @@ object SingleSelectionHelper {
|
||||||
selectedIndex: Int,
|
selectedIndex: Int,
|
||||||
name: String,
|
name: String,
|
||||||
showApply: Boolean,
|
showApply: Boolean,
|
||||||
dismissCallback: () -> Unit,
|
dismissCallback: () -> Unit,
|
||||||
callback: (Int) -> Unit,
|
callback: (Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
val builder =
|
val builder =
|
||||||
|
@ -211,4 +251,25 @@ object SingleSelectionHelper {
|
||||||
dismissCallback
|
dismissCallback
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
fun Activity.showNginxTextInputDialog(
|
||||||
|
name: String,
|
||||||
|
value: String,
|
||||||
|
textInputType: Int?,
|
||||||
|
dismissCallback: () -> Unit,
|
||||||
|
callback: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
val builder = BottomSheetDialog(this) // probably the stuff at the bottom
|
||||||
|
builder.setContentView(R.layout.bottom_input_dialog) // input layout
|
||||||
|
|
||||||
|
builder.show()
|
||||||
|
showInputDialog(
|
||||||
|
builder,
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
textInputType, // type is a uri
|
||||||
|
callback,
|
||||||
|
dismissCallback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
10
app/src/main/res/drawable/ic_baseline_text_format_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_text_format_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/white">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M5,17v2h14v-2L5,17zM9.5,12.8h5l0.9,2.2h2.1L12.75,4h-1.5L6.5,15h2.1l0.9,-2.2zM12,5.98L13.87,11h-3.74L12,5.98z"/>
|
||||||
|
</vector>
|
62
app/src/main/res/layout/bottom_input_dialog.xml
Normal file
62
app/src/main/res/layout/bottom_input_dialog.xml
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:nextFocusDown="@id/nginx_text_input"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_rowWeight="1"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Test" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/nginx_text_input"
|
||||||
|
android:nextFocusRight="@id/cancel_btt"
|
||||||
|
android:nextFocusLeft="@id/apply_btt"
|
||||||
|
android:layout_marginBottom="60dp"
|
||||||
|
android:layout_marginHorizontal="10dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:requiresFadingEdge="vertical"
|
||||||
|
tools:text="nginx.com"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_rowWeight="1"
|
||||||
|
android:autofillHints="Autofill Hint"
|
||||||
|
android:inputType="text"
|
||||||
|
tools:ignore="LabelFor" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/apply_btt_holder"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:gravity="bottom|end"
|
||||||
|
android:layout_marginTop="-60dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
style="@style/WhiteButton"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:text="@string/sort_apply"
|
||||||
|
android:id="@+id/apply_btt"
|
||||||
|
android:layout_width="wrap_content" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
style="@style/BlackButton"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:text="@string/sort_cancel"
|
||||||
|
android:id="@+id/cancel_btt"
|
||||||
|
android:layout_width="wrap_content" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
|
@ -32,7 +32,7 @@
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<array name="dns_pref">
|
<array name="dns_pref">
|
||||||
<item>None</item>
|
<item>@string/none</item>
|
||||||
<item>Google</item>
|
<item>Google</item>
|
||||||
<item>Cloudflare</item>
|
<item>Cloudflare</item>
|
||||||
<!-- <item>OpenDns</item>-->
|
<!-- <item>OpenDns</item>-->
|
||||||
|
@ -59,6 +59,21 @@
|
||||||
<item>3</item>
|
<item>3</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<array name="limit_title_pref_names">
|
||||||
|
<item>@string/none</item>
|
||||||
|
<item>16 characters</item>
|
||||||
|
<item>32 characters</item>
|
||||||
|
<item>64 characters</item>
|
||||||
|
<item>128 characters</item>
|
||||||
|
</array>
|
||||||
|
<array name="limit_title_pref_values">
|
||||||
|
<item>0</item>
|
||||||
|
<item>16</item>
|
||||||
|
<item>32</item>
|
||||||
|
<item>64</item>
|
||||||
|
<item>128</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
<array name="video_buffer_length_names">
|
<array name="video_buffer_length_names">
|
||||||
<item>@string/automatic</item>
|
<item>@string/automatic</item>
|
||||||
<item>1min</item>
|
<item>1min</item>
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<string name="subtitle_settings_key" translatable="false">subtitle_settings_key</string>
|
<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="subtitle_settings_chromecast_key" translatable="false">subtitle_settings_chromecast_key</string>
|
||||||
<string name="quality_pref_key" translatable="false">quality_pref_key</string>
|
<string name="quality_pref_key" translatable="false">quality_pref_key</string>
|
||||||
|
<string name="prefer_limit_title_key" translatable="false">prefer_limit_title_key</string>
|
||||||
<string name="video_buffer_size_key" translatable="false">video_buffer_size_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_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_clear_key" translatable="false">video_buffer_clear_key</string>
|
||||||
|
@ -31,6 +32,9 @@
|
||||||
<string name="provider_lang_key" translatable="false">provider_lang_key</string>
|
<string name="provider_lang_key" translatable="false">provider_lang_key</string>
|
||||||
<string name="dns_key" translatable="false">dns_key</string>
|
<string name="dns_key" translatable="false">dns_key</string>
|
||||||
<string name="download_path_key" translatable="false">download_path_key</string>
|
<string name="download_path_key" translatable="false">download_path_key</string>
|
||||||
|
<string name="nginx_url_key" translatable="false">nginx_url_key</string>
|
||||||
|
<string name="nginx_credentials" translatable="false">nginx_credentials</string>
|
||||||
|
<string name="nginx_info" translatable="false">nginx_info</string>
|
||||||
<string name="app_name_download_path" translatable="false">Cloudstream</string>
|
<string name="app_name_download_path" translatable="false">Cloudstream</string>
|
||||||
<string name="app_layout_key" translatable="false">app_layout_key</string>
|
<string name="app_layout_key" translatable="false">app_layout_key</string>
|
||||||
<string name="primary_color_key" translatable="false">primary_color_key</string>
|
<string name="primary_color_key" translatable="false">primary_color_key</string>
|
||||||
|
@ -227,6 +231,12 @@
|
||||||
<string name="backup_failed_error_format">Error backing up %s</string>
|
<string name="backup_failed_error_format">Error backing up %s</string>
|
||||||
|
|
||||||
<string name="search">Search</string>
|
<string name="search">Search</string>
|
||||||
|
<string name="nginx_category">Nginx Settings</string>
|
||||||
|
<string name="nginx_credentials_title">Nginx Credential</string>
|
||||||
|
<string name="nginx_credentials_summary">You have to use the following format mycoolusername:mysecurepassword123</string>
|
||||||
|
<string name="nginx_info_title">What is Nginx ?</string>
|
||||||
|
<string name="nginx_info_summary">Nginx is a software that can be used to display files from a server that you own. Click to see a Nginx setup guide</string>
|
||||||
|
|
||||||
<string name="settings_info">Info</string>
|
<string name="settings_info">Info</string>
|
||||||
<string name="advanced_search">Advanced Search</string>
|
<string name="advanced_search">Advanced Search</string>
|
||||||
<string name="advanced_search_des">Gives you the search results separated by provider</string>
|
<string name="advanced_search_des">Gives you the search results separated by provider</string>
|
||||||
|
@ -339,6 +349,7 @@
|
||||||
<string name="dont_show_again">Don\'t show again</string>
|
<string name="dont_show_again">Don\'t show again</string>
|
||||||
<string name="update">Update</string>
|
<string name="update">Update</string>
|
||||||
<string name="watch_quality_pref">Preferred watch quality</string>
|
<string name="watch_quality_pref">Preferred watch quality</string>
|
||||||
|
<string name="limit_title">Limit title characters on player</string>
|
||||||
<string name="video_buffer_size_settings">Video buffer 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_length_settings">Video buffer length</string>
|
||||||
<string name="video_buffer_disk_settings">Video cache on disk</string>
|
<string name="video_buffer_disk_settings">Video cache on disk</string>
|
||||||
|
@ -352,6 +363,8 @@
|
||||||
|
|
||||||
<string name="download_path_pref">Download path</string>
|
<string name="download_path_pref">Download path</string>
|
||||||
|
|
||||||
|
<string name="nginx_url_pref">Nginx server url</string>
|
||||||
|
|
||||||
<string name="display_subbed_dubbed_settings">Display Dubbed/Subbed Anime</string>
|
<string name="display_subbed_dubbed_settings">Display Dubbed/Subbed Anime</string>
|
||||||
|
|
||||||
<string name="resize_fit">Fit to screen</string>
|
<string name="resize_fit">Fit to screen</string>
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
android:key="@string/quality_pref_key"
|
android:key="@string/quality_pref_key"
|
||||||
android:title="@string/watch_quality_pref"
|
android:title="@string/watch_quality_pref"
|
||||||
android:icon="@drawable/ic_baseline_hd_24" />
|
android:icon="@drawable/ic_baseline_hd_24" />
|
||||||
|
<Preference
|
||||||
|
android:key="@string/prefer_limit_title_key"
|
||||||
|
android:title="@string/limit_title"
|
||||||
|
android:icon="@drawable/ic_baseline_text_format_24" />
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:icon="@drawable/ic_baseline_picture_in_picture_alt_24"
|
android:icon="@drawable/ic_baseline_picture_in_picture_alt_24"
|
||||||
|
@ -162,6 +166,31 @@
|
||||||
app:defaultValue="true" />
|
app:defaultValue="true" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="@string/nginx_category"
|
||||||
|
android:title="@string/nginx_category"
|
||||||
|
app:isPreferenceVisible="true">
|
||||||
|
<Preference
|
||||||
|
android:key="@string/nginx_url_key"
|
||||||
|
android:title="@string/nginx_url_pref"
|
||||||
|
android:icon="@drawable/ic_baseline_play_arrow_24" />
|
||||||
|
<Preference
|
||||||
|
android:key="@string/nginx_credentials"
|
||||||
|
android:title="@string/nginx_credentials_title"
|
||||||
|
android:icon="@drawable/video_locked"
|
||||||
|
android:summary="@string/nginx_credentials_summary"/>
|
||||||
|
<Preference
|
||||||
|
android:key="@string/nginx_info"
|
||||||
|
android:title="@string/nginx_info_title"
|
||||||
|
android:icon="@drawable/ic_baseline_play_arrow_24"
|
||||||
|
android:summary="@string/nginx_info_summary" >
|
||||||
|
<intent
|
||||||
|
android:action="android.intent.action.VIEW"
|
||||||
|
android:data="https://www.sarlays.com/use-nginx-with-cloudstream/" />
|
||||||
|
</Preference>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="info"
|
android:key="info"
|
||||||
android:title="@string/settings_info"
|
android:title="@string/settings_info"
|
||||||
|
|
120
docs/index.html
120
docs/index.html
|
@ -7,131 +7,17 @@
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto">
|
||||||
<title>CloudStream-3 Supported Sites</title>
|
<title>CloudStream-3 Supported Sites</title>
|
||||||
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
|
<link rel="stylesheet" href="style.css">
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: "Roboto", sans-serif;
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
.whiteText {
|
|
||||||
color : #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
color : #000;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.redButton {
|
|
||||||
}
|
|
||||||
.blueButton {
|
|
||||||
}
|
|
||||||
.greenButton {
|
|
||||||
}
|
|
||||||
.yellowButton {
|
|
||||||
}
|
|
||||||
.row {
|
|
||||||
padding: 0px 10px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
border-spacing: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.yellowButton::before {
|
|
||||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-6.62744-5.3726-12-12-12-6.62744 0-12 5.37256-12 12 0 6.6274 5.37256 12 12 12zm0-17.5c.4141 0 .75.33582.75.75v4.5c0 .4142-.3359.75-.75.75s-.75-.3358-.75-.75v-4.5c0-.41418.3359-.75.75-.75zm.8242 9.5658c.0635-.0919.1118-.195.1416-.3054.0132-.0482.0225-.0979.0283-.1487.0039-.0366.0059-.074.0059-.1117 0-.5522-.4478-1-1-1s-1 .4478-1 1 .4478 1 1 1c.3423 0 .644-.172.8242-.4342z' fill='%23dbab09'/%3E%3C/svg%3e");
|
|
||||||
}
|
|
||||||
|
|
||||||
.blueButton::before {
|
|
||||||
filter: sepia(100%) saturate(300%) brightness(70%) hue-rotate(180deg);
|
|
||||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-6.62744-5.3726-12-12-12-6.62744 0-12 5.37256-12 12 0 6.6274 5.37256 12 12 12zm0-17.5c.4141 0 .75.33582.75.75v4.5c0 .4142-.3359.75-.75.75s-.75-.3358-.75-.75v-4.5c0-.41418.3359-.75.75-.75zm.8242 9.5658c.0635-.0919.1118-.195.1416-.3054.0132-.0482.0225-.0979.0283-.1487.0039-.0366.0059-.074.0059-.1117 0-.5522-.4478-1-1-1s-1 .4478-1 1 .4478 1 1 1c.3423 0 .644-.172.8242-.4342z' fill='%23dbab09'/%3E%3C/svg%3e");
|
|
||||||
}
|
|
||||||
|
|
||||||
.redButton::before {
|
|
||||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-6.62744-5.3726-12-12-12-6.62744 0-12 5.37256-12 12 0 6.6274 5.37256 12 12 12zm0-17.5c.4141 0 .75.33582.75.75v4.5c0 .4142-.3359.75-.75.75s-.75-.3358-.75-.75v-4.5c0-.41418.3359-.75.75-.75zm.8242 9.5658c.0635-.0919.1118-.195.1416-.3054.0132-.0482.0225-.0979.0283-.1487.0039-.0366.0059-.074.0059-.1117 0-.5522-.4478-1-1-1s-1 .4478-1 1 .4478 1 1 1c.3423 0 .644-.172.8242-.4342z' fill='%23d73a49'/%3E%3C/svg%3e");
|
|
||||||
}
|
|
||||||
|
|
||||||
.greenButton::before{
|
|
||||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='15' height='15' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m1 12c0-6.07513 4.92487-11 11-11 6.0751 0 11 4.92487 11 11 0 6.0751-4.9249 11-11 11-6.07513 0-11-4.9249-11-11zm16.2803-2.71967c.2929-.29289.2929-.76777 0-1.06066s-.7677-.29289-1.0606 0l-5.9697 5.96963-2.46967-2.4696c-.29289-.2929-.76777-.2929-1.06066 0s-.29289.7677 0 1.0606l3 3c.29293.2929.76773.2929 1.06063 0z' fill='%2328a745'/%3E%3C/svg%3e");ontent: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicator::before {
|
|
||||||
display: inline-block;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
content: "";
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
background-size: 100% 100%;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center center;
|
|
||||||
margin-right:10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
<h1>Site supported:</h1>
|
<h1>Sites supported (<span id="count">0</span>):</h1>
|
||||||
<table>
|
<table>
|
||||||
<tbody id="siteList"></tbody>
|
<tbody id="siteList"></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script src="script.js" type="text/javascript"></script>
|
||||||
var status = document.getElementById("status");
|
|
||||||
var mainContainer = document.getElementById("siteList");
|
|
||||||
$(document).ready(function () {
|
|
||||||
$.getJSON("providers.json", function (data) {
|
|
||||||
status.innerHTML = "Parsing...";
|
|
||||||
for (var key in data) {
|
|
||||||
status.innerHTML = "Reading..." + key;
|
|
||||||
if (data.hasOwnProperty(key)) {
|
|
||||||
var value = data[key];
|
|
||||||
if(value.url == "NONE") { continue; }
|
|
||||||
|
|
||||||
var _status = value.status
|
|
||||||
|
|
||||||
var node = document.createElement("tr");
|
|
||||||
node.classList.add("row");
|
|
||||||
|
|
||||||
var _a = document.createElement("a");
|
|
||||||
_a.setAttribute('href', value.url);
|
|
||||||
_a.innerHTML = value.name
|
|
||||||
|
|
||||||
var _statusText = "Unknown";
|
|
||||||
var _buttonText = "yellow";
|
|
||||||
switch (_status) {
|
|
||||||
case 0:
|
|
||||||
_statusText = "Unavailable";
|
|
||||||
_buttonText = "red";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_statusText = "Available";
|
|
||||||
_buttonText = "green";
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_statusText = "Slow";
|
|
||||||
_buttonText = "yellow";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_statusText = "Beta";
|
|
||||||
_buttonText = "blue";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_a.classList.add(_buttonText+"Button");
|
|
||||||
_a.classList.add("indicator");
|
|
||||||
_a.classList.add("button");
|
|
||||||
node.appendChild(_a);
|
|
||||||
mainContainer.appendChild(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).fail(function () {
|
|
||||||
console.log("An error has occurred.");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,287 +1,322 @@
|
||||||
{
|
{
|
||||||
"AkwamProvider": {
|
"AkwamProvider": {
|
||||||
"name": "Akwam",
|
"name": "Akwam",
|
||||||
"url": "https://akwam.to",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://akwam.to"
|
||||||
},
|
},
|
||||||
"AllAnimeProvider": {
|
"AllAnimeProvider": {
|
||||||
"name": "AllAnime",
|
"name": "AllAnime",
|
||||||
"url": "https://allanime.site",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://allanime.site"
|
||||||
},
|
},
|
||||||
"AllMoviesForYouProvider": {
|
"AllMoviesForYouProvider": {
|
||||||
"name": "AllMoviesForYou",
|
"name": "AllMoviesForYou",
|
||||||
"url": "https://allmoviesforyou.net",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://allmoviesforyou.net"
|
||||||
},
|
},
|
||||||
"AnimeFlickProvider": {
|
"AnimeFlickProvider": {
|
||||||
"name": "AnimeFlick",
|
"name": "AnimeFlick",
|
||||||
"url": "https://animeflick.net",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://animeflick.net"
|
||||||
},
|
},
|
||||||
"AnimePaheProvider": {
|
"AnimePaheProvider": {
|
||||||
"name": "AnimePahe",
|
"name": "AnimePahe",
|
||||||
"url": "https://animepahe.com",
|
"status": 0,
|
||||||
"status": 0
|
"url": "https://animepahe.com"
|
||||||
},
|
},
|
||||||
"AnimeWorldProvider": {
|
"AnimeWorldProvider": {
|
||||||
"name": "AnimeWorld",
|
"name": "AnimeWorld",
|
||||||
"url": "https://www.animeworld.tv",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://www.animeworld.tv"
|
||||||
|
},
|
||||||
|
"AnimeflvProvider": {
|
||||||
|
"name": "Animeflv",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://www3.animeflv.net"
|
||||||
},
|
},
|
||||||
"AnimeflvnetProvider": {
|
"AnimeflvnetProvider": {
|
||||||
"name": "Animeflv.net",
|
"name": "Animeflv.net",
|
||||||
"url": "https://www3.animeflv.net",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://www3.animeflv.net"
|
||||||
},
|
},
|
||||||
"AnimekisaProvider": {
|
"AnimekisaProvider": {
|
||||||
"name": "Animekisa",
|
"name": "Animekisa",
|
||||||
"url": "https://animekisa.in",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://animekisa.in"
|
||||||
},
|
},
|
||||||
"AsianLoadProvider": {
|
"ApiMDBProvider": {
|
||||||
"name": "AsianLoad",
|
"name": "ApiMDB",
|
||||||
"url": "https://asianembed.io",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://v2.apimdb.net"
|
||||||
},
|
},
|
||||||
"AsiaFlixProvider": {
|
"AsiaFlixProvider": {
|
||||||
"name": "AsiaFlix",
|
"name": "AsiaFlix",
|
||||||
"url": "https://asiaflix.app",
|
"status": 3,
|
||||||
"status": 3
|
"url": "https://asiaflix.app"
|
||||||
|
},
|
||||||
|
"AsianLoadProvider": {
|
||||||
|
"name": "AsianLoad",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://asianembed.io"
|
||||||
},
|
},
|
||||||
"BflixProvider": {
|
"BflixProvider": {
|
||||||
"name": "Bflix",
|
"name": "Bflix",
|
||||||
"url": "https://bflix.to",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://fmovies.to"
|
||||||
},
|
|
||||||
"FmoviesToProvider": {
|
|
||||||
"name": "Fmovies.to",
|
|
||||||
"url": "https://fmovies.to",
|
|
||||||
"status": 1
|
|
||||||
},
|
|
||||||
"SflixProProvider": {
|
|
||||||
"name": "Sflix.pro",
|
|
||||||
"url": "https://sflix.pro",
|
|
||||||
"status": 1
|
|
||||||
},
|
},
|
||||||
"CinecalidadProvider": {
|
"CinecalidadProvider": {
|
||||||
"name": "Cinecalidad",
|
"name": "Cinecalidad",
|
||||||
"url": "https://cinecalidad.lol",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://cinecalidad.lol"
|
||||||
},
|
},
|
||||||
"CrossTmdbProvider": {
|
"CrossTmdbProvider": {
|
||||||
"name": "MultiMovie",
|
"name": "MultiMovie",
|
||||||
"url": "NONE",
|
"status": 1,
|
||||||
"status": 1
|
"url": "NONE"
|
||||||
},
|
},
|
||||||
"CuevanaProvider": {
|
"CuevanaProvider": {
|
||||||
"name": "Cuevana",
|
"name": "Cuevana",
|
||||||
"url": "https://cuevana3.me",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://cuevana3.me"
|
||||||
},
|
|
||||||
"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.id",
|
|
||||||
"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": {
|
"DopeboxProvider": {
|
||||||
"name": "Dopebox",
|
"name": "Dopebox",
|
||||||
"url": "https://dopebox.to",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://dopebox.to"
|
||||||
},
|
},
|
||||||
"SolarmovieProvider": {
|
"DoramasYTProvider": {
|
||||||
"name": "Solarmovie",
|
"name": "DoramasYT",
|
||||||
"url": "https://solarmovie.pe",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://doramasyt.com"
|
||||||
|
},
|
||||||
|
"DramaSeeProvider": {
|
||||||
|
"name": "DramaSee",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://dramasee.net"
|
||||||
|
},
|
||||||
|
"DubbedAnimeProvider": {
|
||||||
|
"name": "DubbedAnime",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://bestdubbedanime.com"
|
||||||
|
},
|
||||||
|
"EgyBestProvider": {
|
||||||
|
"name": "EgyBest",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://www.egy.best"
|
||||||
|
},
|
||||||
|
"EntrePeliculasySeriesProvider": {
|
||||||
|
"name": "EntrePeliculasySeries",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://entrepeliculasyseries.nu"
|
||||||
|
},
|
||||||
|
"EntrepeliculasyseriesProvider": {
|
||||||
|
"name": "EntrePeliculasySeries",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://entrepeliculasyseries.nu"
|
||||||
|
},
|
||||||
|
"FilmanProvider": {
|
||||||
|
"name": "filman.cc",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://filman.cc"
|
||||||
|
},
|
||||||
|
"FmoviesToProvider": {
|
||||||
|
"name": "Fmovies.to",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://fmovies.to"
|
||||||
|
},
|
||||||
|
"FrenchStreamProvider": {
|
||||||
|
"name": "French Stream",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://french-stream.re"
|
||||||
|
},
|
||||||
|
"GogoanimeProvider": {
|
||||||
|
"name": "GogoAnime",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://gogoanime.film"
|
||||||
|
},
|
||||||
|
"HDMProvider": {
|
||||||
|
"name": "HD Movies",
|
||||||
|
"status": 0,
|
||||||
|
"url": "https://hdm.to"
|
||||||
|
},
|
||||||
|
"IHaveNoTvProvider": {
|
||||||
|
"name": "I Have No TV",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://ihavenotv.com"
|
||||||
|
},
|
||||||
|
"KawaiifuProvider": {
|
||||||
|
"name": "Kawaiifu",
|
||||||
|
"status": 0,
|
||||||
|
"url": "https://kawaiifu.com"
|
||||||
|
},
|
||||||
|
"KdramaHoodProvider": {
|
||||||
|
"name": "KDramaHood",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://kdramahood.com"
|
||||||
|
},
|
||||||
|
"LookMovieProvider": {
|
||||||
|
"name": "LookMovie",
|
||||||
|
"status": 0,
|
||||||
|
"url": "https://lookmovie.io"
|
||||||
|
},
|
||||||
|
"MeloMovieProvider": {
|
||||||
|
"name": "MeloMovie",
|
||||||
|
"status": 0,
|
||||||
|
"url": "https://melomovie.com"
|
||||||
|
},
|
||||||
|
"MonoschinosProvider": {
|
||||||
|
"name": "Monoschinos",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://monoschinos2.com"
|
||||||
|
},
|
||||||
|
"MultiAnimeProvider": {
|
||||||
|
"name": "MultiAnime",
|
||||||
|
"status": 1,
|
||||||
|
"url": ""
|
||||||
|
},
|
||||||
|
"MyCimaProvider": {
|
||||||
|
"name": "MyCima",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://mycima.tv"
|
||||||
|
},
|
||||||
|
"NginxProvider": {
|
||||||
|
"name": "Nginx",
|
||||||
|
"status": 1,
|
||||||
|
"url": ""
|
||||||
|
},
|
||||||
|
"NineAnimeProvider": {
|
||||||
|
"name": "9Anime",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://9anime.id"
|
||||||
|
},
|
||||||
|
"NyaaProvider": {
|
||||||
|
"name": "Nyaa",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://nyaa.si"
|
||||||
|
},
|
||||||
|
"PeliSmartProvider": {
|
||||||
|
"name": "PeliSmart",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://pelismart.com"
|
||||||
|
},
|
||||||
|
"PelisflixProvider": {
|
||||||
|
"name": "Pelisflix",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://pelisflix.li"
|
||||||
|
},
|
||||||
|
"PelisplusHDProvider": {
|
||||||
|
"name": "PelisplusHD",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://pelisplushd.net"
|
||||||
|
},
|
||||||
|
"PelisplusProvider": {
|
||||||
|
"name": "Pelisplus",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://pelisplus.icu"
|
||||||
|
},
|
||||||
|
"PinoyHDXyzProvider": {
|
||||||
|
"name": "Pinoy-HD",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://www.pinoy-hd.xyz"
|
||||||
|
},
|
||||||
|
"PinoyMoviePediaProvider": {
|
||||||
|
"name": "Pinoy Moviepedia",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://pinoymoviepedia.ru"
|
||||||
|
},
|
||||||
|
"PinoyMoviesEsProvider": {
|
||||||
|
"name": "Pinoy Movies",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://pinoymovies.es"
|
||||||
},
|
},
|
||||||
"SeriesflixProvider": {
|
"SeriesflixProvider": {
|
||||||
"name": "Seriesflix",
|
"name": "Seriesflix",
|
||||||
"url": "https://seriesflix.video",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://seriesflix.video"
|
||||||
|
},
|
||||||
|
"SflixProProvider": {
|
||||||
|
"name": "Sflix.pro",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://sflix.pro"
|
||||||
|
},
|
||||||
|
"SflixProvider": {
|
||||||
|
"name": "Sflix.to",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://dopebox.to"
|
||||||
},
|
},
|
||||||
"SoaptwoDayProvider": {
|
"SoaptwoDayProvider": {
|
||||||
"name": "Soap2Day",
|
"name": "Soap2Day",
|
||||||
"url": "https://secretlink.xyz",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://secretlink.xyz"
|
||||||
|
},
|
||||||
|
"SolarmovieProvider": {
|
||||||
|
"name": "Solarmovie",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://solarmovie.pe"
|
||||||
},
|
},
|
||||||
"TenshiProvider": {
|
"TenshiProvider": {
|
||||||
"name": "Tenshi.moe",
|
"name": "Tenshi.moe",
|
||||||
"url": "https://tenshi.moe",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://tenshi.moe"
|
||||||
},
|
|
||||||
"TrailersTwoProvider": {
|
|
||||||
"name": "Trailers.to",
|
|
||||||
"url": "https://trailers.to",
|
|
||||||
"status": 1
|
|
||||||
},
|
},
|
||||||
"TheFlixToProvider": {
|
"TheFlixToProvider": {
|
||||||
"name": "TheFlix.to",
|
"name": "TheFlix.to",
|
||||||
"url": "https://theflix.to",
|
"status": 0,
|
||||||
"status": 0
|
"url": "https://theflix.to"
|
||||||
|
},
|
||||||
|
"TmdbProvider": {
|
||||||
|
"name": "Tmdb",
|
||||||
|
"status": 1,
|
||||||
|
"url": ""
|
||||||
|
},
|
||||||
|
"TrailersTwoProvider": {
|
||||||
|
"name": "Trailers.to",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://trailers.to"
|
||||||
},
|
},
|
||||||
"TwoEmbedProvider": {
|
"TwoEmbedProvider": {
|
||||||
"name": "2Embed",
|
"name": "2Embed",
|
||||||
"url": "https://www.2embed.ru",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://www.2embed.ru"
|
||||||
},
|
},
|
||||||
"VMoveeProvider": {
|
"VMoveeProvider": {
|
||||||
"name": "VMovee",
|
"name": "VMovee",
|
||||||
"url": "https://www.vmovee.watch",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://www.vmovee.watch"
|
||||||
},
|
},
|
||||||
"VfFilmProvider": {
|
"VfFilmProvider": {
|
||||||
"name": "vf-film.me",
|
"name": "vf-film.me",
|
||||||
"url": "https://vf-film.me",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://vf-film.me"
|
||||||
},
|
},
|
||||||
"VfSerieProvider": {
|
"VfSerieProvider": {
|
||||||
"name": "vf-serie.org",
|
"name": "vf-serie.org",
|
||||||
"url": "https://vf-serie.org",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://vf-serie.org"
|
||||||
},
|
},
|
||||||
"VidEmbedProvider": {
|
"VidEmbedProvider": {
|
||||||
"name": "VidEmbed",
|
"name": "VidEmbed",
|
||||||
"url": "https://vidembed.cc",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://vidembed.cc"
|
||||||
},
|
},
|
||||||
"WatchAsianProvider": {
|
"WatchAsianProvider": {
|
||||||
"name": "WatchAsian",
|
"name": "WatchAsian",
|
||||||
"url": "https://watchasian.sh",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://watchasian.sh"
|
||||||
},
|
},
|
||||||
"WatchCartoonOnlineProvider": {
|
"WatchCartoonOnlineProvider": {
|
||||||
"name": "WatchCartoonOnline",
|
"name": "WatchCartoonOnline",
|
||||||
"url": "https://www.wcostream.com",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://www.wcostream.com"
|
||||||
},
|
},
|
||||||
"WcoProvider": {
|
"WcoProvider": {
|
||||||
"name": "WCO Stream",
|
"name": "WCO Stream",
|
||||||
"url": "https://wcostream.cc",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://wcostream.cc"
|
||||||
},
|
},
|
||||||
"ZoroProvider": {
|
"ZoroProvider": {
|
||||||
"name": "Zoro",
|
"name": "Zoro",
|
||||||
"url": "https://zoro.to",
|
"status": 1,
|
||||||
"status": 1
|
"url": "https://zoro.to"
|
||||||
}
|
}
|
||||||
}
|
}
|
49
docs/script.js
Normal file
49
docs/script.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
const count = document.getElementById("count")
|
||||||
|
const mainContainer = document.getElementById("siteList");
|
||||||
|
fetch("providers.json" + "?v=" + Date.now())
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(function (data) {
|
||||||
|
count.innerHTML = Object.keys(data).length;
|
||||||
|
for (var key in data) {
|
||||||
|
if (data.hasOwnProperty(key)) {
|
||||||
|
var value = data[key];
|
||||||
|
if (value.url == "NONE") { continue; }
|
||||||
|
|
||||||
|
var _status = value.status
|
||||||
|
|
||||||
|
var node = document.createElement("tr");
|
||||||
|
node.classList.add("row");
|
||||||
|
|
||||||
|
var _a = document.createElement("a");
|
||||||
|
_a.setAttribute('href', value.url);
|
||||||
|
_a.innerHTML = value.name
|
||||||
|
|
||||||
|
var _statusText = "Unknown";
|
||||||
|
var _buttonText = "yellow";
|
||||||
|
switch (_status) {
|
||||||
|
case 0:
|
||||||
|
_statusText = "Unavailable";
|
||||||
|
_buttonText = "red";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
_statusText = "Available";
|
||||||
|
_buttonText = "green";
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
_statusText = "Slow";
|
||||||
|
_buttonText = "yellow";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
_statusText = "Beta";
|
||||||
|
_buttonText = "blue";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_a.classList.add(_buttonText + "Button");
|
||||||
|
_a.classList.add("indicator");
|
||||||
|
_a.classList.add("button");
|
||||||
|
node.appendChild(_a);
|
||||||
|
mainContainer.appendChild(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
49
docs/style.css
Normal file
49
docs/style.css
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
body {
|
||||||
|
font-family: "Roboto", sans-serif;
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
.whiteText {
|
||||||
|
color : #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
color : #000;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
padding: 0px 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-spacing: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yellowButton::before {
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-6.62744-5.3726-12-12-12-6.62744 0-12 5.37256-12 12 0 6.6274 5.37256 12 12 12zm0-17.5c.4141 0 .75.33582.75.75v4.5c0 .4142-.3359.75-.75.75s-.75-.3358-.75-.75v-4.5c0-.41418.3359-.75.75-.75zm.8242 9.5658c.0635-.0919.1118-.195.1416-.3054.0132-.0482.0225-.0979.0283-.1487.0039-.0366.0059-.074.0059-.1117 0-.5522-.4478-1-1-1s-1 .4478-1 1 .4478 1 1 1c.3423 0 .644-.172.8242-.4342z' fill='%23dbab09'/%3E%3C/svg%3e");
|
||||||
|
}
|
||||||
|
|
||||||
|
.blueButton::before {
|
||||||
|
filter: sepia(100%) saturate(300%) brightness(70%) hue-rotate(180deg);
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-6.62744-5.3726-12-12-12-6.62744 0-12 5.37256-12 12 0 6.6274 5.37256 12 12 12zm0-17.5c.4141 0 .75.33582.75.75v4.5c0 .4142-.3359.75-.75.75s-.75-.3358-.75-.75v-4.5c0-.41418.3359-.75.75-.75zm.8242 9.5658c.0635-.0919.1118-.195.1416-.3054.0132-.0482.0225-.0979.0283-.1487.0039-.0366.0059-.074.0059-.1117 0-.5522-.4478-1-1-1s-1 .4478-1 1 .4478 1 1 1c.3423 0 .644-.172.8242-.4342z' fill='%23dbab09'/%3E%3C/svg%3e");
|
||||||
|
}
|
||||||
|
|
||||||
|
.redButton::before {
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-6.62744-5.3726-12-12-12-6.62744 0-12 5.37256-12 12 0 6.6274 5.37256 12 12 12zm0-17.5c.4141 0 .75.33582.75.75v4.5c0 .4142-.3359.75-.75.75s-.75-.3358-.75-.75v-4.5c0-.41418.3359-.75.75-.75zm.8242 9.5658c.0635-.0919.1118-.195.1416-.3054.0132-.0482.0225-.0979.0283-.1487.0039-.0366.0059-.074.0059-.1117 0-.5522-.4478-1-1-1s-1 .4478-1 1 .4478 1 1 1c.3423 0 .644-.172.8242-.4342z' fill='%23d73a49'/%3E%3C/svg%3e");
|
||||||
|
}
|
||||||
|
|
||||||
|
.greenButton::before{
|
||||||
|
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg width='15' height='15' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m1 12c0-6.07513 4.92487-11 11-11 6.0751 0 11 4.92487 11 11 0 6.0751-4.9249 11-11 11-6.07513 0-11-4.9249-11-11zm16.2803-2.71967c.2929-.29289.2929-.76777 0-1.06066s-.7677-.29289-1.0606 0l-5.9697 5.96963-2.46967-2.4696c-.29289-.2929-.76777-.2929-1.06066 0s-.29289.7677 0 1.0606l3 3c.29293.2929.76773.2929 1.06063 0z' fill='%2328a745'/%3E%3C/svg%3e");ontent: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator::before {
|
||||||
|
display: inline-block;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
content: "";
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
margin-right:10px;
|
||||||
|
}
|
Loading…
Reference in a new issue