settings change + flashbang mode fixes

This commit is contained in:
LagradOst 2022-06-09 15:50:55 +02:00
parent db04dd2781
commit 162ce53a82
37 changed files with 357 additions and 604 deletions

View file

@ -36,7 +36,7 @@ android {
targetSdkVersion 30 targetSdkVersion 30
versionCode 47 versionCode 47
versionName "2.10.26" versionName "2.10.27"
resValue "string", "app_version", resValue "string", "app_version",
"${defaultConfig.versionName}${versionNameSuffix ?: ""}" "${defaultConfig.versionName}${versionNameSuffix ?: ""}"

View file

@ -53,7 +53,6 @@ object APIHolder {
PelisflixProvider(), PelisflixProvider(),
SeriesflixProvider(), SeriesflixProvider(),
IHaveNoTvProvider(), // Documentaries provider IHaveNoTvProvider(), // Documentaries provider
LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
VMoveeProvider(), VMoveeProvider(),
AllMoviesForYouProvider(), AllMoviesForYouProvider(),
VidEmbedProvider(), VidEmbedProvider(),
@ -472,12 +471,6 @@ fun base64Encode(array: ByteArray): String {
class ErrorLoadingException(message: String? = null) : Exception(message) class ErrorLoadingException(message: String? = null) : Exception(message)
fun parseRating(ratingString: String?): Int? {
if (ratingString == null) return null
val floatRating = ratingString.toFloatOrNull() ?: return null
return (floatRating * 10).toInt()
}
fun MainAPI.fixUrlNull(url: String?): String? { fun MainAPI.fixUrlNull(url: String?): String? {
if (url.isNullOrEmpty()) { if (url.isNullOrEmpty()) {
return null return null

View file

@ -137,6 +137,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
R.id.navigation_settings_ui, R.id.navigation_settings_ui,
R.id.navigation_settings_account, R.id.navigation_settings_account,
R.id.navigation_settings_lang, R.id.navigation_settings_lang,
R.id.navigation_settings_general,
).contains(destination.id) ).contains(destination.id)
val landscape = when (resources.configuration.orientation) { val landscape = when (resources.configuration.orientation) {

View file

@ -1,298 +0,0 @@
package com.lagradost.cloudstream3.movieproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.unixTime
import com.lagradost.cloudstream3.extractors.M3u8Manifest
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.Jsoup
//BE AWARE THAT weboas.is is a clone of lookmovie
class LookMovieProvider : MainAPI() {
override val hasQuickSearch = true
override var name = "LookMovie"
override var mainUrl = "https://lookmovie.io"
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
)
data class LookMovieSearchResult(
@JsonProperty("backdrop") val backdrop: String?,
@JsonProperty("imdb_rating") val imdb_rating: String,
@JsonProperty("poster") val poster: String?,
@JsonProperty("slug") val slug: String,
@JsonProperty("title") val title: String,
@JsonProperty("year") val year: String?,
// @JsonProperty("flag_quality") val flag_quality: Int?,
)
data class LookMovieTokenRoot(
@JsonProperty("data") val data: LookMovieTokenResult?,
@JsonProperty("success") val success: Boolean,
)
data class LookMovieTokenResult(
@JsonProperty("accessToken") val accessToken: String,
@JsonProperty("subtitles") val subtitles: List<LookMovieTokenSubtitle>?,
)
data class LookMovieTokenSubtitle(
@JsonProperty("language") val language: String,
@JsonProperty("source") val source: String?,
//@JsonProperty("source_id") val source_id: String,
//@JsonProperty("kind") val kind: String,
//@JsonProperty("id") val id: String,
@JsonProperty("file") val file: String,
)
data class LookMovieSearchResultRoot(
// @JsonProperty("per_page") val per_page: Int?,
// @JsonProperty("total") val total: Int?,
@JsonProperty("result") val result: List<LookMovieSearchResult>?,
)
data class LookMovieEpisode(
@JsonProperty("title") var title: String,
@JsonProperty("index") var index: String,
@JsonProperty("episode") var episode: String,
@JsonProperty("id_episode") var idEpisode: Int,
@JsonProperty("season") var season: String,
)
override suspend fun quickSearch(query: String): List<SearchResponse> {
val movieUrl = "$mainUrl/api/v1/movies/search/?q=$query"
val movieResponse = app.get(movieUrl).text
val movies = mapper.readValue<LookMovieSearchResultRoot>(movieResponse).result
val showsUrl = "$mainUrl/api/v1/shows/search/?q=$query"
val showsResponse = app.get(showsUrl).text
val shows = mapper.readValue<LookMovieSearchResultRoot>(showsResponse).result
val returnValue = ArrayList<SearchResponse>()
if (!movies.isNullOrEmpty()) {
for (m in movies) {
val url = "$mainUrl/movies/view/${m.slug}"
returnValue.add(
MovieSearchResponse(
m.title,
url,
this.name,
TvType.Movie,
m.poster ?: m.backdrop,
m.year?.toIntOrNull()
)
)
}
}
if (!shows.isNullOrEmpty()) {
for (s in shows) {
val url = "$mainUrl/shows/view/${s.slug}"
returnValue.add(
MovieSearchResponse(
s.title,
url,
this.name,
TvType.TvSeries,
s.poster ?: s.backdrop,
s.year?.toIntOrNull()
)
)
}
}
return returnValue
}
override suspend fun search(query: String): List<SearchResponse> {
suspend fun search(query: String, isMovie: Boolean): List<SearchResponse> {
val url = "$mainUrl/${if (isMovie) "movies" else "shows"}/search/?q=$query"
val response = app.get(url).text
val document = Jsoup.parse(response)
val items = document.select("div.flex-wrap-movielist > div.movie-item-style-1")
return items.map { item ->
val titleHolder = item.selectFirst("> div.mv-item-infor > h6 > a")
val href = fixUrl(titleHolder!!.attr("href"))
val name = titleHolder.text()
val posterHolder = item.selectFirst("> div.image__placeholder > a")
val poster = posterHolder!!.selectFirst("> img")?.attr("data-src")
val year = posterHolder.selectFirst("> p.year")?.text()?.toIntOrNull()
if (isMovie) {
MovieSearchResponse(
name, href, this.name, TvType.Movie, poster, year
)
} else
TvSeriesSearchResponse(
name, href, this.name, TvType.TvSeries, poster, year, null
)
}
}
val movieList = search(query, true).toMutableList()
val seriesList = search(query, false)
movieList.addAll(seriesList)
return movieList
}
data class LookMovieLinkLoad(val url: String, val extraUrl: String, val isMovie: Boolean)
private fun addSubtitles(
subs: List<LookMovieTokenSubtitle>?,
subtitleCallback: (SubtitleFile) -> Unit
) {
if (subs == null) return
subs.forEach {
if (it.file.endsWith(".vtt"))
subtitleCallback.invoke(SubtitleFile(it.language, fixUrl(it.file)))
}
}
private suspend fun loadCurrentLinks(url: String, callback: (ExtractorLink) -> Unit) {
val response = app.get(url.replace("\$unixtime", unixTime.toString())).text
M3u8Manifest.extractLinks(response).forEach {
callback.invoke(
ExtractorLink(
this.name,
"${this.name} - ${it.second}",
fixUrl(it.first),
"",
getQualityFromName(it.second),
true
)
)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val localData: LookMovieLinkLoad = mapper.readValue(data)
if (localData.isMovie) {
val tokenResponse = app.get(localData.url).text
val root = mapper.readValue<LookMovieTokenRoot>(tokenResponse)
val accessToken = root.data?.accessToken ?: return false
addSubtitles(root.data.subtitles, subtitleCallback)
loadCurrentLinks(localData.extraUrl.replace("\$accessToken", accessToken), callback)
return true
} else {
loadCurrentLinks(localData.url, callback)
val subResponse = app.get(localData.extraUrl).text
val subs = mapper.readValue<List<LookMovieTokenSubtitle>>(subResponse)
addSubtitles(subs, subtitleCallback)
}
return true
}
override suspend fun load(url: String): LoadResponse? {
val response = app.get(url).text
val document = Jsoup.parse(response)
val isMovie = url.contains("/movies/")
val watchHeader = document.selectFirst("div.watch-heading")
val nameHeader = watchHeader!!.selectFirst("> h1.bd-hd")
val year = nameHeader!!.selectFirst("> span")?.text()?.toIntOrNull()
val title = nameHeader.ownText()
val rating =
parseRating(watchHeader.selectFirst("> div.movie-rate > div.rate > p > span")!!.text())
val imgElement = document.selectFirst("div.movie-img > p.movie__poster")
val img = imgElement?.attr("style")
var poster = if (img.isNullOrEmpty()) null else "url\\((.*?)\\)".toRegex()
.find(img)?.groupValues?.get(1)
if (poster.isNullOrEmpty()) poster = imgElement?.attr("data-background-image")
val descript = document.selectFirst("p.description-short")!!.text()
val id = "${if (isMovie) "id_movie" else "id_show"}:(.*?),".toRegex()
.find(response)?.groupValues?.get(1)
?.replace(" ", "")
?: return null
val realSlug = url.replace("$mainUrl/${if (isMovie) "movies" else "shows"}/view/", "")
val realUrl =
"$mainUrl/api/v1/security/${if (isMovie) "movie" else "show"}-access?${if (isMovie) "id_movie=$id" else "slug=$realSlug"}&token=1&sk=&step=1"
if (isMovie) {
val localData =
LookMovieLinkLoad(
realUrl,
"$mainUrl/manifests/movies/json/$id/\$unixtime/\$accessToken/master.m3u8",
true
).toJson()
return MovieLoadResponse(
title,
url,
this.name,
TvType.Movie,
localData,
poster,
year,
descript,
rating
)
} else {
val tokenResponse = app.get(realUrl).text
val root = mapper.readValue<LookMovieTokenRoot>(tokenResponse)
val accessToken = root.data?.accessToken ?: return null
val window =
"window\\['show_storage'] =((.|\\n)*?<)".toRegex().find(response)?.groupValues?.get(
1
)
?: return null
// val id = "id_show:(.*?),".toRegex().find(response.text)?.groupValues?.get(1) ?: return null
val season = "seasons:.*\\[((.|\\n)*?)]".toRegex().find(window)?.groupValues?.get(1)
?: return null
fun String.fixSeasonJson(replace: String): String {
return this.replace("$replace:", "\"$replace\":")
}
val json = season
.replace("\'", "\"")
.fixSeasonJson("title")
.fixSeasonJson("id_episode")
.fixSeasonJson("episode")
.fixSeasonJson("index")
.fixSeasonJson("season")
val realJson = "[" + json.substring(0, json.lastIndexOf(',')) + "]"
val episodes = mapper.readValue<List<LookMovieEpisode>>(realJson).map {
val localData =
LookMovieLinkLoad(
"$mainUrl/manifests/shows/json/$accessToken/\$unixtime/${it.idEpisode}/master.m3u8",
"https://lookmovie.io/api/v1/shows/episode-subtitles/?id_episode=${it.idEpisode}",
false
).toJson()
Episode(
localData,
it.title,
it.season.toIntOrNull(),
it.episode.toIntOrNull(),
)
}.toList()
return TvSeriesLoadResponse(
title,
url,
this.name,
TvType.TvSeries,
ArrayList(episodes),
poster,
year,
descript,
null,
rating
)
}
}
}

View file

@ -1786,7 +1786,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
} }
result_description.setOnClickListener { result_description.setOnClickListener {
val builder: AlertDialog.Builder = val builder: AlertDialog.Builder =
AlertDialog.Builder(requireContext()) AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
builder.setMessage(d.plot) builder.setMessage(d.plot)
.setTitle(if (d.type == TvType.Torrent) R.string.torrent_plot else R.string.result_plot) .setTitle(if (d.type == TvType.Torrent) R.string.torrent_plot else R.string.result_plot)
.show() .show()

View file

@ -11,7 +11,6 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
@ -24,7 +23,6 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.openSub
import com.lagradost.cloudstream3.syncproviders.AuthAPI import com.lagradost.cloudstream3.syncproviders.AuthAPI
import com.lagradost.cloudstream3.syncproviders.InAppAuthAPI import com.lagradost.cloudstream3.syncproviders.InAppAuthAPI
import com.lagradost.cloudstream3.syncproviders.OAuth2API import com.lagradost.cloudstream3.syncproviders.OAuth2API
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.beneneCount
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.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
@ -38,7 +36,7 @@ import kotlinx.android.synthetic.main.add_account_input.*
class SettingsAccount : PreferenceFragmentCompat() { class SettingsAccount : PreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setUpToolbar(R.string.category_credits) setUpToolbar(R.string.category_account)
} }
private fun showLoginInfo(api: AccountManager, info: AuthAPI.LoginInfo) { private fun showLoginInfo(api: AccountManager, info: AuthAPI.LoginInfo) {
@ -179,16 +177,7 @@ class SettingsAccount : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard() hideKeyboard()
setPreferencesFromResource(R.xml.settings_credits_account, rootKey) setPreferencesFromResource(R.xml.settings_account, rootKey)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.legal_notice_key)?.setOnPreferenceClickListener {
val builder: AlertDialog.Builder = AlertDialog.Builder(it.context)
builder.setTitle(R.string.legal_notice)
builder.setMessage(R.string.legal_notice_text)
builder.show()
return@setOnPreferenceClickListener true
}
val syncApis = val syncApis =
listOf( listOf(
@ -213,33 +202,5 @@ class SettingsAccount : PreferenceFragmentCompat() {
} }
} }
} }
try {
beneneCount = settingsManager.getInt(getString(R.string.benene_count), 0)
getPref(R.string.benene_count)?.let { pref ->
pref.summary =
if (beneneCount <= 0) getString(R.string.benene_count_text_none) else getString(
R.string.benene_count_text
).format(
beneneCount
)
pref.setOnPreferenceClickListener {
try {
beneneCount++
settingsManager.edit().putInt(getString(R.string.benene_count), beneneCount)
.apply()
it.summary = getString(R.string.benene_count_text).format(beneneCount)
} catch (e: Exception) {
logError(e)
}
return@setOnPreferenceClickListener true
}
}
} catch (e: Exception) {
e.printStackTrace()
}
} }
} }

View file

@ -40,7 +40,7 @@ class SettingsFragment : Fragment() {
} }
} }
fun PreferenceFragmentCompat?.setUpToolbar(@StringRes title : Int) { fun PreferenceFragmentCompat?.setUpToolbar(@StringRes title: Int) {
if (this == null) return if (this == null) return
settings_toolbar?.apply { settings_toolbar?.apply {
setTitle(title) setTitle(title)
@ -131,6 +131,7 @@ class SettingsFragment : Fragment() {
} }
listOf( listOf(
Pair(settings_general, R.id.action_navigation_settings_to_navigation_settings_general),
Pair(settings_player, R.id.action_navigation_settings_to_navigation_settings_player), Pair(settings_player, R.id.action_navigation_settings_to_navigation_settings_player),
Pair(settings_credits, R.id.action_navigation_settings_to_navigation_settings_account), Pair(settings_credits, R.id.action_navigation_settings_to_navigation_settings_account),
Pair(settings_ui, R.id.action_navigation_settings_to_navigation_settings_ui), Pair(settings_ui, R.id.action_navigation_settings_to_navigation_settings_ui),

View file

@ -0,0 +1,182 @@
package com.lagradost.cloudstream3.ui.settings
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
import java.io.File
class SettingsGeneral : PreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpToolbar(R.string.category_general)
}
// Open file picker
private val pathPicker =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
// It lies, it can be null if file manager quits.
if (uri == null) return@registerForActivityResult
val context = context ?: AcraApplication.context ?: return@registerForActivityResult
// RW perms for the path
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flags)
val file = UniFile.fromUri(context, uri)
println("Selected URI path: $uri - Full path: ${file.filePath}")
// Stores the real URI using download_path_key
// Important that the URI is stored instead of filepath due to permissions.
PreferenceManager.getDefaultSharedPreferences(context)
.edit().putString(getString(R.string.download_path_key), uri.toString()).apply()
// From URI -> File path
// File path here is purely for cosmetic purposes in settings
(file.filePath ?: uri.toString()).let {
PreferenceManager.getDefaultSharedPreferences(context)
.edit().putString(getString(R.string.download_path_pref), it).apply()
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard()
setPreferencesFromResource(R.xml.settins_general, rootKey)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.legal_notice_key)?.setOnPreferenceClickListener {
val builder: AlertDialog.Builder =
AlertDialog.Builder(it.context, R.style.AlertDialogCustom)
builder.setTitle(R.string.legal_notice)
builder.setMessage(R.string.legal_notice_text)
builder.show()
return@setOnPreferenceClickListener true
}
getPref(R.string.dns_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.dns_pref)
val prefValues = resources.getIntArray(R.array.dns_pref_values)
val currentDns =
settingsManager.getInt(getString(R.string.dns_pref), 0)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentDns),
getString(R.string.dns_pref),
true,
{}) {
settingsManager.edit().putInt(getString(R.string.dns_pref), prefValues[it]).apply()
(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) }
}
return@setOnPreferenceClickListener true
}
fun getDownloadDirs(): List<String> {
return normalSafeApiCall {
val defaultDir = VideoDownloadManager.getDownloadDir()?.filePath
// app_name_download_path = Cloudstream and does not change depending on release.
// DOES NOT WORK ON SCOPED STORAGE.
val secondaryDir =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath +
File.separator + resources.getString(R.string.app_name_download_path)
val first = listOf(defaultDir, secondaryDir)
(try {
val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second }
(first +
requireContext().getExternalFilesDirs("").mapNotNull { it.path } +
currentDir)
} catch (e: Exception) {
first
}).filterNotNull().distinct()
} ?: emptyList()
}
getPref(R.string.download_path_key)?.setOnPreferenceClickListener {
val dirs = getDownloadDirs()
val currentDir =
settingsManager.getString(getString(R.string.download_path_pref), null)
?: VideoDownloadManager.getDownloadDir().toString()
activity?.showBottomDialog(
dirs + listOf("Custom"),
dirs.indexOf(currentDir),
getString(R.string.download_path_pref),
true,
{}) {
// Last = custom
if (it == dirs.size) {
try {
pathPicker.launch(Uri.EMPTY)
} catch (e: Exception) {
logError(e)
}
} else {
// Sets both visual and actual paths.
// key = used path
// pref = visual path
settingsManager.edit()
.putString(getString(R.string.download_path_key), dirs[it]).apply()
settingsManager.edit()
.putString(getString(R.string.download_path_pref), dirs[it]).apply()
}
}
return@setOnPreferenceClickListener true
}
try {
SettingsFragment.beneneCount =
settingsManager.getInt(getString(R.string.benene_count), 0)
getPref(R.string.benene_count)?.let { pref ->
pref.summary =
if (SettingsFragment.beneneCount <= 0) getString(R.string.benene_count_text_none) else getString(
R.string.benene_count_text
).format(
SettingsFragment.beneneCount
)
pref.setOnPreferenceClickListener {
try {
SettingsFragment.beneneCount++
settingsManager.edit().putInt(
getString(R.string.benene_count),
SettingsFragment.beneneCount
)
.apply()
it.summary =
getString(R.string.benene_count_text).format(SettingsFragment.beneneCount)
} catch (e: Exception) {
logError(e)
}
return@setOnPreferenceClickListener true
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View file

@ -1,21 +1,11 @@
package com.lagradost.cloudstream3.ui.settings package com.lagradost.cloudstream3.ui.settings
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.view.View import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getFolderSize import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getFolderSize
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.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
@ -25,43 +15,12 @@ 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.UIHelper.hideKeyboard import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
import java.io.File
class SettingsPlayer : PreferenceFragmentCompat() { class SettingsPlayer : PreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setUpToolbar(R.string.category_player) setUpToolbar(R.string.category_player)
} }
// Open file picker
private val pathPicker =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
// It lies, it can be null if file manager quits.
if (uri == null) return@registerForActivityResult
val context = context ?: AcraApplication.context ?: return@registerForActivityResult
// RW perms for the path
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flags)
val file = UniFile.fromUri(context, uri)
println("Selected URI path: $uri - Full path: ${file.filePath}")
// Stores the real URI using download_path_key
// Important that the URI is stored instead of filepath due to permissions.
PreferenceManager.getDefaultSharedPreferences(context)
.edit().putString(getString(R.string.download_path_key), uri.toString()).apply()
// From URI -> File path
// File path here is purely for cosmetic purposes in settings
(file.filePath ?: uri.toString()).let {
PreferenceManager.getDefaultSharedPreferences(context)
.edit().putString(getString(R.string.download_path_pref), it).apply()
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard() hideKeyboard()
setPreferencesFromResource(R.xml.settings_player, rootKey) setPreferencesFromResource(R.xml.settings_player, rootKey)
@ -86,24 +45,6 @@ class SettingsPlayer : PreferenceFragmentCompat() {
} }
return@setOnPreferenceClickListener true return@setOnPreferenceClickListener true
} }
getPref(R.string.dns_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.dns_pref)
val prefValues = resources.getIntArray(R.array.dns_pref_values)
val currentDns =
settingsManager.getInt(getString(R.string.dns_pref), 0)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentDns),
getString(R.string.dns_pref),
true,
{}) {
settingsManager.edit().putInt(getString(R.string.dns_pref), prefValues[it]).apply()
(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) }
}
return@setOnPreferenceClickListener true
}
getPref(R.string.prefer_limit_title_key)?.setOnPreferenceClickListener { getPref(R.string.prefer_limit_title_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.limit_title_pref_names) val prefNames = resources.getStringArray(R.array.limit_title_pref_names)
@ -242,60 +183,6 @@ class SettingsPlayer : PreferenceFragmentCompat() {
return@setOnPreferenceClickListener true return@setOnPreferenceClickListener true
} }
} }
fun getDownloadDirs(): List<String> {
return normalSafeApiCall {
val defaultDir = VideoDownloadManager.getDownloadDir()?.filePath
// app_name_download_path = Cloudstream and does not change depending on release.
// DOES NOT WORK ON SCOPED STORAGE.
val secondaryDir =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath +
File.separator + resources.getString(R.string.app_name_download_path)
val first = listOf(defaultDir, secondaryDir)
(try {
val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second }
(first +
requireContext().getExternalFilesDirs("").mapNotNull { it.path } +
currentDir)
} catch (e: Exception) {
first
}).filterNotNull().distinct()
} ?: emptyList()
}
getPref(R.string.download_path_key)?.setOnPreferenceClickListener {
val dirs = getDownloadDirs()
val currentDir =
settingsManager.getString(getString(R.string.download_path_pref), null)
?: VideoDownloadManager.getDownloadDir().toString()
activity?.showBottomDialog(
dirs + listOf("Custom"),
dirs.indexOf(currentDir),
getString(R.string.download_path_pref),
true,
{}) {
// Last = custom
if (it == dirs.size) {
try {
pathPicker.launch(Uri.EMPTY)
} catch (e: Exception) {
logError(e)
}
} else {
// Sets both visual and actual paths.
// key = used path
// pref = visual path
settingsManager.edit()
.putString(getString(R.string.download_path_key), dirs[it]).apply()
settingsManager.edit()
.putString(getString(R.string.download_path_pref), dirs[it]).apply()
}
}
return@setOnPreferenceClickListener true
}
} }
} }

View file

@ -1,12 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24" android:viewportHeight="24"
app:tint="?attr/white"> android:tint="?attr/white">
<path <path
android:fillColor="@android:color/white" android:fillColor="@android:color/white"
android:pathData="M3,3v8h8L11,3L3,3zM9,9L5,9L5,5h4v4zM3,13v8h8v-8L3,13zM9,19L5,19v-4h4v4zM13,3v8h8L21,3h-8zM19,9h-4L15,5h4v4zM13,13v8h8v-8h-8zM19,19h-4v-4h4v4z" android:pathData="M3,3v8h8L11,3L3,3zM9,9L5,9L5,5h4v4zM3,13v8h8v-8L3,13zM9,19L5,19v-4h4v4zM13,3v8h8L21,3h-8zM19,9h-4L15,5h4v4zM13,13v8h8v-8h-8zM19,19h-4v-4h4v4z"
android:fillType="evenOdd"/> android:fillType="evenOdd" />
</vector> </vector>

View file

@ -44,6 +44,7 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<EditText <EditText
android:textColorHint="?attr/grayTextColor"
android:hint="@string/example_username" android:hint="@string/example_username"
android:autofillHints="username" android:autofillHints="username"
android:id="@+id/login_username_input" android:id="@+id/login_username_input"
@ -57,6 +58,7 @@
tools:ignore="LabelFor" /> tools:ignore="LabelFor" />
<EditText <EditText
android:textColorHint="?attr/grayTextColor"
android:autofillHints="emailAddress" android:autofillHints="emailAddress"
android:hint="@string/example_email" android:hint="@string/example_email"
android:id="@+id/login_email_input" android:id="@+id/login_email_input"
@ -72,6 +74,7 @@
tools:ignore="LabelFor" /> tools:ignore="LabelFor" />
<EditText <EditText
android:textColorHint="?attr/grayTextColor"
android:hint="@string/example_ip" android:hint="@string/example_ip"
android:id="@+id/login_server_input" android:id="@+id/login_server_input"
android:nextFocusRight="@id/cancel_btt" android:nextFocusRight="@id/cancel_btt"
@ -85,6 +88,7 @@
tools:ignore="LabelFor" /> tools:ignore="LabelFor" />
<EditText <EditText
android:textColorHint="?attr/grayTextColor"
android:hint="@string/example_password" android:hint="@string/example_password"
android:id="@+id/login_password_input" android:id="@+id/login_password_input"
android:nextFocusRight="@id/cancel_btt" android:nextFocusRight="@id/cancel_btt"

View file

@ -117,7 +117,7 @@
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:paddingBottom="5dp" android:paddingBottom="5dp"
android:paddingTop="5dp" android:paddingTop="5dp"
android:textColor="@color/textColor" android:textColor="?attr/textColor"
android:id="@+id/imageText" android:id="@+id/imageText"
android:minLines="2" android:minLines="2"
android:maxLines="2" android:maxLines="2"

View file

@ -52,8 +52,15 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
<TextView
android:nextFocusDown="@id/settings_player"
android:id="@+id/settings_general"
style="@style/SettingsItem"
android:text="@string/category_general" />
<TextView <TextView
android:nextFocusUp="@id/settings_general"
android:nextFocusDown="@id/settings_lang" android:nextFocusDown="@id/settings_lang"
android:id="@+id/settings_player" android:id="@+id/settings_player"
@ -89,7 +96,7 @@
android:id="@+id/settings_credits" android:id="@+id/settings_credits"
style="@style/SettingsItem" style="@style/SettingsItem"
android:text="@string/category_credits" /> android:text="@string/category_account" />
<TextView <TextView
android:padding="10dp" android:padding="10dp"

View file

@ -1,18 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/primaryBlackBackground" >
<ImageView
android:id="@+id/imgPoster"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:scaleType="fitCenter" android:background="?attr/primaryBlackBackground">
android:adjustViewBounds="true"
android:src="@drawable/default_cover" <ImageView
android:background="#fffff0" android:id="@+id/imgPoster"
android:contentDescription="@string/poster_image" android:layout_width="match_parent"
/> android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:src="@drawable/default_cover"
android:background="#fffff0"
android:contentDescription="@string/poster_image" />
</LinearLayout> </LinearLayout>

View file

@ -44,6 +44,7 @@
app:tint="?attr/textColor" /> app:tint="?attr/textColor" />
<EditText <EditText
android:textColorHint="?attr/grayTextColor"
android:id="@+id/result_sync_current_episodes" android:id="@+id/result_sync_current_episodes"
style="@style/AppEditStyle" style="@style/AppEditStyle"
tools:hint="20" tools:hint="20"

View file

@ -11,70 +11,70 @@
android:clickable="true" android:clickable="true"
android:id="@+id/search_result_root"> android:id="@+id/search_result_root">
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:layout_margin="2dp" android:layout_margin="2dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="2dp"
android:elevation="10dp"
app:cardCornerRadius="@dimen/rounded_image_radius"
android:id="@+id/background_card"
app:cardBackgroundColor="?attr/primaryGrayBackground">
<ImageView
android:id="@+id/imageView"
tools:src="@drawable/example_poster"
android:duplicateParentState="true"
android:scaleType="centerCrop"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginBottom="2dp" android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:elevation="10dp" android:contentDescription="@string/search_poster_img_des" />
app:cardCornerRadius="@dimen/rounded_image_radius"
android:id="@+id/background_card"
app:cardBackgroundColor="?attr/primaryGrayBackground">
<ImageView
android:id="@+id/imageView"
tools:src="@drawable/example_poster"
android:duplicateParentState="true"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/search_poster_img_des" />
<TextView
tools:text="@string/quality_hd"
android:id="@+id/text_quality"
android:textColor="@color/textColor"
style="@style/SearchBox"
android:background="@drawable/type_bg_color" />
<LinearLayout
android:orientation="vertical"
android:layout_gravity="end"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="@string/app_dubbed_text"
android:id="@+id/text_is_dub"
android:layout_gravity="end"
style="@style/SearchBox"
android:background="@drawable/dub_bg_color" />
<TextView
android:id="@+id/text_is_sub"
android:text="@string/app_subbed_text"
android:layout_gravity="end"
style="@style/SearchBox"
android:background="@drawable/sub_bg_color" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<TextView <TextView
tools:text="The Perfect Run\nThe Perfect Run" tools:text="@string/quality_hd"
android:layout_width="match_parent" android:id="@+id/text_quality"
android:layout_height="wrap_content"
android:textSize="13sp"
android:gravity="center"
android:layout_gravity="bottom"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:textColor="@color/textColor" android:textColor="@color/textColor"
android:id="@+id/imageText" style="@style/SearchBox"
android:minLines="2" android:background="@drawable/type_bg_color" />
android:maxLines="2"
android:paddingStart="5dp" <LinearLayout
android:paddingEnd="5dp" android:orientation="vertical"
android:ellipsize="end" /> android:layout_gravity="end"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="@string/app_dubbed_text"
android:id="@+id/text_is_dub"
android:layout_gravity="end"
style="@style/SearchBox"
android:background="@drawable/dub_bg_color" />
<TextView
android:id="@+id/text_is_sub"
android:text="@string/app_subbed_text"
android:layout_gravity="end"
style="@style/SearchBox"
android:background="@drawable/sub_bg_color" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<TextView
tools:text="The Perfect Run\nThe Perfect Run"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="13sp"
android:gravity="center"
android:layout_gravity="bottom"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:textColor="?attr/textColor"
android:id="@+id/imageText"
android:minLines="2"
android:maxLines="2"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:ellipsize="end" />
</LinearLayout> </LinearLayout>

View file

@ -119,6 +119,15 @@
app:popEnterAnim="@anim/enter_anim" app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" /> app:popExitAnim="@anim/exit_anim" />
<fragment
android:id="@+id/navigation_settings_general"
android:label="@string/title_settings"
android:name="com.lagradost.cloudstream3.ui.settings.SettingsGeneral"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<fragment <fragment
android:id="@+id/navigation_settings_lang" android:id="@+id/navigation_settings_lang"
android:label="@string/title_settings" android:label="@string/title_settings"
@ -290,6 +299,13 @@
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
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim"
android:id="@+id/action_navigation_settings_to_navigation_settings_general"
app:destination="@id/navigation_settings_general" />
</fragment> </fragment>
<fragment <fragment

View file

@ -246,7 +246,7 @@
<string name="resize_fill">امتداد</string> <string name="resize_fill">امتداد</string>
<string name="resize_zoom">تكبير</string> <string name="resize_zoom">تكبير</string>
<string name="general">عام</string> <string name="category_general">عام</string>
<string name="provider_lang_settings">لغات الموفر</string> <string name="provider_lang_settings">لغات الموفر</string>
<string name="app_layout">واجهة التطبيق</string> <string name="app_layout">واجهة التطبيق</string>
<string name="preferred_media_settings">النوع المفضل من المشاهدة</string> <string name="preferred_media_settings">النوع المفضل من المشاهدة</string>

View file

@ -238,7 +238,7 @@
<string name="search">Búsqueda</string> <string name="search">Búsqueda</string>
<string name="category_nginx">Nginx</string> <string name="category_nginx">Nginx</string>
<string name="category_credits">Créditos y cuenta</string> <string name="category_account">Créditos y cuenta</string>
<string name="category_updates">Actualizaciones y copia de seguridad</string> <string name="category_updates">Actualizaciones y copia de seguridad</string>
<string name="nginx_credentials_title">Credencial Nginx</string> <string name="nginx_credentials_title">Credencial Nginx</string>
<string name="nginx_credentials_summary">Tienes que usar el siguiente formato minombredeusuariogenial:micontraseñasegura123</string> <string name="nginx_credentials_summary">Tienes que usar el siguiente formato minombredeusuariogenial:micontraseñasegura123</string>
@ -408,7 +408,7 @@
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
CloudStream 3 at your own risk. CloudStream 3 at your own risk.
</string> </string>
<string name="general">General</string> <string name="category_general">General</string>
<string name="random_button_settings">Botón aleatorio</string> <string name="random_button_settings">Botón aleatorio</string>
<string name="random_button_settings_desc">Mostrar botón aleatorio en la página de inicio</string> <string name="random_button_settings_desc">Mostrar botón aleatorio en la página de inicio</string>
<string name="provider_lang_settings">Idiomas del proveedor</string> <string name="provider_lang_settings">Idiomas del proveedor</string>

View file

@ -193,7 +193,7 @@
<string name="app_theme_settings">Thème de l\'application</string> <string name="app_theme_settings">Thème de l\'application</string>
<string name="player_speed_text_format" formatted="true">Vitesse (%.2fx)</string> <string name="player_speed_text_format" formatted="true">Vitesse (%.2fx)</string>
<string name="use_system_brightness_settings">Utiliser la luminosité du système</string> <string name="use_system_brightness_settings">Utiliser la luminosité du système</string>
<string name="general">Général</string> <string name="category_general">Général</string>
<string name="dns_pref">DNS avec HTTPS</string> <string name="dns_pref">DNS avec HTTPS</string>
<string name="display_subbed_dubbed_settings">Afficher les animés en Anglais (Dub) / sous-titrés</string> <string name="display_subbed_dubbed_settings">Afficher les animés en Anglais (Dub) / sous-titrés</string>
<string name="phone_layout">Disposition en mode téléphone</string> <string name="phone_layout">Disposition en mode téléphone</string>

View file

@ -188,7 +188,7 @@
<string name="search">Cari</string> <string name="search">Cari</string>
<string name="category_nginx">Nginx</string> <string name="category_nginx">Nginx</string>
<string name="category_credits">Kredit dan akun</string> <string name="category_account">Kredit dan akun</string>
<string name="category_updates">Update dan cadangan</string> <string name="category_updates">Update dan cadangan</string>
<string name="nginx_credentials_title">Kredensial Nginx</string> <string name="nginx_credentials_title">Kredensial Nginx</string>
<string name="nginx_credentials_summary">Kamu harus menggunakan format berikut namaku:passwordku123</string> <string name="nginx_credentials_summary">Kamu harus menggunakan format berikut namaku:passwordku123</string>
@ -359,7 +359,7 @@
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
CloudStream 3 at your own risk. CloudStream 3 at your own risk.
</string> </string>
<string name="general">Umum</string> <string name="category_general">Umum</string>
<string name="random_button_settings">Tombol Acak</string> <string name="random_button_settings">Tombol Acak</string>
<string name="random_button_settings_desc">Tampilkan tombol acak di Beranda</string> <string name="random_button_settings_desc">Tampilkan tombol acak di Beranda</string>
<string name="provider_lang_settings">Bahasa provider</string> <string name="provider_lang_settings">Bahasa provider</string>

View file

@ -181,7 +181,7 @@
<string name="search">Cerca</string> <string name="search">Cerca</string>
<string name="category_nginx">Nginx</string> <string name="category_nginx">Nginx</string>
<string name="category_credits">Accounts e Crediti</string> <string name="category_account">Accounts e Crediti</string>
<string name="category_updates">Aggiornamenti e Backup</string> <string name="category_updates">Aggiornamenti e Backup</string>
<string name="nginx_credentials_title">Credenziali Nginx</string> <string name="nginx_credentials_title">Credenziali Nginx</string>
<string name="nginx_credentials_summary">È necessario utilizzare il seguente formato mycoolusername:mysecurepassword123</string> <string name="nginx_credentials_summary">È necessario utilizzare il seguente formato mycoolusername:mysecurepassword123</string>
@ -328,7 +328,7 @@
<string name="resize_zoom">Zoom</string> <string name="resize_zoom">Zoom</string>
<string name="legal_notice">Disclaimer</string> <string name="legal_notice">Disclaimer</string>
<string name="general">Generale</string> <string name="category_general">Generale</string>
<string name="random_button_settings">Random</string> <string name="random_button_settings">Random</string>
<string name="random_button_settings_desc">Mostra pulsante Random nella homepage</string> <string name="random_button_settings_desc">Mostra pulsante Random nella homepage</string>
<string name="provider_lang_settings">Lingua provider</string> <string name="provider_lang_settings">Lingua provider</string>

View file

@ -220,7 +220,7 @@
<string name="resize_zoom">Зумирај</string> <string name="resize_zoom">Зумирај</string>
<string name="legal_notice">Disclaimer</string> <string name="legal_notice">Disclaimer</string>
<string name="general">Генерално</string> <string name="category_general">Генерално</string>
<string name="provider_lang_settings">Јазици на провајдерите</string> <string name="provider_lang_settings">Јазици на провајдерите</string>
<string name="app_layout">Распоред на апликацијата</string> <string name="app_layout">Распоред на апликацијата</string>
<string name="preferred_media_settings">Претпочитани медиуми</string> <string name="preferred_media_settings">Претпочитани медиуми</string>

View file

@ -188,7 +188,7 @@
<string name="resize_zoom">uhuoh o a ohahuhohoa hah</string> <string name="resize_zoom">uhuoh o a ohahuhohoa hah</string>
<string name="provider_lang_settings">ua hu ouo o aoau hah ah</string> <string name="provider_lang_settings">ua hu ouo o aoau hah ah</string>
<string name="legal_notice">ah huu oouhhau aoaoaaohoo ha</string> <string name="legal_notice">ah huu oouhhau aoaoaaohoo ha</string>
<string name="general">a ahu uoo uoahuo uo</string> <string name="category_general">a ahu uoo uoahuo uo</string>
<string name="app_layout">uo u ohouao</string> <string name="app_layout">uo u ohouao</string>
<string name="automatic">uuoouhh hhuhuuh ouhoaao hau aouo</string> <string name="automatic">uuoouhh hhuhuuh ouhoaao hau aouo</string>
<string name="tv_layout">uha uh huo uooaah u</string> <string name="tv_layout">uha uh huo uooaah u</string>

View file

@ -221,7 +221,7 @@
<string name="resize_fit">Tilpass til skjermen</string> <string name="resize_fit">Tilpass til skjermen</string>
<string name="resize_fill">Tøye ut</string> <string name="resize_fill">Tøye ut</string>
<string name="resize_zoom">Zoome</string> <string name="resize_zoom">Zoome</string>
<string name="general">Grunnleggende</string> <string name="category_general">Grunnleggende</string>
<string name="provider_lang_settings">Leverandør Språk</string> <string name="provider_lang_settings">Leverandør Språk</string>
<string name="app_layout">App Oppsett</string> <string name="app_layout">App Oppsett</string>
<string name="automatic">Automatisk</string> <string name="automatic">Automatisk</string>

View file

@ -270,7 +270,7 @@
<string name="legal_notice">Zastrzeżenie</string> <string name="legal_notice">Zastrzeżenie</string>
<string name="provider_lang_settings">Języki dostawców</string> <string name="provider_lang_settings">Języki dostawców</string>
<string name="general">Ogólne</string> <string name="category_general">Ogólne</string>
<string name="app_layout">Układ aplikacji</string> <string name="app_layout">Układ aplikacji</string>
<string name="preferred_media_settings">Preferowane media</string> <string name="preferred_media_settings">Preferowane media</string>

View file

@ -258,7 +258,7 @@
responsabilidade do usuário de evitar qualquer ação que possa violar as leis que regem sua localidade. Utilizar responsabilidade do usuário de evitar qualquer ação que possa violar as leis que regem sua localidade. Utilizar
CloudStream 3 por sua própria conta e risco. CloudStream 3 por sua própria conta e risco.
</string> </string>
<string name="general">Geral</string> <string name="category_general">Geral</string>
<string name="provider_lang_settings">Idiomas dos Origems</string> <string name="provider_lang_settings">Idiomas dos Origems</string>
<string name="app_layout">Layout do App</string> <string name="app_layout">Layout do App</string>
<string name="preferred_media_settings">Mídia preferida</string> <string name="preferred_media_settings">Mídia preferida</string>

View file

@ -259,7 +259,7 @@
responsabilitatea utilizatorului de a evita orice acțiune care ar putea încălca legile care guvernează localitatea sa. Utilizați responsabilitatea utilizatorului de a evita orice acțiune care ar putea încălca legile care guvernează localitatea sa. Utilizați
CloudStream 3 pe propriul risc. CloudStream 3 pe propriul risc.
</string> </string>
<string name="general">Generală</string> <string name="category_general">Generală</string>
<string name="provider_lang_settings">Limbile Furnizorului</string> <string name="provider_lang_settings">Limbile Furnizorului</string>
<string name="app_layout">Aranjament-ul Aplicației</string> <string name="app_layout">Aranjament-ul Aplicației</string>
<string name="preferred_media_settings">Media Preferată</string> <string name="preferred_media_settings">Media Preferată</string>

View file

@ -199,7 +199,7 @@
<string name="resume">Återuppta</string> <string name="resume">Återuppta</string>
<string name="storage_error">Ett nerladdningsfel uppstod, kolla om appen har lagringsbehörigheter</string> <string name="storage_error">Ett nerladdningsfel uppstod, kolla om appen har lagringsbehörigheter</string>
<string name="watch_quality_pref">Föredragen videokvalitet</string> <string name="watch_quality_pref">Föredragen videokvalitet</string>
<string name="general">Allmänna Inställningar</string> <string name="category_general">Allmänna Inställningar</string>
<string name="subs_font_size">Textstorlek</string> <string name="subs_font_size">Textstorlek</string>
<string name="use_system_brightness_settings">Använd system ljusstyrka</string> <string name="use_system_brightness_settings">Använd system ljusstyrka</string>
<string name="use_system_brightness_settings_des">Använder systemets ljusstyrka instället för en svart överlaga</string> <string name="use_system_brightness_settings_des">Använder systemets ljusstyrka instället för en svart överlaga</string>

View file

@ -231,7 +231,7 @@
<string name="resize_fill">Punan ang buong screen</string> <string name="resize_fill">Punan ang buong screen</string>
<string name="resize_zoom">Zoom</string> <string name="resize_zoom">Zoom</string>
<string name="general">Pangkalahatan</string> <string name="category_general">Pangkalahatan</string>
<string name="provider_lang_settings">Lenggwahe ng Provider</string> <string name="provider_lang_settings">Lenggwahe ng Provider</string>
<string name="app_layout">App Layout</string> <string name="app_layout">App Layout</string>
<string name="automatic">Awtomatik</string> <string name="automatic">Awtomatik</string>

View file

@ -344,7 +344,7 @@
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
CloudStream 3 at your own risk. CloudStream 3 at your own risk.
</string> </string>
<string name="general">Genel</string> <string name="category_general">Genel</string>
<string name="provider_lang_settings">Sağlayıcı Dilleri</string> <string name="provider_lang_settings">Sağlayıcı Dilleri</string>
<string name="app_layout">Uygulama Düzeni</string> <string name="app_layout">Uygulama Düzeni</string>
<string name="preferred_media_settings">Tercih Edilen Medya</string> <string name="preferred_media_settings">Tercih Edilen Medya</string>

View file

@ -243,7 +243,7 @@
<string name="resize_fill">Kéo dãn</string> <string name="resize_fill">Kéo dãn</string>
<string name="resize_zoom">Phóng to</string> <string name="resize_zoom">Phóng to</string>
<string name="general">Tổng quan</string> <string name="category_general">Tổng quan</string>
<string name="provider_lang_settings">Ngôn ngữ nhà cung cấp</string> <string name="provider_lang_settings">Ngôn ngữ nhà cung cấp</string>
<string name="app_layout">Giao diện App</string> <string name="app_layout">Giao diện App</string>
<string name="preferred_media_settings">Thể loại ưu tiên</string> <string name="preferred_media_settings">Thể loại ưu tiên</string>

View file

@ -306,7 +306,7 @@
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
CloudStream 3 at your own risk. CloudStream 3 at your own risk.
</string> </string>
<string name="general">全局</string> <string name="category_general">全局</string>
<string name="provider_lang_settings">内容提供者语言</string> <string name="provider_lang_settings">内容提供者语言</string>
<string name="app_layout">应用布局</string> <string name="app_layout">应用布局</string>
<string name="preferred_media_settings">首选媒体</string> <string name="preferred_media_settings">首选媒体</string>

View file

@ -35,9 +35,6 @@
<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>
@ -241,11 +238,8 @@
<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="category_nginx">Nginx</string> <string name="category_account">Accounts</string>
<string name="category_credits">Credits and account</string>
<string name="category_updates">Updates and backup</string> <string name="category_updates">Updates and backup</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_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="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>
@ -414,15 +408,15 @@
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
CloudStream 3 at your own risk. CloudStream 3 at your own risk.
</string> </string>
<string name="general">General</string> <string name="category_general">General</string>
<string name="random_button_settings">Random Button</string> <string name="random_button_settings">Random Button</string>
<string name="random_button_settings_desc">Show random button on Homepage</string> <string name="random_button_settings_desc">Show random button on Homepage</string>
<string name="provider_lang_settings">Provider languages</string> <string name="provider_lang_settings">Provider languages</string>
<string name="app_layout">App Layout</string> <string name="app_layout">App Layout</string>
<string name="preferred_media_settings">Preferred media</string> <string name="preferred_media_settings">Preferred media</string>
<string name="subtitles_encoding">Subtitle encoding</string> <string name="subtitles_encoding">Subtitle encoding</string>
<string name="category_preferred_media_and_lang">Preferred media and language</string> <string name="category_preferred_media_and_lang">Language</string>
<string name="category_ui">User interface</string> <string name="category_ui">Layout</string>
<string name="automatic">Auto</string> <string name="automatic">Auto</string>
<string name="tv_layout">TV layout</string> <string name="tv_layout">TV layout</string>
@ -535,4 +529,5 @@
<string name="error_invalid_id">Invalid id</string> <string name="error_invalid_id">Invalid id</string>
<string name="subtitles_remove_captions">Remove closed captions from subtitles</string> <string name="subtitles_remove_captions">Remove closed captions from subtitles</string>
<string name="subtitles_remove_bloat">Remove bloat from subtitles</string> <string name="subtitles_remove_bloat">Remove bloat from subtitles</string>
<string name="extras">Extras</string>
</resources> </resources>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
android:key="@string/mal_key"
android:icon="@drawable/mal_logo" />
<Preference
android:key="@string/anilist_key"
android:icon="@drawable/ic_anilist_icon" />
<Preference
android:key="@string/opensubtitles_key"
android:icon="@drawable/open_subtitles_icon" />
<Preference
android:key="@string/nginx_key"
android:icon="@drawable/nginx" />
<Preference
android:title="@string/nginx_info_title"
android:icon="@drawable/nginx_question"
android:summary="@string/nginx_info_summary">
<intent
android:action="android.intent.action.VIEW"
android:data="https://www.sarlays.com/use-nginx-with-cloudstream/" />
</Preference>
</PreferenceScreen>

View file

@ -12,16 +12,6 @@
android:icon="@drawable/ic_outline_subtitles_24" android:icon="@drawable/ic_outline_subtitles_24"
app:summary="@string/chromecast_subtitles_settings_des" /> app:summary="@string/chromecast_subtitles_settings_des" />
<Preference
android:key="@string/dns_key"
android:title="@string/dns_pref"
android:summary="@string/dns_pref_summary"
android:icon="@drawable/ic_baseline_dns_24" />
<Preference
android:key="@string/download_path_key"
android:title="@string/download_path_pref"
android:icon="@drawable/netflix_download" />
<Preference <Preference
android:key="@string/quality_pref_key" android:key="@string/quality_pref_key"

View file

@ -1,29 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<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
android:key="@string/mal_key"
android:icon="@drawable/mal_logo" />
<Preference <Preference
android:key="@string/anilist_key" android:key="@string/dns_key"
android:icon="@drawable/ic_anilist_icon" /> android:title="@string/dns_pref"
<Preference android:summary="@string/dns_pref_summary"
android:key="@string/opensubtitles_key" android:icon="@drawable/ic_baseline_dns_24" />
android:icon="@drawable/open_subtitles_icon" />
<Preference
android:key="@string/nginx_key"
android:icon="@drawable/nginx" />
<Preference <Preference
android:key="@string/nginx_info" android:key="@string/download_path_key"
android:title="@string/nginx_info_title" android:title="@string/download_path_pref"
android:icon="@drawable/nginx_question" android:icon="@drawable/netflix_download" />
android:summary="@string/nginx_info_summary">
<intent
android:action="android.intent.action.VIEW"
android:data="https://www.sarlays.com/use-nginx-with-cloudstream/" />
</Preference>
<Preference <Preference
android:key="@string/legal_notice_key" android:key="@string/legal_notice_key"