Merge remote-tracking branch 'upstream/master'

# Conflicts:
#	app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt
This commit is contained in:
Antony 2022-08-22 00:29:31 +02:00
commit af35ddf598
39 changed files with 351 additions and 308 deletions

View file

@ -41,6 +41,7 @@ import com.lagradost.cloudstream3.CommonActivity.updateLocale
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.network.initClient import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.plugins.PluginManager import com.lagradost.cloudstream3.plugins.PluginManager
import com.lagradost.cloudstream3.plugins.PluginManager.loadSinglePlugin
import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.OAuth2Apis import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.OAuth2Apis
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.accountManagers import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.accountManagers
@ -78,6 +79,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.navigate import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.requestRW import com.lagradost.cloudstream3.utils.UIHelper.requestRW
import com.lagradost.cloudstream3.utils.USER_PROVIDER_API import com.lagradost.cloudstream3.utils.USER_PROVIDER_API
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.Requests
import com.lagradost.nicehttp.ResponseParser import com.lagradost.nicehttp.ResponseParser
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
@ -130,6 +132,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
companion object { companion object {
const val TAG = "MAINACT" const val TAG = "MAINACT"
val afterPluginsLoadedEvent = Event<Boolean>() val afterPluginsLoadedEvent = Event<Boolean>()
val mainPluginsLoadedEvent =
Event<Boolean>() // homepage api, used to speed up time to load for homepage
val afterRepositoryLoadedEvent = Event<Boolean>() val afterRepositoryLoadedEvent = Event<Boolean>()
} }
@ -436,6 +440,12 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
changeStatusBarState(isEmulatorSettings()) changeStatusBarState(isEmulatorSettings())
ioSafe { ioSafe {
getKey<String>(USER_SELECTED_HOMEPAGE_API)?.let { homeApi ->
mainPluginsLoadedEvent.invoke(loadSinglePlugin(this@MainActivity, homeApi))
} ?: run {
mainPluginsLoadedEvent.invoke(false)
}
if (settingsManager.getBoolean(getString(R.string.auto_update_plugins_key), true)) { if (settingsManager.getBoolean(getString(R.string.auto_update_plugins_key), true)) {
PluginManager.updateAllOnlinePluginsAndLoadThem(this@MainActivity) PluginManager.updateAllOnlinePluginsAndLoadThem(this@MainActivity)
} else { } else {

View file

@ -0,0 +1,102 @@
package com.lagradost.cloudstream3.network
import android.util.Log
import android.webkit.CookieManager
import androidx.annotation.AnyThread
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.debugWarning
import com.lagradost.nicehttp.Requests.Companion.await
import com.lagradost.nicehttp.cookies
import kotlinx.coroutines.runBlocking
import okhttp3.*
@AnyThread
class CloudflareKiller : Interceptor {
companion object {
const val TAG = "CloudflareKiller"
fun parseCookieMap(cookie: String): Map<String, String> {
return cookie.split(";").associate {
val split = it.split("=")
(split.getOrNull(0)?.trim() ?: "") to (split.getOrNull(1)?.trim() ?: "")
}.filter { it.key.isNotBlank() && it.value.isNotBlank() }
}
}
val savedCookies: MutableMap<String, Map<String, String>> = mutableMapOf()
override fun intercept(chain: Interceptor.Chain): Response = runBlocking {
val request = chain.request()
val cookies = savedCookies[request.url.host]
if (cookies == null) {
bypassCloudflare(request)?.let {
Log.d(TAG, "Succeeded bypassing cloudflare: ${request.url}")
return@runBlocking it
}
} else {
return@runBlocking proceed(request, cookies)
}
debugWarning({ true }) { "Failed cloudflare at: ${request.url}" }
return@runBlocking chain.proceed(request)
}
private fun getWebViewCookie(url: String): String? {
return CookieManager.getInstance()?.getCookie(url)
}
/**
* Returns true if the cf cookies were successfully fetched from the CookieManager
* Also saves the cookies.
* */
private fun trySolveWithSavedCookies(request: Request): Boolean {
// Not sure if this takes expiration into account
return getWebViewCookie(request.url.toString())?.let { cookie ->
cookie.contains("cf_clearance").also { solved ->
if (solved) savedCookies[request.url.host] = parseCookieMap(cookie)
}
} ?: false
}
private suspend fun proceed(request: Request, cookies: Map<String, String>): Response {
val userAgentMap = WebViewResolver.getWebViewUserAgent()?.let {
mapOf("user-agent" to it)
} ?: emptyMap()
val headers =
getHeaders(request.headers.toMap() + userAgentMap, cookies + request.cookies)
return app.baseClient.newCall(
request.newBuilder()
.headers(headers)
.build()
).await()
}
private suspend fun bypassCloudflare(request: Request): Response? {
val url = request.url.toString()
// If no cookies then try to get them
// Remove this if statement if cookies expire
if (!trySolveWithSavedCookies(request)) {
Log.d(TAG, "Loading webview to solve cloudflare for ${request.url}")
WebViewResolver(
// Never exit based on url
Regex(".^"),
// Cloudflare needs default user agent
userAgent = null,
// Cannot use okhttp (i think intercepting cookies fails which causes the issues)
useOkhttp = false,
// Match every url for the requestCallBack
additionalUrls = listOf(Regex("."))
).resolveUsingWebView(
url
) {
trySolveWithSavedCookies(request)
}
}
val cookies = savedCookies[request.url.host] ?: return null
return proceed(request, cookies)
}
}

View file

@ -1,13 +1,10 @@
package com.lagradost.cloudstream3.network package com.lagradost.cloudstream3.network
import androidx.annotation.AnyThread import androidx.annotation.AnyThread
import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.nicehttp.Requests.Companion.await import com.lagradost.nicehttp.Requests.Companion.await
import com.lagradost.nicehttp.getCookies import com.lagradost.nicehttp.cookies
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import okhttp3.Headers
import okhttp3.Headers.Companion.toHeaders
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response

View file

@ -43,10 +43,10 @@ fun Requests.initClient(context: Context): OkHttpClient {
return baseClient return baseClient
} }
val Request.cookies: Map<String, String> //val Request.cookies: Map<String, String>
get() { // get() {
return this.headers.getCookies("Cookie") // return this.headers.getCookies("Cookie")
} // }
private val DEFAULT_HEADERS = mapOf("user-agent" to USER_AGENT) private val DEFAULT_HEADERS = mapOf("user-agent" to USER_AGENT)

View file

@ -4,10 +4,12 @@ import android.annotation.SuppressLint
import android.net.http.SslError import android.net.http.SslError
import android.webkit.* import android.webkit.*
import com.lagradost.cloudstream3.AcraApplication import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.USER_AGENT import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.Coroutines.mainWork
import com.lagradost.nicehttp.requestCreator import com.lagradost.nicehttp.requestCreator
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -15,16 +17,39 @@ import okhttp3.Interceptor
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import java.net.URI import java.net.URI
import java.util.concurrent.TimeUnit
/** /**
* When used as Interceptor additionalUrls cannot be returned, use WebViewResolver(...).resolveUsingWebView(...) * When used as Interceptor additionalUrls cannot be returned, use WebViewResolver(...).resolveUsingWebView(...)
* @param interceptUrl will stop the WebView when reaching this url. * @param interceptUrl will stop the WebView when reaching this url.
* @param additionalUrls this will make resolveUsingWebView also return all other requests matching the list of Regex. * @param additionalUrls this will make resolveUsingWebView also return all other requests matching the list of Regex.
* @param userAgent if null then will use the default user agent
* @param useOkhttp will try to use the okhttp client as much as possible, but this might cause some requests to fail. Disable for cloudflare.
* */ * */
class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> = emptyList()) : class WebViewResolver(
val interceptUrl: Regex,
val additionalUrls: List<Regex> = emptyList(),
val userAgent: String? = USER_AGENT,
val useOkhttp: Boolean = true
) :
Interceptor { Interceptor {
companion object {
var webViewUserAgent: String? = null
@JvmName("getWebViewUserAgent1")
fun getWebViewUserAgent(): String? {
return webViewUserAgent ?: context?.let { ctx ->
runBlocking {
mainWork {
WebView(ctx).settings.userAgentString.also { userAgent ->
webViewUserAgent = userAgent
}
}
}
}
}
}
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request() val request = chain.request()
return runBlocking { return runBlocking {
@ -38,7 +63,7 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
referer: String? = null, referer: String? = null,
method: String = "GET", method: String = "GET",
requestCallBack: (Request) -> Boolean = { false }, requestCallBack: (Request) -> Boolean = { false },
) : Pair<Request?, List<Request>> { ): Pair<Request?, List<Request>> {
return resolveUsingWebView( return resolveUsingWebView(
requestCreator(method, url, referer = referer), requestCallBack requestCreator(method, url, referer = referer), requestCallBack
) )
@ -57,12 +82,15 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
val headers = request.headers val headers = request.headers
println("Initial web-view request: $url") println("Initial web-view request: $url")
var webView: WebView? = null var webView: WebView? = null
// Extra assurance it exits as it should.
var shouldExit = false
fun destroyWebView() { fun destroyWebView() {
main { main {
webView?.stopLoading() webView?.stopLoading()
webView?.destroy() webView?.destroy()
webView = null webView = null
shouldExit = true
println("Destroyed webview") println("Destroyed webview")
} }
} }
@ -72,7 +100,7 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
main { main {
// Useful for debugging // Useful for debugging
// WebView.setWebContentsDebuggingEnabled(true) WebView.setWebContentsDebuggingEnabled(true)
try { try {
webView = WebView( webView = WebView(
AcraApplication.context AcraApplication.context
@ -81,9 +109,14 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
// Bare minimum to bypass captcha // Bare minimum to bypass captcha
settings.javaScriptEnabled = true settings.javaScriptEnabled = true
settings.domStorageEnabled = true settings.domStorageEnabled = true
settings.userAgentString = USER_AGENT
webViewUserAgent = settings.userAgentString
// Don't set user agent, setting user agent will make cloudflare break.
if (userAgent != null) {
settings.userAgentString = userAgent
}
// Blocks unnecessary images, remove if captcha fucks. // Blocks unnecessary images, remove if captcha fucks.
settings.blockNetworkImage = true // settings.blockNetworkImage = true
} }
webView?.webViewClient = object : WebViewClient() { webView?.webViewClient = object : WebViewClient() {
@ -92,11 +125,11 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
request: WebResourceRequest request: WebResourceRequest
): WebResourceResponse? = runBlocking { ): WebResourceResponse? = runBlocking {
val webViewUrl = request.url.toString() val webViewUrl = request.url.toString()
// println("Loading WebView URL: $webViewUrl") println("Loading WebView URL: $webViewUrl")
if (interceptUrl.containsMatchIn(webViewUrl)) { if (interceptUrl.containsMatchIn(webViewUrl)) {
fixedRequest = request.toRequest().also { fixedRequest = request.toRequest().also {
if (requestCallBack(it)) destroyWebView() requestCallBack(it)
} }
println("Web-view request finished: $webViewUrl") println("Web-view request finished: $webViewUrl")
destroyWebView() destroyWebView()
@ -158,22 +191,22 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
null, null,
null null
) )
webViewUrl.contains("recaptcha") || webViewUrl.contains("/cdn-cgi/") -> super.shouldInterceptRequest(
webViewUrl.contains("recaptcha") -> super.shouldInterceptRequest(
view, view,
request request
) )
request.method == "GET" -> app.get( useOkhttp && request.method == "GET" -> app.get(
webViewUrl, webViewUrl,
headers = request.requestHeaders headers = request.requestHeaders
).okhttpResponse.toWebResourceResponse() ).okhttpResponse.toWebResourceResponse()
request.method == "POST" -> app.post( useOkhttp && request.method == "POST" -> app.post(
webViewUrl, webViewUrl,
headers = request.requestHeaders headers = request.requestHeaders
).okhttpResponse.toWebResourceResponse() ).okhttpResponse.toWebResourceResponse()
else -> return@runBlocking super.shouldInterceptRequest(
else -> super.shouldInterceptRequest(
view, view,
request request
) )
@ -204,7 +237,7 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
val delayTime = 100L val delayTime = 100L
// A bit sloppy, but couldn't find a better way // A bit sloppy, but couldn't find a better way
while (loop < totalTime / delayTime) { while (loop < totalTime / delayTime && !shouldExit) {
if (fixedRequest != null) return fixedRequest to extraRequestList if (fixedRequest != null) return fixedRequest to extraRequestList
delay(delayTime) delay(delayTime)
loop += 1 loop += 1
@ -212,30 +245,31 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
println("Web-view timeout after ${totalTime / 1000}s") println("Web-view timeout after ${totalTime / 1000}s")
destroyWebView() destroyWebView()
return null to extraRequestList return fixedRequest to extraRequestList
} }
fun WebResourceRequest.toRequest(): Request { }
val webViewUrl = this.url.toString()
return requestCreator( fun WebResourceRequest.toRequest(): Request {
this.method, val webViewUrl = this.url.toString()
webViewUrl,
this.requestHeaders,
)
}
fun Response.toWebResourceResponse(): WebResourceResponse { return requestCreator(
val contentTypeValue = this.header("Content-Type") this.method,
// 1. contentType. 2. charset webViewUrl,
val typeRegex = Regex("""(.*);(?:.*charset=(.*)(?:|;)|)""") this.requestHeaders,
return if (contentTypeValue != null) { )
val found = typeRegex.find(contentTypeValue) }
val contentType = found?.groupValues?.getOrNull(1)?.ifBlank { null } ?: contentTypeValue
val charset = found?.groupValues?.getOrNull(2)?.ifBlank { null } fun Response.toWebResourceResponse(): WebResourceResponse {
WebResourceResponse(contentType, charset, this.body?.byteStream()) val contentTypeValue = this.header("Content-Type")
} else { // 1. contentType. 2. charset
WebResourceResponse("application/octet-stream", null, this.body?.byteStream()) val typeRegex = Regex("""(.*);(?:.*charset=(.*)(?:|;)|)""")
} return if (contentTypeValue != null) {
val found = typeRegex.find(contentTypeValue)
val contentType = found?.groupValues?.getOrNull(1)?.ifBlank { null } ?: contentTypeValue
val charset = found?.groupValues?.getOrNull(2)?.ifBlank { null }
WebResourceResponse(contentType, charset, this.body.byteStream())
} else {
WebResourceResponse("application/octet-stream", null, this.body.byteStream())
} }
} }

View file

@ -125,7 +125,7 @@ object PluginManager {
Environment.getExternalStorageDirectory().absolutePath + "/Cloudstream3/plugins" Environment.getExternalStorageDirectory().absolutePath + "/Cloudstream3/plugins"
// Maps filepath to plugin // Maps filepath to plugin
private val plugins: MutableMap<String, Plugin> = val plugins: MutableMap<String, Plugin> =
LinkedHashMap<String, Plugin>() LinkedHashMap<String, Plugin>()
// Maps urls to plugin // Maps urls to plugin
@ -164,6 +164,18 @@ object PluginManager {
var allCurrentOutDatedPlugins: Set<OnlinePluginData> = emptySet() var allCurrentOutDatedPlugins: Set<OnlinePluginData> = emptySet()
suspend fun loadSinglePlugin(activity: Activity, apiName: String): Boolean {
return (getPluginsOnline().firstOrNull { it.internalName == apiName }
?: getPluginsLocal().firstOrNull { it.internalName == apiName })?.let { savedData ->
// OnlinePluginData(savedData, onlineData)
loadPlugin(
activity,
File(savedData.filePath),
savedData
)
} ?: false
}
/** /**
* Needs to be run before other plugin loading because plugin loading can not be overwritten * Needs to be run before other plugin loading because plugin loading can not be overwritten
* 1. Gets all online data about the downloaded plugins * 1. Gets all online data about the downloaded plugins
@ -376,7 +388,7 @@ object PluginManager {
file ?: return false, file ?: return false,
PluginData(internalName, pluginUrl, true, file.absolutePath, PLUGIN_VERSION_NOT_SET) PluginData(internalName, pluginUrl, true, file.absolutePath, PLUGIN_VERSION_NOT_SET)
) )
} catch (e : Exception) { } catch (e: Exception) {
logError(e) logError(e)
return false return false
} }

View file

@ -1,16 +1,16 @@
package com.lagradost.cloudstream3.ui package com.lagradost.cloudstream3.ui
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.WebResourceRequest import android.webkit.WebResourceRequest
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.USER_AGENT import com.lagradost.cloudstream3.network.WebViewResolver
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringRepo import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringRepo
import com.lagradost.cloudstream3.utils.AppUtils.loadRepository import com.lagradost.cloudstream3.utils.AppUtils.loadRepository
import kotlinx.android.synthetic.main.fragment_webview.* import kotlinx.android.synthetic.main.fragment_webview.*
@ -48,7 +48,9 @@ class WebviewFragment : Fragment() {
} }
web_view.settings.javaScriptEnabled = true web_view.settings.javaScriptEnabled = true
web_view.settings.domStorageEnabled = true web_view.settings.domStorageEnabled = true
web_view.settings.userAgentString = USER_AGENT
WebViewResolver.webViewUserAgent = web_view.settings.userAgentString
// web_view.settings.userAgentString = USER_AGENT
web_view.loadUrl(url) web_view.loadUrl(url)
} }

View file

@ -37,6 +37,7 @@ import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import com.lagradost.cloudstream3.utils.VideoDownloadManager import com.lagradost.cloudstream3.utils.VideoDownloadManager
import kotlinx.android.synthetic.main.fragment_downloads.* import kotlinx.android.synthetic.main.fragment_downloads.*
import kotlinx.android.synthetic.main.stream_input.* import kotlinx.android.synthetic.main.stream_input.*
import android.text.format.Formatter.formatShortFileSize
const val DOWNLOAD_NAVIGATE_TO = "downloadpage" const val DOWNLOAD_NAVIGATE_TO = "downloadpage"
@ -44,10 +45,6 @@ const val DOWNLOAD_NAVIGATE_TO = "downloadpage"
class DownloadFragment : Fragment() { class DownloadFragment : Fragment() {
private lateinit var downloadsViewModel: DownloadViewModel private lateinit var downloadsViewModel: DownloadViewModel
private fun getBytesAsText(bytes: Long): String {
return "%.1f".format(bytes / 1000000000f)
}
private fun View.setLayoutWidth(weight: Long) { private fun View.setLayoutWidth(weight: Long) {
val param = LinearLayout.LayoutParams( val param = LinearLayout.LayoutParams(
0, 0,
@ -101,7 +98,7 @@ class DownloadFragment : Fragment() {
download_free_txt?.text = download_free_txt?.text =
getString(R.string.storage_size_format).format( getString(R.string.storage_size_format).format(
getString(R.string.free_storage), getString(R.string.free_storage),
getBytesAsText(it) formatShortFileSize(view.context, it)
) )
download_free?.setLayoutWidth(it) download_free?.setLayoutWidth(it)
} }
@ -109,7 +106,7 @@ class DownloadFragment : Fragment() {
download_used_txt?.text = download_used_txt?.text =
getString(R.string.storage_size_format).format( getString(R.string.storage_size_format).format(
getString(R.string.used_storage), getString(R.string.used_storage),
getBytesAsText(it) formatShortFileSize(view.context, it)
) )
download_used?.setLayoutWidth(it) download_used?.setLayoutWidth(it)
download_storage_appbar?.isVisible = it > 0 download_storage_appbar?.isVisible = it > 0
@ -118,7 +115,7 @@ class DownloadFragment : Fragment() {
download_app_txt?.text = download_app_txt?.text =
getString(R.string.storage_size_format).format( getString(R.string.storage_size_format).format(
getString(R.string.app_storage), getString(R.string.app_storage),
getBytesAsText(it) formatShortFileSize(view.context, it)
) )
download_app?.setLayoutWidth(it) download_app?.setLayoutWidth(it)
} }

View file

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3.ui.download package com.lagradost.cloudstream3.ui.download
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.text.format.Formatter.formatShortFileSize
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -113,7 +114,7 @@ class DownloadHeaderAdapter(
} }
title.text = d.name title.text = d.name
val mbString = "%.1f".format(card.totalBytes / 1000000f) val mbString = formatShortFileSize(itemView.context, card.totalBytes)
//val isMovie = d.type.isMovieType() //val isMovie = d.type.isMovieType()
if (card.child != null) { if (card.child != null) {

View file

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3.ui.download package com.lagradost.cloudstream3.ui.download
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.text.format.Formatter.formatShortFileSize
import android.view.View import android.view.View
import android.view.animation.DecelerateInterpolator import android.view.animation.DecelerateInterpolator
import android.widget.ImageView import android.widget.ImageView
@ -171,8 +172,8 @@ class EasyDownloadButton : IDisposable {
} }
textView?.visibility = View.VISIBLE textView?.visibility = View.VISIBLE
progressBar.visibility = View.VISIBLE progressBar.visibility = View.VISIBLE
val currentMbString = "%.1f".format(setCurrentBytes / 1000000f) val currentMbString = formatShortFileSize(textView?.context, setCurrentBytes)
val totalMbString = "%.1f".format(setTotalBytes / 1000000f) val totalMbString = formatShortFileSize(textView?.context, setTotalBytes)
textView?.text = textView?.text =
if (isTextPercentage) "%d%%".format(setCurrentBytes * 100L / setTotalBytes) else if (isTextPercentage) "%d%%".format(setCurrentBytes * 100L / setTotalBytes) else

View file

@ -31,8 +31,8 @@ import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
import com.lagradost.cloudstream3.MainActivity.Companion.mainPluginsLoadedEvent
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observe
@ -60,7 +60,6 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.deleteAllResumeStateIds
import com.lagradost.cloudstream3.utils.DataStoreHelper.removeLastWatched import com.lagradost.cloudstream3.utils.DataStoreHelper.removeLastWatched
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState
import com.lagradost.cloudstream3.utils.Event import com.lagradost.cloudstream3.utils.Event
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showOptionSelectStringRes import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showOptionSelectStringRes
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
@ -70,6 +69,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.UIHelper.setImageBlur import com.lagradost.cloudstream3.utils.UIHelper.setImageBlur
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
import com.lagradost.cloudstream3.widget.CenterZoomLayoutManager import com.lagradost.cloudstream3.widget.CenterZoomLayoutManager
import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.home_api_fab import kotlinx.android.synthetic.main.fragment_home.home_api_fab
@ -437,11 +437,13 @@ class HomeFragment : Fragment() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
reloadStored() reloadStored()
afterPluginsLoadedEvent += ::loadHomePage afterPluginsLoadedEvent += ::firstLoadHomePage
mainPluginsLoadedEvent += ::firstLoadHomePage
} }
override fun onStop() { override fun onStop() {
afterPluginsLoadedEvent -= ::loadHomePage afterPluginsLoadedEvent -= ::firstLoadHomePage
mainPluginsLoadedEvent -= ::firstLoadHomePage
super.onStop() super.onStop()
} }
@ -454,6 +456,14 @@ class HomeFragment : Fragment() {
homeViewModel.loadStoredData(list) homeViewModel.loadStoredData(list)
} }
private var hasBeenConsumed = false
private fun firstLoadHomePage(successful: Boolean = false) {
// dirty hack to make it only load once
if(hasBeenConsumed) return
hasBeenConsumed = true
loadHomePage(successful)
}
private fun loadHomePage(successful: Boolean = false) { private fun loadHomePage(successful: Boolean = false) {
val apiName = context?.getKey<String>(USER_SELECTED_HOMEPAGE_API) val apiName = context?.getKey<String>(USER_SELECTED_HOMEPAGE_API)
@ -962,13 +972,13 @@ class HomeFragment : Fragment() {
reloadStored() reloadStored()
loadHomePage() loadHomePage()
home_loaded.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { view, _, scrollY, _, oldScrollY -> home_loaded.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { v, _, scrollY, _, oldScrollY ->
val dy = scrollY - oldScrollY val dy = scrollY - oldScrollY
if (dy > 0) { //check for scroll down if (dy > 0) { //check for scroll down
home_api_fab?.shrink() // hide home_api_fab?.shrink() // hide
home_random?.shrink() home_random?.shrink()
} else if (dy < -5) { } else if (dy < -5) {
if (view?.context?.isTvSettings() == false) { if (v.context?.isTvSettings() == false) {
home_api_fab?.extend() // show home_api_fab?.extend() // show
home_random?.extend() home_random?.extend()
} }

View file

@ -27,6 +27,7 @@ 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.getPref import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
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.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
@ -209,6 +210,7 @@ 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_account) setUpToolbar(R.string.category_account)
setPaddingBottom()
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

View file

@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.ui.home.HomeFragment
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.utils.UIHelper.navigate import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import kotlinx.android.synthetic.main.main_settings.* import kotlinx.android.synthetic.main.main_settings.*
import kotlinx.android.synthetic.main.standard_toolbar.* import kotlinx.android.synthetic.main.standard_toolbar.*
import java.io.File import java.io.File
@ -40,6 +41,15 @@ class SettingsFragment : Fragment() {
} }
} }
/**
* On TV you cannot properly scroll to the bottom of settings, this fixes that.
* */
fun PreferenceFragmentCompat.setPaddingBottom() {
if (this.context?.isTvSettings() == true) {
listView?.setPadding(0, 0, 0, 100.toPx)
}
}
fun Fragment?.setUpToolbar(title: String) { fun Fragment?.setUpToolbar(title: String) {
if (this == null) return if (this == null) return
settings_toolbar?.apply { settings_toolbar?.apply {

View file

@ -25,6 +25,7 @@ import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.network.initClient import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.ui.EasterEggMonke import com.lagradost.cloudstream3.ui.EasterEggMonke
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.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
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
@ -42,6 +43,7 @@ class SettingsGeneral : 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_general) setUpToolbar(R.string.category_general)
setPaddingBottom()
} }
data class CustomSite( data class CustomSite(

View file

@ -12,6 +12,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.mvvm.logError 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.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.showDialog
@ -61,6 +62,7 @@ class SettingsLang : 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_preferred_media_and_lang) setUpToolbar(R.string.category_preferred_media_and_lang)
setPaddingBottom()
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

View file

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3.ui.settings package com.lagradost.cloudstream3.ui.settings
import android.os.Bundle import android.os.Bundle
import android.text.format.Formatter.formatShortFileSize
import android.view.View import android.view.View
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@ -8,6 +9,7 @@ import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
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.setPaddingBottom
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
import com.lagradost.cloudstream3.ui.subtitles.ChromecastSubtitlesFragment import com.lagradost.cloudstream3.ui.subtitles.ChromecastSubtitlesFragment
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
@ -20,6 +22,7 @@ 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)
setPaddingBottom()
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard() hideKeyboard()
@ -164,8 +167,7 @@ class SettingsPlayer : PreferenceFragmentCompat() {
fun updateSummery() { fun updateSummery() {
try { try {
pref.summary = pref.summary = formatShortFileSize(view?.context, getFolderSize(cacheDir))
getString(R.string.mb_format).format(getFolderSize(cacheDir) / (1024L * 1024L))
} catch (e: Exception) { } catch (e: Exception) {
logError(e) logError(e)
} }

View file

@ -9,6 +9,7 @@ import com.lagradost.cloudstream3.SearchQuality
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
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.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
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
@ -19,6 +20,7 @@ class SettingsUI : 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_ui) setUpToolbar(R.string.category_ui)
setPaddingBottom()
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard() hideKeyboard()

View file

@ -13,6 +13,7 @@ import com.lagradost.cloudstream3.CommonActivity
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
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.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
import com.lagradost.cloudstream3.utils.BackupUtils.backup import com.lagradost.cloudstream3.utils.BackupUtils.backup
import com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt import com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt
@ -31,6 +32,7 @@ class SettingsUpdates : 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_updates) setUpToolbar(R.string.category_updates)
setPaddingBottom()
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

View file

@ -134,7 +134,8 @@ class PluginAdapter(
//} //}
if (data.isDownloaded) { if (data.isDownloaded) {
val plugin = PluginManager.urlPlugins[metadata.url] // On local plugins page the filepath is provided instead of url.
val plugin = PluginManager.urlPlugins[metadata.url] ?: PluginManager.plugins[metadata.url]
if (plugin?.openSettings != null) { if (plugin?.openSettings != null) {
itemView.action_settings?.isVisible = true itemView.action_settings?.isVisible = true
itemView.action_settings.setOnClickListener { itemView.action_settings.setOnClickListener {

View file

@ -6,10 +6,22 @@ import android.widget.SearchView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.map
import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.CommonActivity
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.getPairList import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.getPairList
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
import com.lagradost.cloudstream3.ui.settings.appLanguages
import com.lagradost.cloudstream3.ui.settings.getCurrentLocale
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
import kotlinx.android.synthetic.main.fragment_plugins.* import kotlinx.android.synthetic.main.fragment_plugins.*
const val PLUGINS_BUNDLE_NAME = "name" const val PLUGINS_BUNDLE_NAME = "name"
@ -32,6 +44,7 @@ class PluginsFragment : Fragment() {
// Since the ViewModel is getting reused the tvTypes must be cleared between uses // Since the ViewModel is getting reused the tvTypes must be cleared between uses
pluginViewModel.tvTypes.clear() pluginViewModel.tvTypes.clear()
pluginViewModel.languages = listOf()
pluginViewModel.search(null) pluginViewModel.search(null)
val name = arguments?.getString(PLUGINS_BUNDLE_NAME) val name = arguments?.getString(PLUGINS_BUNDLE_NAME)
@ -50,6 +63,27 @@ class PluginsFragment : Fragment() {
R.id.download_all -> { R.id.download_all -> {
PluginsViewModel.downloadAll(activity, url, pluginViewModel) PluginsViewModel.downloadAll(activity, url, pluginViewModel)
} }
R.id.lang_filter -> {
val tempLangs = appLanguages.toMutableList()
val languageCodes = mutableListOf("none") + tempLangs.map { (_, _, iso) -> iso }
val languageNames =
mutableListOf(getString(R.string.no_data)) + tempLangs.map { (emoji, name, iso) ->
val flag =
emoji.ifBlank { SubtitleHelper.getFlagFromIso(iso) ?: "ERROR" }
"$flag $name"
}
val selectedList =
pluginViewModel.languages.map { it -> languageCodes.indexOf(it) }
activity?.showMultiDialog(
languageNames,
selectedList,
getString(R.string.provider_lang_settings),
{}) { newList ->
pluginViewModel.languages = newList.map { it -> languageCodes[it] }
pluginViewModel.updateFilteredPlugins()
}
}
else -> {} else -> {}
} }
return@setOnMenuItemClickListener true return@setOnMenuItemClickListener true
@ -94,6 +128,11 @@ class PluginsFragment : Fragment() {
pluginViewModel.handlePluginAction(activity, url, it, isLocal) pluginViewModel.handlePluginAction(activity, url, it, isLocal)
} }
if (context?.isTvSettings() == true) {
// Scrolling down does not reveal the whole RecyclerView on TV, add to bypass that.
plugin_recycler_view?.setPadding(0, 0, 0, 200.toPx)
}
observe(pluginViewModel.filteredPlugins) { (scrollToTop, list) -> observe(pluginViewModel.filteredPlugins) { (scrollToTop, list) ->
(plugin_recycler_view?.adapter as? PluginAdapter?)?.updateList(list) (plugin_recycler_view?.adapter as? PluginAdapter?)?.updateList(list)
@ -104,6 +143,7 @@ class PluginsFragment : Fragment() {
if (isLocal) { if (isLocal) {
// No download button and no categories on local // No download button and no categories on local
settings_toolbar?.menu?.findItem(R.id.download_all)?.isVisible = false settings_toolbar?.menu?.findItem(R.id.download_all)?.isVisible = false
settings_toolbar?.menu?.findItem(R.id.lang_filter)?.isVisible = false
pluginViewModel.updatePluginListLocal() pluginViewModel.updatePluginListLocal()
tv_types_scroll_view?.isVisible = false tv_types_scroll_view?.isVisible = false
} else { } else {
@ -123,11 +163,14 @@ class PluginsFragment : Fragment() {
home_select_others home_select_others
) )
// val supportedTypes: Array<String> =
// pluginViewModel.filteredPlugins.value!!.second.flatMap { it -> it.plugin.second.tvTypes ?: listOf("Other") }.distinct().toTypedArray()
// Copy pasted code // Copy pasted code
for ((button, validTypes) in pairList) { for ((button, validTypes) in pairList) {
val validTypesMapped = validTypes.map { it.name } val validTypesMapped = validTypes.map { it.name }
val isValid = val isValid = true
true //validAPIs.any { api -> validTypes.any { api.supportedTypes.contains(it) } } //validTypes.any { it -> supportedTypes.contains(it.name) }
button?.isVisible = isValid button?.isVisible = isValid
if (isValid) { if (isValid) {
fun buttonContains(): Boolean { fun buttonContains(): Boolean {

View file

@ -38,6 +38,7 @@ class PluginsViewModel : ViewModel() {
var filteredPlugins: LiveData<PluginViewDataUpdate> = _filteredPlugins var filteredPlugins: LiveData<PluginViewDataUpdate> = _filteredPlugins
val tvTypes = mutableListOf<String>() val tvTypes = mutableListOf<String>()
var languages = listOf<String>()
private var currentQuery: String? = null private var currentQuery: String? = null
companion object { companion object {
@ -175,7 +176,7 @@ class PluginsViewModel : ViewModel() {
} }
this.plugins = list this.plugins = list
_filteredPlugins.postValue(false to list.filterTvTypes().sortByQuery(currentQuery)) _filteredPlugins.postValue(false to list.filterTvTypes().filterLang().sortByQuery(currentQuery))
} }
// Perhaps can be optimized? // Perhaps can be optimized?
@ -187,6 +188,16 @@ class PluginsViewModel : ViewModel() {
} }
} }
private fun List<PluginViewData>.filterLang(): List<PluginViewData> {
if (languages.isEmpty()) return this
return this.filter {
if (it.plugin.second.language == null) {
return@filter languages.contains("none")
}
languages.contains(it.plugin.second.language)
}
}
private fun List<PluginViewData>.sortByQuery(query: String?): List<PluginViewData> { private fun List<PluginViewData>.sortByQuery(query: String?): List<PluginViewData> {
return if (query == null) { return if (query == null) {
// Return list to base state if no query // Return list to base state if no query
@ -197,7 +208,7 @@ class PluginsViewModel : ViewModel() {
} }
fun updateFilteredPlugins() { fun updateFilteredPlugins() {
_filteredPlugins.postValue(false to plugins.filterTvTypes().sortByQuery(currentQuery)) _filteredPlugins.postValue(false to plugins.filterTvTypes().filterLang().sortByQuery(currentQuery))
} }
fun updatePluginList(repositoryUrl: String) = viewModelScope.launchSafe { fun updatePluginList(repositoryUrl: String) = viewModelScope.launchSafe {
@ -223,6 +234,6 @@ class PluginsViewModel : ViewModel() {
} }
plugins = downloadedPlugins plugins = downloadedPlugins
_filteredPlugins.postValue(false to downloadedPlugins.filterTvTypes().sortByQuery(currentQuery)) _filteredPlugins.postValue(false to downloadedPlugins.filterTvTypes().filterLang().sortByQuery(currentQuery))
} }
} }

View file

@ -288,7 +288,7 @@ object AppUtils {
return this.packageManager.hasSystemFeature("android.software.webview") return this.packageManager.hasSystemFeature("android.software.webview")
} }
private fun openWebView(fragment: Fragment?, url: String) { fun openWebView(fragment: Fragment?, url: String) {
if (fragment?.context?.hasWebView() == true) if (fragment?.context?.hasWebView() == true)
normalSafeApiCall { normalSafeApiCall {
fragment fragment

View file

@ -43,6 +43,13 @@ object Coroutines {
} }
} }
suspend fun <T, V> V.mainWork(work: suspend (CoroutineScope.(V) -> T)): T {
val value = this
return withContext(Dispatchers.Main) {
work(value)
}
}
fun runOnMainThread(work: (() -> Unit)) { fun runOnMainThread(work: (() -> Unit)) {
val mainHandler = Handler(Looper.getMainLooper()) val mainHandler = Handler(Looper.getMainLooper())
mainHandler.post { mainHandler.post {

View file

@ -127,6 +127,7 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:clipToPadding="false"
android:id="@+id/plugin_recycler_view" android:id="@+id/plugin_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -8,6 +8,11 @@
app:actionViewClass="android.widget.SearchView" app:actionViewClass="android.widget.SearchView"
app:searchHintIcon="@drawable/search_icon" app:searchHintIcon="@drawable/search_icon"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item
android:id="@+id/lang_filter"
android:icon="@drawable/ic_baseline_language_24"
android:title="@string/provider_lang_settings"
app:showAsAction="collapseActionView|ifRoom" />
<item <item
android:id="@+id/download_all" android:id="@+id/download_all"
android:icon="@drawable/netflix_download" android:icon="@drawable/netflix_download"

View file

@ -1,21 +1,8 @@
<!--https://newbedev.com/concatenate-multiple-strings-in-xml--> <!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
<resources> <resources>
<!-- KEYS DON'T TRANSLATE --> <!-- KEYS DON'T TRANSLATE -->
<string name="bottom_title_key" translatable="false">bottom_title_key</string>
<string name="override_site_key" translatable="false">override_site_key</string>
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
<string name="mb_format" translatable="false" formatted="true">%dMB</string>
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rating_format" translatable="false" formatted="true">%.1f/10.0</string>
<string name="year_format" translatable="false" formatted="true">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
<string name="cast_format" formatted="true">Elenco: %s</string> <string name="cast_format" formatted="true">Elenco: %s</string>
<string name="next_episode_format" formatted="true">O episódio %d vai ser lançado em</string> <string name="next_episode_format" formatted="true">O episódio %d vai ser lançado em</string>
@ -29,9 +16,7 @@
<string name="episode_poster_img_des">Episode Poster</string> <string name="episode_poster_img_des">Episode Poster</string>
<string name="home_main_poster_img_des">Main Poster</string> <string name="home_main_poster_img_des">Main Poster</string>
<string name="home_next_random_img_des">Next Random</string> <string name="home_next_random_img_des">Next Random</string>
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
<string name="go_back_img_des">Go back</string> <string name="go_back_img_des">Go back</string>
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
<string name="home_change_provider_img_des">Change Provider</string> <string name="home_change_provider_img_des">Change Provider</string>
<string name="preview_background_img_des">Preview Background</string> <string name="preview_background_img_des">Preview Background</string>
@ -54,7 +39,6 @@
<string name="no_data">Sem dados</string> <string name="no_data">Sem dados</string>
<string name="episode_more_options_des">Mais Opções</string> <string name="episode_more_options_des">Mais Opções</string>
<string name="next_episode">Próximo episódio</string> <string name="next_episode">Próximo episódio</string>
<string name="result_plot" translatable="false">@string/synopsis</string>
<string name="result_tags">Gêneros</string> <string name="result_tags">Gêneros</string>
<string name="result_share">Compartilhar</string> <string name="result_share">Compartilhar</string>
<string name="result_open_in_browser">Abrir no Navegador</string> <string name="result_open_in_browser">Abrir no Navegador</string>
@ -86,7 +70,6 @@
<string name="download_failed">Download Falhado</string> <string name="download_failed">Download Falhado</string>
<string name="download_canceled">Download Cancelado</string> <string name="download_canceled">Download Cancelado</string>
<string name="download_done">Download Finalizado</string> <string name="download_done">Download Finalizado</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="stream">Transmitir</string> <string name="stream">Transmitir</string>
<string name="error_loading_links_toast">Erro Carregando Links</string> <string name="error_loading_links_toast">Erro Carregando Links</string>
@ -236,7 +219,6 @@
<string name="delete_file">Deletar Arquivo</string> <string name="delete_file">Deletar Arquivo</string>
<string name="delete">Deletar</string> <string name="delete">Deletar</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">Pausar</string> <string name="pause">Pausar</string>
<string name="resume">Retomar</string> <string name="resume">Retomar</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -303,10 +285,6 @@
<string name="show_dub">Etiqueta Dub</string> <string name="show_dub">Etiqueta Dub</string>
<string name="show_sub">Etiqueta Sub</string> <string name="show_sub">Etiqueta Sub</string>
<string name="show_title">Título</string> <string name="show_title">Título</string>
<string name="show_hd_key" translatable="false">show_hd_key</string>
<string name="show_dub_key" translatable="false">show_dub_key</string>
<string name="show_sub_key" translatable="false">show_sub_key</string>
<string name="show_title_key" translatable="false">show_title_key</string>
<string name="poster_ui_settings">Alternar elementos da interface no pôster</string> <string name="poster_ui_settings">Alternar elementos da interface no pôster</string>
<string name="no_update_found">Nenhuma Atualização encontrada</string> <string name="no_update_found">Nenhuma Atualização encontrada</string>
@ -350,7 +328,6 @@
<string name="resize_zoom">Zoom</string> <string name="resize_zoom">Zoom</string>
<string name="legal_notice">Aviso Legal</string> <string name="legal_notice">Aviso Legal</string>
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application <string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
@ -389,10 +366,6 @@
<!-- account stuff --> <!-- account stuff -->
<string name="anilist_key" translatable="false">anilist_key</string>
<string name="mal_key" translatable="false">mal_key</string>
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
<string name="nginx_key" translatable="false">nginx_key</string>
<string name="example_password">senha123</string> <string name="example_password">senha123</string>
<string name="example_username">MeuNomeLegal</string> <string name="example_username">MeuNomeLegal</string>
<string name="example_email">oi@mundo.com</string> <string name="example_email">oi@mundo.com</string>
@ -432,7 +405,6 @@
<string name="all">Tudo</string> <string name="all">Tudo</string>
<string name="max">Max</string> <string name="max">Max</string>
<string name="min">Min</string> <string name="min">Min</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">Contornado</string> <string name="subtitles_outline">Contornado</string>
<string name="subtitles_depressed">Afundado</string> <string name="subtitles_depressed">Afundado</string>
<string name="subtitles_shadow">Sombreado</string> <string name="subtitles_shadow">Sombreado</string>

View file

@ -3,17 +3,6 @@
<!-- KEYS DON'T TRANSLATE --> <!-- KEYS DON'T TRANSLATE -->
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
<string name="mb_format" translatable="false" formatted="true">%dMB</string>
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rating_format" translatable="false" formatted="true">%.1f/10.0</string>
<string name="year_format" translatable="false" formatted="true">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
<string name="cast_format" formatted="true">Hrají: %s</string> <string name="cast_format" formatted="true">Hrají: %s</string>
@ -23,9 +12,7 @@
<string name="episode_poster_img_des">Episode Poster</string> <string name="episode_poster_img_des">Episode Poster</string>
<string name="home_main_poster_img_des">Main Poster</string> <string name="home_main_poster_img_des">Main Poster</string>
<string name="home_next_random_img_des">Next Random</string> <string name="home_next_random_img_des">Next Random</string>
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
<string name="go_back_img_des">Go back</string> <string name="go_back_img_des">Go back</string>
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
<string name="home_change_provider_img_des">Change Provider</string> <string name="home_change_provider_img_des">Change Provider</string>
<string name="preview_background_img_des">Preview Background</string> <string name="preview_background_img_des">Preview Background</string>
@ -48,7 +35,6 @@
<string name="no_data">Žádná data</string> <string name="no_data">Žádná data</string>
<string name="episode_more_options_des">Další možnosti</string> <string name="episode_more_options_des">Další možnosti</string>
<string name="next_episode">Další epizoda</string> <string name="next_episode">Další epizoda</string>
<string name="result_plot" translatable="false">@string/synopsis</string>
<string name="result_tags">Žánry</string> <string name="result_tags">Žánry</string>
<string name="result_share">Sdílet</string> <string name="result_share">Sdílet</string>
<string name="result_open_in_browser">Otevřít v prohlížeči</string> <string name="result_open_in_browser">Otevřít v prohlížeči</string>
@ -80,7 +66,6 @@
<string name="download_failed">Stahování selhalo</string> <string name="download_failed">Stahování selhalo</string>
<string name="download_canceled">Stahování zrušeno</string> <string name="download_canceled">Stahování zrušeno</string>
<string name="download_done">Stahování dokončeno</string> <string name="download_done">Stahování dokončeno</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="error_loading_links_toast">Chyba při načítání odkazů</string> <string name="error_loading_links_toast">Chyba při načítání odkazů</string>
<string name="download_storage_text">Interní úložiště</string> <string name="download_storage_text">Interní úložiště</string>
@ -229,7 +214,6 @@
<string name="delete_file">Smazat soubor</string> <string name="delete_file">Smazat soubor</string>
<string name="delete">Smazat</string> <string name="delete">Smazat</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">Pozastavit</string> <string name="pause">Pozastavit</string>
<string name="resume">Pokračovat</string> <string name="resume">Pokračovat</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -296,10 +280,6 @@
<string name="show_dub">Štítek dabingu</string> <string name="show_dub">Štítek dabingu</string>
<string name="show_sub">Štítek titulků</string> <string name="show_sub">Štítek titulků</string>
<string name="show_title">Název</string> <string name="show_title">Název</string>
<string name="show_hd_key" translatable="false">show_hd_key</string>
<string name="show_dub_key" translatable="false">show_dub_key</string>
<string name="show_sub_key" translatable="false">show_sub_key</string>
<string name="show_title_key" translatable="false">show_title_key</string>
<string name="poster_ui_settings">Přepnout prvky UI na plakátu</string> <string name="poster_ui_settings">Přepnout prvky UI na plakátu</string>
<string name="no_update_found">Nenalezeny žádné aktualizace</string> <string name="no_update_found">Nenalezeny žádné aktualizace</string>
@ -339,7 +319,6 @@
<string name="resize_zoom">Přiblížit</string> <string name="resize_zoom">Přiblížit</string>
<string name="legal_notice">Odmítnutí odpovědnosti</string> <string name="legal_notice">Odmítnutí odpovědnosti</string>
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
<string name="legal_notice_text" translatable="false">Jakékoli právní otázky týkající se obsahu této aplikace <string name="legal_notice_text" translatable="false">Jakékoli právní otázky týkající se obsahu této aplikace
je třeba řešit se samotnými hostiteli a poskytovateli souborů, protože s nimi nejsme nijak spojeni. je třeba řešit se samotnými hostiteli a poskytovateli souborů, protože s nimi nejsme nijak spojeni.
@ -378,10 +357,6 @@
<!-- account stuff --> <!-- account stuff -->
<string name="anilist_key" translatable="false">anilist_key</string>
<string name="mal_key" translatable="false">mal_key</string>
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
<string name="nginx_key" translatable="false">nginx_key</string>
<string name="example_password">heslo123</string> <string name="example_password">heslo123</string>
<string name="example_username">MojeSuperJmeno</string> <string name="example_username">MojeSuperJmeno</string>
<string name="example_email">ahoj@svete.cz</string> <string name="example_email">ahoj@svete.cz</string>
@ -418,7 +393,6 @@
<string name="all">Vše</string> <string name="all">Vše</string>
<string name="max">Max</string> <string name="max">Max</string>
<string name="min">Min</string> <string name="min">Min</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">Ohraničení</string> <string name="subtitles_outline">Ohraničení</string>
<string name="subtitles_depressed">Potlačené</string> <string name="subtitles_depressed">Potlačené</string>
<string name="subtitles_shadow">Stín</string> <string name="subtitles_shadow">Stín</string>

View file

@ -1,17 +1,6 @@
<!--https://newbedev.com/concatenate-multiple-strings-in-xml--> <!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
<resources> <resources>
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
<string name="mb_format" translatable="false" formatted="true">%dMB</string>
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rating_format" translatable="false" formatted="true">%.1f/10.0</string>
<string name="year_format" translatable="false" formatted="true">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
<string name="cast_format" formatted="true">Reparto: %s</string> <string name="cast_format" formatted="true">Reparto: %s</string>
<string name="next_episode_format" formatted="true">El episodio %d se publicará en</string> <string name="next_episode_format" formatted="true">El episodio %d se publicará en</string>
@ -26,9 +15,7 @@
<string name="episode_poster_img_des">Episode Poster</string> <string name="episode_poster_img_des">Episode Poster</string>
<string name="home_main_poster_img_des">Main Poster</string> <string name="home_main_poster_img_des">Main Poster</string>
<string name="home_next_random_img_des">Next Random</string> <string name="home_next_random_img_des">Next Random</string>
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
<string name="go_back_img_des">Go back</string> <string name="go_back_img_des">Go back</string>
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
<string name="home_change_provider_img_des">Change Provider</string> <string name="home_change_provider_img_des">Change Provider</string>
<string name="preview_background_img_des">Preview Background</string> <string name="preview_background_img_des">Preview Background</string>
@ -50,9 +37,8 @@
<string name="no_data">Sin datos</string> <string name="no_data">Sin datos</string>
<string name="episode_more_options_des">Más opciones</string> <string name="episode_more_options_des">Más opciones</string>
<string name="next_episode">Siguiente episodio</string> <string name="next_episode">Siguiente episodio</string>
<string name="result_plot" translatable="false">@string/synopsis</string> <string name="result_tags">Géneros</string>
<string name="result_tags">Géneros</string>
<string name="result_share">Compartir</string> <string name="result_share">Compartir</string>
<string name="result_open_in_browser">Abrir en el navegador</string> <string name="result_open_in_browser">Abrir en el navegador</string>
<string name="skip_loading">Omitir carga</string> <string name="skip_loading">Omitir carga</string>
@ -82,8 +68,7 @@
<string name="download_started">Descarga iniciada</string> <string name="download_started">Descarga iniciada</string>
<string name="download_failed">Descarga fallida</string> <string name="download_failed">Descarga fallida</string>
<string name="download_canceled">Descarga cancelada</string> <string name="download_canceled">Descarga cancelada</string>
<string name="download_done">Descarga realizada</string> <string name="download_done">Descarga realizada</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="stream">Transmitir</string> <string name="stream">Transmitir</string>
<string name="error_loading_links_toast">Error al cargar enlaces</string> <string name="error_loading_links_toast">Error al cargar enlaces</string>
@ -229,9 +214,8 @@
<string name="no_episodes_found">No se encontraron episodios</string> <string name="no_episodes_found">No se encontraron episodios</string>
<string name="delete_file">Eliminar archivo</string> <string name="delete_file">Eliminar archivo</string>
<string name="delete">Eliminar</string> <string name="delete">Eliminar</string>
<string name="cancel" translatable="false">@string/sort_cancel</string> <string name="pause">Pausar</string>
<string name="pause">Pausar</string>
<string name="resume">Reanudar</string> <string name="resume">Reanudar</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
<string name="go_forward_30">+30</string> <string name="go_forward_30">+30</string>
@ -296,12 +280,8 @@
<string name="show_hd">Etiqueta de calidad</string> <string name="show_hd">Etiqueta de calidad</string>
<string name="show_dub">Etiqueta de doblaje</string> <string name="show_dub">Etiqueta de doblaje</string>
<string name="show_sub">Etiqueta de subtitulado</string> <string name="show_sub">Etiqueta de subtitulado</string>
<string name="show_title">Título</string> <string name="show_title">Título</string>
<string name="show_hd_key" translatable="false">show_hd_key</string> <string name="poster_ui_settings">Alternar elementos de la interfaz de usuario en el póster</string>
<string name="show_dub_key" translatable="false">show_dub_key</string>
<string name="show_sub_key" translatable="false">show_sub_key</string>
<string name="show_title_key" translatable="false">show_title_key</string>
<string name="poster_ui_settings">Alternar elementos de la interfaz de usuario en el póster</string>
<string name="no_update_found">No se encontró ninguna actualización</string> <string name="no_update_found">No se encontró ninguna actualización</string>
<string name="check_for_update">Buscar actualizaciones</string> <string name="check_for_update">Buscar actualizaciones</string>
@ -343,9 +323,8 @@
<string name="resize_fill">Estirar</string> <string name="resize_fill">Estirar</string>
<string name="resize_zoom">Zoom</string> <string name="resize_zoom">Zoom</string>
<string name="legal_notice">Descargo de responsabilidad</string> <string name="legal_notice">Descargo de responsabilidad</string>
<string name="legal_notice_key" translatable="false">legal_notice_key</string> <string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
In case of copyright infringement, please directly contact the responsible parties or the streaming websites. In case of copyright infringement, please directly contact the responsible parties or the streaming websites.
@ -382,11 +361,7 @@
<string name="bottom_title_settings_des">Coloca el título debajo del póster</string> <string name="bottom_title_settings_des">Coloca el título debajo del póster</string>
<!-- account stuff --> <!-- account stuff -->
<string name="anilist_key" translatable="false">anilist_key</string>
<string name="mal_key" translatable="false">mal_key</string>
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
<string name="nginx_key" translatable="false">nginx_key</string>
<string name="example_password">contraseña123</string> <string name="example_password">contraseña123</string>
<string name="example_username">MiNombreDeUsuarioGenial</string> <string name="example_username">MiNombreDeUsuarioGenial</string>
<string name="example_email">hola@mundo.com</string> <string name="example_email">hola@mundo.com</string>
@ -424,9 +399,8 @@
<string name="normal">Normal</string> <string name="normal">Normal</string>
<string name="all">Todo</string> <string name="all">Todo</string>
<string name="max">Máximo</string> <string name="max">Máximo</string>
<string name="min">Mínimo</string> <string name="min">Mínimo</string>
<string name="subtitles_none" translatable="false">@string/none</string> <string name="subtitles_outline">Contorno</string>
<string name="subtitles_outline">Contorno</string>
<string name="subtitles_depressed">Deprimido</string> <string name="subtitles_depressed">Deprimido</string>
<string name="subtitles_shadow">Sombra</string> <string name="subtitles_shadow">Sombra</string>
<string name="subtitles_raised">Elevado</string> <string name="subtitles_raised">Elevado</string>

View file

@ -293,5 +293,4 @@
<string name="poster_image">Image de l\'affiche</string> <string name="poster_image">Image de l\'affiche</string>
<string name="authenticated_user">Connecté %s</string> <string name="authenticated_user">Connecté %s</string>
<string name="action_add_to_bookmarks">Définir le statut de visionage</string> <string name="action_add_to_bookmarks">Définir le statut de visionage</string>
<string name="nginx_info_title">Qu\'est-ce qu\'Nginx ?</string>
</resources> </resources>

View file

@ -2,17 +2,6 @@
<resources> <resources>
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
<string name="mb_format" translatable="false" formatted="true">%dMB</string>
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rating_format" translatable="false" formatted="true">%.1f/10.0</string>
<string name="year_format" translatable="false" formatted="true">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
<string name="cast_format" formatted="true">Pemeran: %s</string> <string name="cast_format" formatted="true">Pemeran: %s</string>
@ -22,9 +11,7 @@
<string name="episode_poster_img_des">Episode Poster</string> <string name="episode_poster_img_des">Episode Poster</string>
<string name="home_main_poster_img_des">Main Poster</string> <string name="home_main_poster_img_des">Main Poster</string>
<string name="home_next_random_img_des">Next Random</string> <string name="home_next_random_img_des">Next Random</string>
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
<string name="go_back_img_des">Go back</string> <string name="go_back_img_des">Go back</string>
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
<string name="home_change_provider_img_des">Change Provider</string> <string name="home_change_provider_img_des">Change Provider</string>
<string name="preview_background_img_des">Preview Background</string> <string name="preview_background_img_des">Preview Background</string>
@ -47,7 +34,6 @@
<string name="no_data">Tidak Ada Data</string> <string name="no_data">Tidak Ada Data</string>
<string name="episode_more_options_des">Opsi Lanjutan</string> <string name="episode_more_options_des">Opsi Lanjutan</string>
<string name="next_episode">Episode selanjutnya</string> <string name="next_episode">Episode selanjutnya</string>
<string name="result_plot" translatable="false">@string/synopsis</string>
<string name="result_tags">Genre</string> <string name="result_tags">Genre</string>
<string name="result_share">Bagikan</string> <string name="result_share">Bagikan</string>
<string name="result_open_in_browser">Buka Di Browser</string> <string name="result_open_in_browser">Buka Di Browser</string>
@ -79,7 +65,6 @@
<string name="download_failed">Download Gagal</string> <string name="download_failed">Download Gagal</string>
<string name="download_canceled">Download Dibatalkan</string> <string name="download_canceled">Download Dibatalkan</string>
<string name="download_done">Download Selesai</string> <string name="download_done">Download Selesai</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="error_loading_links_toast">Error Memuat Tautan</string> <string name="error_loading_links_toast">Error Memuat Tautan</string>
<string name="download_storage_text">Penyimpanan Internal</string> <string name="download_storage_text">Penyimpanan Internal</string>
@ -225,7 +210,6 @@
<string name="delete_file">Hapus File</string> <string name="delete_file">Hapus File</string>
<string name="delete">Hapus</string> <string name="delete">Hapus</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">Jeda</string> <string name="pause">Jeda</string>
<string name="resume">Lanjutkan</string> <string name="resume">Lanjutkan</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -292,10 +276,6 @@
<string name="show_dub">Label dub</string> <string name="show_dub">Label dub</string>
<string name="show_sub">Label sub</string> <string name="show_sub">Label sub</string>
<string name="show_title">Judul</string> <string name="show_title">Judul</string>
<string name="show_hd_key" translatable="false">show_hd_key</string>
<string name="show_dub_key" translatable="false">show_dub_key</string>
<string name="show_sub_key" translatable="false">show_sub_key</string>
<string name="show_title_key" translatable="false">show_title_key</string>
<string name="poster_ui_settings">Aktifkan atau nonaktifkan elemen UI pada poster</string> <string name="poster_ui_settings">Aktifkan atau nonaktifkan elemen UI pada poster</string>
<string name="no_update_found">Tidak Ada Update Yang Ditemukan</string> <string name="no_update_found">Tidak Ada Update Yang Ditemukan</string>
@ -335,7 +315,6 @@
<string name="resize_zoom">Zoom</string> <string name="resize_zoom">Zoom</string>
<string name="legal_notice">Peringatan</string> <string name="legal_notice">Peringatan</string>
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application <string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
@ -373,8 +352,6 @@
<!-- account stuff --> <!-- account stuff -->
<string name="anilist_key" translatable="false">anilist_key</string>
<string name="mal_key" translatable="false">mal_key</string>
<!-- <!--
<string name="mal_account_settings" translatable="false">MAL</string> <string name="mal_account_settings" translatable="false">MAL</string>
<string name="anilist_account_settings" translatable="false">AniList</string> <string name="anilist_account_settings" translatable="false">AniList</string>
@ -405,7 +382,6 @@
<string name="all">Semua</string> <string name="all">Semua</string>
<string name="max">Maks</string> <string name="max">Maks</string>
<string name="min">Min</string> <string name="min">Min</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">Garis luar</string> <string name="subtitles_outline">Garis luar</string>
<string name="subtitles_depressed">Depresi</string> <string name="subtitles_depressed">Depresi</string>
<string name="subtitles_shadow">Bayangan</string> <string name="subtitles_shadow">Bayangan</string>

View file

@ -1,16 +1,6 @@
<!--https://newbedev.com/concatenate-multiple-strings-in-xml--> <!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
<resources> <resources>
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rating_format" translatable="false" formatted="true">%.1f/10.0</string>
<string name="year_format" translatable="false" formatted="true">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
<string name="cast_format" formatted="true">Cast: %s</string> <string name="cast_format" formatted="true">Cast: %s</string>
<string name="next_episode_format" formatted="true">L\'episodio %d uscirà in</string> <string name="next_episode_format" formatted="true">L\'episodio %d uscirà in</string>
@ -79,7 +69,6 @@
<string name="download_failed">Download fallito</string> <string name="download_failed">Download fallito</string>
<string name="download_canceled">Download cancellato</string> <string name="download_canceled">Download cancellato</string>
<string name="download_done">Download completato</string> <string name="download_done">Download completato</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="stream">Stream</string> <string name="stream">Stream</string>
<string name="error_loading_links_toast">Errore durante il caricamento dei link</string> <string name="error_loading_links_toast">Errore durante il caricamento dei link</string>
@ -227,7 +216,6 @@
<string name="delete_file">Elimina file</string> <string name="delete_file">Elimina file</string>
<string name="delete">Elimina</string> <string name="delete">Elimina</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">Pausa</string> <string name="pause">Pausa</string>
<string name="resume">Riprendi</string> <string name="resume">Riprendi</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -390,7 +378,6 @@
<string name="all">Tutto</string> <string name="all">Tutto</string>
<string name="max">Max</string> <string name="max">Max</string>
<string name="min">Min</string> <string name="min">Min</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">Contorno</string> <string name="subtitles_outline">Contorno</string>
<string name="subtitles_depressed">Bassorilievo</string> <string name="subtitles_depressed">Bassorilievo</string>
<string name="subtitles_shadow">Ombra</string> <string name="subtitles_shadow">Ombra</string>

View file

@ -1,17 +1,6 @@
<!--https://newbedev.com/concatenate-multiple-strings-in-xml--> <!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
<resources> <resources>
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" formatted="true" translatable="false">%d %s | %sMB</string>
<string name="storage_size_format" formatted="true" translatable="false">%s • %sGB</string>
<string name="download_size_format" formatted="true" translatable="false">%sMB / %sMB</string>
<string name="mb_format" formatted="true" translatable="false">%dMB</string>
<string name="episode_name_format" formatted="true" translatable="false">%s %s</string>
<string name="ffw_text_format" formatted="true" translatable="false">+%d</string>
<string name="rew_text_format" formatted="true" translatable="false">-%d</string>
<string name="ffw_text_regular_format" formatted="true" translatable="false">%d</string>
<string name="rew_text_regular_format" formatted="true" translatable="false">%d</string>
<string name="rating_format" formatted="true" translatable="false">%.1f/10.0</string>
<string name="year_format" formatted="true" translatable="false">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
<string name="cast_format" formatted="true">Cast: %s</string> <string name="cast_format" formatted="true">Cast: %s</string>
<string name="next_episode_format" formatted="true">Aflevering %d zal worden uitgebracht in</string> <string name="next_episode_format" formatted="true">Aflevering %d zal worden uitgebracht in</string>
@ -25,9 +14,7 @@
<string name="episode_poster_img_des">Aflevering Poster</string> <string name="episode_poster_img_des">Aflevering Poster</string>
<string name="home_main_poster_img_des">Hoofdposter</string> <string name="home_main_poster_img_des">Hoofdposter</string>
<string name="home_next_random_img_des">Volgende willekeurig</string> <string name="home_next_random_img_des">Volgende willekeurig</string>
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
<string name="go_back_img_des">Ga terug</string> <string name="go_back_img_des">Ga terug</string>
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
<string name="home_change_provider_img_des">Wijzig provider</string> <string name="home_change_provider_img_des">Wijzig provider</string>
<string name="preview_background_img_des">Voorbeeld Achtergrond</string> <string name="preview_background_img_des">Voorbeeld Achtergrond</string>
@ -51,7 +38,6 @@
<string name="no_data">Geen gegevens</string> <string name="no_data">Geen gegevens</string>
<string name="episode_more_options_des">Meer Opties</string> <string name="episode_more_options_des">Meer Opties</string>
<string name="next_episode">Volgende aflevering</string> <string name="next_episode">Volgende aflevering</string>
<string name="result_plot" translatable="false">@string/synopsis</string>
<string name="result_tags">Genres</string> <string name="result_tags">Genres</string>
<string name="result_share">Deel</string> <string name="result_share">Deel</string>
<string name="result_open_in_browser">Openen in Browser</string> <string name="result_open_in_browser">Openen in Browser</string>
@ -234,7 +220,6 @@
<string name="delete_file">Verwijder bestand</string> <string name="delete_file">Verwijder bestand</string>
<string name="delete">Verwijder</string> <string name="delete">Verwijder</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">Pauze</string> <string name="pause">Pauze</string>
<string name="resume">Hervatten</string> <string name="resume">Hervatten</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -302,10 +287,6 @@
<string name="show_dub">Dub label</string> <string name="show_dub">Dub label</string>
<string name="show_sub">Sub label</string> <string name="show_sub">Sub label</string>
<string name="show_title">Titel</string> <string name="show_title">Titel</string>
<string name="show_hd_key" translatable="false">show_hd_key</string>
<string name="show_dub_key" translatable="false">show_dub_key</string>
<string name="show_sub_key" translatable="false">show_sub_key</string>
<string name="show_title_key" translatable="false">show_title_key</string>
<string name="poster_ui_settings">Schakel UI-elementen op poster</string> <string name="poster_ui_settings">Schakel UI-elementen op poster</string>
<string name="no_update_found">Geen update gevonden</string> <string name="no_update_found">Geen update gevonden</string>
@ -371,10 +352,6 @@
<!-- account stuff --> <!-- account stuff -->
<string name="anilist_key" translatable="false">anilist_key</string>
<string name="mal_key" translatable="false">mal_key</string>
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
<string name="nginx_key" translatable="false">nginx_key</string>
<string name="example_password">wachtwoord123</string> <string name="example_password">wachtwoord123</string>
<string name="example_username">MijnCoolGebruikersnaam</string> <string name="example_username">MijnCoolGebruikersnaam</string>
<string name="example_email">hello@Wereld.com</string> <string name="example_email">hello@Wereld.com</string>
@ -414,7 +391,6 @@
<string name="all">Allemaal</string> <string name="all">Allemaal</string>
<string name="max">Max</string> <string name="max">Max</string>
<string name="min">Min</string> <string name="min">Min</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">Overzicht</string> <string name="subtitles_outline">Overzicht</string>
<string name="subtitles_depressed">Depressed</string> <string name="subtitles_depressed">Depressed</string>
<string name="subtitles_shadow">Schaduw</string> <string name="subtitles_shadow">Schaduw</string>

View file

@ -232,7 +232,6 @@
<string name="preferred_media_settings">Foretrukket Videoinnhold</string> <string name="preferred_media_settings">Foretrukket Videoinnhold</string>
<string name="legal_notice" translatable="false">Disclaimer</string> <string name="legal_notice" translatable="false">Disclaimer</string>
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application <string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.

View file

@ -430,4 +430,10 @@
<string name="other_singular">Wideo</string> <string name="other_singular">Wideo</string>
<string name="view_public_repositories_button">Zobacz repozytoria społeczności</string> <string name="view_public_repositories_button">Zobacz repozytoria społeczności</string>
<string name="view_public_repositories_button_short">Publiczna lista</string> <string name="view_public_repositories_button_short">Publiczna lista</string>
<string name="example_lang_name">Kod języka (en)</string>
<string name="subtitles_filter_lang">Filtrowanie wg preferowanego języka mediów</string>
<string name="uppercase_all_subtitles">Wszystkie napisy wielką literą</string>
<string name="download_all_plugins_from_repo">Pobrać wszystkie rozszerzenia z tego repozytorium?</string>
<string name="single_plugin_disabled">%s (Wyłączone)</string>
<string name="pref_filter_search_quality">Ukryj wybraną jakość wideo w wynikach wyszukiwania</string>
</resources> </resources>

View file

@ -1,17 +1,6 @@
<!--https://newbedev.com/concatenate-multiple-strings-in-xml--> <!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
<resources> <resources>
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
<string name="mb_format" translatable="false" formatted="true">%dMB</string>
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rating_format" translatable="false" formatted="true">%.1f/10.0</string>
<string name="year_format" translatable="false" formatted="true">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
<string name="cast_format" formatted="true">Distribuție: %s</string> <string name="cast_format" formatted="true">Distribuție: %s</string>
<string name="next_episode_format" formatted="true">Episodul %d va fi lansat în</string> <string name="next_episode_format" formatted="true">Episodul %d va fi lansat în</string>
@ -78,7 +67,6 @@
<string name="download_failed">Descărcare eșuată</string> <string name="download_failed">Descărcare eșuată</string>
<string name="download_canceled">Descărcare anulată</string> <string name="download_canceled">Descărcare anulată</string>
<string name="download_done">Descărcare finalizată</string> <string name="download_done">Descărcare finalizată</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="stream">Stream</string> <string name="stream">Stream</string>
<string name="error_loading_links_toast">Eroare la încărcarea linkurilor</string> <string name="error_loading_links_toast">Eroare la încărcarea linkurilor</string>
@ -226,7 +214,6 @@
<string name="delete_file">Ștergeți fișierul</string> <string name="delete_file">Ștergeți fișierul</string>
<string name="delete">Ștergeți</string> <string name="delete">Ștergeți</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">Pauză</string> <string name="pause">Pauză</string>
<string name="resume">Continuă</string> <string name="resume">Continuă</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -405,7 +392,6 @@
<string name="all">Tot</string> <string name="all">Tot</string>
<string name="max">Maxim</string> <string name="max">Maxim</string>
<string name="min">Minim</string> <string name="min">Minim</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">Contur</string> <string name="subtitles_outline">Contur</string>
<string name="subtitles_depressed">Deprimat</string> <string name="subtitles_depressed">Deprimat</string>
<string name="subtitles_shadow">Umbră</string> <string name="subtitles_shadow">Umbră</string>

View file

@ -1,17 +1,6 @@
<!--https://newbedev.com/concatenate-multiple-strings-in-xml--> <!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
<resources> <resources>
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" formatted="true" translatable="false">%d %s | %sMB</string>
<string name="storage_size_format" formatted="true" translatable="false">%s • %sGB</string>
<string name="download_size_format" formatted="true" translatable="false">%sMB / %sMB</string>
<string name="mb_format" formatted="true" translatable="false">%dMB</string>
<string name="episode_name_format" formatted="true" translatable="false">%s %s</string>
<string name="ffw_text_format" formatted="true" translatable="false">+%d</string>
<string name="rew_text_format" formatted="true" translatable="false">-%d</string>
<string name="ffw_text_regular_format" formatted="true" translatable="false">%d</string>
<string name="rew_text_regular_format" formatted="true" translatable="false">%d</string>
<string name="rating_format" formatted="true" translatable="false">%.1f/10.0</string>
<string name="year_format" formatted="true" translatable="false">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
<string name="cast_format" formatted="true">Cast: %s</string> <string name="cast_format" formatted="true">Cast: %s</string>
<string name="next_episode_format" formatted="true">Bölüm %d şu tarihte yayınlanacak: </string> <string name="next_episode_format" formatted="true">Bölüm %d şu tarihte yayınlanacak: </string>
@ -25,9 +14,7 @@
<string name="episode_poster_img_des">Episode Poster</string> <string name="episode_poster_img_des">Episode Poster</string>
<string name="home_main_poster_img_des">Main Poster</string> <string name="home_main_poster_img_des">Main Poster</string>
<string name="home_next_random_img_des">Next Random</string> <string name="home_next_random_img_des">Next Random</string>
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
<string name="go_back_img_des">Go back</string> <string name="go_back_img_des">Go back</string>
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
<string name="home_change_provider_img_des">Change Provider</string> <string name="home_change_provider_img_des">Change Provider</string>
<string name="preview_background_img_des">Preview Background</string> <string name="preview_background_img_des">Preview Background</string>
@ -51,7 +38,6 @@
<string name="no_data">Veri yok</string> <string name="no_data">Veri yok</string>
<string name="episode_more_options_des">Daha fazla seçenek</string> <string name="episode_more_options_des">Daha fazla seçenek</string>
<string name="next_episode">Sonraki bölüm</string> <string name="next_episode">Sonraki bölüm</string>
<string name="result_plot" translatable="false">@string/synopsis</string>
<string name="result_tags">Türler</string> <string name="result_tags">Türler</string>
<string name="result_share">Paylaş</string> <string name="result_share">Paylaş</string>
<string name="result_open_in_browser">Tarayıcıda aç</string> <string name="result_open_in_browser">Tarayıcıda aç</string>
@ -84,7 +70,6 @@
<string name="download_failed">İndirme başarısız oldu</string> <string name="download_failed">İndirme başarısız oldu</string>
<string name="download_canceled">İndirme iptal edildi</string> <string name="download_canceled">İndirme iptal edildi</string>
<string name="download_done">İndirme bitti</string> <string name="download_done">İndirme bitti</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="stream">Yayınla</string> <string name="stream">Yayınla</string>
<string name="error_loading_links_toast">Bağlantılar yüklenirken hata oluştu</string> <string name="error_loading_links_toast">Bağlantılar yüklenirken hata oluştu</string>
@ -232,7 +217,6 @@
<string name="delete_file">Dosyayı sil</string> <string name="delete_file">Dosyayı sil</string>
<string name="delete">Sil</string> <string name="delete">Sil</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">Durdur</string> <string name="pause">Durdur</string>
<string name="resume">Sürdür</string> <string name="resume">Sürdür</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -300,10 +284,6 @@
<string name="show_dub">Dublaj etiketi</string> <string name="show_dub">Dublaj etiketi</string>
<string name="show_sub">Alt yazı etiketi</string> <string name="show_sub">Alt yazı etiketi</string>
<string name="show_title">Başlık</string> <string name="show_title">Başlık</string>
<string name="show_hd_key" translatable="false">show_hd_key</string>
<string name="show_dub_key" translatable="false">show_dub_key</string>
<string name="show_sub_key" translatable="false">show_sub_key</string>
<string name="show_title_key" translatable="false">show_title_key</string>
<string name="poster_ui_settings">Poster üzerindeki öğeler</string> <string name="poster_ui_settings">Poster üzerindeki öğeler</string>
<string name="no_update_found">Güncelleme bulunamadı</string> <string name="no_update_found">Güncelleme bulunamadı</string>
@ -347,7 +327,6 @@
<string name="resize_zoom">Yakınlaştır</string> <string name="resize_zoom">Yakınlaştır</string>
<string name="legal_notice">Disclaimer</string> <string name="legal_notice">Disclaimer</string>
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application <string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
@ -386,10 +365,6 @@
<!-- account stuff --> <!-- account stuff -->
<string name="anilist_key" translatable="false">anilist_key</string>
<string name="mal_key" translatable="false">mal_key</string>
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
<string name="nginx_key" translatable="false">nginx_key</string>
<string name="example_password">şifre123</string> <string name="example_password">şifre123</string>
<string name="example_username">HavalıKullanıcıAdı</string> <string name="example_username">HavalıKullanıcıAdı</string>
<string name="example_email">hello@world.com</string> <string name="example_email">hello@world.com</string>
@ -429,7 +404,6 @@
<string name="all">Hepsi</string> <string name="all">Hepsi</string>
<string name="max">Maksimum</string> <string name="max">Maksimum</string>
<string name="min">Minimum</string> <string name="min">Minimum</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">Dış hat</string> <string name="subtitles_outline">Dış hat</string>
<string name="subtitles_depressed">Çökmüş</string> <string name="subtitles_depressed">Çökmüş</string>
<string name="subtitles_shadow">Gölge</string> <string name="subtitles_shadow">Gölge</string>

View file

@ -3,17 +3,6 @@
<!-- KEYS DON'T TRANSLATE --> <!-- KEYS DON'T TRANSLATE -->
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
<string name="mb_format" translatable="false" formatted="true">%dMB</string>
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
<string name="rating_format" translatable="false" formatted="true">%.1f/10.0</string>
<string name="year_format" translatable="false" formatted="true">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%s Tập %d</string> <string name="app_dub_sub_episode_text_format" formatted="true">%s Tập %d</string>
<string name="cast_format" formatted="true">Diễn viên: %s</string> <string name="cast_format" formatted="true">Diễn viên: %s</string>
<string name="next_episode_format" formatted="true">Tập %d sẽ ra mắt sau</string> <string name="next_episode_format" formatted="true">Tập %d sẽ ra mắt sau</string>
@ -27,9 +16,7 @@
<string name="episode_poster_img_des">Episode Poster</string> <string name="episode_poster_img_des">Episode Poster</string>
<string name="home_main_poster_img_des">Main Poster</string> <string name="home_main_poster_img_des">Main Poster</string>
<string name="home_next_random_img_des">Next Random</string> <string name="home_next_random_img_des">Next Random</string>
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
<string name="go_back_img_des">Go back</string> <string name="go_back_img_des">Go back</string>
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
<string name="home_change_provider_img_des">Change Provider</string> <string name="home_change_provider_img_des">Change Provider</string>
<string name="preview_background_img_des">Preview Background</string> <string name="preview_background_img_des">Preview Background</string>
@ -52,7 +39,6 @@
<string name="no_data">Không có dữ liệu</string> <string name="no_data">Không có dữ liệu</string>
<string name="episode_more_options_des">Thêm tuỳ chọn</string> <string name="episode_more_options_des">Thêm tuỳ chọn</string>
<string name="next_episode">Tập tiếp theo</string> <string name="next_episode">Tập tiếp theo</string>
<string name="result_plot" translatable="false">@string/synopsis</string>
<string name="result_tags">Thể loại</string> <string name="result_tags">Thể loại</string>
<string name="result_share">Chia sẻ</string> <string name="result_share">Chia sẻ</string>
<string name="result_open_in_browser">Mở bằng trình duyệt</string> <string name="result_open_in_browser">Mở bằng trình duyệt</string>
@ -84,7 +70,6 @@
<string name="download_failed">Tải lỗi</string> <string name="download_failed">Tải lỗi</string>
<string name="download_canceled">Đã hủy</string> <string name="download_canceled">Đã hủy</string>
<string name="download_done">Tải thành công</string> <string name="download_done">Tải thành công</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="stream">Stream</string> <string name="stream">Stream</string>
<string name="error_loading_links_toast">Đã có lỗi xảy ra</string> <string name="error_loading_links_toast">Đã có lỗi xảy ra</string>
@ -232,7 +217,6 @@
<string name="delete_file">Xóa Tệp</string> <string name="delete_file">Xóa Tệp</string>
<string name="delete">Xóa</string> <string name="delete">Xóa</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">Tạm Dừng</string> <string name="pause">Tạm Dừng</string>
<string name="resume">Tiếp Tục</string> <string name="resume">Tiếp Tục</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -298,10 +282,6 @@
<string name="show_dub">Nhãn lồng tiếng</string> <string name="show_dub">Nhãn lồng tiếng</string>
<string name="show_sub">Nhãn phụ đề</string> <string name="show_sub">Nhãn phụ đề</string>
<string name="show_title">Tiêu đề</string> <string name="show_title">Tiêu đề</string>
<string name="show_hd_key" translatable="false">show_hd_key</string>
<string name="show_dub_key" translatable="false">show_dub_key</string>
<string name="show_sub_key" translatable="false">show_sub_key</string>
<string name="show_title_key" translatable="false">show_title_key</string>
<string name="poster_ui_settings">Thay đổi giao diện trên poster</string> <string name="poster_ui_settings">Thay đổi giao diện trên poster</string>
<string name="no_update_found">Bạn đang dùng phiên bản mới nhất</string> <string name="no_update_found">Bạn đang dùng phiên bản mới nhất</string>
@ -345,7 +325,6 @@
<string name="resize_zoom">Phóng to</string> <string name="resize_zoom">Phóng to</string>
<string name="legal_notice">Disclaimer</string> <string name="legal_notice">Disclaimer</string>
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application <string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
@ -383,10 +362,6 @@
<string name="bottom_title_settings_des">Đặt tiêu đề dưới poster</string> <string name="bottom_title_settings_des">Đặt tiêu đề dưới poster</string>
<!-- account stuff --> <!-- account stuff -->
<string name="anilist_key" translatable="false">anilist_key</string>
<string name="mal_key" translatable="false">mal_key</string>
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
<string name="nginx_key" translatable="false">nginx_key</string>
<string name="example_password">Mật khẩu</string> <string name="example_password">Mật khẩu</string>
<string name="example_username">Tài khoản</string> <string name="example_username">Tài khoản</string>
<string name="example_email">Email</string> <string name="example_email">Email</string>
@ -426,7 +401,6 @@
<string name="all">Tất cả</string> <string name="all">Tất cả</string>
<string name="max">Tối đa</string> <string name="max">Tối đa</string>
<string name="min">Tối thiểu</string> <string name="min">Tối thiểu</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">Viền</string> <string name="subtitles_outline">Viền</string>
<string name="subtitles_depressed">Chìm</string> <string name="subtitles_depressed">Chìm</string>
<string name="subtitles_shadow">Đổ bóng</string> <string name="subtitles_shadow">Đổ bóng</string>

View file

@ -10,9 +10,7 @@
<string name="episode_poster_img_des">剧集海报</string> <string name="episode_poster_img_des">剧集海报</string>
<string name="home_main_poster_img_des">主海报</string> <string name="home_main_poster_img_des">主海报</string>
<string name="home_next_random_img_des">随机下一个</string> <string name="home_next_random_img_des">随机下一个</string>
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
<string name="go_back_img_des">返回</string> <string name="go_back_img_des">返回</string>
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
<string name="home_change_provider_img_des">更改内容提供者</string> <string name="home_change_provider_img_des">更改内容提供者</string>
<string name="preview_background_img_des">预览背景</string> <string name="preview_background_img_des">预览背景</string>
@ -33,7 +31,6 @@
<string name="no_data">无数据</string> <string name="no_data">无数据</string>
<string name="episode_more_options_des">更多选项</string> <string name="episode_more_options_des">更多选项</string>
<string name="next_episode">下一集</string> <string name="next_episode">下一集</string>
<string name="result_plot" translatable="false">@string/synopsis</string>
<string name="result_tags">类型</string> <string name="result_tags">类型</string>
<string name="result_share">分享</string> <string name="result_share">分享</string>
<string name="result_open_in_browser">在浏览器中打开</string> <string name="result_open_in_browser">在浏览器中打开</string>
@ -65,7 +62,6 @@
<string name="download_failed">下载失败</string> <string name="download_failed">下载失败</string>
<string name="download_canceled">下载取消</string> <string name="download_canceled">下载取消</string>
<string name="download_done">下载完毕</string> <string name="download_done">下载完毕</string>
<string name="download_format" translatable="false">%s - %s</string>
<string name="error_loading_links_toast">加载链接时出错</string> <string name="error_loading_links_toast">加载链接时出错</string>
<string name="download_storage_text">内部存储</string> <string name="download_storage_text">内部存储</string>
@ -196,7 +192,6 @@
<string name="delete_file">删除文件</string> <string name="delete_file">删除文件</string>
<string name="delete">删除</string> <string name="delete">删除</string>
<string name="cancel" translatable="false">@string/sort_cancel</string>
<string name="pause">暂停</string> <string name="pause">暂停</string>
<string name="resume">继续</string> <string name="resume">继续</string>
<string name="go_back_30">-30</string> <string name="go_back_30">-30</string>
@ -287,7 +282,6 @@
<string name="resize_zoom">缩放</string> <string name="resize_zoom">缩放</string>
<string name="legal_notice">免责声明</string> <string name="legal_notice">免责声明</string>
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application <string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
@ -318,8 +312,6 @@
<string name="app_theme_settings">应用主题</string> <string name="app_theme_settings">应用主题</string>
<!-- account stuff --> <!-- account stuff -->
<string name="anilist_key" translatable="false">anilist_key</string>
<string name="mal_key" translatable="false">mal_key</string>
<!-- <!--
<string name="mal_account_settings" translatable="false">MAL</string> <string name="mal_account_settings" translatable="false">MAL</string>
<string name="anilist_account_settings" translatable="false">AniList</string> <string name="anilist_account_settings" translatable="false">AniList</string>
@ -344,7 +336,6 @@
<string name="all">全部</string> <string name="all">全部</string>
<string name="max">最大</string> <string name="max">最大</string>
<string name="min">最小</string> <string name="min">最小</string>
<string name="subtitles_none" translatable="false">@string/none</string>
<string name="subtitles_outline">轮廓</string> <string name="subtitles_outline">轮廓</string>
<string name="subtitles_depressed">降低</string> <string name="subtitles_depressed">降低</string>
<string name="subtitles_shadow">阴影</string> <string name="subtitles_shadow">阴影</string>

View file

@ -56,10 +56,9 @@
<string name="pref_filter_search_quality_key" translatable="false">pref_filter_search_quality_key</string> <string name="pref_filter_search_quality_key" translatable="false">pref_filter_search_quality_key</string>
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG --> <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
<string name="extra_info_format" formatted="true" translatable="false">%d %s | %sMB</string> <string name="extra_info_format" formatted="true" translatable="false">%d %s | %s</string>
<string name="storage_size_format" formatted="true" translatable="false">%s • %sGB</string> <string name="storage_size_format" formatted="true" translatable="false">%s • %s</string>
<string name="download_size_format" formatted="true" translatable="false">%sMB / %sMB</string> <string name="download_size_format" formatted="true" translatable="false">%s / %s</string>
<string name="mb_format" formatted="true" translatable="false">%dMB</string>
<string name="episode_name_format" formatted="true" translatable="false">%s %s</string> <string name="episode_name_format" formatted="true" translatable="false">%s %s</string>
<string name="ffw_text_format" formatted="true" translatable="false">+%d</string> <string name="ffw_text_format" formatted="true" translatable="false">+%d</string>
<string name="rew_text_format" formatted="true" translatable="false">-%d</string> <string name="rew_text_format" formatted="true" translatable="false">-%d</string>