mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge branch 'recloudstream:master' into master
This commit is contained in:
commit
c0f57b1368
18 changed files with 288 additions and 95 deletions
76
.github/workflows/build_to_archive.yml
vendored
Normal file
76
.github/workflows/build_to_archive.yml
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
name: Archive build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
paths-ignore:
|
||||||
|
- '*.md'
|
||||||
|
- '*.json'
|
||||||
|
- '**/wcokey.txt'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: "Archive-build"
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Generate access token
|
||||||
|
id: generate_token
|
||||||
|
uses: tibdex/github-app-token@v1
|
||||||
|
with:
|
||||||
|
app_id: ${{ secrets.GH_APP_ID }}
|
||||||
|
private_key: ${{ secrets.GH_APP_KEY }}
|
||||||
|
repository: "recloudstream/secrets"
|
||||||
|
- name: Generate access token (archive)
|
||||||
|
id: generate_archive_token
|
||||||
|
uses: tibdex/github-app-token@v1
|
||||||
|
with:
|
||||||
|
app_id: ${{ secrets.GH_APP_ID }}
|
||||||
|
private_key: ${{ secrets.GH_APP_KEY }}
|
||||||
|
repository: "recloudstream/cloudstream-archive"
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Set up JDK 11
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
java-version: '11'
|
||||||
|
distribution: 'adopt'
|
||||||
|
- name: Grant execute permission for gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
|
- name: Fetch keystore
|
||||||
|
id: fetch_keystore
|
||||||
|
run: |
|
||||||
|
TMP_KEYSTORE_FILE_PATH="${RUNNER_TEMP}"/keystore
|
||||||
|
mkdir -p "${TMP_KEYSTORE_FILE_PATH}"
|
||||||
|
curl -H "Authorization: token ${{ steps.generate_token.outputs.token }}" -o "${TMP_KEYSTORE_FILE_PATH}/prerelease_keystore.keystore" "https://raw.githubusercontent.com/recloudstream/secrets/master/keystore.jks"
|
||||||
|
curl -H "Authorization: token ${{ steps.generate_token.outputs.token }}" -o "keystore_password.txt" "https://raw.githubusercontent.com/recloudstream/secrets/master/keystore_password.txt"
|
||||||
|
KEY_PWD="$(cat keystore_password.txt)"
|
||||||
|
echo "::add-mask::${KEY_PWD}"
|
||||||
|
echo "key_pwd=$KEY_PWD" >> $GITHUB_OUTPUT
|
||||||
|
- name: Run Gradle
|
||||||
|
run: |
|
||||||
|
./gradlew assemblePrerelease
|
||||||
|
env:
|
||||||
|
SIGNING_KEY_ALIAS: "key0"
|
||||||
|
SIGNING_KEY_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}
|
||||||
|
SIGNING_STORE_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: "recloudstream/cloudstream-archive"
|
||||||
|
token: ${{ steps.generate_archive_token.outputs.token }}
|
||||||
|
path: "archive"
|
||||||
|
|
||||||
|
- name: Move build
|
||||||
|
run: |
|
||||||
|
cp app/build/outputs/apk/prerelease/release/*.apk "archive/$(git rev-parse --short HEAD).apk"
|
||||||
|
|
||||||
|
- name: Push archive
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/archive
|
||||||
|
git config --local user.email "actions@github.com"
|
||||||
|
git config --local user.name "GitHub Actions"
|
||||||
|
git add .
|
||||||
|
git commit --amend -m "Build $GITHUB_SHA" || exit 0 # do not error if nothing to commit
|
||||||
|
git push --force
|
|
@ -18,7 +18,6 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSet
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf
|
import com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -31,6 +30,12 @@ const val USER_AGENT =
|
||||||
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
||||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the constant for the all languages preference, if this is set then it is
|
||||||
|
* the equivalent of all languages being set
|
||||||
|
**/
|
||||||
|
const val AllLanguagesName = "universal"
|
||||||
|
|
||||||
object APIHolder {
|
object APIHolder {
|
||||||
val unixTime: Long
|
val unixTime: Long
|
||||||
get() = System.currentTimeMillis() / 1000L
|
get() = System.currentTimeMillis() / 1000L
|
||||||
|
@ -159,7 +164,8 @@ object APIHolder {
|
||||||
|
|
||||||
val hashSet = HashSet<String>()
|
val hashSet = HashSet<String>()
|
||||||
val activeLangs = getApiProviderLangSettings()
|
val activeLangs = getApiProviderLangSettings()
|
||||||
hashSet.addAll(apis.filter { activeLangs.contains(it.lang) }.map { it.name })
|
val hasUniversal = activeLangs.contains(AllLanguagesName)
|
||||||
|
hashSet.addAll(apis.filter { hasUniversal || activeLangs.contains(it.lang) }.map { it.name })
|
||||||
|
|
||||||
/*val set = settingsManager.getStringSet(
|
/*val set = settingsManager.getStringSet(
|
||||||
this.getString(R.string.search_providers_list_key),
|
this.getString(R.string.search_providers_list_key),
|
||||||
|
@ -193,26 +199,17 @@ object APIHolder {
|
||||||
return list.filter { names.contains(it) }.map { DubStatus.valueOf(it) }.toHashSet()
|
return list.filter { names.contains(it) }.map { DubStatus.valueOf(it) }.toHashSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets all the activated provider languages
|
|
||||||
* Used to obey the preference provider_lang_key
|
|
||||||
* but it turned out too complicated and unnecessary with extensions.
|
|
||||||
**/
|
|
||||||
fun Context.getApiProviderLangSettings(): HashSet<String> {
|
fun Context.getApiProviderLangSettings(): HashSet<String> {
|
||||||
val langs = apis.map { it.lang }.toSet()
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) }
|
val hashSet = hashSetOf(AllLanguagesName) // def is all languages
|
||||||
return langs.toHashSet()
|
|
||||||
|
|
||||||
// val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
// val hashSet = HashSet<String>()
|
|
||||||
// hashSet.add("en") // def is only en
|
// hashSet.add("en") // def is only en
|
||||||
// val list = settingsManager.getStringSet(
|
val list = settingsManager.getStringSet(
|
||||||
// this.getString(R.string.provider_lang_key),
|
this.getString(R.string.provider_lang_key),
|
||||||
// hashSet.toMutableSet()
|
hashSet
|
||||||
// )
|
)
|
||||||
//
|
|
||||||
// if (list.isNullOrEmpty()) return hashSet
|
if (list.isNullOrEmpty()) return hashSet
|
||||||
// return list.toHashSet()
|
return list.toHashSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getApiTypeSettings(): HashSet<TvType> {
|
fun Context.getApiTypeSettings(): HashSet<TvType> {
|
||||||
|
@ -254,7 +251,8 @@ object APIHolder {
|
||||||
null
|
null
|
||||||
} ?: default
|
} ?: default
|
||||||
val langs = this.getApiProviderLangSettings()
|
val langs = this.getApiProviderLangSettings()
|
||||||
val allApis = apis.filter { langs.contains(it.lang) }
|
val hasUniversal = langs.contains(AllLanguagesName)
|
||||||
|
val allApis = apis.filter { hasUniversal || langs.contains(it.lang) }
|
||||||
.filter { api -> api.hasMainPage || !hasHomePageIsRequired }
|
.filter { api -> api.hasMainPage || !hasHomePageIsRequired }
|
||||||
return if (currentPrefMedia.isEmpty()) {
|
return if (currentPrefMedia.isEmpty()) {
|
||||||
allApis
|
allApis
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
|
|
||||||
|
open class Jeniusplay : ExtractorApi() {
|
||||||
|
override val name = "Jeniusplay"
|
||||||
|
override val mainUrl = "https://jeniusplay.com"
|
||||||
|
override val requiresReferer = true
|
||||||
|
|
||||||
|
override suspend fun getUrl(
|
||||||
|
url: String,
|
||||||
|
referer: String?,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
val document = app.get(url, referer = "$mainUrl/").document
|
||||||
|
val hash = url.split("/").last().substringAfter("data=")
|
||||||
|
|
||||||
|
val m3uLink = app.post(
|
||||||
|
url = "$mainUrl/player/index.php?data=$hash&do=getVideo",
|
||||||
|
data = mapOf("hash" to hash, "r" to "$referer"),
|
||||||
|
referer = url,
|
||||||
|
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
|
||||||
|
).parsed<ResponseSource>().videoSource
|
||||||
|
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
this.name,
|
||||||
|
m3uLink,
|
||||||
|
url,
|
||||||
|
).forEach(callback)
|
||||||
|
|
||||||
|
|
||||||
|
document.select("script").map { script ->
|
||||||
|
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
|
||||||
|
val subData =
|
||||||
|
getAndUnpack(script.data()).substringAfter("\"tracks\":[").substringBefore("],")
|
||||||
|
tryParseJson<List<Tracks>>("[$subData]")?.map { subtitle ->
|
||||||
|
subtitleCallback.invoke(
|
||||||
|
SubtitleFile(
|
||||||
|
getLanguage(subtitle.label ?: ""),
|
||||||
|
subtitle.file
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLanguage(str: String): String {
|
||||||
|
return when {
|
||||||
|
str.contains("indonesia", true) || str
|
||||||
|
.contains("bahasa", true) -> "Indonesian"
|
||||||
|
else -> str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ResponseSource(
|
||||||
|
@JsonProperty("hls") val hls: Boolean,
|
||||||
|
@JsonProperty("videoSource") val videoSource: String,
|
||||||
|
@JsonProperty("securedLink") val securedLink: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Tracks(
|
||||||
|
@JsonProperty("kind") val kind: String?,
|
||||||
|
@JsonProperty("file") val file: String,
|
||||||
|
@JsonProperty("label") val label: String?,
|
||||||
|
)
|
||||||
|
}
|
|
@ -6,7 +6,11 @@ import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
|
|
||||||
class Moviehab : ExtractorApi() {
|
class MoviehabNet : Moviehab() {
|
||||||
|
override var mainUrl = "https://play.moviehab.net"
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Moviehab : ExtractorApi() {
|
||||||
override var name = "Moviehab"
|
override var name = "Moviehab"
|
||||||
override var mainUrl = "https://play.moviehab.com"
|
override var mainUrl = "https://play.moviehab.com"
|
||||||
override val requiresReferer = false
|
override val requiresReferer = false
|
||||||
|
|
|
@ -70,6 +70,28 @@ object RepositoryManager {
|
||||||
getKey("PREBUILT_REPOSITORIES") ?: emptyArray()
|
getKey("PREBUILT_REPOSITORIES") ?: emptyArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun parseRepoUrl(url: String): String? {
|
||||||
|
val fixedUrl = url.trim()
|
||||||
|
return if (fixedUrl.contains("^https?://".toRegex())) {
|
||||||
|
fixedUrl
|
||||||
|
} else if (fixedUrl.contains("^(cloudstreamrepo://)|(https://cs\\.repo/\\??)".toRegex())) {
|
||||||
|
fixedUrl.replace("^(cloudstreamrepo://)|(https://cs\\.repo/\\??)".toRegex(), "").let {
|
||||||
|
return@let if (!it.contains("^https?://".toRegex()))
|
||||||
|
"https://${it}"
|
||||||
|
else fixedUrl
|
||||||
|
}
|
||||||
|
} else if (fixedUrl.matches("^[a-zA-Z0-9!_-]+$".toRegex())) {
|
||||||
|
suspendSafeApiCall {
|
||||||
|
app.get("https://l.cloudstream.cf/${fixedUrl}").let {
|
||||||
|
return@let if (it.isSuccessful && !it.url.startsWith("https://cutt.ly/branded-domains")) it.url
|
||||||
|
else app.get("https://cutt.ly/${fixedUrl}").let let2@{ it2 ->
|
||||||
|
return@let2 if (it2.isSuccessful) it2.url else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun parseRepository(url: String): Repository? {
|
suspend fun parseRepository(url: String): Repository? {
|
||||||
return suspendSafeApiCall {
|
return suspendSafeApiCall {
|
||||||
// Take manifestVersion and such into account later
|
// Take manifestVersion and such into account later
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.lagradost.cloudstream3.ui.home
|
package com.lagradost.cloudstream3.ui.home
|
||||||
|
|
||||||
|
import android.animation.LayoutTransition
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -23,12 +24,15 @@ import androidx.fragment.app.activityViewModels
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.transition.ChangeBounds
|
||||||
|
import androidx.transition.TransitionManager
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.chip.ChipGroup
|
import com.google.android.material.chip.ChipGroup
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.allProviders
|
||||||
import com.lagradost.cloudstream3.APIHolder.apis
|
import com.lagradost.cloudstream3.APIHolder.apis
|
||||||
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||||
|
@ -346,7 +350,9 @@ class HomeFragment : Fragment() {
|
||||||
builder.setContentView(R.layout.home_select_mainpage)
|
builder.setContentView(R.layout.home_select_mainpage)
|
||||||
builder.show()
|
builder.show()
|
||||||
builder.let { dialog ->
|
builder.let { dialog ->
|
||||||
val isMultiLang = getApiProviderLangSettings().size > 1
|
val isMultiLang = getApiProviderLangSettings().let { set ->
|
||||||
|
set.size > 1 || set.contains(AllLanguagesName)
|
||||||
|
}
|
||||||
//dialog.window?.setGravity(Gravity.BOTTOM)
|
//dialog.window?.setGravity(Gravity.BOTTOM)
|
||||||
|
|
||||||
var currentApiName = selectedApiName
|
var currentApiName = selectedApiName
|
||||||
|
@ -574,10 +580,15 @@ class HomeFragment : Fragment() {
|
||||||
setPageTransformer(false, HomeScrollTransformer())
|
setPageTransformer(false, HomeScrollTransformer())
|
||||||
adapter = HomeScrollAdapter { load ->
|
adapter = HomeScrollAdapter { load ->
|
||||||
load.apply {
|
load.apply {
|
||||||
|
home_preview_title_holder?.let { parent ->
|
||||||
|
TransitionManager.beginDelayedTransition(parent, ChangeBounds())
|
||||||
|
}
|
||||||
|
|
||||||
home_preview_tags?.text = tags?.joinToString(" • ") ?: ""
|
home_preview_tags?.text = tags?.joinToString(" • ") ?: ""
|
||||||
home_preview_tags?.isGone = tags.isNullOrEmpty()
|
home_preview_tags?.isGone = tags.isNullOrEmpty()
|
||||||
home_preview_image?.setImage(posterUrl, posterHeaders)
|
home_preview_image?.setImage(posterUrl, posterHeaders)
|
||||||
home_preview_title?.text = name
|
home_preview_title?.text = name
|
||||||
|
|
||||||
home_preview_play?.setOnClickListener {
|
home_preview_play?.setOnClickListener {
|
||||||
activity?.loadResult(url, apiName, START_ACTION_RESUME_LATEST)
|
activity?.loadResult(url, apiName, START_ACTION_RESUME_LATEST)
|
||||||
//activity.loadSearchResult(url, START_ACTION_RESUME_LATEST)
|
//activity.loadSearchResult(url, START_ACTION_RESUME_LATEST)
|
||||||
|
|
|
@ -221,7 +221,9 @@ class SearchFragment : Fragment() {
|
||||||
builder.setContentView(R.layout.home_select_mainpage)
|
builder.setContentView(R.layout.home_select_mainpage)
|
||||||
builder.show()
|
builder.show()
|
||||||
builder.let { dialog ->
|
builder.let { dialog ->
|
||||||
val isMultiLang = ctx.getApiProviderLangSettings().size > 1
|
val isMultiLang = ctx.getApiProviderLangSettings().let { set ->
|
||||||
|
set.size > 1 || set.contains(AllLanguagesName)
|
||||||
|
}
|
||||||
|
|
||||||
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
|
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
|
||||||
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
|
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.lagradost.cloudstream3.ui.settings
|
package com.lagradost.cloudstream3.ui.settings
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
@ -9,17 +8,15 @@ import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||||
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
|
||||||
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.UIHelper.hideKeyboard
|
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||||
|
import kotlin.reflect.jvm.internal.impl.descriptors.deserialization.PlatformDependentDeclarationFilter.All
|
||||||
|
|
||||||
|
|
||||||
class SettingsProviders : PreferenceFragmentCompat() {
|
class SettingsProviders : PreferenceFragmentCompat() {
|
||||||
|
@ -63,13 +60,17 @@ class SettingsProviders : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
getPref(R.string.prefer_media_type_key)?.setOnPreferenceClickListener {
|
getPref(R.string.prefer_media_type_key)?.setOnPreferenceClickListener {
|
||||||
val names = enumValues<TvType>().sorted().map { it.name }
|
val names = enumValues<TvType>().sorted().map { it.name }
|
||||||
val default = enumValues<TvType>().sorted().filter { it != TvType.NSFW }.map { it.ordinal }
|
val default =
|
||||||
|
enumValues<TvType>().sorted().filter { it != TvType.NSFW }.map { it.ordinal }
|
||||||
val defaultSet = default.map { it.toString() }.toSet()
|
val defaultSet = default.map { it.toString() }.toSet()
|
||||||
val currentList = try {
|
val currentList = try {
|
||||||
settingsManager.getStringSet(getString(R.string.prefer_media_type_key), defaultSet)?.map {
|
settingsManager.getStringSet(getString(R.string.prefer_media_type_key), defaultSet)
|
||||||
|
?.map {
|
||||||
it.toInt()
|
it.toInt()
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) { null } ?: default
|
} catch (e: Throwable) {
|
||||||
|
null
|
||||||
|
} ?: default
|
||||||
|
|
||||||
activity?.showMultiDialog(
|
activity?.showMultiDialog(
|
||||||
names,
|
names,
|
||||||
|
@ -89,20 +90,23 @@ class SettingsProviders : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
getPref(R.string.provider_lang_key)?.setOnPreferenceClickListener {
|
getPref(R.string.provider_lang_key)?.setOnPreferenceClickListener {
|
||||||
activity?.getApiProviderLangSettings()?.let { current ->
|
activity?.getApiProviderLangSettings()?.let { current ->
|
||||||
val langs = APIHolder.apis.map { it.lang }.toSet()
|
val languages = APIHolder.apis.map { it.lang }.toSet()
|
||||||
.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) }
|
.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) } + AllLanguagesName
|
||||||
|
|
||||||
val currentList = ArrayList<Int>()
|
val currentList = current.map {
|
||||||
for (i in current) {
|
languages.indexOf(it)
|
||||||
currentList.add(langs.indexOf(i))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val names = langs.map {
|
val names = languages.map {
|
||||||
|
if (it == AllLanguagesName) {
|
||||||
|
Pair(it, getString(R.string.all_languages_preference))
|
||||||
|
} else {
|
||||||
val emoji = SubtitleHelper.getFlagFromIso(it)
|
val emoji = SubtitleHelper.getFlagFromIso(it)
|
||||||
val name = SubtitleHelper.fromTwoLettersToLanguage(it)
|
val name = SubtitleHelper.fromTwoLettersToLanguage(it)
|
||||||
val fullName = "$emoji $name"
|
val fullName = "$emoji $name"
|
||||||
Pair(it, fullName)
|
Pair(it, fullName)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
activity?.showMultiDialog(
|
activity?.showMultiDialog(
|
||||||
names.map { it.second },
|
names.map { it.second },
|
||||||
|
|
|
@ -33,8 +33,6 @@ import com.lagradost.cloudstream3.widget.LinearRecycleViewLayoutManager
|
||||||
import kotlinx.android.synthetic.main.add_repo_input.*
|
import kotlinx.android.synthetic.main.add_repo_input.*
|
||||||
import kotlinx.android.synthetic.main.fragment_extensions.*
|
import kotlinx.android.synthetic.main.fragment_extensions.*
|
||||||
|
|
||||||
const val PUBLIC_REPOSITORIES_LIST = "https://recloudstream.github.io/repos/"
|
|
||||||
|
|
||||||
class ExtensionsFragment : Fragment() {
|
class ExtensionsFragment : Fragment() {
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -186,15 +184,7 @@ class ExtensionsFragment : Fragment() {
|
||||||
(activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager?)?.primaryClip?.getItemAt(
|
(activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager?)?.primaryClip?.getItemAt(
|
||||||
0
|
0
|
||||||
)?.text?.toString()?.let { copy ->
|
)?.text?.toString()?.let { copy ->
|
||||||
// Fix our own repo links and only paste the text if it's a link.
|
dialog.repo_url_input?.setText(copy)
|
||||||
if (copy.startsWith("http")) {
|
|
||||||
val fixedUrl = if (copy.startsWith("https://cs.repo")) {
|
|
||||||
"https://" + copy.substringAfter("?")
|
|
||||||
} else {
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
dialog.repo_url_input?.setText(fixedUrl)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dialog.list_repositories?.setOnClickListener {
|
// dialog.list_repositories?.setOnClickListener {
|
||||||
|
@ -206,13 +196,12 @@ class ExtensionsFragment : Fragment() {
|
||||||
// dialog.text2?.text = provider.name
|
// dialog.text2?.text = provider.name
|
||||||
dialog.apply_btt?.setOnClickListener secondListener@{
|
dialog.apply_btt?.setOnClickListener secondListener@{
|
||||||
val name = dialog.repo_name_input?.text?.toString()
|
val name = dialog.repo_name_input?.text?.toString()
|
||||||
|
ioSafe {
|
||||||
val url = dialog.repo_url_input?.text?.toString()
|
val url = dialog.repo_url_input?.text?.toString()
|
||||||
|
?.let { it1 -> RepositoryManager.parseRepoUrl(it1) }
|
||||||
if (url.isNullOrBlank()) {
|
if (url.isNullOrBlank()) {
|
||||||
showToast(activity, R.string.error_invalid_data, Toast.LENGTH_SHORT)
|
showToast(activity, R.string.error_invalid_data, Toast.LENGTH_SHORT)
|
||||||
return@secondListener
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
ioSafe {
|
|
||||||
val fixedName = if (!name.isNullOrBlank()) name
|
val fixedName = if (!name.isNullOrBlank()) name
|
||||||
else RepositoryManager.parseRepository(url)?.name ?: "No name"
|
else RepositoryManager.parseRepository(url)?.name ?: "No name"
|
||||||
|
|
||||||
|
@ -222,6 +211,7 @@ class ExtensionsFragment : Fragment() {
|
||||||
extensionViewModel.loadRepositories()
|
extensionViewModel.loadRepositories()
|
||||||
this@ExtensionsFragment.activity?.downloadAllPluginsDialog(url, fixedName)
|
this@ExtensionsFragment.activity?.downloadAllPluginsDialog(url, fixedName)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
dialog.dismissSafe(activity)
|
dialog.dismissSafe(activity)
|
||||||
}
|
}
|
||||||
dialog.cancel_btt?.setOnClickListener {
|
dialog.cancel_btt?.setOnClickListener {
|
||||||
|
|
|
@ -7,6 +7,9 @@ import android.view.ViewGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.apis
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
||||||
|
import com.lagradost.cloudstream3.AllLanguagesName
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
|
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
||||||
|
@ -96,7 +99,14 @@ class SetupFragmentExtensions : Fragment() {
|
||||||
next_btt?.setOnClickListener {
|
next_btt?.setOnClickListener {
|
||||||
// Continue setup
|
// Continue setup
|
||||||
if (isSetup)
|
if (isSetup)
|
||||||
|
if (
|
||||||
|
// If any available languages
|
||||||
|
apis.distinctBy { it.lang }.size > 1
|
||||||
|
) {
|
||||||
|
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_provider_languages)
|
||||||
|
} else {
|
||||||
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_media)
|
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_media)
|
||||||
|
}
|
||||||
else
|
else
|
||||||
findNavController().navigate(R.id.navigation_home)
|
findNavController().navigate(R.id.navigation_home)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import com.lagradost.cloudstream3.CommonActivity
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
|
||||||
import com.lagradost.cloudstream3.ui.settings.appLanguages
|
import com.lagradost.cloudstream3.ui.settings.appLanguages
|
||||||
import com.lagradost.cloudstream3.ui.settings.getCurrentLocale
|
import com.lagradost.cloudstream3.ui.settings.getCurrentLocale
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
|
@ -85,7 +84,7 @@ class SetupFragmentLanguage : Fragment() {
|
||||||
&& PluginManager.getPluginsLocal().isEmpty()
|
&& PluginManager.getPluginsLocal().isEmpty()
|
||||||
//&& PREBUILT_REPOSITORIES.isNotEmpty()
|
//&& PREBUILT_REPOSITORIES.isNotEmpty()
|
||||||
) R.id.action_navigation_global_to_navigation_setup_extensions
|
) R.id.action_navigation_global_to_navigation_setup_extensions
|
||||||
else R.id.action_navigation_setup_language_to_navigation_setup_media
|
else R.id.action_navigation_setup_language_to_navigation_setup_provider_languages
|
||||||
|
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
nextDestination,
|
nextDestination,
|
||||||
|
|
|
@ -12,6 +12,7 @@ import androidx.navigation.fragment.findNavController
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.lagradost.cloudstream3.APIHolder
|
import com.lagradost.cloudstream3.APIHolder
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
|
||||||
|
import com.lagradost.cloudstream3.AllLanguagesName
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||||
|
@ -39,14 +40,21 @@ class SetupFragmentProviderLanguage : Fragment() {
|
||||||
|
|
||||||
val current = this.getApiProviderLangSettings()
|
val current = this.getApiProviderLangSettings()
|
||||||
val langs = APIHolder.apis.map { it.lang }.toSet()
|
val langs = APIHolder.apis.map { it.lang }.toSet()
|
||||||
.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) }
|
.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) } + AllLanguagesName
|
||||||
|
|
||||||
|
val currentList =
|
||||||
|
current.map { langs.indexOf(it) }.filter { it != -1 } // TODO LOOK INTO
|
||||||
|
|
||||||
val currentList = current.map { langs.indexOf(it) }.filter { it != -1 } // TODO LOOK INTO
|
|
||||||
val languageNames = langs.map {
|
val languageNames = langs.map {
|
||||||
|
if (it == AllLanguagesName) {
|
||||||
|
getString(R.string.all_languages_preference)
|
||||||
|
} else {
|
||||||
val emoji = SubtitleHelper.getFlagFromIso(it)
|
val emoji = SubtitleHelper.getFlagFromIso(it)
|
||||||
val name = SubtitleHelper.fromTwoLettersToLanguage(it)
|
val name = SubtitleHelper.fromTwoLettersToLanguage(it)
|
||||||
"$emoji $name"
|
"$emoji $name"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
arrayAdapter.addAll(languageNames)
|
arrayAdapter.addAll(languageNames)
|
||||||
|
|
||||||
listview1?.adapter = arrayAdapter
|
listview1?.adapter = arrayAdapter
|
||||||
|
|
|
@ -329,6 +329,8 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
||||||
Vidmolyme(),
|
Vidmolyme(),
|
||||||
Voe(),
|
Voe(),
|
||||||
Moviehab(),
|
Moviehab(),
|
||||||
|
MoviehabNet(),
|
||||||
|
Jeniusplay(),
|
||||||
|
|
||||||
Gdriveplayerapi(),
|
Gdriveplayerapi(),
|
||||||
Gdriveplayerapp(),
|
Gdriveplayerapp(),
|
||||||
|
|
|
@ -363,19 +363,20 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/home_preview_title_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/home_preview_title"
|
android:id="@+id/home_preview_title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingStart="30dp"
|
|
||||||
android:paddingEnd="30dp"
|
|
||||||
android:paddingBottom="10dp"
|
android:paddingBottom="10dp"
|
||||||
|
android:paddingHorizontal="30dp"
|
||||||
android:textColor="?attr/white"
|
android:textColor="?attr/white"
|
||||||
android:textSize="17sp"
|
android:textSize="17sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
@ -392,7 +393,7 @@
|
||||||
tools:text="5 seasons 50 episodes" />-->
|
tools:text="5 seasons 50 episodes" />-->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/home_preview_tags"
|
android:id="@+id/home_preview_tags"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingStart="30dp"
|
android:paddingStart="30dp"
|
||||||
|
|
|
@ -522,13 +522,6 @@
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
<action
|
|
||||||
android:id="@+id/action_navigation_setup_language_to_navigation_setup_media"
|
|
||||||
app:destination="@id/navigation_setup_media"
|
|
||||||
app:enterAnim="@anim/enter_anim"
|
|
||||||
app:exitAnim="@anim/exit_anim"
|
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<action
|
<action
|
||||||
|
|
|
@ -637,4 +637,5 @@
|
||||||
<string name="player_settings_play_in_web">Web Video Cast</string>
|
<string name="player_settings_play_in_web">Web Video Cast</string>
|
||||||
<string name="player_settings_play_in_browser">Browser</string>
|
<string name="player_settings_play_in_browser">Browser</string>
|
||||||
<string name="app_not_found_error">App not found</string>
|
<string name="app_not_found_error">App not found</string>
|
||||||
|
<string name="all_languages_preference">All Languages</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
<item name="chipStrokeColor">@color/transparent</item>
|
<item name="chipStrokeColor">@color/transparent</item>
|
||||||
<item name="textColor">@color/chip_color_text</item>
|
<item name="textColor">@color/chip_color_text</item>
|
||||||
<item name="android:textColor">@color/chip_color_text</item>
|
<item name="android:textColor">@color/chip_color_text</item>
|
||||||
|
<item name="checkedIconTint">@color/chip_color_text</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AmoledMode">
|
<style name="AmoledMode">
|
||||||
|
@ -137,13 +138,13 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="OverlayPrimaryColorMonetTwo">
|
<style name="OverlayPrimaryColorMonetTwo">
|
||||||
<item name="colorPrimary">@color/material_dynamic_tertiary80</item>
|
<item name="colorPrimary">@color/material_dynamic_secondary80</item>
|
||||||
<item name="android:colorPrimary">@color/material_dynamic_tertiary80</item>
|
<item name="android:colorPrimary">@color/material_dynamic_secondary80</item>
|
||||||
<item name="colorPrimaryDark">@color/material_dynamic_tertiary30</item>
|
<item name="colorPrimaryDark">@color/material_dynamic_secondary30</item>
|
||||||
<item name="colorAccent">@color/material_dynamic_tertiary80</item>
|
<item name="colorAccent">@color/material_dynamic_secondary80</item>
|
||||||
<item name="colorOnPrimary">@color/material_dynamic_tertiary20</item>
|
<item name="colorOnPrimary">@color/material_dynamic_secondary20</item>
|
||||||
<!-- Needed for leanback fuckery -->
|
<!-- Needed for leanback fuckery -->
|
||||||
<item name="android:colorAccent">@color/material_dynamic_tertiary30</item>
|
<item name="android:colorAccent">@color/material_dynamic_secondary30</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="OverlayPrimaryColorBlue">
|
<style name="OverlayPrimaryColorBlue">
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<Preference
|
<Preference
|
||||||
app:isPreferenceVisible="false"
|
|
||||||
android:icon="@drawable/ic_baseline_language_24"
|
android:icon="@drawable/ic_baseline_language_24"
|
||||||
android:key="@string/provider_lang_key"
|
android:key="@string/provider_lang_key"
|
||||||
android:title="@string/provider_lang_settings" />
|
android:title="@string/provider_lang_settings" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue