mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
3d398f0b92
72 changed files with 2884 additions and 1790 deletions
6
app/CMakeLists.txt
Normal file
6
app/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Set this to the minimum version your project supports.
|
||||||
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
project(CrashHandler)
|
||||||
|
find_library(log-lib log)
|
||||||
|
add_library(native-lib SHARED src/main/cpp/native-lib.cpp)
|
||||||
|
target_link_libraries(native-lib ${log-lib})
|
|
@ -32,6 +32,13 @@ android {
|
||||||
enable = true
|
enable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disable this for now
|
||||||
|
//externalNativeBuild {
|
||||||
|
// cmake {
|
||||||
|
// path("CMakeLists.txt")
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
create("prerelease") {
|
create("prerelease") {
|
||||||
if (prereleaseStoreFile != null) {
|
if (prereleaseStoreFile != null) {
|
||||||
|
@ -49,10 +56,10 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.lagradost.cloudstream3"
|
applicationId = "com.lagradost.cloudstream3"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 33
|
targetSdk = 29
|
||||||
|
|
||||||
versionCode = 59
|
versionCode = 59
|
||||||
versionName = "4.1.3"
|
versionName = "4.1.8"
|
||||||
|
|
||||||
resValue("string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}")
|
resValue("string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}")
|
||||||
resValue("string", "commit_hash", "git rev-parse --short HEAD".execute() ?: "")
|
resValue("string", "commit_hash", "git rev-parse --short HEAD".execute() ?: "")
|
||||||
|
@ -165,7 +172,7 @@ dependencies {
|
||||||
androidTestImplementation("androidx.test:core")
|
androidTestImplementation("androidx.test:core")
|
||||||
|
|
||||||
//implementation("io.karn:khttp-android:0.1.2") //okhttp instead
|
//implementation("io.karn:khttp-android:0.1.2") //okhttp instead
|
||||||
// implementation("org.jsoup:jsoup:1.13.1")
|
// implementation("org.jsoup:jsoup:1.13.1")
|
||||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1")
|
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1")
|
||||||
|
|
||||||
implementation("androidx.preference:preference-ktx:1.2.0")
|
implementation("androidx.preference:preference-ktx:1.2.0")
|
||||||
|
@ -181,22 +188,22 @@ dependencies {
|
||||||
// implementation("androidx.leanback:leanback-paging:1.1.0-alpha09")
|
// implementation("androidx.leanback:leanback-paging:1.1.0-alpha09")
|
||||||
|
|
||||||
// Media 3
|
// Media 3
|
||||||
implementation("androidx.media3:media3-common:1.1.0")
|
implementation("androidx.media3:media3-common:1.1.1")
|
||||||
implementation("androidx.media3:media3-exoplayer:1.1.0")
|
implementation("androidx.media3:media3-exoplayer:1.1.1")
|
||||||
implementation("androidx.media3:media3-datasource-okhttp:1.1.0")
|
implementation("androidx.media3:media3-datasource-okhttp:1.1.1")
|
||||||
implementation("androidx.media3:media3-ui:1.1.0")
|
implementation("androidx.media3:media3-ui:1.1.1")
|
||||||
implementation("androidx.media3:media3-session:1.1.0")
|
implementation("androidx.media3:media3-session:1.1.1")
|
||||||
implementation("androidx.media3:media3-cast:1.1.0")
|
implementation("androidx.media3:media3-cast:1.1.1")
|
||||||
implementation("androidx.media3:media3-exoplayer-hls:1.1.0")
|
implementation("androidx.media3:media3-exoplayer-hls:1.1.1")
|
||||||
implementation("androidx.media3:media3-exoplayer-dash:1.1.0")
|
implementation("androidx.media3:media3-exoplayer-dash:1.1.1")
|
||||||
// Custom ffmpeg extension for audio codecs
|
// Custom ffmpeg extension for audio codecs
|
||||||
implementation("com.github.recloudstream:media-ffmpeg:1.1.0")
|
implementation("com.github.recloudstream:media-ffmpeg:1.1.0")
|
||||||
|
|
||||||
//implementation("com.google.android.exoplayer:extension-leanback:2.14.0")
|
//implementation("com.google.android.exoplayer:extension-leanback:2.14.0")
|
||||||
|
|
||||||
// Bug reports
|
// Bug reports
|
||||||
implementation("ch.acra:acra-core:5.8.4")
|
implementation("ch.acra:acra-core:5.11.0")
|
||||||
implementation("ch.acra:acra-toast:5.8.4")
|
implementation("ch.acra:acra-toast:5.11.0")
|
||||||
|
|
||||||
compileOnly("com.google.auto.service:auto-service-annotations:1.0")
|
compileOnly("com.google.auto.service:auto-service-annotations:1.0")
|
||||||
//either for java sources:
|
//either for java sources:
|
||||||
|
@ -220,18 +227,18 @@ dependencies {
|
||||||
implementation("androidx.work:work-runtime-ktx:2.8.1")
|
implementation("androidx.work:work-runtime-ktx:2.8.1")
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
// implementation("com.squareup.okhttp3:okhttp:4.9.2")
|
// implementation("com.squareup.okhttp3:okhttp:4.9.2")
|
||||||
// implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1")
|
// implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1")
|
||||||
implementation("com.github.Blatzar:NiceHttp:0.4.3")
|
implementation("com.github.Blatzar:NiceHttp:0.4.3")
|
||||||
// To fix SSL fuckery on android 9
|
// To fix SSL fuckery on android 9
|
||||||
implementation("org.conscrypt:conscrypt-android:2.2.1")
|
implementation("org.conscrypt:conscrypt-android:2.2.1")
|
||||||
// Util to skip the URI file fuckery 🙏
|
// Util to skip the URI file fuckery 🙏
|
||||||
implementation("com.github.tachiyomiorg:unifile:17bec43")
|
implementation("com.github.LagradOst:SafeFile:0.0.2")
|
||||||
|
|
||||||
// API because cba maintaining it myself
|
// API because cba maintaining it myself
|
||||||
implementation("com.uwetrottmann.tmdb2:tmdb-java:2.6.0")
|
implementation("com.uwetrottmann.tmdb2:tmdb-java:2.6.0")
|
||||||
|
|
||||||
implementation("com.github.discord:OverlappingPanels:0.1.3")
|
implementation("com.github.discord:OverlappingPanels:0.1.5")
|
||||||
// debugImplementation because LeakCanary should only run in debug builds.
|
// debugImplementation because LeakCanary should only run in debug builds.
|
||||||
//debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12")
|
//debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12")
|
||||||
|
|
||||||
|
@ -243,11 +250,9 @@ dependencies {
|
||||||
// used for subtitle decoding https://github.com/albfernandez/juniversalchardet
|
// used for subtitle decoding https://github.com/albfernandez/juniversalchardet
|
||||||
implementation("com.github.albfernandez:juniversalchardet:2.4.0")
|
implementation("com.github.albfernandez:juniversalchardet:2.4.0")
|
||||||
|
|
||||||
// slow af yt
|
|
||||||
//implementation("com.github.HaarigerHarald:android-youtubeExtractor:master-SNAPSHOT")
|
|
||||||
|
|
||||||
// newpipe yt taken from https://github.com/TeamNewPipe/NewPipe/blob/dev/app/build.gradle#L204
|
// newpipe yt taken from https://github.com/TeamNewPipe/NewPipe/blob/dev/app/build.gradle#L204
|
||||||
implementation("com.github.TeamNewPipe:NewPipeExtractor:8495ad619e")
|
// this should be updated frequently to avoid trailer fu*kery
|
||||||
|
implementation("com.github.TeamNewPipe:NewPipeExtractor:1f08d28")
|
||||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.6")
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.6")
|
||||||
|
|
||||||
// Library/extensions searching with Levenshtein distance
|
// Library/extensions searching with Levenshtein distance
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" /> <!-- Used for updates without prompt -->
|
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" /> <!-- Used for updates without prompt -->
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Used for update service -->
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Used for update service -->
|
||||||
|
|
||||||
<!-- <permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <!– Used for getting if vlc is installed –> -->
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <!-- Required for getting arbitrary Aniyomi packages -->
|
||||||
<!-- Fixes android tv fuckery -->
|
<!-- Fixes android tv fuckery -->
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.touchscreen"
|
android:name="android.hardware.touchscreen"
|
||||||
|
|
28
app/src/main/cpp/native-lib.cpp
Normal file
28
app/src/main/cpp/native-lib.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#include <jni.h>
|
||||||
|
#include <csignal>
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#define TAG "CloudStream Crash Handler"
|
||||||
|
volatile sig_atomic_t gSignalStatus = 0;
|
||||||
|
void handleNativeCrash(int signal) {
|
||||||
|
gSignalStatus = signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_com_lagradost_cloudstream3_NativeCrashHandler_initNativeCrashHandler(JNIEnv *env, jobject) {
|
||||||
|
#define REGISTER_SIGNAL(X) signal(X, handleNativeCrash);
|
||||||
|
REGISTER_SIGNAL(SIGSEGV)
|
||||||
|
#undef REGISTER_SIGNAL
|
||||||
|
}
|
||||||
|
|
||||||
|
//extern "C" JNIEXPORT void JNICALL
|
||||||
|
//Java_com_lagradost_cloudstream3_NativeCrashHandler_triggerNativeCrash(JNIEnv *env, jobject thiz) {
|
||||||
|
// int *p = nullptr;
|
||||||
|
// *p = 0;
|
||||||
|
//}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT int JNICALL
|
||||||
|
Java_com_lagradost_cloudstream3_NativeCrashHandler_getSignalStatus(JNIEnv *env, jobject) {
|
||||||
|
//__android_log_print(ANDROID_LOG_INFO, TAG, "Got signal status %d", gSignalStatus);
|
||||||
|
return gSignalStatus;
|
||||||
|
}
|
|
@ -43,9 +43,9 @@ class CustomReportSender : ReportSender {
|
||||||
override fun send(context: Context, errorContent: CrashReportData) {
|
override fun send(context: Context, errorContent: CrashReportData) {
|
||||||
println("Sending report")
|
println("Sending report")
|
||||||
val url =
|
val url =
|
||||||
"https://docs.google.com/forms/d/e/1FAIpQLSdOlbgCx7NeaxjvEGyEQlqdh2nCvwjm2vwpP1VwW7REj9Ri3Q/formResponse"
|
"https://docs.google.com/forms/d/e/1FAIpQLSfO4r353BJ79TTY_-t5KWSIJT2xfqcQWY81xjAA1-1N0U2eSg/formResponse"
|
||||||
val data = mapOf(
|
val data = mapOf(
|
||||||
"entry.753293084" to errorContent.toJSON()
|
"entry.1993829403" to errorContent.toJSON()
|
||||||
)
|
)
|
||||||
|
|
||||||
thread { // to not run it on main thread
|
thread { // to not run it on main thread
|
||||||
|
@ -104,12 +104,17 @@ class ExceptionHandler(val errorFile: File, val onError: (() -> Unit)) :
|
||||||
}
|
}
|
||||||
|
|
||||||
class AcraApplication : Application() {
|
class AcraApplication : Application() {
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
Thread.setDefaultUncaughtExceptionHandler(ExceptionHandler(filesDir.resolve("last_error")) {
|
//NativeCrashHandler.initCrashHandler()
|
||||||
|
ExceptionHandler(filesDir.resolve("last_error")) {
|
||||||
val intent = context!!.packageManager.getLaunchIntentForPackage(context!!.packageName)
|
val intent = context!!.packageManager.getLaunchIntentForPackage(context!!.packageName)
|
||||||
startActivity(Intent.makeRestartActivityTask(intent!!.component))
|
startActivity(Intent.makeRestartActivityTask(intent!!.component))
|
||||||
})
|
}.also {
|
||||||
|
exceptionHandler = it
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun attachBaseContext(base: Context?) {
|
override fun attachBaseContext(base: Context?) {
|
||||||
|
@ -121,10 +126,10 @@ class AcraApplication : Application() {
|
||||||
buildConfigClass = BuildConfig::class.java
|
buildConfigClass = BuildConfig::class.java
|
||||||
reportFormat = StringFormat.JSON
|
reportFormat = StringFormat.JSON
|
||||||
|
|
||||||
reportContent = arrayOf(
|
reportContent = listOf(
|
||||||
ReportField.BUILD_CONFIG, ReportField.USER_CRASH_DATE,
|
ReportField.BUILD_CONFIG, ReportField.USER_CRASH_DATE,
|
||||||
ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL,
|
ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL,
|
||||||
ReportField.STACK_TRACE
|
ReportField.STACK_TRACE,
|
||||||
)
|
)
|
||||||
|
|
||||||
// removed this due to bug when starting the app, moved it to when it actually crashes
|
// removed this due to bug when starting the app, moved it to when it actually crashes
|
||||||
|
@ -137,6 +142,8 @@ class AcraApplication : Application() {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
var exceptionHandler: ExceptionHandler? = null
|
||||||
|
|
||||||
/** Use to get activity from Context */
|
/** Use to get activity from Context */
|
||||||
tailrec fun Context.getActivity(): Activity? = this as? Activity
|
tailrec fun Context.getActivity(): Activity? = this as? Activity
|
||||||
?: (this as? ContextWrapper)?.baseContext?.getActivity()
|
?: (this as? ContextWrapper)?.baseContext?.getActivity()
|
||||||
|
@ -211,6 +218,5 @@ class AcraApplication : Application() {
|
||||||
activity?.supportFragmentManager?.fragments?.lastOrNull()
|
activity?.supportFragmentManager?.fragments?.lastOrNull()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ class DownloaderTestImpl private constructor(builder: OkHttpClient.Builder) : Do
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val USER_AGENT =
|
private const val USER_AGENT =
|
||||||
"Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0"
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
|
||||||
private var instance: DownloaderTestImpl? = null
|
private var instance: DownloaderTestImpl? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,7 +29,7 @@ import java.util.*
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
const val USER_AGENT =
|
const val USER_AGENT =
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
|
||||||
|
|
||||||
//val baseHeader = mapOf("User-Agent" to USER_AGENT)
|
//val baseHeader = mapOf("User-Agent" to USER_AGENT)
|
||||||
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
||||||
|
|
|
@ -144,6 +144,7 @@ import com.lagradost.cloudstream3.utils.USER_PROVIDER_API
|
||||||
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_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 com.lagradost.safefile.SafeFile
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -279,6 +280,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "MAINACT"
|
const val TAG = "MAINACT"
|
||||||
var lastError: String? = null
|
var lastError: String? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setting this will automatically enter the query in the search
|
* Setting this will automatically enter the query in the search
|
||||||
* next time the search fragment is opened.
|
* next time the search fragment is opened.
|
||||||
|
@ -286,7 +288,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
*
|
*
|
||||||
* This is a very bad solution but I was unable to find a better one.
|
* This is a very bad solution but I was unable to find a better one.
|
||||||
**/
|
**/
|
||||||
private var nextSearchQuery: String? = null
|
var nextSearchQuery: String? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires every time a new batch of plugins have been loaded, no guarantee about how often this is run and on which thread
|
* Fires every time a new batch of plugins have been loaded, no guarantee about how often this is run and on which thread
|
||||||
|
@ -362,9 +364,14 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
loadRepository(url)
|
loadRepository(url)
|
||||||
return true
|
return true
|
||||||
} else if (safeURI(str)?.scheme == appStringSearch) {
|
} else if (safeURI(str)?.scheme == appStringSearch) {
|
||||||
|
val query = str.substringAfter("$appStringSearch://")
|
||||||
nextSearchQuery =
|
nextSearchQuery =
|
||||||
URLDecoder.decode(str.substringAfter("$appStringSearch://"), "UTF-8")
|
try {
|
||||||
|
URLDecoder.decode(query, "UTF-8")
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
logError(t)
|
||||||
|
query
|
||||||
|
}
|
||||||
// Use both navigation views to support both layouts.
|
// Use both navigation views to support both layouts.
|
||||||
// It might be better to use the QuickSearch.
|
// It might be better to use the QuickSearch.
|
||||||
activity?.findViewById<BottomNavigationView>(R.id.nav_view)?.selectedItemId =
|
activity?.findViewById<BottomNavigationView>(R.id.nav_view)?.selectedItemId =
|
||||||
|
@ -854,7 +861,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
RecyclerView::class.java.declaredMethods.firstOrNull {
|
RecyclerView::class.java.declaredMethods.firstOrNull {
|
||||||
it.name == "scrollStep"
|
it.name == "scrollStep"
|
||||||
}?.also { it.isAccessible = true }
|
}?.also { it.isAccessible = true }
|
||||||
} catch (t : Throwable) {
|
} catch (t: Throwable) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -901,11 +908,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
if (dx > 0) dx else 0
|
if (dx > 0) dx else 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!NO_MOVE_LIST) {
|
if (!NO_MOVE_LIST) {
|
||||||
parent.smoothScrollBy(rdx, 0)
|
parent.smoothScrollBy(rdx, 0)
|
||||||
}else {
|
} else {
|
||||||
val smoothScroll = reflectedScroll
|
val smoothScroll = reflectedScroll
|
||||||
if(smoothScroll == null) {
|
if (smoothScroll == null) {
|
||||||
parent.smoothScrollBy(rdx, 0)
|
parent.smoothScrollBy(rdx, 0)
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
@ -915,12 +922,12 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
val out = IntArray(2)
|
val out = IntArray(2)
|
||||||
smoothScroll.invoke(parent, rdx, 0, out)
|
smoothScroll.invoke(parent, rdx, 0, out)
|
||||||
val scrolledX = out[0]
|
val scrolledX = out[0]
|
||||||
if(abs(scrolledX) <= 0) { // newFocus.measuredWidth*2
|
if (abs(scrolledX) <= 0) { // newFocus.measuredWidth*2
|
||||||
smoothScroll.invoke(parent, -rdx, 0, out)
|
smoothScroll.invoke(parent, -rdx, 0, out)
|
||||||
parent.smoothScrollBy(scrolledX, 0)
|
parent.smoothScrollBy(scrolledX, 0)
|
||||||
if (NO_MOVE_LIST) targetDx = scrolledX
|
if (NO_MOVE_LIST) targetDx = scrolledX
|
||||||
}
|
}
|
||||||
} catch (t : Throwable) {
|
} catch (t: Throwable) {
|
||||||
parent.smoothScrollBy(rdx, 0)
|
parent.smoothScrollBy(rdx, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1126,10 +1133,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
snackbar.show()
|
snackbar.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ioSafe { SafeFile.check(this@MainActivity) }
|
||||||
|
|
||||||
if (PluginManager.checkSafeModeFile()) {
|
if (PluginManager.checkSafeModeFile()) {
|
||||||
normalSafeApiCall {
|
normalSafeApiCall {
|
||||||
|
@ -1315,7 +1322,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
if (navDestination.matchDestination(R.id.navigation_search) && !nextSearchQuery.isNullOrBlank()) {
|
if (navDestination.matchDestination(R.id.navigation_search) && !nextSearchQuery.isNullOrBlank()) {
|
||||||
bundle?.apply {
|
bundle?.apply {
|
||||||
this.putString(SearchFragment.SEARCH_QUERY, nextSearchQuery)
|
this.putString(SearchFragment.SEARCH_QUERY, nextSearchQuery)
|
||||||
nextSearchQuery = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.lagradost.cloudstream3
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.MainActivity.Companion.lastError
|
||||||
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
|
import com.lagradost.cloudstream3.plugins.PluginManager.checkSafeModeFile
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
object NativeCrashHandler {
|
||||||
|
// external fun triggerNativeCrash()
|
||||||
|
/*private external fun initNativeCrashHandler()
|
||||||
|
private external fun getSignalStatus(): Int
|
||||||
|
|
||||||
|
private fun initSignalPolling() = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
|
||||||
|
//launch {
|
||||||
|
// delay(10000)
|
||||||
|
// triggerNativeCrash()
|
||||||
|
//}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
delay(10_000)
|
||||||
|
val signal = getSignalStatus()
|
||||||
|
// Signal is initialized to zero
|
||||||
|
if (signal == 0) continue
|
||||||
|
|
||||||
|
// Do not crash in safe mode!
|
||||||
|
if (lastError != null) continue
|
||||||
|
if (checkSafeModeFile()) continue
|
||||||
|
|
||||||
|
AcraApplication.exceptionHandler?.uncaughtException(
|
||||||
|
Thread.currentThread(),
|
||||||
|
RuntimeException("Native crash with code: $signal. Try uninstalling extensions.\n")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initCrashHandler() {
|
||||||
|
try {
|
||||||
|
System.loadLibrary("native-lib")
|
||||||
|
initNativeCrashHandler()
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
// Make debug crash.
|
||||||
|
if (BuildConfig.DEBUG) throw t
|
||||||
|
logError(t)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
initSignalPolling()
|
||||||
|
}*/
|
||||||
|
}
|
|
@ -1,13 +1,11 @@
|
||||||
package com.lagradost.cloudstream3.extractors
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.USER_AGENT
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
|
||||||
import android.util.Log
|
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
|
||||||
open class Cda: ExtractorApi() {
|
open class Cda: ExtractorApi() {
|
||||||
|
|
|
@ -10,24 +10,39 @@ open class Mp4Upload : ExtractorApi() {
|
||||||
override var name = "Mp4Upload"
|
override var name = "Mp4Upload"
|
||||||
override var mainUrl = "https://www.mp4upload.com"
|
override var mainUrl = "https://www.mp4upload.com"
|
||||||
private val srcRegex = Regex("""player\.src\("(.*?)"""")
|
private val srcRegex = Regex("""player\.src\("(.*?)"""")
|
||||||
override val requiresReferer = true
|
private val srcRegex2 = Regex("""player\.src\([\w\W]*src: "(.*?)"""")
|
||||||
|
|
||||||
|
override val requiresReferer = true
|
||||||
|
private val idMatch = Regex("""mp4upload\.com/(embed-|)([A-Za-z0-9]*)""")
|
||||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
with(app.get(url)) {
|
val realUrl = idMatch.find(url)?.groupValues?.get(2)?.let { id ->
|
||||||
getAndUnpack(this.text).let { unpackedText ->
|
"$mainUrl/embed-$id.html"
|
||||||
val quality = unpackedText.lowercase().substringAfter(" height=").substringBefore(" ").toIntOrNull()
|
} ?: url
|
||||||
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
val response = app.get(realUrl)
|
||||||
return listOf(
|
val unpackedText = getAndUnpack(response.text)
|
||||||
ExtractorLink(
|
val quality =
|
||||||
name,
|
unpackedText.lowercase().substringAfter(" height=").substringBefore(" ").toIntOrNull()
|
||||||
name,
|
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||||
link,
|
return listOf(
|
||||||
url,
|
ExtractorLink(
|
||||||
quality ?: Qualities.Unknown.value,
|
name,
|
||||||
)
|
name,
|
||||||
)
|
link,
|
||||||
}
|
url,
|
||||||
}
|
quality ?: Qualities.Unknown.value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
srcRegex2.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||||
|
return listOf(
|
||||||
|
ExtractorLink(
|
||||||
|
name,
|
||||||
|
name,
|
||||||
|
link,
|
||||||
|
url,
|
||||||
|
quality ?: Qualities.Unknown.value,
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ open class Rabbitstream : ExtractorApi() {
|
||||||
override val requiresReferer = false
|
override val requiresReferer = false
|
||||||
open val embed = "ajax/embed-4"
|
open val embed = "ajax/embed-4"
|
||||||
open val key = "https://raw.githubusercontent.com/enimax-anime/key/e4/key.txt"
|
open val key = "https://raw.githubusercontent.com/enimax-anime/key/e4/key.txt"
|
||||||
private var rawKey: String? = null
|
|
||||||
|
|
||||||
override suspend fun getUrl(
|
override suspend fun getUrl(
|
||||||
url: String,
|
url: String,
|
||||||
|
@ -82,9 +81,10 @@ open class Rabbitstream : ExtractorApi() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getRawKey(): String = rawKey ?: app.get(key).text.also { rawKey = it }
|
private suspend fun getRawKey(): String = app.get(key).text
|
||||||
|
|
||||||
private fun extractRealKey(originalString: String?, stops: String): Pair<String, String> {
|
private fun extractRealKey(originalString: String?, stops: String): Pair<String, String> {
|
||||||
val table = parseJson<List<List<Int>>>(stops)
|
val table = parseJson<List<List<Int>>>(stops)
|
||||||
|
|
|
@ -23,7 +23,7 @@ data class VisualDownloadChildCached(
|
||||||
val data: VideoDownloadHelper.DownloadEpisodeCached,
|
val data: VideoDownloadHelper.DownloadEpisodeCached,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class DownloadClickEvent(val action: Int, val data: EasyDownloadButton.IMinimumData)
|
data class DownloadClickEvent(val action: Int, val data: VideoDownloadHelper.DownloadEpisodeCached)
|
||||||
|
|
||||||
class DownloadChildAdapter(
|
class DownloadChildAdapter(
|
||||||
var cardList: List<VisualDownloadChildCached>,
|
var cardList: List<VisualDownloadChildCached>,
|
||||||
|
|
|
@ -1,264 +0,0 @@
|
||||||
package com.lagradost.cloudstream3.ui.download
|
|
||||||
|
|
||||||
import android.animation.ObjectAnimator
|
|
||||||
import android.text.format.Formatter.formatShortFileSize
|
|
||||||
import android.view.View
|
|
||||||
import android.view.animation.DecelerateInterpolator
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.view.isGone
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.widget.ContentLoadingProgressBar
|
|
||||||
import com.google.android.material.button.MaterialButton
|
|
||||||
import com.lagradost.cloudstream3.R
|
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines
|
|
||||||
import com.lagradost.cloudstream3.utils.IDisposable
|
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
|
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
|
||||||
|
|
||||||
class EasyDownloadButton : IDisposable {
|
|
||||||
interface IMinimumData {
|
|
||||||
val id: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
private var _clickCallback: ((DownloadClickEvent) -> Unit)? = null
|
|
||||||
private var _imageChangeCallback: ((Pair<Int, String>) -> Unit)? = null
|
|
||||||
|
|
||||||
override fun dispose() {
|
|
||||||
try {
|
|
||||||
_clickCallback = null
|
|
||||||
_imageChangeCallback = null
|
|
||||||
downloadProgressEventListener?.let { VideoDownloadManager.downloadProgressEvent -= it }
|
|
||||||
downloadStatusEventListener?.let { VideoDownloadManager.downloadStatusEvent -= it }
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var downloadProgressEventListener: ((Triple<Int, Long, Long>) -> Unit)? = null
|
|
||||||
private var downloadStatusEventListener: ((Pair<Int, VideoDownloadManager.DownloadType>) -> Unit)? =
|
|
||||||
null
|
|
||||||
|
|
||||||
fun setUpMaterialButton(
|
|
||||||
setupCurrentBytes: Long?,
|
|
||||||
setupTotalBytes: Long?,
|
|
||||||
progressBar: ContentLoadingProgressBar,
|
|
||||||
downloadButton: MaterialButton,
|
|
||||||
textView: TextView?,
|
|
||||||
data: IMinimumData,
|
|
||||||
clickCallback: (DownloadClickEvent) -> Unit,
|
|
||||||
) {
|
|
||||||
setUpDownloadButton(
|
|
||||||
setupCurrentBytes,
|
|
||||||
setupTotalBytes,
|
|
||||||
progressBar,
|
|
||||||
textView,
|
|
||||||
data,
|
|
||||||
downloadButton,
|
|
||||||
{
|
|
||||||
downloadButton.setIconResource(it.first)
|
|
||||||
downloadButton.text = it.second
|
|
||||||
},
|
|
||||||
clickCallback
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setUpMoreButton(
|
|
||||||
setupCurrentBytes: Long?,
|
|
||||||
setupTotalBytes: Long?,
|
|
||||||
progressBar: ContentLoadingProgressBar,
|
|
||||||
downloadImage: ImageView,
|
|
||||||
textView: TextView?,
|
|
||||||
textViewProgress: TextView?,
|
|
||||||
clickableView: View,
|
|
||||||
isTextPercentage: Boolean,
|
|
||||||
data: IMinimumData,
|
|
||||||
clickCallback: (DownloadClickEvent) -> Unit,
|
|
||||||
) {
|
|
||||||
setUpDownloadButton(
|
|
||||||
setupCurrentBytes,
|
|
||||||
setupTotalBytes,
|
|
||||||
progressBar,
|
|
||||||
textViewProgress,
|
|
||||||
data,
|
|
||||||
clickableView,
|
|
||||||
{ (image, text) ->
|
|
||||||
downloadImage.isVisible = textViewProgress?.isGone ?: true
|
|
||||||
downloadImage.setImageResource(image)
|
|
||||||
textView?.text = text
|
|
||||||
},
|
|
||||||
clickCallback, isTextPercentage
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setUpButton(
|
|
||||||
setupCurrentBytes: Long?,
|
|
||||||
setupTotalBytes: Long?,
|
|
||||||
progressBar: ContentLoadingProgressBar,
|
|
||||||
downloadImage: ImageView,
|
|
||||||
textView: TextView?,
|
|
||||||
data: IMinimumData,
|
|
||||||
clickCallback: (DownloadClickEvent) -> Unit,
|
|
||||||
) {
|
|
||||||
setUpDownloadButton(
|
|
||||||
setupCurrentBytes,
|
|
||||||
setupTotalBytes,
|
|
||||||
progressBar,
|
|
||||||
textView,
|
|
||||||
data,
|
|
||||||
downloadImage,
|
|
||||||
{
|
|
||||||
downloadImage.setImageResource(it.first)
|
|
||||||
},
|
|
||||||
clickCallback
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setUpDownloadButton(
|
|
||||||
setupCurrentBytes: Long?,
|
|
||||||
setupTotalBytes: Long?,
|
|
||||||
progressBar: ContentLoadingProgressBar,
|
|
||||||
textView: TextView?,
|
|
||||||
data: IMinimumData,
|
|
||||||
downloadView: View,
|
|
||||||
downloadImageChangeCallback: (Pair<Int, String>) -> Unit,
|
|
||||||
clickCallback: (DownloadClickEvent) -> Unit,
|
|
||||||
isTextPercentage: Boolean = false
|
|
||||||
) {
|
|
||||||
_clickCallback = clickCallback
|
|
||||||
_imageChangeCallback = downloadImageChangeCallback
|
|
||||||
var lastState: VideoDownloadManager.DownloadType? = null
|
|
||||||
var currentBytes = setupCurrentBytes ?: 0
|
|
||||||
var totalBytes = setupTotalBytes ?: 0
|
|
||||||
var needImageUpdate = true
|
|
||||||
|
|
||||||
fun changeDownloadImage(state: VideoDownloadManager.DownloadType) {
|
|
||||||
lastState = state
|
|
||||||
if (currentBytes <= 0) needImageUpdate = true
|
|
||||||
val img = if (currentBytes > 0) {
|
|
||||||
when (state) {
|
|
||||||
VideoDownloadManager.DownloadType.IsPaused -> Pair(
|
|
||||||
R.drawable.ic_baseline_play_arrow_24,
|
|
||||||
R.string.download_paused
|
|
||||||
)
|
|
||||||
VideoDownloadManager.DownloadType.IsDownloading -> Pair(
|
|
||||||
R.drawable.netflix_pause,
|
|
||||||
R.string.downloading
|
|
||||||
)
|
|
||||||
else -> Pair(R.drawable.ic_baseline_delete_outline_24, R.string.downloaded)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Pair(R.drawable.netflix_download, R.string.download)
|
|
||||||
}
|
|
||||||
_imageChangeCallback?.invoke(
|
|
||||||
Pair(
|
|
||||||
img.first,
|
|
||||||
downloadView.context.getString(img.second)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fixDownloadedBytes(setCurrentBytes: Long, setTotalBytes: Long, animate: Boolean) {
|
|
||||||
currentBytes = setCurrentBytes
|
|
||||||
totalBytes = setTotalBytes
|
|
||||||
|
|
||||||
if (currentBytes == 0L) {
|
|
||||||
changeDownloadImage(VideoDownloadManager.DownloadType.IsStopped)
|
|
||||||
textView?.visibility = View.GONE
|
|
||||||
progressBar.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
if (lastState == VideoDownloadManager.DownloadType.IsStopped) {
|
|
||||||
changeDownloadImage(VideoDownloadManager.getDownloadState(data.id))
|
|
||||||
}
|
|
||||||
textView?.visibility = View.VISIBLE
|
|
||||||
progressBar.visibility = View.VISIBLE
|
|
||||||
val currentMbString = formatShortFileSize(textView?.context, setCurrentBytes)
|
|
||||||
val totalMbString = formatShortFileSize(textView?.context, setTotalBytes)
|
|
||||||
|
|
||||||
textView?.text =
|
|
||||||
if (isTextPercentage) "%d%%".format(setCurrentBytes * 100L / setTotalBytes) else
|
|
||||||
textView?.context?.getString(R.string.download_size_format)
|
|
||||||
?.format(currentMbString, totalMbString)
|
|
||||||
|
|
||||||
progressBar.let { bar ->
|
|
||||||
bar.max = (setTotalBytes / 1000).toInt()
|
|
||||||
|
|
||||||
if (animate) {
|
|
||||||
val animation: ObjectAnimator = ObjectAnimator.ofInt(
|
|
||||||
bar,
|
|
||||||
"progress",
|
|
||||||
bar.progress,
|
|
||||||
(setCurrentBytes / 1000).toInt()
|
|
||||||
)
|
|
||||||
animation.duration = 500
|
|
||||||
animation.setAutoCancel(true)
|
|
||||||
animation.interpolator = DecelerateInterpolator()
|
|
||||||
animation.start()
|
|
||||||
} else {
|
|
||||||
bar.progress = (setCurrentBytes / 1000).toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fixDownloadedBytes(currentBytes, totalBytes, false)
|
|
||||||
changeDownloadImage(VideoDownloadManager.getDownloadState(data.id))
|
|
||||||
|
|
||||||
downloadProgressEventListener = { downloadData: Triple<Int, Long, Long> ->
|
|
||||||
if (data.id == downloadData.first) {
|
|
||||||
if (downloadData.second != currentBytes || downloadData.third != totalBytes) { // TO PREVENT WASTING UI TIME
|
|
||||||
Coroutines.runOnMainThread {
|
|
||||||
fixDownloadedBytes(downloadData.second, downloadData.third, true)
|
|
||||||
changeDownloadImage(VideoDownloadManager.getDownloadState(data.id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadStatusEventListener =
|
|
||||||
{ downloadData: Pair<Int, VideoDownloadManager.DownloadType> ->
|
|
||||||
if (data.id == downloadData.first) {
|
|
||||||
if (lastState != downloadData.second || needImageUpdate) { // TO PREVENT WASTING UI TIME
|
|
||||||
Coroutines.runOnMainThread {
|
|
||||||
changeDownloadImage(downloadData.second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadProgressEventListener?.let { VideoDownloadManager.downloadProgressEvent += it }
|
|
||||||
downloadStatusEventListener?.let { VideoDownloadManager.downloadStatusEvent += it }
|
|
||||||
|
|
||||||
downloadView.setOnClickListener {
|
|
||||||
if (currentBytes <= 0 || totalBytes <= 0) {
|
|
||||||
_clickCallback?.invoke(DownloadClickEvent(DOWNLOAD_ACTION_DOWNLOAD, data))
|
|
||||||
} else {
|
|
||||||
val list = arrayListOf(
|
|
||||||
Pair(DOWNLOAD_ACTION_PLAY_FILE, R.string.popup_play_file),
|
|
||||||
Pair(DOWNLOAD_ACTION_DELETE_FILE, R.string.popup_delete_file),
|
|
||||||
)
|
|
||||||
|
|
||||||
// DON'T RESUME A DOWNLOADED FILE lastState != VideoDownloadManager.DownloadType.IsDone &&
|
|
||||||
if ((currentBytes * 100 / totalBytes) < 98) {
|
|
||||||
list.add(
|
|
||||||
if (lastState == VideoDownloadManager.DownloadType.IsDownloading)
|
|
||||||
Pair(DOWNLOAD_ACTION_PAUSE_DOWNLOAD, R.string.popup_pause_download)
|
|
||||||
else
|
|
||||||
Pair(DOWNLOAD_ACTION_RESUME_DOWNLOAD, R.string.popup_resume_download)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
it.popupMenuNoIcons(
|
|
||||||
list
|
|
||||||
) {
|
|
||||||
_clickCallback?.invoke(DownloadClickEvent(itemId, data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadView.setOnLongClickListener {
|
|
||||||
clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_LONG_CLICK, data))
|
|
||||||
return@setOnLongClickListener true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,7 +22,7 @@ data class DownloadMetadata(
|
||||||
val progressPercentage: Long
|
val progressPercentage: Long
|
||||||
get() = if (downloadedLength < 1024) 0 else maxOf(
|
get() = if (downloadedLength < 1024) 0 else maxOf(
|
||||||
0,
|
0,
|
||||||
minOf(100, (downloadedLength * 100L) / totalLength)
|
minOf(100, (downloadedLength * 100L) / (totalLength + 1))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,38 +101,41 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
||||||
|
|
||||||
open fun setProgress(downloadedBytes: Long, totalBytes: Long) {
|
open fun setProgress(downloadedBytes: Long, totalBytes: Long) {
|
||||||
isZeroBytes = downloadedBytes == 0L
|
isZeroBytes = downloadedBytes == 0L
|
||||||
val steps = 10000L
|
progressBar.post {
|
||||||
progressBar.max = steps.toInt()
|
val steps = 10000L
|
||||||
// div by zero error and 1 byte off is ok impo
|
progressBar.max = steps.toInt()
|
||||||
val progress = (downloadedBytes * steps / (totalBytes + 1L)).toInt()
|
// div by zero error and 1 byte off is ok impo
|
||||||
|
|
||||||
val animation = ProgressBarAnimation(
|
val progress = (downloadedBytes * steps / (totalBytes + 1L)).toInt()
|
||||||
progressBar,
|
|
||||||
progressBar.progress.toFloat(),
|
|
||||||
progress.toFloat()
|
|
||||||
).apply {
|
|
||||||
fillAfter = true
|
|
||||||
duration =
|
|
||||||
if (progress > progressBar.progress) // we don't want to animate backward changes in progress
|
|
||||||
100
|
|
||||||
else
|
|
||||||
0L
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isZeroBytes) {
|
val animation = ProgressBarAnimation(
|
||||||
progressText?.isVisible = false
|
progressBar,
|
||||||
} else {
|
progressBar.progress.toFloat(),
|
||||||
progressText?.apply {
|
progress.toFloat()
|
||||||
val currentMbString = Formatter.formatShortFileSize(context, downloadedBytes)
|
).apply {
|
||||||
val totalMbString = Formatter.formatShortFileSize(context, totalBytes)
|
fillAfter = true
|
||||||
text =
|
duration =
|
||||||
//if (isTextPercentage) "%d%%".format(setCurrentBytes * 100L / setTotalBytes) else
|
if (progress > progressBar.progress) // we don't want to animate backward changes in progress
|
||||||
context?.getString(R.string.download_size_format)
|
100
|
||||||
?.format(currentMbString, totalMbString)
|
else
|
||||||
|
0L
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
progressBar.startAnimation(animation)
|
if (isZeroBytes) {
|
||||||
|
progressText?.isVisible = false
|
||||||
|
} else {
|
||||||
|
progressText?.apply {
|
||||||
|
val currentMbString = Formatter.formatShortFileSize(context, downloadedBytes)
|
||||||
|
val totalMbString = Formatter.formatShortFileSize(context, totalBytes)
|
||||||
|
text =
|
||||||
|
//if (isTextPercentage) "%d%%".format(setCurrentBytes * 100L / setTotalBytes) else
|
||||||
|
context?.getString(R.string.download_size_format)
|
||||||
|
?.format(currentMbString, totalMbString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progressBar.startAnimation(animation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun downloadStatusEvent(data: Pair<Int, VideoDownloadManager.DownloadType>) {
|
fun downloadStatusEvent(data: Pair<Int, VideoDownloadManager.DownloadType>) {
|
||||||
|
|
|
@ -21,14 +21,17 @@ class DownloadButton(context: Context, attributeSet: AttributeSet) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setStatus(status: DownloadStatusTell?) {
|
override fun setStatus(status: DownloadStatusTell?) {
|
||||||
super.setStatus(status)
|
mainText?.post {
|
||||||
val txt = when (status) {
|
val txt = when (status) {
|
||||||
DownloadStatusTell.IsPaused -> R.string.download_paused
|
DownloadStatusTell.IsPaused -> R.string.download_paused
|
||||||
DownloadStatusTell.IsDownloading -> R.string.downloading
|
DownloadStatusTell.IsDownloading -> R.string.downloading
|
||||||
DownloadStatusTell.IsDone -> R.string.downloaded
|
DownloadStatusTell.IsDone -> R.string.downloaded
|
||||||
else -> R.string.download
|
else -> R.string.download
|
||||||
|
}
|
||||||
|
mainText?.setText(txt)
|
||||||
}
|
}
|
||||||
mainText?.setText(txt)
|
super.setStatus(status)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setDefaultClickListener(
|
override fun setDefaultClickListener(
|
||||||
|
|
|
@ -174,7 +174,7 @@ open class PieFetchButton(context: Context, attributeSet: AttributeSet) :
|
||||||
|
|
||||||
currentMetaData.apply {
|
currentMetaData.apply {
|
||||||
// DON'T RESUME A DOWNLOADED FILE lastState != VideoDownloadManager.DownloadType.IsDone &&
|
// DON'T RESUME A DOWNLOADED FILE lastState != VideoDownloadManager.DownloadType.IsDone &&
|
||||||
if ((downloadedLength * 100 / totalLength) < 98) {
|
if (progressPercentage < 98) {
|
||||||
list.add(
|
list.add(
|
||||||
if (status == VideoDownloadManager.DownloadType.IsDownloading)
|
if (status == VideoDownloadManager.DownloadType.IsDownloading)
|
||||||
Pair(DOWNLOAD_ACTION_PAUSE_DOWNLOAD, R.string.popup_pause_download)
|
Pair(DOWNLOAD_ACTION_PAUSE_DOWNLOAD, R.string.popup_pause_download)
|
||||||
|
@ -248,33 +248,34 @@ open class PieFetchButton(context: Context, attributeSet: AttributeSet) :
|
||||||
//progressBar.isVisible =
|
//progressBar.isVisible =
|
||||||
// status != null && status != DownloadStatusTell.Complete && status != DownloadStatusTell.Error
|
// status != null && status != DownloadStatusTell.Complete && status != DownloadStatusTell.Error
|
||||||
//progressBarBackground.isVisible = status != null && status != DownloadStatusTell.Complete
|
//progressBarBackground.isVisible = status != null && status != DownloadStatusTell.Complete
|
||||||
val isPreActive = isZeroBytes && status == DownloadStatusTell.IsDownloading
|
progressBarBackground.post {
|
||||||
|
val isPreActive = isZeroBytes && status == DownloadStatusTell.IsDownloading
|
||||||
|
if (animateWaiting && (status == DownloadStatusTell.IsPending || isPreActive)) {
|
||||||
|
val animation = AnimationUtils.loadAnimation(context, waitingAnimation)
|
||||||
|
progressBarBackground.startAnimation(animation)
|
||||||
|
} else {
|
||||||
|
progressBarBackground.clearAnimation()
|
||||||
|
}
|
||||||
|
|
||||||
if (animateWaiting && (status == DownloadStatusTell.IsPending || isPreActive)) {
|
val progressDrawable =
|
||||||
val animation = AnimationUtils.loadAnimation(context, waitingAnimation)
|
if (status == DownloadStatusTell.IsDownloading && !isPreActive) activeOutline else nonActiveOutline
|
||||||
progressBarBackground.startAnimation(animation)
|
|
||||||
} else {
|
progressBarBackground.background =
|
||||||
progressBarBackground.clearAnimation()
|
ContextCompat.getDrawable(context, progressDrawable)
|
||||||
|
|
||||||
|
val drawable = getDrawableFromStatus(status)
|
||||||
|
statusView.setImageDrawable(drawable)
|
||||||
|
val isDrawable = drawable != null
|
||||||
|
|
||||||
|
statusView.isVisible = isDrawable
|
||||||
|
val hide = hideWhenIcon && isDrawable
|
||||||
|
if (hide) {
|
||||||
|
progressBar.clearAnimation()
|
||||||
|
progressBarBackground.clearAnimation()
|
||||||
|
}
|
||||||
|
progressBarBackground.isGone = hide
|
||||||
|
progressBar.isGone = hide
|
||||||
}
|
}
|
||||||
|
|
||||||
val progressDrawable =
|
|
||||||
if (status == DownloadStatusTell.IsDownloading && !isPreActive) activeOutline else nonActiveOutline
|
|
||||||
|
|
||||||
progressBarBackground.background =
|
|
||||||
ContextCompat.getDrawable(context, progressDrawable)
|
|
||||||
|
|
||||||
val drawable = getDrawableFromStatus(status)
|
|
||||||
statusView.setImageDrawable(drawable)
|
|
||||||
val isDrawable = drawable != null
|
|
||||||
|
|
||||||
statusView.isVisible = isDrawable
|
|
||||||
val hide = hideWhenIcon && isDrawable
|
|
||||||
if (hide) {
|
|
||||||
progressBar.clearAnimation()
|
|
||||||
progressBarBackground.clearAnimation()
|
|
||||||
}
|
|
||||||
progressBarBackground.isGone = hide
|
|
||||||
progressBar.isGone = hide
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resetView() {
|
override fun resetView() {
|
||||||
|
|
|
@ -658,12 +658,14 @@ class HomeFragment : Fragment() {
|
||||||
return@observeNullable
|
return@observeNullable
|
||||||
}
|
}
|
||||||
|
|
||||||
bottomSheetDialog = activity?.loadHomepageList(item, expandCallback = {
|
val (items, delete) = item
|
||||||
|
|
||||||
|
bottomSheetDialog = activity?.loadHomepageList(items, expandCallback = {
|
||||||
homeViewModel.expandAndReturn(it)
|
homeViewModel.expandAndReturn(it)
|
||||||
}, dismissCallback = {
|
}, dismissCallback = {
|
||||||
homeViewModel.popup(null)
|
homeViewModel.popup(null)
|
||||||
bottomSheetDialog = null
|
bottomSheetDialog = null
|
||||||
})
|
}, deleteCallback = delete)
|
||||||
}
|
}
|
||||||
|
|
||||||
homeViewModel.reloadStored()
|
homeViewModel.reloadStored()
|
||||||
|
|
|
@ -246,7 +246,7 @@ class HomeParentItemAdapterPreview(
|
||||||
private val previewViewpagerText: ViewGroup =
|
private val previewViewpagerText: ViewGroup =
|
||||||
itemView.findViewById(R.id.home_preview_viewpager_text)
|
itemView.findViewById(R.id.home_preview_viewpager_text)
|
||||||
|
|
||||||
// private val previewHeader: FrameLayout = itemView.findViewById(R.id.home_preview)
|
// private val previewHeader: FrameLayout = itemView.findViewById(R.id.home_preview)
|
||||||
private var resumeHolder: View = itemView.findViewById(R.id.home_watch_holder)
|
private var resumeHolder: View = itemView.findViewById(R.id.home_watch_holder)
|
||||||
private var resumeRecyclerView: RecyclerView =
|
private var resumeRecyclerView: RecyclerView =
|
||||||
itemView.findViewById(R.id.home_watch_child_recyclerview)
|
itemView.findViewById(R.id.home_watch_child_recyclerview)
|
||||||
|
@ -257,7 +257,7 @@ class HomeParentItemAdapterPreview(
|
||||||
private var homeAccount: View? =
|
private var homeAccount: View? =
|
||||||
itemView.findViewById(R.id.home_preview_switch_account)
|
itemView.findViewById(R.id.home_preview_switch_account)
|
||||||
|
|
||||||
private var topPadding : View? = itemView.findViewById(R.id.home_padding)
|
private var topPadding: View? = itemView.findViewById(R.id.home_padding)
|
||||||
|
|
||||||
private val homeNonePadding: View = itemView.findViewById(R.id.home_none_padding)
|
private val homeNonePadding: View = itemView.findViewById(R.id.home_none_padding)
|
||||||
|
|
||||||
|
@ -283,7 +283,11 @@ class HomeParentItemAdapterPreview(
|
||||||
item.plot ?: ""
|
item.plot ?: ""
|
||||||
|
|
||||||
homePreviewText.text = item.name
|
homePreviewText.text = item.name
|
||||||
populateChips(homePreviewTags,item.tags ?: emptyList(), R.style.ChipFilledSemiTransparent)
|
populateChips(
|
||||||
|
homePreviewTags,
|
||||||
|
item.tags ?: emptyList(),
|
||||||
|
R.style.ChipFilledSemiTransparent
|
||||||
|
)
|
||||||
|
|
||||||
homePreviewTags.isGone =
|
homePreviewTags.isGone =
|
||||||
item.tags.isNullOrEmpty()
|
item.tags.isNullOrEmpty()
|
||||||
|
@ -413,7 +417,7 @@ class HomeParentItemAdapterPreview(
|
||||||
Pair(itemView.findViewById(R.id.home_plan_to_watch_btt), WatchType.PLANTOWATCH),
|
Pair(itemView.findViewById(R.id.home_plan_to_watch_btt), WatchType.PLANTOWATCH),
|
||||||
)
|
)
|
||||||
|
|
||||||
private val toggleListHolder : ChipGroup? = itemView.findViewById(R.id.home_type_holder)
|
private val toggleListHolder: ChipGroup? = itemView.findViewById(R.id.home_type_holder)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
previewViewpager.setPageTransformer(HomeScrollTransformer())
|
previewViewpager.setPageTransformer(HomeScrollTransformer())
|
||||||
|
@ -422,8 +426,14 @@ class HomeParentItemAdapterPreview(
|
||||||
resumeRecyclerView.adapter = resumeAdapter
|
resumeRecyclerView.adapter = resumeAdapter
|
||||||
bookmarkRecyclerView.adapter = bookmarkAdapter
|
bookmarkRecyclerView.adapter = bookmarkAdapter
|
||||||
|
|
||||||
resumeRecyclerView.setLinearListLayout(nextLeft = R.id.nav_rail_view, nextRight = FOCUS_SELF)
|
resumeRecyclerView.setLinearListLayout(
|
||||||
bookmarkRecyclerView.setLinearListLayout(nextLeft = R.id.nav_rail_view, nextRight = FOCUS_SELF)
|
nextLeft = R.id.nav_rail_view,
|
||||||
|
nextRight = FOCUS_SELF
|
||||||
|
)
|
||||||
|
bookmarkRecyclerView.setLinearListLayout(
|
||||||
|
nextLeft = R.id.nav_rail_view,
|
||||||
|
nextRight = FOCUS_SELF
|
||||||
|
)
|
||||||
|
|
||||||
fixPaddingStatusbarMargin(topPadding)
|
fixPaddingStatusbarMargin(topPadding)
|
||||||
|
|
||||||
|
@ -539,7 +549,7 @@ class HomeParentItemAdapterPreview(
|
||||||
resumeAdapter.updateList(resumeWatching)
|
resumeAdapter.updateList(resumeWatching)
|
||||||
|
|
||||||
if (binding is FragmentHomeHeadBinding) {
|
if (binding is FragmentHomeHeadBinding) {
|
||||||
binding.homeBookmarkParentItemTitle.setOnClickListener {
|
binding.homeWatchParentItemTitle.setOnClickListener {
|
||||||
viewModel.popup(
|
viewModel.popup(
|
||||||
HomeViewModel.ExpandableHomepageList(
|
HomeViewModel.ExpandableHomepageList(
|
||||||
HomePageList(
|
HomePageList(
|
||||||
|
@ -547,7 +557,10 @@ class HomeParentItemAdapterPreview(
|
||||||
resumeWatching,
|
resumeWatching,
|
||||||
false
|
false
|
||||||
), 1, false
|
), 1, false
|
||||||
)
|
),
|
||||||
|
deleteCallback = {
|
||||||
|
viewModel.deleteResumeWatching()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -572,10 +585,12 @@ class HomeParentItemAdapterPreview(
|
||||||
list,
|
list,
|
||||||
false
|
false
|
||||||
), 1, false
|
), 1, false
|
||||||
)
|
), deleteCallback = {
|
||||||
|
viewModel.deleteBookmarks(list)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.deleteAllBookmarkedData
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.deleteAllResumeStateIds
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData
|
||||||
|
@ -92,6 +94,21 @@ class HomeViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteResumeWatching() {
|
||||||
|
deleteAllResumeStateIds()
|
||||||
|
loadResumeWatching()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteBookmarks(list: List<SearchResponse>) {
|
||||||
|
list.forEach { DataStoreHelper.deleteBookmarkedData(it.id) }
|
||||||
|
loadStoredData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteBookmarks() {
|
||||||
|
deleteAllBookmarkedData()
|
||||||
|
loadStoredData()
|
||||||
|
}
|
||||||
|
|
||||||
var repo: APIRepository? = null
|
var repo: APIRepository? = null
|
||||||
|
|
||||||
private val _apiName = MutableLiveData<String>()
|
private val _apiName = MutableLiveData<String>()
|
||||||
|
@ -394,11 +411,14 @@ class HomeViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val _popup = MutableLiveData<ExpandableHomepageList?>(null)
|
private val _popup = MutableLiveData<Pair<ExpandableHomepageList, (() -> Unit)?>?>(null)
|
||||||
val popup: LiveData<ExpandableHomepageList?> = _popup
|
val popup: LiveData<Pair<ExpandableHomepageList, (() -> Unit)?>?> = _popup
|
||||||
|
|
||||||
fun popup(list: ExpandableHomepageList?) {
|
fun popup(list: ExpandableHomepageList?, deleteCallback: (() -> Unit)? = null) {
|
||||||
_popup.postValue(list)
|
if (list == null)
|
||||||
|
_popup.postValue(null)
|
||||||
|
else
|
||||||
|
_popup.postValue(list to deleteCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bookmarksUpdated(unused: Boolean) {
|
private fun bookmarksUpdated(unused: Boolean) {
|
||||||
|
@ -436,8 +456,7 @@ class HomeViewModel : ViewModel() {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reloadStored() {
|
fun loadStoredData() {
|
||||||
loadResumeWatching()
|
|
||||||
val list = EnumSet.noneOf(WatchType::class.java)
|
val list = EnumSet.noneOf(WatchType::class.java)
|
||||||
getKey<IntArray>(HOME_BOOKMARK_VALUE_LIST)?.map { WatchType.fromInternalId(it) }?.let {
|
getKey<IntArray>(HOME_BOOKMARK_VALUE_LIST)?.map { WatchType.fromInternalId(it) }?.let {
|
||||||
list.addAll(it)
|
list.addAll(it)
|
||||||
|
@ -445,6 +464,11 @@ class HomeViewModel : ViewModel() {
|
||||||
loadStoredData(list)
|
loadStoredData(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun reloadStored() {
|
||||||
|
loadResumeWatching()
|
||||||
|
loadStoredData()
|
||||||
|
}
|
||||||
|
|
||||||
fun click(load: LoadClickCallback) {
|
fun click(load: LoadClickCallback) {
|
||||||
loadResult(load.response.url, load.response.apiName, load.action)
|
loadResult(load.response.url, load.response.apiName, load.action)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
package com.lagradost.cloudstream3.ui.player
|
package com.lagradost.cloudstream3.ui.player
|
||||||
|
|
||||||
|
import android.content.ContentUris
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.hippo.unifile.UniFile
|
|
||||||
import com.lagradost.cloudstream3.CommonActivity
|
import com.lagradost.cloudstream3.CommonActivity
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorUri
|
import com.lagradost.cloudstream3.utils.ExtractorUri
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||||
|
import com.lagradost.safefile.SafeFile
|
||||||
|
|
||||||
const val DTAG = "PlayerActivity"
|
const val DTAG = "PlayerActivity"
|
||||||
|
|
||||||
|
@ -50,14 +51,17 @@ class DownloadedPlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playUri(uri: Uri) {
|
private fun playUri(uri: Uri) {
|
||||||
val name = UniFile.fromUri(this, uri).name
|
val name = SafeFile.fromUri(this, uri)?.name()
|
||||||
this.navigate(
|
this.navigate(
|
||||||
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
|
||||||
DownloadFileGenerator(
|
DownloadFileGenerator(
|
||||||
listOf(
|
listOf(
|
||||||
ExtractorUri(
|
ExtractorUri(
|
||||||
uri = uri,
|
uri = uri,
|
||||||
name = name ?: getString(R.string.downloaded_file)
|
name = name ?: getString(R.string.downloaded_file),
|
||||||
|
// well not the same as a normal id, but we take it as users may want to
|
||||||
|
// play downloaded files and save the location
|
||||||
|
id = kotlin.runCatching { ContentUris.parseId(uri) }.getOrNull()?.hashCode()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,9 +2,11 @@ package com.lagradost.cloudstream3.ui.player
|
||||||
|
|
||||||
import android.animation.ObjectAnimator
|
import android.animation.ObjectAnimator
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
|
@ -16,6 +18,7 @@ import android.util.DisplayMetrics
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
|
import android.view.Surface
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
@ -56,6 +59,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||||
import com.lagradost.cloudstream3.utils.Vector2
|
import com.lagradost.cloudstream3.utils.Vector2
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
|
|
||||||
const val MINIMUM_SEEK_TIME = 7000L // when swipe seeking
|
const val MINIMUM_SEEK_TIME = 7000L // when swipe seeking
|
||||||
const val MINIMUM_VERTICAL_SWIPE = 2.0f // in percentage
|
const val MINIMUM_VERTICAL_SWIPE = 2.0f // in percentage
|
||||||
const val MINIMUM_HORIZONTAL_SWIPE = 2.0f // in percentage
|
const val MINIMUM_HORIZONTAL_SWIPE = 2.0f // in percentage
|
||||||
|
@ -292,6 +296,36 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
player.getCurrentPreferredSubtitle() == null
|
player.getCurrentPreferredSubtitle() == null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun lockOrientation(activity: Activity) {
|
||||||
|
val display =
|
||||||
|
(activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
|
||||||
|
val rotation = display.rotation
|
||||||
|
val currentOrientation = activity.resources.configuration.orientation
|
||||||
|
var orientation = 0
|
||||||
|
when (currentOrientation) {
|
||||||
|
Configuration.ORIENTATION_LANDSCAPE -> orientation =
|
||||||
|
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
||||||
|
|
||||||
|
Configuration.ORIENTATION_SQUARE, Configuration.ORIENTATION_UNDEFINED, Configuration.ORIENTATION_PORTRAIT -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||||
|
//Configuration.ORIENTATION_PORTRAIT -> orientation =
|
||||||
|
// if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_270) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
|
||||||
|
}
|
||||||
|
activity.requestedOrientation = orientation
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateOrientation() {
|
||||||
|
activity?.apply {
|
||||||
|
if(lockRotation) {
|
||||||
|
if(isLocked) {
|
||||||
|
lockOrientation(this)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected fun enterFullscreen() {
|
protected fun enterFullscreen() {
|
||||||
if (isFullScreenPlayer) {
|
if (isFullScreenPlayer) {
|
||||||
activity?.hideSystemUI()
|
activity?.hideSystemUI()
|
||||||
|
@ -301,8 +335,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
activity?.window?.attributes = params
|
activity?.window?.attributes = params
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lockRotation)
|
updateOrientation()
|
||||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun exitFullscreen() {
|
protected fun exitFullscreen() {
|
||||||
|
@ -561,6 +594,8 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
isLocked = !isLocked
|
isLocked = !isLocked
|
||||||
|
updateOrientation()
|
||||||
|
|
||||||
if (isLocked && isShowing) {
|
if (isLocked && isShowing) {
|
||||||
playerBinding?.playerHolder?.postDelayed({
|
playerBinding?.playerHolder?.postDelayed({
|
||||||
if (isLocked && isShowing) {
|
if (isLocked && isShowing) {
|
||||||
|
|
|
@ -21,13 +21,11 @@ import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.media3.common.Format.NO_VALUE
|
import androidx.media3.common.Format.NO_VALUE
|
||||||
import androidx.media3.common.MimeTypes
|
import androidx.media3.common.MimeTypes
|
||||||
import com.hippo.unifile.UniFile
|
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.databinding.DialogOnlineSubtitlesBinding
|
import com.lagradost.cloudstream3.databinding.DialogOnlineSubtitlesBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentPlayerBinding
|
import com.lagradost.cloudstream3.databinding.FragmentPlayerBinding
|
||||||
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding
|
|
||||||
import com.lagradost.cloudstream3.databinding.PlayerSelectSourceAndSubsBinding
|
import com.lagradost.cloudstream3.databinding.PlayerSelectSourceAndSubsBinding
|
||||||
import com.lagradost.cloudstream3.databinding.PlayerSelectTracksBinding
|
import com.lagradost.cloudstream3.databinding.PlayerSelectTracksBinding
|
||||||
import com.lagradost.cloudstream3.mvvm.*
|
import com.lagradost.cloudstream3.mvvm.*
|
||||||
|
@ -52,6 +50,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
|
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||||
|
import com.lagradost.safefile.SafeFile
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
@ -135,7 +134,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
return durPos.position
|
return durPos.position
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentVerifyLink: Job? = null
|
private var currentVerifyLink: Job? = null
|
||||||
|
|
||||||
private fun loadExtractorJob(extractorLink: ExtractorLink?) {
|
private fun loadExtractorJob(extractorLink: ExtractorLink?) {
|
||||||
currentVerifyLink?.cancel()
|
currentVerifyLink?.cancel()
|
||||||
|
@ -520,15 +519,16 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
if (uri == null) return@normalSafeApiCall
|
if (uri == null) return@normalSafeApiCall
|
||||||
val ctx = context ?: AcraApplication.context ?: return@normalSafeApiCall
|
val ctx = context ?: AcraApplication.context ?: return@normalSafeApiCall
|
||||||
// RW perms for the path
|
// RW perms for the path
|
||||||
val flags =
|
ctx.contentResolver.takePersistableUriPermission(
|
||||||
|
uri,
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
)
|
||||||
|
|
||||||
ctx.contentResolver.takePersistableUriPermission(uri, flags)
|
val file = SafeFile.fromUri(ctx, uri)
|
||||||
|
val fileName = file?.name()
|
||||||
val file = UniFile.fromUri(ctx, uri)
|
println("Loaded subtitle file. Selected URI path: $uri - Name: $fileName")
|
||||||
println("Loaded subtitle file. Selected URI path: $uri - Name: ${file.name}")
|
|
||||||
// DO NOT REMOVE THE FILE EXTENSION FROM NAME, IT'S NEEDED FOR MIME TYPES
|
// DO NOT REMOVE THE FILE EXTENSION FROM NAME, IT'S NEEDED FOR MIME TYPES
|
||||||
val name = file.name ?: uri.toString()
|
val name = fileName ?: uri.toString()
|
||||||
|
|
||||||
val subtitleData = SubtitleData(
|
val subtitleData = SubtitleData(
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -23,7 +23,6 @@ import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.NestedScrollView
|
import androidx.core.widget.NestedScrollView
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.discord.panels.OverlappingPanelsLayout
|
import com.discord.panels.OverlappingPanelsLayout
|
||||||
import com.discord.panels.PanelsChildGestureRegionObserver
|
import com.discord.panels.PanelsChildGestureRegionObserver
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||||
|
@ -62,8 +61,6 @@ import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.html
|
import com.lagradost.cloudstream3.utils.AppUtils.html
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
|
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.isLtr
|
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.isRtl
|
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
@ -81,8 +78,13 @@ import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||||
|
|
||||||
|
|
||||||
open class ResultFragmentPhone : FullScreenPlayer(),
|
open class ResultFragmentPhone : FullScreenPlayer() {
|
||||||
PanelsChildGestureRegionObserver.GestureRegionsListener {
|
private val gestureRegionsListener = object : PanelsChildGestureRegionObserver.GestureRegionsListener {
|
||||||
|
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
||||||
|
binding?.resultOverlappingPanels?.setChildGestureRegions(gestureRegions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected lateinit var viewModel: ResultViewModel2
|
protected lateinit var viewModel: ResultViewModel2
|
||||||
protected lateinit var syncModel: SyncViewModel
|
protected lateinit var syncModel: SyncViewModel
|
||||||
|
|
||||||
|
@ -211,14 +213,17 @@ open class ResultFragmentPhone : FullScreenPlayer(),
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
|
||||||
//somehow this still leaks and I dont know why????
|
//somehow this still leaks and I dont know why????
|
||||||
// todo look at https://github.com/discord/OverlappingPanels/blob/70b4a7cf43c6771873b1e091029d332896d41a1a/sample_app/src/main/java/com/discord/sampleapp/MainActivity.kt
|
// todo look at https://github.com/discord/OverlappingPanels/blob/70b4a7cf43c6771873b1e091029d332896d41a1a/sample_app/src/main/java/com/discord/sampleapp/MainActivity.kt
|
||||||
PanelsChildGestureRegionObserver.Provider.get().let { obs ->
|
PanelsChildGestureRegionObserver.Provider.get().let { obs ->
|
||||||
resultBinding?.resultCastItems?.let {
|
resultBinding?.resultCastItems?.let {
|
||||||
obs.unregister(it)
|
obs.unregister(it)
|
||||||
}
|
}
|
||||||
obs.removeGestureRegionsUpdateListener(this)
|
|
||||||
|
obs.removeGestureRegionsUpdateListener(gestureRegionsListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUIEvent -= ::updateUI
|
updateUIEvent -= ::updateUI
|
||||||
binding = null
|
binding = null
|
||||||
resultBinding = null
|
resultBinding = null
|
||||||
|
@ -287,6 +292,8 @@ open class ResultFragmentPhone : FullScreenPlayer(),
|
||||||
it.colorFromAttribute(R.attr.primaryBlackBackground)
|
it.colorFromAttribute(R.attr.primaryBlackBackground)
|
||||||
}
|
}
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get()
|
||||||
|
.addGestureRegionsUpdateListener(gestureRegionsListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
|
@ -323,7 +330,16 @@ open class ResultFragmentPhone : FullScreenPlayer(),
|
||||||
setUrl(storedData.url)
|
setUrl(storedData.url)
|
||||||
syncModel.addFromUrl(storedData.url)
|
syncModel.addFromUrl(storedData.url)
|
||||||
val api = APIHolder.getApiFromNameNull(storedData.apiName)
|
val api = APIHolder.getApiFromNameNull(storedData.apiName)
|
||||||
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
|
||||||
|
PanelsChildGestureRegionObserver.Provider.get().apply {
|
||||||
|
resultBinding?.resultCastItems?.let {
|
||||||
|
register(it)
|
||||||
|
}
|
||||||
|
addGestureRegionsUpdateListener(gestureRegionsListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ===== ===== =====
|
// ===== ===== =====
|
||||||
|
|
||||||
resultBinding?.apply {
|
resultBinding?.apply {
|
||||||
|
@ -374,9 +390,8 @@ open class ResultFragmentPhone : FullScreenPlayer(),
|
||||||
DownloadButtonSetup.handleDownloadClick(downloadClickEvent)
|
DownloadButtonSetup.handleDownloadClick(downloadClickEvent)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
resultCastItems.let {
|
|
||||||
PanelsChildGestureRegionObserver.Provider.get().register(it)
|
|
||||||
}
|
|
||||||
resultScroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
resultScroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||||
val dy = scrollY - oldScrollY
|
val dy = scrollY - oldScrollY
|
||||||
if (dy > 0) { //check for scroll down
|
if (dy > 0) { //check for scroll down
|
||||||
|
@ -1055,11 +1070,7 @@ open class ResultFragmentPhone : FullScreenPlayer(),
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(this)
|
PanelsChildGestureRegionObserver.Provider.get().addGestureRegionsUpdateListener(gestureRegionsListener)
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
|
|
||||||
binding?.resultOverlappingPanels?.setChildGestureRegions(gestureRegions)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||||
|
@ -1114,4 +1125,4 @@ open class ResultFragmentPhone : FullScreenPlayer(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ open class ResultTrailerPlayer : ResultFragmentPhone(), IOnBackPressed {
|
||||||
|
|
||||||
private fun fixPlayerSize() {
|
private fun fixPlayerSize() {
|
||||||
playerWidthHeight?.let { (w, h) ->
|
playerWidthHeight?.let { (w, h) ->
|
||||||
|
if(w <= 0 || h <= 0) return@let
|
||||||
|
|
||||||
val orientation = context?.resources?.configuration?.orientation ?: return
|
val orientation = context?.resources?.configuration?.orientation ?: return
|
||||||
|
|
||||||
val sw = if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
val sw = if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
|
@ -118,9 +120,6 @@ open class ResultTrailerPlayer : ResultFragmentPhone(), IOnBackPressed {
|
||||||
override fun onTracksInfoChanged() {}
|
override fun onTracksInfoChanged() {}
|
||||||
|
|
||||||
override fun exitedPipMode() {}
|
override fun exitedPipMode() {}
|
||||||
|
|
||||||
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {}
|
|
||||||
|
|
||||||
private fun updateFullscreen(fullscreen: Boolean) {
|
private fun updateFullscreen(fullscreen: Boolean) {
|
||||||
isFullScreenPlayer = fullscreen
|
isFullScreenPlayer = fullscreen
|
||||||
lockRotation = fullscreen
|
lockRotation = fullscreen
|
||||||
|
|
|
@ -591,12 +591,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
link,
|
link,
|
||||||
"$fileName ${link.name}",
|
"$fileName ${link.name}",
|
||||||
folder,
|
folder,
|
||||||
if (link.url.contains(".srt")) ".srt" else "vtt",
|
if (link.url.contains(".srt")) "srt" else "vtt",
|
||||||
false,
|
false,
|
||||||
null
|
null, createNotificationCallback = {}
|
||||||
) {
|
)
|
||||||
// no notification
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,7 +719,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.map { ExtractorSubtitleLink(it.name, it.url, "") }
|
.map { ExtractorSubtitleLink(it.name, it.url, "") }.take(3)
|
||||||
.forEach { link ->
|
.forEach { link ->
|
||||||
val fileName = VideoDownloadManager.getFileName(context, meta)
|
val fileName = VideoDownloadManager.getFileName(context, meta)
|
||||||
downloadSubtitle(context, link, fileName, folder)
|
downloadSubtitle(context, link, fileName, folder)
|
||||||
|
@ -1707,7 +1705,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
else -> {
|
else -> {
|
||||||
if (response.type.isLiveStream())
|
if (response.type.isLiveStream())
|
||||||
R.string.play_livestream_button
|
R.string.play_livestream_button
|
||||||
else if (response.type.isMovieType()) // this wont break compatibility as you only need to override isMovieType
|
else if (response.isMovie()) // this wont break compatibility as you only need to override isMovieType
|
||||||
R.string.play_movie_button
|
R.string.play_movie_button
|
||||||
else null
|
else null
|
||||||
}
|
}
|
||||||
|
@ -2340,4 +2338,4 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ class SearchFragment : Fragment() {
|
||||||
|
|
||||||
fun newInstance(query: String): Bundle {
|
fun newInstance(query: String): Bundle {
|
||||||
return Bundle().apply {
|
return Bundle().apply {
|
||||||
putString(SEARCH_QUERY, query)
|
if(query.isNotBlank()) putString(SEARCH_QUERY, query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ class SearchFragment : Fragment() {
|
||||||
reloadRepos()
|
reloadRepos()
|
||||||
|
|
||||||
binding?.apply {
|
binding?.apply {
|
||||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? =
|
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
||||||
SearchAdapter(
|
SearchAdapter(
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
searchAutofitResults,
|
searchAutofitResults,
|
||||||
|
@ -530,11 +530,18 @@ class SearchFragment : Fragment() {
|
||||||
searchMasterRecycler.layoutManager = GridLayoutManager(context, 1)
|
searchMasterRecycler.layoutManager = GridLayoutManager(context, 1)
|
||||||
|
|
||||||
// Automatically search the specified query, this allows the app search to launch from intent
|
// Automatically search the specified query, this allows the app search to launch from intent
|
||||||
arguments?.getString(SEARCH_QUERY)?.let { query ->
|
var sq = arguments?.getString(SEARCH_QUERY) ?: savedInstanceState?.getString(SEARCH_QUERY)
|
||||||
|
if(sq.isNullOrBlank()) {
|
||||||
|
sq = MainActivity.nextSearchQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
sq?.let { query ->
|
||||||
if (query.isBlank()) return@let
|
if (query.isBlank()) return@let
|
||||||
mainSearch.setQuery(query, true)
|
mainSearch.setQuery(query, true)
|
||||||
// Clear the query as to not make it request the same query every time the page is opened
|
// Clear the query as to not make it request the same query every time the page is opened
|
||||||
arguments?.putString(SEARCH_QUERY, null)
|
arguments?.remove(SEARCH_QUERY)
|
||||||
|
savedInstanceState?.remove(SEARCH_QUERY)
|
||||||
|
MainActivity.nextSearchQuery = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,7 @@ package com.lagradost.cloudstream3.ui.settings
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
@ -13,7 +11,6 @@ import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.hippo.unifile.UniFile
|
|
||||||
import com.lagradost.cloudstream3.APIHolder.allProviders
|
import com.lagradost.cloudstream3.APIHolder.allProviders
|
||||||
import com.lagradost.cloudstream3.AcraApplication
|
import com.lagradost.cloudstream3.AcraApplication
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
|
@ -41,7 +38,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||||
import com.lagradost.cloudstream3.utils.USER_PROVIDER_API
|
import com.lagradost.cloudstream3.utils.USER_PROVIDER_API
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
|
||||||
import java.io.File
|
import com.lagradost.safefile.SafeFile
|
||||||
|
|
||||||
fun getCurrentLocale(context: Context): String {
|
fun getCurrentLocale(context: Context): String {
|
||||||
val res = context.resources
|
val res = context.resources
|
||||||
|
@ -57,6 +54,8 @@ fun getCurrentLocale(context: Context): String {
|
||||||
// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes leave blank for auto
|
// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes leave blank for auto
|
||||||
val appLanguages = arrayListOf(
|
val appLanguages = arrayListOf(
|
||||||
/* begin language list */
|
/* begin language list */
|
||||||
|
Triple("", "ajp", "ajp"),
|
||||||
|
Triple("", "አማርኛ", "am"),
|
||||||
Triple("", "العربية", "ar"),
|
Triple("", "العربية", "ar"),
|
||||||
Triple("", "ars", "ars"),
|
Triple("", "ars", "ars"),
|
||||||
Triple("", "български", "bg"),
|
Triple("", "български", "bg"),
|
||||||
|
@ -69,6 +68,7 @@ val appLanguages = arrayListOf(
|
||||||
Triple("", "Esperanto", "eo"),
|
Triple("", "Esperanto", "eo"),
|
||||||
Triple("", "español", "es"),
|
Triple("", "español", "es"),
|
||||||
Triple("", "فارسی", "fa"),
|
Triple("", "فارسی", "fa"),
|
||||||
|
Triple("", "fil", "fil"),
|
||||||
Triple("", "français", "fr"),
|
Triple("", "français", "fr"),
|
||||||
Triple("", "galego", "gl"),
|
Triple("", "galego", "gl"),
|
||||||
Triple("", "हिन्दी", "hi"),
|
Triple("", "हिन्दी", "hi"),
|
||||||
|
@ -84,6 +84,7 @@ val appLanguages = arrayListOf(
|
||||||
Triple("", "македонски", "mk"),
|
Triple("", "македонски", "mk"),
|
||||||
Triple("", "മലയാളം", "ml"),
|
Triple("", "മലയാളം", "ml"),
|
||||||
Triple("", "bahasa Melayu", "ms"),
|
Triple("", "bahasa Melayu", "ms"),
|
||||||
|
Triple("", "ဗမာစာ", "my"),
|
||||||
Triple("", "Nederlands", "nl"),
|
Triple("", "Nederlands", "nl"),
|
||||||
Triple("", "norsk nynorsk", "nn"),
|
Triple("", "norsk nynorsk", "nn"),
|
||||||
Triple("", "norsk bokmål", "no"),
|
Triple("", "norsk bokmål", "no"),
|
||||||
|
@ -97,6 +98,7 @@ val appLanguages = arrayListOf(
|
||||||
Triple("", "Soomaaliga", "so"),
|
Triple("", "Soomaaliga", "so"),
|
||||||
Triple("", "svenska", "sv"),
|
Triple("", "svenska", "sv"),
|
||||||
Triple("", "தமிழ்", "ta"),
|
Triple("", "தமிழ்", "ta"),
|
||||||
|
Triple("", "ትግርኛ", "ti"),
|
||||||
Triple("", "Tagalog", "tl"),
|
Triple("", "Tagalog", "tl"),
|
||||||
Triple("", "Türkçe", "tr"),
|
Triple("", "Türkçe", "tr"),
|
||||||
Triple("", "українська", "uk"),
|
Triple("", "українська", "uk"),
|
||||||
|
@ -137,8 +139,9 @@ class SettingsGeneral : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
context.contentResolver.takePersistableUriPermission(uri, flags)
|
context.contentResolver.takePersistableUriPermission(uri, flags)
|
||||||
|
|
||||||
val file = UniFile.fromUri(context, uri)
|
val file = SafeFile.fromUri(context, uri)
|
||||||
println("Selected URI path: $uri - Full path: ${file.filePath}")
|
val filePath = file?.filePath()
|
||||||
|
println("Selected URI path: $uri - Full path: $filePath")
|
||||||
|
|
||||||
// Stores the real URI using download_path_key
|
// Stores the real URI using download_path_key
|
||||||
// Important that the URI is stored instead of filepath due to permissions.
|
// Important that the URI is stored instead of filepath due to permissions.
|
||||||
|
@ -147,7 +150,7 @@ class SettingsGeneral : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
// From URI -> File path
|
// From URI -> File path
|
||||||
// File path here is purely for cosmetic purposes in settings
|
// File path here is purely for cosmetic purposes in settings
|
||||||
(file.filePath ?: uri.toString()).let {
|
(filePath ?: uri.toString()).let {
|
||||||
PreferenceManager.getDefaultSharedPreferences(context)
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.edit().putString(getString(R.string.download_path_pref), it).apply()
|
.edit().putString(getString(R.string.download_path_pref), it).apply()
|
||||||
}
|
}
|
||||||
|
@ -304,25 +307,23 @@ class SettingsGeneral : PreferenceFragmentCompat() {
|
||||||
}
|
}
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDownloadDirs(): List<String> {
|
fun getDownloadDirs(): List<String> {
|
||||||
return normalSafeApiCall {
|
return normalSafeApiCall {
|
||||||
val defaultDir = VideoDownloadManager.getDownloadDir()?.filePath
|
context?.let { ctx ->
|
||||||
|
val defaultDir = VideoDownloadManager.getDefaultDir(ctx)?.filePath()
|
||||||
|
|
||||||
// app_name_download_path = Cloudstream and does not change depending on release.
|
val first = listOf(defaultDir)
|
||||||
// DOES NOT WORK ON SCOPED STORAGE.
|
(try {
|
||||||
val secondaryDir =
|
val currentDir = ctx.getBasePath().let { it.first?.filePath() ?: it.second }
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath +
|
|
||||||
File.separator + resources.getString(R.string.app_name_download_path)
|
|
||||||
val first = listOf(defaultDir, secondaryDir)
|
|
||||||
(try {
|
|
||||||
val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second }
|
|
||||||
|
|
||||||
(first +
|
(first +
|
||||||
requireContext().getExternalFilesDirs("").mapNotNull { it.path } +
|
ctx.getExternalFilesDirs("").mapNotNull { it.path } +
|
||||||
currentDir)
|
currentDir)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
first
|
first
|
||||||
}).filterNotNull().distinct()
|
}).filterNotNull().distinct()
|
||||||
|
}
|
||||||
} ?: emptyList()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +338,7 @@ class SettingsGeneral : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
val currentDir =
|
val currentDir =
|
||||||
settingsManager.getString(getString(R.string.download_path_pref), null)
|
settingsManager.getString(getString(R.string.download_path_pref), null)
|
||||||
?: VideoDownloadManager.getDownloadDir().toString()
|
?: context?.let { ctx -> VideoDownloadManager.getDefaultDir(ctx)?.filePath() }
|
||||||
|
|
||||||
activity?.showBottomDialog(
|
activity?.showBottomDialog(
|
||||||
dirs + listOf("Custom"),
|
dirs + listOf("Custom"),
|
||||||
|
|
|
@ -116,13 +116,14 @@ class SettingsUpdates : PreferenceFragmentCompat() {
|
||||||
null,
|
null,
|
||||||
"txt",
|
"txt",
|
||||||
false
|
false
|
||||||
).fileStream
|
).openNew()
|
||||||
fileStream?.writer()?.write(text)
|
fileStream.writer().write(text)
|
||||||
} catch (e: Exception) {
|
dialog.dismissSafe(activity)
|
||||||
logError(e)
|
} catch (t: Throwable) {
|
||||||
|
logError(t)
|
||||||
|
showToast(t.message)
|
||||||
} finally {
|
} finally {
|
||||||
fileStream?.closeQuietly()
|
fileStream?.closeQuietly()
|
||||||
dialog.dismissSafe(activity)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.closeBtt.setOnClickListener {
|
binding.closeBtt.setOnClickListener {
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
package com.lagradost.cloudstream3.utils
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.ContentValues
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.provider.MediaStore
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
@ -28,6 +25,7 @@ import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_T
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_UNIXTIME_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_UNIXTIME_KEY
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_USER_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_USER_KEY
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.OpenSubtitlesApi.Companion.OPEN_SUBTITLES_USER_KEY
|
import com.lagradost.cloudstream3.syncproviders.providers.OpenSubtitlesApi.Companion.OPEN_SUBTITLES_USER_KEY
|
||||||
|
import com.lagradost.cloudstream3.ui.result.txt
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getDefaultSharedPrefs
|
import com.lagradost.cloudstream3.utils.DataStore.getDefaultSharedPrefs
|
||||||
|
@ -36,9 +34,9 @@ import com.lagradost.cloudstream3.utils.DataStore.mapper
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKeyRaw
|
import com.lagradost.cloudstream3.utils.DataStore.setKeyRaw
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
|
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.setupStream
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.isDownloadDir
|
import okhttp3.internal.closeQuietly
|
||||||
import java.io.IOException
|
import java.io.OutputStream
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
@ -146,59 +144,25 @@ object BackupUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SimpleDateFormat")
|
@SuppressLint("SimpleDateFormat")
|
||||||
fun FragmentActivity.backup() {
|
fun FragmentActivity.backup() = ioSafe {
|
||||||
|
var fileStream: OutputStream? = null
|
||||||
|
var printStream: PrintWriter? = null
|
||||||
try {
|
try {
|
||||||
if (!checkWrite()) {
|
if (!checkWrite()) {
|
||||||
showToast(getString(R.string.backup_failed), Toast.LENGTH_LONG)
|
showToast(R.string.backup_failed, Toast.LENGTH_LONG)
|
||||||
requestRW()
|
requestRW()
|
||||||
return
|
return@ioSafe
|
||||||
}
|
}
|
||||||
|
|
||||||
val subDir = getBasePath().first
|
|
||||||
val date = SimpleDateFormat("yyyy_MM_dd_HH_mm").format(Date(currentTimeMillis()))
|
val date = SimpleDateFormat("yyyy_MM_dd_HH_mm").format(Date(currentTimeMillis()))
|
||||||
val ext = "json"
|
val ext = "txt"
|
||||||
val displayName = "CS3_Backup_${date}"
|
val displayName = "CS3_Backup_${date}"
|
||||||
val backupFile = getBackup()
|
val backupFile = getBackup()
|
||||||
|
val stream = setupStream(this@backup, displayName, null, ext, false)
|
||||||
|
|
||||||
val steam = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
fileStream = stream.openNew()
|
||||||
&& subDir?.isDownloadDir() == true
|
printStream = PrintWriter(fileStream)
|
||||||
) {
|
|
||||||
val cr = this.contentResolver
|
|
||||||
val contentUri =
|
|
||||||
MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) // USE INSTEAD OF MediaStore.Downloads.EXTERNAL_CONTENT_URI
|
|
||||||
//val currentMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
|
||||||
|
|
||||||
val newFile = ContentValues().apply {
|
|
||||||
put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
|
|
||||||
put(MediaStore.MediaColumns.TITLE, displayName)
|
|
||||||
// While it a json file we store as txt because not
|
|
||||||
// all file managers support mimetype json
|
|
||||||
put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
|
|
||||||
//put(MediaStore.MediaColumns.RELATIVE_PATH, folder)
|
|
||||||
}
|
|
||||||
|
|
||||||
val newFileUri = cr.insert(
|
|
||||||
contentUri,
|
|
||||||
newFile
|
|
||||||
) ?: throw IOException("Error creating file uri")
|
|
||||||
cr.openOutputStream(newFileUri, "w")
|
|
||||||
?: throw IOException("Error opening stream")
|
|
||||||
} else {
|
|
||||||
val fileName = "$displayName.$ext"
|
|
||||||
val rFile = subDir?.findFile(fileName)
|
|
||||||
if (rFile?.exists() == true) {
|
|
||||||
rFile.delete()
|
|
||||||
}
|
|
||||||
val file =
|
|
||||||
subDir?.createFile(fileName)
|
|
||||||
?: throw IOException("Error creating file")
|
|
||||||
if (!file.exists()) throw IOException("File does not exist")
|
|
||||||
file.openOutputStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
val printStream = PrintWriter(steam)
|
|
||||||
printStream.print(mapper.writeValueAsString(backupFile))
|
printStream.print(mapper.writeValueAsString(backupFile))
|
||||||
printStream.close()
|
|
||||||
|
|
||||||
showToast(
|
showToast(
|
||||||
R.string.backup_success,
|
R.string.backup_success,
|
||||||
|
@ -208,12 +172,15 @@ object BackupUtils {
|
||||||
logError(e)
|
logError(e)
|
||||||
try {
|
try {
|
||||||
showToast(
|
showToast(
|
||||||
getString(R.string.backup_failed_error_format).format(e.toString()),
|
txt(R.string.backup_failed_error_format, e.toString()),
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
printStream?.closeQuietly()
|
||||||
|
fileStream?.closeQuietly()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -353,6 +353,12 @@ object DataStoreHelper {
|
||||||
removeKeys(folder2)
|
removeKeys(folder2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteBookmarkedData(id : Int?) {
|
||||||
|
if (id == null) return
|
||||||
|
removeKey("$currentAccount/$RESULT_WATCH_STATE", id.toString())
|
||||||
|
removeKey("$currentAccount/$RESULT_WATCH_STATE_DATA", id.toString())
|
||||||
|
}
|
||||||
|
|
||||||
fun getAllResumeStateIds(): List<Int>? {
|
fun getAllResumeStateIds(): List<Int>? {
|
||||||
val folder = "$currentAccount/$RESULT_RESUME_WATCHING"
|
val folder = "$currentAccount/$RESULT_RESUME_WATCHING"
|
||||||
return getKeys(folder)?.mapNotNull {
|
return getKeys(folder)?.mapNotNull {
|
||||||
|
@ -519,12 +525,10 @@ object DataStoreHelper {
|
||||||
|
|
||||||
fun setResultWatchState(id: Int?, status: Int) {
|
fun setResultWatchState(id: Int?, status: Int) {
|
||||||
if (id == null) return
|
if (id == null) return
|
||||||
val folder = "$currentAccount/$RESULT_WATCH_STATE"
|
|
||||||
if (status == WatchType.NONE.internalId) {
|
if (status == WatchType.NONE.internalId) {
|
||||||
removeKey(folder, id.toString())
|
deleteBookmarkedData(id)
|
||||||
removeKey("$currentAccount/$RESULT_WATCH_STATE_DATA", id.toString())
|
|
||||||
} else {
|
} else {
|
||||||
setKey(folder, id.toString(), status)
|
setKey("$currentAccount/$RESULT_WATCH_STATE", id.toString(), status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import androidx.work.ForegroundInfo
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.WORK_KEY_INFO
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.WORK_KEY_INFO
|
||||||
|
@ -15,6 +16,7 @@ import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadCheck
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadEpisode
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadEpisode
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadFromResume
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadFromResume
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadStatusEvent
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadStatusEvent
|
||||||
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getDownloadResumePackage
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
const val DOWNLOAD_CHECK = "DownloadCheck"
|
const val DOWNLOAD_CHECK = "DownloadCheck"
|
||||||
|
@ -25,28 +27,32 @@ class DownloadFileWorkManager(val context: Context, private val workerParams: Wo
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
val key = workerParams.inputData.getString("key")
|
val key = workerParams.inputData.getString("key")
|
||||||
try {
|
try {
|
||||||
println("KEY $key")
|
|
||||||
if (key == DOWNLOAD_CHECK) {
|
if (key == DOWNLOAD_CHECK) {
|
||||||
downloadCheck(applicationContext, ::handleNotification)?.let {
|
downloadCheck(applicationContext, ::handleNotification)
|
||||||
awaitDownload(it)
|
|
||||||
}
|
|
||||||
} else if (key != null) {
|
} else if (key != null) {
|
||||||
val info = applicationContext.getKey<VideoDownloadManager.DownloadInfo>(WORK_KEY_INFO, key)
|
val info =
|
||||||
|
applicationContext.getKey<VideoDownloadManager.DownloadInfo>(WORK_KEY_INFO, key)
|
||||||
val pkg =
|
val pkg =
|
||||||
applicationContext.getKey<VideoDownloadManager.DownloadResumePackage>(WORK_KEY_PACKAGE, key)
|
applicationContext.getKey<VideoDownloadManager.DownloadResumePackage>(
|
||||||
if (info != null) {
|
WORK_KEY_PACKAGE,
|
||||||
downloadEpisode(
|
key
|
||||||
applicationContext,
|
|
||||||
info.source,
|
|
||||||
info.folder,
|
|
||||||
info.ep,
|
|
||||||
info.links,
|
|
||||||
::handleNotification
|
|
||||||
)
|
)
|
||||||
awaitDownload(info.ep.id)
|
|
||||||
|
if (info != null) {
|
||||||
|
getDownloadResumePackage(applicationContext, info.ep.id)?.let { dpkg ->
|
||||||
|
downloadFromResume(applicationContext, dpkg, ::handleNotification)
|
||||||
|
} ?: run {
|
||||||
|
downloadEpisode(
|
||||||
|
applicationContext,
|
||||||
|
info.source,
|
||||||
|
info.folder,
|
||||||
|
info.ep,
|
||||||
|
info.links,
|
||||||
|
::handleNotification
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if (pkg != null) {
|
} else if (pkg != null) {
|
||||||
downloadFromResume(applicationContext, pkg, ::handleNotification)
|
downloadFromResume(applicationContext, pkg, ::handleNotification)
|
||||||
awaitDownload(pkg.item.ep.id)
|
|
||||||
}
|
}
|
||||||
removeKeys(key)
|
removeKeys(key)
|
||||||
}
|
}
|
||||||
|
@ -73,6 +79,7 @@ class DownloadFileWorkManager(val context: Context, private val workerParams: Wo
|
||||||
VideoDownloadManager.DownloadType.IsDone, VideoDownloadManager.DownloadType.IsFailed, VideoDownloadManager.DownloadType.IsStopped -> {
|
VideoDownloadManager.DownloadType.IsDone, VideoDownloadManager.DownloadType.IsFailed, VideoDownloadManager.DownloadType.IsStopped -> {
|
||||||
isDone = true
|
isDone = true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
package com.lagradost.cloudstream3.utils
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||||
import com.lagradost.cloudstream3.app
|
import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.delay
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.spec.IvParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
/** backwards api surface */
|
||||||
class M3u8Helper {
|
class M3u8Helper {
|
||||||
companion object {
|
companion object {
|
||||||
private val generator = M3u8Helper()
|
|
||||||
suspend fun generateM3u8(
|
suspend fun generateM3u8(
|
||||||
source: String,
|
source: String,
|
||||||
streamUrl: String,
|
streamUrl: String,
|
||||||
|
@ -20,34 +20,59 @@ class M3u8Helper {
|
||||||
headers: Map<String, String> = mapOf(),
|
headers: Map<String, String> = mapOf(),
|
||||||
name: String = source
|
name: String = source
|
||||||
): List<ExtractorLink> {
|
): List<ExtractorLink> {
|
||||||
return generator.m3u8Generation(
|
return M3u8Helper2.generateM3u8(source, streamUrl, referer, quality, headers, name)
|
||||||
M3u8Stream(
|
|
||||||
streamUrl = streamUrl,
|
|
||||||
quality = quality,
|
|
||||||
headers = headers,
|
|
||||||
), null
|
|
||||||
)
|
|
||||||
.map { stream ->
|
|
||||||
ExtractorLink(
|
|
||||||
source,
|
|
||||||
name = name,
|
|
||||||
stream.streamUrl,
|
|
||||||
referer,
|
|
||||||
stream.quality ?: Qualities.Unknown.value,
|
|
||||||
true,
|
|
||||||
stream.headers,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data class M3u8Stream(
|
||||||
|
val streamUrl: String,
|
||||||
|
val quality: Int? = null,
|
||||||
|
val headers: Map<String, String> = mapOf()
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun m3u8Generation(m3u8: M3u8Stream, returnThis: Boolean? = true): List<M3u8Stream> {
|
||||||
|
return M3u8Helper2.m3u8Generation(m3u8, returnThis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object M3u8Helper2 {
|
||||||
|
suspend fun generateM3u8(
|
||||||
|
source: String,
|
||||||
|
streamUrl: String,
|
||||||
|
referer: String,
|
||||||
|
quality: Int? = null,
|
||||||
|
headers: Map<String, String> = mapOf(),
|
||||||
|
name: String = source
|
||||||
|
): List<ExtractorLink> {
|
||||||
|
return m3u8Generation(
|
||||||
|
M3u8Helper.M3u8Stream(
|
||||||
|
streamUrl = streamUrl,
|
||||||
|
quality = quality,
|
||||||
|
headers = headers,
|
||||||
|
), null
|
||||||
|
)
|
||||||
|
.map { stream ->
|
||||||
|
ExtractorLink(
|
||||||
|
source,
|
||||||
|
name = name,
|
||||||
|
stream.streamUrl,
|
||||||
|
referer,
|
||||||
|
stream.quality ?: Qualities.Unknown.value,
|
||||||
|
true,
|
||||||
|
stream.headers,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val ENCRYPTION_DETECTION_REGEX = Regex("#EXT-X-KEY:METHOD=([^,]+),")
|
private val ENCRYPTION_DETECTION_REGEX = Regex("#EXT-X-KEY:METHOD=([^,]+),")
|
||||||
private val ENCRYPTION_URL_IV_REGEX =
|
private val ENCRYPTION_URL_IV_REGEX =
|
||||||
Regex("#EXT-X-KEY:METHOD=([^,]+),URI=\"([^\"]+)\"(?:,IV=(.*))?")
|
Regex("#EXT-X-KEY:METHOD=([^,]+),URI=\"([^\"]+)\"(?:,IV=(.*))?")
|
||||||
private val QUALITY_REGEX =
|
private val QUALITY_REGEX =
|
||||||
Regex("""#EXT-X-STREAM-INF:(?:(?:.*?(?:RESOLUTION=\d+x(\d+)).*?\s+(.*))|(?:.*?\s+(.*)))""")
|
Regex("""#EXT-X-STREAM-INF:(?:(?:.*?(?:RESOLUTION=\d+x(\d+)).*?\s+(.*))|(?:.*?\s+(.*)))""")
|
||||||
private val TS_EXTENSION_REGEX =
|
private val TS_EXTENSION_REGEX =
|
||||||
Regex("""(.*\.ts.*|.*\.jpg.*)""") //.jpg here 'case vizcloud uses .jpg instead of .ts
|
Regex("""#EXTINF:.*\n(.+?\n)""") // fuck it we ball, who cares about the type anyways
|
||||||
|
//Regex("""(.*\.(ts|jpg|html).*)""") //.jpg here 'case vizcloud uses .jpg instead of .ts
|
||||||
|
|
||||||
private fun absoluteExtensionDetermination(url: String): String? {
|
private fun absoluteExtensionDetermination(url: String): String? {
|
||||||
val split = url.split("/")
|
val split = url.split("/")
|
||||||
|
@ -64,21 +89,17 @@ class M3u8Helper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val defaultIvGen = sequence {
|
private fun defaultIv(index: Int) : ByteArray {
|
||||||
var initial = 1
|
return toBytes16Big(index+1)
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
fun getDecrypted(
|
||||||
yield(toBytes16Big(initial))
|
|
||||||
++initial
|
|
||||||
}
|
|
||||||
}.iterator()
|
|
||||||
|
|
||||||
private fun getDecrypter(
|
|
||||||
secretKey: ByteArray,
|
secretKey: ByteArray,
|
||||||
data: ByteArray,
|
data: ByteArray,
|
||||||
iv: ByteArray = "".toByteArray()
|
iv: ByteArray = byteArrayOf(),
|
||||||
|
index : Int,
|
||||||
): ByteArray {
|
): ByteArray {
|
||||||
val ivKey = if (iv.isEmpty()) defaultIvGen.next() else iv
|
val ivKey = if (iv.isEmpty()) defaultIv(index) else iv
|
||||||
val c = Cipher.getInstance("AES/CBC/PKCS5Padding")
|
val c = Cipher.getInstance("AES/CBC/PKCS5Padding")
|
||||||
val skSpec = SecretKeySpec(secretKey, "AES")
|
val skSpec = SecretKeySpec(secretKey, "AES")
|
||||||
val ivSpec = IvParameterSpec(ivKey)
|
val ivSpec = IvParameterSpec(ivKey)
|
||||||
|
@ -91,13 +112,8 @@ class M3u8Helper {
|
||||||
return st != null && (st.value.isNotEmpty() || st.destructured.component1() != "NONE")
|
return st != null && (st.value.isNotEmpty() || st.destructured.component1() != "NONE")
|
||||||
}
|
}
|
||||||
|
|
||||||
data class M3u8Stream(
|
|
||||||
val streamUrl: String,
|
|
||||||
val quality: Int? = null,
|
|
||||||
val headers: Map<String, String> = mapOf()
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun selectBest(qualities: List<M3u8Stream>): M3u8Stream? {
|
private fun selectBest(qualities: List<M3u8Helper.M3u8Stream>): M3u8Helper.M3u8Stream? {
|
||||||
val result = qualities.sortedBy {
|
val result = qualities.sortedBy {
|
||||||
if (it.quality != null && it.quality <= 1080) it.quality else 0
|
if (it.quality != null && it.quality <= 1080) it.quality else 0
|
||||||
}.filter {
|
}.filter {
|
||||||
|
@ -113,19 +129,16 @@ class M3u8Helper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isNotCompleteUrl(url: String): Boolean {
|
private fun isNotCompleteUrl(url: String): Boolean {
|
||||||
return !url.contains("https://") && !url.contains("http://")
|
return !url.startsWith("https://") && !url.startsWith("http://")
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun m3u8Generation(m3u8: M3u8Stream, returnThis: Boolean? = true): List<M3u8Stream> {
|
suspend fun m3u8Generation(m3u8: M3u8Helper.M3u8Stream, returnThis: Boolean? = true): List<M3u8Helper.M3u8Stream> {
|
||||||
// return listOf(m3u8)
|
val list = mutableListOf<M3u8Helper.M3u8Stream>()
|
||||||
val list = mutableListOf<M3u8Stream>()
|
|
||||||
|
|
||||||
val m3u8Parent = getParentLink(m3u8.streamUrl)
|
val m3u8Parent = getParentLink(m3u8.streamUrl)
|
||||||
val response = app.get(m3u8.streamUrl, headers = m3u8.headers, verify = false).text
|
val response = app.get(m3u8.streamUrl, headers = m3u8.headers, verify = false).text
|
||||||
|
|
||||||
// var hasAnyContent = false
|
|
||||||
for (match in QUALITY_REGEX.findAll(response)) {
|
for (match in QUALITY_REGEX.findAll(response)) {
|
||||||
// hasAnyContent = true
|
|
||||||
var (quality, m3u8Link, m3u8Link2) = match.destructured
|
var (quality, m3u8Link, m3u8Link2) = match.destructured
|
||||||
if (m3u8Link.isEmpty()) m3u8Link = m3u8Link2
|
if (m3u8Link.isEmpty()) m3u8Link = m3u8Link2
|
||||||
if (absoluteExtensionDetermination(m3u8Link) == "m3u8") {
|
if (absoluteExtensionDetermination(m3u8Link) == "m3u8") {
|
||||||
|
@ -136,21 +149,21 @@ class M3u8Helper {
|
||||||
println(m3u8.streamUrl)
|
println(m3u8.streamUrl)
|
||||||
}
|
}
|
||||||
list += m3u8Generation(
|
list += m3u8Generation(
|
||||||
M3u8Stream(
|
M3u8Helper.M3u8Stream(
|
||||||
m3u8Link,
|
m3u8Link,
|
||||||
quality.toIntOrNull(),
|
quality.toIntOrNull(),
|
||||||
m3u8.headers
|
m3u8.headers
|
||||||
), false
|
), false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
list += M3u8Stream(
|
list += M3u8Helper.M3u8Stream(
|
||||||
m3u8Link,
|
m3u8Link,
|
||||||
quality.toIntOrNull(),
|
quality.toIntOrNull(),
|
||||||
m3u8.headers
|
m3u8.headers
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (returnThis != false) {
|
if (returnThis != false) {
|
||||||
list += M3u8Stream(
|
list += M3u8Helper.M3u8Stream(
|
||||||
m3u8.streamUrl,
|
m3u8.streamUrl,
|
||||||
Qualities.Unknown.value,
|
Qualities.Unknown.value,
|
||||||
m3u8.headers
|
m3u8.headers
|
||||||
|
@ -160,113 +173,134 @@ class M3u8Helper {
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class LazyHlsDownloadData(
|
||||||
|
private val encryptionData: ByteArray,
|
||||||
|
private val encryptionIv: ByteArray,
|
||||||
|
private val isEncrypted: Boolean,
|
||||||
|
private val allTsLinks: List<String>,
|
||||||
|
private val relativeUrl: String,
|
||||||
|
private val headers: Map<String, String>,
|
||||||
|
) {
|
||||||
|
val size get() = allTsLinks.size
|
||||||
|
|
||||||
data class HlsDownloadData(
|
suspend fun resolveLinkWhileSafe(
|
||||||
val bytes: ByteArray,
|
index: Int,
|
||||||
val currentIndex: Int,
|
tries: Int = 3,
|
||||||
val totalTs: Int,
|
failDelay: Long = 3000,
|
||||||
val errored: Boolean = false
|
condition : (() -> Boolean)
|
||||||
)
|
): ByteArray? {
|
||||||
|
for (i in 0 until tries) {
|
||||||
|
if(!condition()) return null
|
||||||
|
|
||||||
suspend fun hlsYield(
|
try {
|
||||||
qualities: List<M3u8Stream>,
|
val out = resolveLink(index)
|
||||||
startIndex: Int = 0
|
return if(condition()) out else null
|
||||||
): Iterator<HlsDownloadData> {
|
} catch (e: IllegalArgumentException) {
|
||||||
if (qualities.isEmpty()) return listOf(
|
return null
|
||||||
HlsDownloadData(
|
} catch (e : CancellationException) {
|
||||||
byteArrayOf(),
|
return null
|
||||||
1,
|
} catch (t: Throwable) {
|
||||||
1,
|
delay(failDelay)
|
||||||
true
|
}
|
||||||
)
|
}
|
||||||
).iterator()
|
return null
|
||||||
|
|
||||||
var selected = selectBest(qualities)
|
|
||||||
if (selected == null) {
|
|
||||||
selected = qualities[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun resolveLinkSafe(
|
||||||
|
index: Int,
|
||||||
|
tries: Int = 3,
|
||||||
|
failDelay: Long = 3000
|
||||||
|
): ByteArray? {
|
||||||
|
for (i in 0 until tries) {
|
||||||
|
try {
|
||||||
|
return resolveLink(index)
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
return null
|
||||||
|
} catch (e : CancellationException) {
|
||||||
|
return null
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
delay(failDelay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun resolveLink(index: Int): ByteArray {
|
||||||
|
if (index < 0 || index >= size) throw IllegalArgumentException("index must be in the bounds of the ts")
|
||||||
|
val url = allTsLinks[index]
|
||||||
|
|
||||||
|
val tsResponse = app.get(url, headers = headers, verify = false)
|
||||||
|
val tsData = tsResponse.body.bytes()
|
||||||
|
if (tsData.isEmpty()) throw ErrorLoadingException("no data")
|
||||||
|
|
||||||
|
return if (isEncrypted) {
|
||||||
|
getDecrypted(encryptionData, tsData, encryptionIv, index)
|
||||||
|
} else {
|
||||||
|
tsData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun hslLazy(
|
||||||
|
qualities: List<M3u8Helper.M3u8Stream>
|
||||||
|
): LazyHlsDownloadData {
|
||||||
|
if (qualities.isEmpty()) throw IllegalArgumentException("qualities must be non empty")
|
||||||
|
val selected = selectBest(qualities) ?: qualities.first()
|
||||||
val headers = selected.headers
|
val headers = selected.headers
|
||||||
|
|
||||||
val streams = qualities.map { m3u8Generation(it, false) }.flatten()
|
val streams = qualities.map { m3u8Generation(it, false) }.flatten()
|
||||||
//val sslVerification = if (headers.containsKey("ssl_verification")) headers["ssl_verification"].toBoolean() else true
|
// this selects the best quality of the qualities offered,
|
||||||
|
// due to the recursive nature of m3u8, we only go 2 depth
|
||||||
val secondSelection = selectBest(streams.ifEmpty { listOf(selected) })
|
val secondSelection = selectBest(streams.ifEmpty { listOf(selected) })
|
||||||
if (secondSelection != null) {
|
?: throw IllegalArgumentException("qualities has no streams")
|
||||||
val m3u8Response =
|
|
||||||
runBlocking {
|
|
||||||
app.get(
|
|
||||||
secondSelection.streamUrl,
|
|
||||||
headers = headers,
|
|
||||||
verify = false
|
|
||||||
).text
|
|
||||||
}
|
|
||||||
|
|
||||||
var encryptionUri: String?
|
val m3u8Response =
|
||||||
var encryptionIv = byteArrayOf()
|
app.get(
|
||||||
var encryptionData = byteArrayOf()
|
secondSelection.streamUrl,
|
||||||
|
headers = headers,
|
||||||
|
verify = false
|
||||||
|
).text
|
||||||
|
|
||||||
val encryptionState = isEncrypted(m3u8Response)
|
// encryption, this is because crunchy uses it
|
||||||
|
var encryptionIv = byteArrayOf()
|
||||||
|
var encryptionData = byteArrayOf()
|
||||||
|
|
||||||
if (encryptionState) {
|
val encryptionState = isEncrypted(m3u8Response)
|
||||||
val match =
|
|
||||||
ENCRYPTION_URL_IV_REGEX.find(m3u8Response)!!.destructured // its safe to assume that its not going to be null
|
|
||||||
encryptionUri = match.component2()
|
|
||||||
|
|
||||||
if (isNotCompleteUrl(encryptionUri)) {
|
if (encryptionState) {
|
||||||
encryptionUri = "${getParentLink(secondSelection.streamUrl)}/$encryptionUri"
|
// its safe to assume that its not going to be null
|
||||||
}
|
val match =
|
||||||
|
ENCRYPTION_URL_IV_REGEX.find(m3u8Response)!!.groupValues
|
||||||
|
|
||||||
encryptionIv = match.component3().toByteArray()
|
var encryptionUri = match[2]
|
||||||
val encryptionKeyResponse =
|
|
||||||
runBlocking { app.get(encryptionUri, headers = headers, verify = false) }
|
if (isNotCompleteUrl(encryptionUri)) {
|
||||||
encryptionData = encryptionKeyResponse.body?.bytes() ?: byteArrayOf()
|
encryptionUri = "${getParentLink(secondSelection.streamUrl)}/$encryptionUri"
|
||||||
}
|
}
|
||||||
|
|
||||||
val allTs = TS_EXTENSION_REGEX.findAll(m3u8Response)
|
encryptionIv = match[3].toByteArray()
|
||||||
val allTsList = allTs.toList()
|
val encryptionKeyResponse = app.get(encryptionUri, headers = headers, verify = false)
|
||||||
val totalTs = allTsList.size
|
encryptionData = encryptionKeyResponse.body.bytes()
|
||||||
if (totalTs == 0) {
|
|
||||||
return listOf(HlsDownloadData(byteArrayOf(), 1, 1, true)).iterator()
|
|
||||||
}
|
|
||||||
var lastYield = 0
|
|
||||||
|
|
||||||
val relativeUrl = getParentLink(secondSelection.streamUrl)
|
|
||||||
var retries = 0
|
|
||||||
val tsByteGen = sequence {
|
|
||||||
loop@ for ((index, ts) in allTs.withIndex()) {
|
|
||||||
val url = if (
|
|
||||||
isNotCompleteUrl(ts.destructured.component1())
|
|
||||||
) "$relativeUrl/${ts.destructured.component1()}" else ts.destructured.component1()
|
|
||||||
val c = index + 1 + startIndex
|
|
||||||
|
|
||||||
while (lastYield != c) {
|
|
||||||
try {
|
|
||||||
val tsResponse =
|
|
||||||
runBlocking { app.get(url, headers = headers, verify = false) }
|
|
||||||
var tsData = tsResponse.body?.bytes() ?: byteArrayOf()
|
|
||||||
|
|
||||||
if (encryptionState) {
|
|
||||||
tsData = getDecrypter(encryptionData, tsData, encryptionIv)
|
|
||||||
yield(HlsDownloadData(tsData, c, totalTs))
|
|
||||||
lastYield = c
|
|
||||||
break
|
|
||||||
}
|
|
||||||
yield(HlsDownloadData(tsData, c, totalTs))
|
|
||||||
lastYield = c
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logError(e)
|
|
||||||
if (retries == 3) {
|
|
||||||
yield(HlsDownloadData(byteArrayOf(), c, totalTs, true))
|
|
||||||
break@loop
|
|
||||||
}
|
|
||||||
++retries
|
|
||||||
Thread.sleep(2_000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tsByteGen.iterator()
|
|
||||||
}
|
}
|
||||||
return listOf(HlsDownloadData(byteArrayOf(), 1, 1, true)).iterator()
|
val relativeUrl = getParentLink(secondSelection.streamUrl)
|
||||||
|
val allTsList = TS_EXTENSION_REGEX.findAll(m3u8Response + "\n").map { ts ->
|
||||||
|
val value = ts.groupValues[1]
|
||||||
|
if (isNotCompleteUrl(value)) {
|
||||||
|
"$relativeUrl/${value}"
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}.toList()
|
||||||
|
if (allTsList.isEmpty()) throw IllegalArgumentException("ts must be non empty")
|
||||||
|
|
||||||
|
return LazyHlsDownloadData(
|
||||||
|
encryptionData = encryptionData,
|
||||||
|
encryptionIv = encryptionIv,
|
||||||
|
isEncrypted = encryptionState,
|
||||||
|
allTsLinks = allTsList,
|
||||||
|
relativeUrl = relativeUrl,
|
||||||
|
headers = headers
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,20 +2,18 @@ package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.TvType
|
import com.lagradost.cloudstream3.TvType
|
||||||
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
|
||||||
|
|
||||||
object VideoDownloadHelper {
|
object VideoDownloadHelper {
|
||||||
data class DownloadEpisodeCached(
|
data class DownloadEpisodeCached(
|
||||||
@JsonProperty("name") val name: String?,
|
@JsonProperty("name") val name: String?,
|
||||||
@JsonProperty("poster") val poster: String?,
|
@JsonProperty("poster") val poster: String?,
|
||||||
@JsonProperty("episode") val episode: Int,
|
@JsonProperty("episode") val episode: Int,
|
||||||
@JsonProperty("season") val season: Int?,
|
@JsonProperty("season") val season: Int?,
|
||||||
@JsonProperty("id") override val id: Int,
|
@JsonProperty("id") val id: Int,
|
||||||
@JsonProperty("parentId") val parentId: Int,
|
@JsonProperty("parentId") val parentId: Int,
|
||||||
@JsonProperty("rating") val rating: Int?,
|
@JsonProperty("rating") val rating: Int?,
|
||||||
@JsonProperty("description") val description: String?,
|
@JsonProperty("description") val description: String?,
|
||||||
@JsonProperty("cacheTime") val cacheTime: Long,
|
@JsonProperty("cacheTime") val cacheTime: Long,
|
||||||
) : EasyDownloadButton.IMinimumData
|
)
|
||||||
|
|
||||||
data class DownloadHeaderCached(
|
data class DownloadHeaderCached(
|
||||||
@JsonProperty("apiName") val apiName: String,
|
@JsonProperty("apiName") val apiName: String,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
10
app/src/main/res/drawable/baseline_stop_24.xml
Normal file
10
app/src/main/res/drawable/baseline_stop_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/white"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M6,6h12v12H6z" />
|
||||||
|
</vector>
|
|
@ -61,7 +61,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginStart="-50dp"
|
android:layout_marginStart="-50dp"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:contentDescription="@string/account"
|
android:contentDescription="@string/account"
|
||||||
android:nextFocusLeft="@id/home_search"
|
android:nextFocusLeft="@id/home_search"
|
||||||
android:padding="10dp"
|
android:padding="10dp"
|
||||||
|
@ -288,4 +288,4 @@
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
tools:listitem="@layout/home_result_grid" />
|
tools:listitem="@layout/home_result_grid" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -476,7 +476,7 @@
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
tools:itemCount="2"
|
tools:itemCount="2"
|
||||||
tools:listitem="@layout/cast_item"
|
tools:listitem="@layout/cast_item"
|
||||||
tools:visibility="gone" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/result_vpn"
|
android:id="@+id/result_vpn"
|
||||||
|
@ -905,4 +905,4 @@
|
||||||
android:contentDescription="@string/search_poster_descript"/>
|
android:contentDescription="@string/search_poster_descript"/>
|
||||||
</androidx.cardview.widget.CardView>-->
|
</androidx.cardview.widget.CardView>-->
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
2
app/src/main/res/values-ajp/strings.xml
Normal file
2
app/src/main/res/values-ajp/strings.xml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources/>
|
5
app/src/main/res/values-am/strings.xml
Normal file
5
app/src/main/res/values-am/strings.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_dub_sub_episode_text_format" formatted="true">%s ክፍል %d</string>
|
||||||
|
<string name="cast_format" formatted="true">ተዋናዮች: %s</string>
|
||||||
|
</resources>
|
|
@ -584,4 +584,5 @@
|
||||||
<string name="default_account">@string/default_subtitles</string>
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
<string name="no_plugins_found_error">لا توجد اضافة في المستودع</string>
|
<string name="no_plugins_found_error">لا توجد اضافة في المستودع</string>
|
||||||
<string name="no_repository_found_error">المستودع لم يتم العثور عليه، تحقق من العنوان اوجرب شبكة افتراضية خاصة(vpn)</string>
|
<string name="no_repository_found_error">المستودع لم يتم العثور عليه، تحقق من العنوان اوجرب شبكة افتراضية خاصة(vpn)</string>
|
||||||
|
<string name="already_voted">لقد صوتت بالفعل</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,203 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources/>
|
<resources>
|
||||||
|
<string name="search_poster_img_des">لافتة</string>
|
||||||
|
<string name="home_change_provider_img_des">تغيير مزود</string>
|
||||||
|
<string name="downloading">جارى التحميل</string>
|
||||||
|
<string name="cast_format" formatted="true">بث%s</string>
|
||||||
|
<string name="filler" formatted="true">ملء</string>
|
||||||
|
<string name="skip_loading">تخطي التحميل</string>
|
||||||
|
<string name="loading">تحميل…</string>
|
||||||
|
<string name="pick_subtitle">ترجمات</string>
|
||||||
|
<string name="reload_error">إعادة محاولة الاتصال …</string>
|
||||||
|
<string name="app_dub_sub_episode_text_format" formatted="true">%sييبي%d</string>
|
||||||
|
<string name="next_episode_format" formatted="true">الحلقة%dسيتم نشرها في</string>
|
||||||
|
<string name="next_episode_time_day_format" formatted="true">%dي%dس%dد</string>
|
||||||
|
<string name="next_episode_time_hour_format" formatted="true">%dس%dد</string>
|
||||||
|
<string name="next_episode_time_min_format" formatted="true">%dد</string>
|
||||||
|
<string name="episode_poster_img_des">لافتة الحلقة</string>
|
||||||
|
<string name="home_main_poster_img_des">اللافتة الاساسية</string>
|
||||||
|
<string name="go_back_img_des">اذهب للخالف</string>
|
||||||
|
<string name="preview_background_img_des">معاينة الخلفية</string>
|
||||||
|
<string name="player_speed_text_format" formatted="true">سرعة(%.2fx)</string>
|
||||||
|
<string name="play_with_app_name">فتح مع كلاودستريم</string>
|
||||||
|
<string name="title_home">الصفحة الاساسية</string>
|
||||||
|
<string name="search_hint_site" formatted="true">...%sابحث</string>
|
||||||
|
<string name="no_data">لايوجد بيانات</string>
|
||||||
|
<string name="episode_more_options_des">المزيد من الخيارات</string>
|
||||||
|
<string name="result_open_in_browser">فتح في المتصفح</string>
|
||||||
|
<string name="browser">المتصفح</string>
|
||||||
|
<string name="play_movie_button">شاهد الفلم</string>
|
||||||
|
<string name="play_torrent_button">دفق التورنت</string>
|
||||||
|
<string name="download_started">بدأ التنزيل</string>
|
||||||
|
<string name="home_next_random_img_des">عشوائي قادم</string>
|
||||||
|
<string name="play_trailer_button">تشغيل المقطع الدعائي</string>
|
||||||
|
<string name="result_tags">الأنواع</string>
|
||||||
|
<string name="download_paused">توقف التنزيل</string>
|
||||||
|
<string name="type_plan_to_watch">خطط للمشاهدة</string>
|
||||||
|
<string name="type_none">لا يوجد</string>
|
||||||
|
<string name="type_re_watching">إعادة المشاهدة</string>
|
||||||
|
<string name="new_update_format" formatted="true">!تم العثور على تحديث جديد
|
||||||
|
\n%s->%s</string>
|
||||||
|
<string name="rated_format" formatted="true">%.1f:قدر</string>
|
||||||
|
<string name="duration_format" formatted="true">%dاقل</string>
|
||||||
|
<string name="app_name">كلاودستريم</string>
|
||||||
|
<string name="title_search">بحث</string>
|
||||||
|
<string name="title_downloads">التحميلات</string>
|
||||||
|
<string name="title_settings">اعدادات</string>
|
||||||
|
<string name="search_hint">...بحث</string>
|
||||||
|
<string name="next_episode">الحلقة القادمة</string>
|
||||||
|
<string name="result_share">شارك</string>
|
||||||
|
<string name="type_watching">مشاهدة</string>
|
||||||
|
<string name="type_on_hold">في التوقف</string>
|
||||||
|
<string name="type_completed">مكتمل</string>
|
||||||
|
<string name="type_dropped">توقف</string>
|
||||||
|
<string name="play_livestream_button">تشغيل البث المباشر</string>
|
||||||
|
<string name="pick_source">مصادر</string>
|
||||||
|
<string name="play_episode">تشغيل الحلقة</string>
|
||||||
|
<string name="download_canceled">تم إلغاء التنزيل</string>
|
||||||
|
<string name="download_done">تم التنزيل</string>
|
||||||
|
<string name="downloaded">تنززل</string>
|
||||||
|
<string name="download">تحميل</string>
|
||||||
|
<string name="go_back">عُد</string>
|
||||||
|
<string name="download_failed">التحميل فشل</string>
|
||||||
|
<string name="use_system_brightness_settings_des">استخدم سطوع النظام في مشغل التطبيق بدلاً من التراكب الداكن</string>
|
||||||
|
<string name="restore_success">تم تحميل ملف النسخ الاحتياطي</string>
|
||||||
|
<string name="advanced_search">البحث المتقدم</string>
|
||||||
|
<string name="player_size_settings_des">إزالة الحدود السوداء</string>
|
||||||
|
<string name="player_subtitles_settings">ترجمات</string>
|
||||||
|
<string name="eigengraumode_settings_des">يضيف خيار السرعة في المشغل</string>
|
||||||
|
<string name="double_tap_to_seek_settings">انقر نقرا مزدوجا للبحث</string>
|
||||||
|
<string name="double_tap_to_pause_settings">انقر نقرًا مزدوجًا للإيقاف المؤقت</string>
|
||||||
|
<string name="double_tap_to_seek_amount_settings">اللاعب يبحث عن المبلغ (بالثواني)</string>
|
||||||
|
<string name="swipe_to_seek_settings_des">اسحب من جانب إلى آخر للتحكم بموقعك في الفيديو</string>
|
||||||
|
<string name="autoplay_next_settings_des">ابدأ الحلقة التالية عندما تنتهي الحلقة الحالية</string>
|
||||||
|
<string name="use_system_brightness_settings">استخدام سطوع النظام</string>
|
||||||
|
<string name="episode_sync_settings">تحديث مراقبة التقدم</string>
|
||||||
|
<string name="episode_sync_settings_des">قم بمزامنة تقدم الحلقة الحالية تلقائيًا</string>
|
||||||
|
<string name="swipe_to_change_settings">اسحب لتغيير الإعدادات</string>
|
||||||
|
<string name="restore_settings">استعادة البيانات من النسخة الاحتياطية</string>
|
||||||
|
<string name="restore_failed_format" formatted="true">فشل في استعادة البيانات من الملف %s</string>
|
||||||
|
<string name="double_tap_to_seek_settings_des">انقر مرتين على الجانب الأيمن أو الأيسر للبحث للأمام أو للخلف</string>
|
||||||
|
<string name="backup_success">البيانات المخزنة</string>
|
||||||
|
<string name="double_tap_to_pause_settings_des">اضغط مرتين في المنتصف للتوقف مؤقتًا</string>
|
||||||
|
<string name="backup_failed">أذونات التخزين مفقودة. حاول مرة اخرى.</string>
|
||||||
|
<string name="backup_failed_error_format">حدث خطأ أثناء النسخ الاحتياطي %s</string>
|
||||||
|
<string name="search">بحث</string>
|
||||||
|
<string name="library">مكتبة</string>
|
||||||
|
<string name="settings_info">معلومات</string>
|
||||||
|
<string name="category_updates">التحديثات والنسخ الاحتياطي</string>
|
||||||
|
<string name="advanced_search_des">يعطيك نتائج البحث مفصولة حسب المزود</string>
|
||||||
|
<string name="bug_report_settings_off">يرسل فقط البيانات عن الأعطال</string>
|
||||||
|
<string name="show_trailers_settings">عرض المقطورات</string>
|
||||||
|
<string name="kitsu_settings">عرض الملصقات من كيتسو</string>
|
||||||
|
<string name="category_account">حسابات</string>
|
||||||
|
<string name="bug_report_settings_on">لا يرسل أي بيانات</string>
|
||||||
|
<string name="show_fillers_settings">عرض حلقة حشو للأنمي</string>
|
||||||
|
<string name="pref_filter_search_quality">إخفاء جودة الفيديو المحددة في نتائج البحث</string>
|
||||||
|
<string name="automatic_plugin_updates">تحديثات البرنامج المساعد التلقائي</string>
|
||||||
|
<string name="updates_settings_des">البحث تلقائيًا عن التحديثات الجديدة بعد بدء تشغيل التطبيق.</string>
|
||||||
|
<string name="uprereleases_settings">التحديث إلى الإصداراالمسبق</string>
|
||||||
|
<string name="automatic_plugin_download">تنزيل المكونات الإضافية تلقائيًا</string>
|
||||||
|
<string name="redo_setup_process">إعادة عملية الإعداد</string>
|
||||||
|
<string name="uprereleases_settings_des">ابحث عن تحديثات الإصدار التجريبي بدلاً من الإصدارات الكاملة فقط</string>
|
||||||
|
<string name="automatic_plugin_download_mode_title">حدد الوضع لتصفية تنزيل المكونات الإضافية</string>
|
||||||
|
<string name="automatic_plugin_download_summary">قم تلقائيًا بتثبيت جميع المكونات الإضافية التي لم يتم تثبيتها بعد من المستودعات المضافة.</string>
|
||||||
|
<string name="chromecast_subtitles_settings_des">إعدادات ترجمات كرومكاست</string>
|
||||||
|
<string name="eigengraumode_settings">وضع إيجينجرافي</string>
|
||||||
|
<string name="swipe_to_seek_settings">انتقد للبحث</string>
|
||||||
|
<string name="backup_settings">نسخ إحتياطي للبيانات</string>
|
||||||
|
<string name="updates_settings">إظهار تحديثات التطبيق</string>
|
||||||
|
<string name="player_subtitles_settings_des">إعدادات ترجمات المشغل</string>
|
||||||
|
<string name="chromecast_subtitles_settings">ترجمات كرومكاست</string>
|
||||||
|
<string name="swipe_to_change_settings_des">قم بالتمرير لأعلى أو لأسفل على الجانب الأيسر أو الأيمن لتغيير السطوع أو مستوى الصوت</string>
|
||||||
|
<string name="autoplay_next_settings">التشغيل التلقائي للحلقة القادمة</string>
|
||||||
|
<string name="lightnovel">تطبيق رواية خفيفة من نفس المطورين</string>
|
||||||
|
<string name="benene">أعط بينيني للمطورين</string>
|
||||||
|
<string name="github">جيتهب</string>
|
||||||
|
<string name="anim">تطبيق انيمي من نفس المطورين</string>
|
||||||
|
<string name="app_language">لغة التطبيق</string>
|
||||||
|
<string name="discord">انضم إلى الديسكورد</string>
|
||||||
|
<string name="benene_des">بنيني معطا</string>
|
||||||
|
<string name="apk_installer_settings_des">بعض الهواتف لا تدعم مثبت الحزمة الجديد. جرب الخيار القديم إذا لم يتم تثبيت التحديثات.</string>
|
||||||
|
<string name="apk_installer_settings">مثبت تتبيق</string>
|
||||||
|
<string name="test_passed">اجتاز</string>
|
||||||
|
<string name="episodes">الحلقات</string>
|
||||||
|
<string name="season">موسم</string>
|
||||||
|
<string name="copy_link_toast">تم نسخ الرابط إلى الحافظة</string>
|
||||||
|
<string name="delete">مسح</string>
|
||||||
|
<string name="pause">وقف</string>
|
||||||
|
<string name="update_notification_downloading">جارٍ تنزيل تحديث التطبيق…</string>
|
||||||
|
<string name="subs_default_reset_toast">إعادة التعيين إلى القيمة العادية</string>
|
||||||
|
<string name="season_short">س</string>
|
||||||
|
<string name="episode_format" formatted="true">%d%s</string>
|
||||||
|
<string name="no_chromecast_support_toast">لا يتمتع هذا المزود بدعم كرومكاست</string>
|
||||||
|
<string name="no_links_found_toast">لم يتم العثور على أي روابط</string>
|
||||||
|
<string name="play_episode_toast">تشغيل الحلقة</string>
|
||||||
|
<string name="acra_report_toast">عذرًا، تعطل التطبيق. سيتم إرسال تقرير خطأ مجهول إلى المطورين</string>
|
||||||
|
<string name="season_format">%s%d%s</string>
|
||||||
|
<string name="no_season">لا يوجد موسم</string>
|
||||||
|
<string name="episode">حلقة</string>
|
||||||
|
<string name="episodes_range">%d-%d</string>
|
||||||
|
<string name="episode_short">يي</string>
|
||||||
|
<string name="clear_history">امسح التاريخ</string>
|
||||||
|
<string name="update_notification_installing">جارٍ تثبيت تحديث التطبيق…</string>
|
||||||
|
<string name="start">بدأ</string>
|
||||||
|
<string name="no_episodes_found">لم يتم العثور على أي حلقات</string>
|
||||||
|
<string name="enable_skip_op_from_database_des">إظهار تخطي النوافذ المنبثقة للفتح/الإنهاء</string>
|
||||||
|
<string name="clipboard_too_large">الكثير من النص. غير قادر على الحفظ في الحافظة.</string>
|
||||||
|
<string name="action_mark_as_watched">وضع علامة كما شاهدت</string>
|
||||||
|
<string name="action_remove_from_watched">إزالة من شاهد</string>
|
||||||
|
<string name="delete_file">حذف ملف</string>
|
||||||
|
<string name="test_failed">فشل</string>
|
||||||
|
<string name="resume">اكتمل</string>
|
||||||
|
<string name="go_back_30">-30</string>
|
||||||
|
<string name="go_forward_30">+30</string>
|
||||||
|
<string name="history">تاريخ</string>
|
||||||
|
<string name="confirm_exit_dialog">هل أنت متأكد أنك تريد الخروج؟</string>
|
||||||
|
<string name="yes">نعم</string>
|
||||||
|
<string name="no">لا</string>
|
||||||
|
<string name="update_notification_failed">تعذر تثبيت الإصدار الجديد من التطبيق</string>
|
||||||
|
<string name="apk_installer_legacy">إرث</string>
|
||||||
|
<string name="apk_installer_package_installer">منزل المجموعة</string>
|
||||||
|
<string name="sort_rating_asc">التقييم (من الأقل إلى الأعلى)</string>
|
||||||
|
<string name="sort_updated_new">تم التحديث (من الجديد إلى القديم)</string>
|
||||||
|
<string name="sort_updated_old">تم التحديث (القديم إلى الجديد)</string>
|
||||||
|
<string name="sort_alphabetical_a">أبجديًا (من الألف إلى الياء)</string>
|
||||||
|
<string name="empty_library_no_accounts_message">مكتبتك فارغة :(
|
||||||
|
\nقم بتسجيل الدخول إلى حساب المكتبة أو قم بإضافة العروض إلى مكتبتك المحلية.</string>
|
||||||
|
<string name="safe_mode_file">!تم العثور على ملف الوضع الآمن
|
||||||
|
\n.عدم تحميل أي ملحقات عند بدء التشغيل حتى تتم إزالة الملف</string>
|
||||||
|
<string name="revert">ارجع</string>
|
||||||
|
<string name="subscription_in_progress_notification">تحديث العروض المشتركة</string>
|
||||||
|
<string name="set_default">الوضع العادي</string>
|
||||||
|
<string name="edit">حرر</string>
|
||||||
|
<string name="profiles">ملفات تعريفية</string>
|
||||||
|
<string name="help">مساعدة</string>
|
||||||
|
<string name="quality_profile_help">.هنا يمكنك تغيير كيفية ترتيب المصادر. إذا كان للفيديو أولوية أعلى، فسيظهر في مكان أعلى في تحديد المصدر. مجموع أولوية المصدر وأولوية الجودة هو أولوية الفيديو
|
||||||
|
\n
|
||||||
|
\nالمصدر أ: 3
|
||||||
|
\nالجودة ب: 7
|
||||||
|
\nستكون أولوية الفيديو المدمجة .10
|
||||||
|
\n
|
||||||
|
\n!ملاحظة: إذا كان المجموع 10 أو أكثر، فسيقوم اللاعب تلقائيًا بتخطي التحميل عند تحميل هذا الرابط</string>
|
||||||
|
<string name="already_voted">لقد صوت بالفعل</string>
|
||||||
|
<string name="sort_alphabetical_z">أبجديًا (ياء إلى ألف)</string>
|
||||||
|
<string name="sort_by">ترتيب حسب</string>
|
||||||
|
<string name="subscription_list_name">مشترك</string>
|
||||||
|
<string name="delayed_update_notice">سيتم تحديث التطبيق عند الخروج</string>
|
||||||
|
<string name="sort">رتب</string>
|
||||||
|
<string name="sort_rating_desc">التقييم (من الأعلى إلى الأقل)</string>
|
||||||
|
<string name="select_library">حدد المكتبة</string>
|
||||||
|
<string name="open_with">افتع مع</string>
|
||||||
|
<string name="empty_library_logged_in_message">.هذه القائمة فارغة. حاول التبديل إلى واحد آخر</string>
|
||||||
|
<string name="subscription_new">%sتم الاشتراك في</string>
|
||||||
|
<string name="subscription_deleted">%sتم إلغاء الاشتراك من</string>
|
||||||
|
<string name="subscription_episode_released">!%dتم إصدار الحلقة</string>
|
||||||
|
<string name="profile_background_des">خلفية الملف الشخصي</string>
|
||||||
|
<string name="profile_number">%dملف التعريف</string>
|
||||||
|
<string name="wifi">واي فاي</string>
|
||||||
|
<string name="mobile_data">بيانات الجوال</string>
|
||||||
|
<string name="use">استخدم</string>
|
||||||
|
<string name="unable_to_inflate">%sتعذر إنشاء واجهة المستخدم بشكل صحيح، وهذا خطأ كبير ويجب الإبلاغ عنه على الفور</string>
|
||||||
|
<string name="qualities">الصفات</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<string name="next_episode_time_min_format" formatted="true">%dm</string>
|
<string name="next_episode_time_min_format" formatted="true">%dm</string>
|
||||||
<!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->
|
<!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->
|
||||||
<string name="result_poster_img_des">Poster</string>
|
<string name="result_poster_img_des">Poster</string>
|
||||||
<string name="search_poster_img_des">@string/result_poster_img_des</string>
|
<string name="search_poster_img_des">Pôster</string>
|
||||||
<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>
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
<string name="error_loading_links_toast">Erro Carregando Links</string>
|
<string name="error_loading_links_toast">Erro Carregando Links</string>
|
||||||
<string name="download_storage_text">Armazenamento Interno</string>
|
<string name="download_storage_text">Armazenamento Interno</string>
|
||||||
<string name="app_dubbed_text">Dub</string>
|
<string name="app_dubbed_text">Dub</string>
|
||||||
<string name="app_subbed_text">Leg</string>
|
<string name="app_subbed_text">Sub</string>
|
||||||
<string name="popup_delete_file">Deletar Arquivo</string>
|
<string name="popup_delete_file">Deletar Arquivo</string>
|
||||||
<string name="popup_play_file">Assistir Arquivo</string>
|
<string name="popup_play_file">Assistir Arquivo</string>
|
||||||
<string name="popup_resume_download">Retomar Download</string>
|
<string name="popup_resume_download">Retomar Download</string>
|
||||||
|
@ -156,7 +156,7 @@
|
||||||
<string name="bug_report_settings_on">Não enviar nenhum dado</string>
|
<string name="bug_report_settings_on">Não enviar nenhum dado</string>
|
||||||
<string name="show_fillers_settings">Mostrar episódios de Filler em anime</string>
|
<string name="show_fillers_settings">Mostrar episódios de Filler em anime</string>
|
||||||
<string name="show_trailers_settings">Mostrar trailers</string>
|
<string name="show_trailers_settings">Mostrar trailers</string>
|
||||||
<string name="kitsu_settings">Mostrar posters do kitsu</string>
|
<string name="kitsu_settings">Mostrar posters do Kitsu</string>
|
||||||
<string name="pref_filter_search_quality">Esconder qualidades de vídeo selecionadas nos resultados da Pesquisa</string>
|
<string name="pref_filter_search_quality">Esconder qualidades de vídeo selecionadas nos resultados da Pesquisa</string>
|
||||||
<string name="automatic_plugin_updates">Atualizações de plugin automáticas</string>
|
<string name="automatic_plugin_updates">Atualizações de plugin automáticas</string>
|
||||||
<string name="updates_settings">Mostrar atualizações do app</string>
|
<string name="updates_settings">Mostrar atualizações do app</string>
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
<string name="season_short">S</string>
|
<string name="season_short">S</string>
|
||||||
<string name="episode_short">E</string>
|
<string name="episode_short">E</string>
|
||||||
<string name="no_episodes_found">Nenhum Episódio encontrado</string>
|
<string name="no_episodes_found">Nenhum Episódio encontrado</string>
|
||||||
<string name="delete_file">Deletar Arquivo</string>
|
<string name="delete_file">Apagar Arquivo</string>
|
||||||
<string name="delete">Deletar</string>
|
<string name="delete">Deletar</string>
|
||||||
<string name="pause">Pausar</string>
|
<string name="pause">Pausar</string>
|
||||||
<string name="resume">Retomar</string>
|
<string name="resume">Retomar</string>
|
||||||
|
@ -257,7 +257,7 @@
|
||||||
<string name="dont_show_again">Não mostrar de novo</string>
|
<string name="dont_show_again">Não mostrar de novo</string>
|
||||||
<string name="skip_update">Pular essa Atualização</string>
|
<string name="skip_update">Pular essa Atualização</string>
|
||||||
<string name="update">Atualizar</string>
|
<string name="update">Atualizar</string>
|
||||||
<string name="watch_quality_pref">Qualidade preferida</string>
|
<string name="watch_quality_pref">Qualidade preferida de reprodução (Wi-fi)</string>
|
||||||
<string name="limit_title">Máximo de caracteres do título de vídeos</string>
|
<string name="limit_title">Máximo de caracteres do título de vídeos</string>
|
||||||
<string name="limit_title_rez">Resolução do player de vídeo</string>
|
<string name="limit_title_rez">Resolução do player de vídeo</string>
|
||||||
<string name="video_buffer_size_settings">Tamanho do buffer do vídeo</string>
|
<string name="video_buffer_size_settings">Tamanho do buffer do vídeo</string>
|
||||||
|
@ -410,15 +410,19 @@
|
||||||
<string name="batch_download_finish_format" formatted="true">Transferido %d %s com sucesso</string>
|
<string name="batch_download_finish_format" formatted="true">Transferido %d %s com sucesso</string>
|
||||||
<string name="batch_download_nothing_to_download_format" formatted="true">Tudo %s já transferido</string>
|
<string name="batch_download_nothing_to_download_format" formatted="true">Tudo %s já transferido</string>
|
||||||
<string name="batch_download">Transferência em batch</string>
|
<string name="batch_download">Transferência em batch</string>
|
||||||
<string name="plugin_singular">plugin</string>
|
<string name="plugin_singular">Plugin</string>
|
||||||
<string name="plugin">plugins</string>
|
<string name="plugin">Plugins</string>
|
||||||
<string name="delete_repository_plugins">Isto irá apagar todos os repositórios de plugins</string>
|
<string name="delete_repository_plugins">Isto irá apagar todos os repositórios de plugins</string>
|
||||||
<string name="delete_repository">Apagar repositório</string>
|
<string name="delete_repository">Apagar repositório</string>
|
||||||
<string name="setup_extensions_subtext">Transferir lista de sites a usar</string>
|
<string name="setup_extensions_subtext">Transferir lista de sites a usar</string>
|
||||||
<string name="plugins_downloaded" formatted="true">Transferido: %d</string>
|
<string name="plugins_downloaded" formatted="true">Transferido: %d</string>
|
||||||
<string name="plugins_disabled" formatted="true">Desativado: %d</string>
|
<string name="plugins_disabled" formatted="true">Desativado: %d</string>
|
||||||
<string name="plugins_not_downloaded" formatted="true">Não transferido: %d</string>
|
<string name="plugins_not_downloaded" formatted="true">Não transferido: %d</string>
|
||||||
<string name="blank_repo_message">Adicionar um repositório para instalar extensões de sites</string>
|
<string name="blank_repo_message">CloudStream não tem fontes instaladas por padrão. Você precisa instalar um site de repositórios.
|
||||||
|
\n
|
||||||
|
\nPor causa das limitações do DMCA (Digital Millennium Copyright Act ) feito em nome de Sky UK Limited 🤮nós não podemos adicionar site de repositórios no app.
|
||||||
|
\n
|
||||||
|
\nEntre no nosso Discord ou pesquise online.</string>
|
||||||
<string name="view_public_repositories_button">Ver repositórios da comunidade</string>
|
<string name="view_public_repositories_button">Ver repositórios da comunidade</string>
|
||||||
<string name="view_public_repositories_button_short">Lista pública</string>
|
<string name="view_public_repositories_button_short">Lista pública</string>
|
||||||
<string name="uppercase_all_subtitles">Todas as legendas em maiúsculas</string>
|
<string name="uppercase_all_subtitles">Todas as legendas em maiúsculas</string>
|
||||||
|
@ -428,4 +432,122 @@
|
||||||
<string name="autoplay_next_settings_des">Começa o próximo episódio quando o atual termina</string>
|
<string name="autoplay_next_settings_des">Começa o próximo episódio quando o atual termina</string>
|
||||||
<string name="enable_nsfw_on_providers">Ativar NSFW em fornecedores compatíveis</string>
|
<string name="enable_nsfw_on_providers">Ativar NSFW em fornecedores compatíveis</string>
|
||||||
<string name="category_providers">Fornecedores</string>
|
<string name="category_providers">Fornecedores</string>
|
||||||
|
<string name="revert">Reverter</string>
|
||||||
|
<string name="pref_category_actions">Ações</string>
|
||||||
|
<string name="already_voted">votou com sucesso</string>
|
||||||
|
<string name="update_notification_downloading">Baixando atualização do aplicativo…</string>
|
||||||
|
<string name="referer">Referencias</string>
|
||||||
|
<string name="pref_category_app_updates">Atualizações do App</string>
|
||||||
|
<string name="play_with_app_name">Tocar com CloudStream</string>
|
||||||
|
<string name="automatic_plugin_download_summary">Automaticamente instale todos os plugins não instalados dos repositórios adicionados.</string>
|
||||||
|
<string name="play_trailer_button">Reproduzir Trailer</string>
|
||||||
|
<string name="browser">Navegador</string>
|
||||||
|
<string name="pref_category_backup">Copia de Segurança</string>
|
||||||
|
<string name="android_tv_interface_off_seek_settings_summary">A Barra de Progresso pode ser usada quando o player estiver oculto</string>
|
||||||
|
<string name="subscription_list_name">Inscrever</string>
|
||||||
|
<string name="empty_library_logged_in_message">Essa lista está vazia. Tente mudar para outra.</string>
|
||||||
|
<string name="play_livestream_button">Reproduzir Livestream</string>
|
||||||
|
<string name="test_log">Log do Teste</string>
|
||||||
|
<string name="automatic_plugin_download">Baixa plugins automaticamente</string>
|
||||||
|
<string name="automatic_plugin_download_mode_title">Selecione o modo para filtrar os plugins baixados</string>
|
||||||
|
<string name="test_failed">Teste falhou</string>
|
||||||
|
<string name="android_tv_interface_on_seek_settings_summary">A Barra de Progresso pode ser usada quando o player estiver visível</string>
|
||||||
|
<string name="sort">Organizar</string>
|
||||||
|
<string name="yes">Sim</string>
|
||||||
|
<string name="confirm_exit_dialog">Você tem certeza que deseja sair\?</string>
|
||||||
|
<string name="update_notification_installing">Instalando atualização do aplicativo…</string>
|
||||||
|
<string name="edit">Editar</string>
|
||||||
|
<string name="profiles">Perfis</string>
|
||||||
|
<string name="android_tv_interface_on_seek_settings">Exibindo Player - procure na Barra de Progresso</string>
|
||||||
|
<string name="action_remove_from_watched">Remover dos assistidos</string>
|
||||||
|
<string name="pref_category_extensions">Extensões</string>
|
||||||
|
<string name="sort_alphabetical_a">Alfabética(A => Z)</string>
|
||||||
|
<string name="open_with">Abrir com</string>
|
||||||
|
<string name="select_library">Selecionar Biblioteca</string>
|
||||||
|
<string name="test_passed">Passou</string>
|
||||||
|
<string name="empty_library_no_accounts_message">Sua biblioteca está vazia :0
|
||||||
|
\nEntre numa conta de biblioteca ou adicione Midias para sua biblioteca local.</string>
|
||||||
|
<string name="watch_quality_pref_data">Qualidade preferida de reprodução (Dados Móveis)</string>
|
||||||
|
<string name="apk_installer_legacy">Legado</string>
|
||||||
|
<string name="library">Biblioteca</string>
|
||||||
|
<string name="no">Não</string>
|
||||||
|
<string name="tracks">Trilhas Sonoras</string>
|
||||||
|
<string name="sort_rating_asc">Votação (Baixa para Alta)</string>
|
||||||
|
<string name="update_started">Atualização iniciada</string>
|
||||||
|
<string name="nsfw_singular">Conteúdo +18</string>
|
||||||
|
<string name="help">Ajuda</string>
|
||||||
|
<string name="redo_setup_process">Processo de configuração de Redo</string>
|
||||||
|
<string name="update_notification_failed">Não pudemos instalar a nova versão do App</string>
|
||||||
|
<string name="apk_installer_package_installer">instalador de pacotes</string>
|
||||||
|
<string name="sort_by">Organizar por</string>
|
||||||
|
<string name="sort_rating_desc">Votação (Alta para Baixa)</string>
|
||||||
|
<string name="sort_alphabetical_z">Alfabética(Z => A)</string>
|
||||||
|
<string name="qualities">Qualidade</string>
|
||||||
|
<string name="profile_background_des">Perfil de plano de fundo</string>
|
||||||
|
<string name="quality_profile_help">Aqui você pode alterar como as fontes são ordenadas. Se um vídeo tiver uma prioridade mais alta, aparecerá mais alto na seleção da fonte. A soma da prioridade da fonte e da prioridade da qualidade é a prioridade do vídeo.
|
||||||
|
\n
|
||||||
|
\nFonte A: 3
|
||||||
|
\nQualidade B: 7
|
||||||
|
\nTerá uma prioridade de vídeo combinada de 10.
|
||||||
|
\n
|
||||||
|
\nNOTA: Se a soma for 10 ou mais, o Player pulará automaticamente o carregamento quando o link for carregado!</string>
|
||||||
|
<string name="safe_mode_file">Arquivo de modo de segurança encontrado!
|
||||||
|
\nNão carregar nenhuma extensão na inicialização até que o arquivo seja removido.</string>
|
||||||
|
<string name="subscription_new">Inscrevel em %d</string>
|
||||||
|
<string name="subscription_episode_released">Episódio %d Lançado</string>
|
||||||
|
<string name="set_default">Selecionar padrão</string>
|
||||||
|
<string name="subscription_deleted">Disinscrevel em %d</string>
|
||||||
|
<string name="apk_installer_settings_des">Alguns aparelhos não possuem suporte para este pacote de instalação. Tente a opção legada se a atualização não instalar.</string>
|
||||||
|
<string name="mobile_data">Dados móveis</string>
|
||||||
|
<string name="profile_number">Perfil %d</string>
|
||||||
|
<string name="subscription_in_progress_notification">Atualizando shows inscritos</string>
|
||||||
|
<string name="android_tv_interface_off_seek_settings">Player oculto - Procure na barra de progresso</string>
|
||||||
|
<string name="nsfw">Conteúdo +18</string>
|
||||||
|
<string name="restart">Reiniciar</string>
|
||||||
|
<string name="stop">Parar</string>
|
||||||
|
<string name="action_mark_as_watched">Marcar como assistido</string>
|
||||||
|
<string name="delayed_update_notice">Aplicativo precisa ser fechado para atualizar</string>
|
||||||
|
<string name="enable_skip_op_from_database_des">Mostrar popups pulados para abertura e finalização</string>
|
||||||
|
<string name="episodes_range">%d-%d</string>
|
||||||
|
<string name="player_settings_play_in_app">Player interno</string>
|
||||||
|
<string name="extension_size">Tamanho</string>
|
||||||
|
<string name="skip_type_op">Abrindo</string>
|
||||||
|
<string name="season_format">%s %d%s</string>
|
||||||
|
<string name="plugins_updated" formatted="true">%d plugins atualizados</string>
|
||||||
|
<string name="safe_mode_description">Todos as extensões serão desligadas para ajuda se talvez estejam causando algum bug.</string>
|
||||||
|
<string name="app_not_found_error">Aplicativo não encontrado</string>
|
||||||
|
<string name="skip_type_recap">Recapitular</string>
|
||||||
|
<string name="all_languages_preference">Todas as linguagens</string>
|
||||||
|
<string name="skip_type_format" formatted="true">Pula %s</string>
|
||||||
|
<string name="skip_type_mixed_ed">Mistura terminada</string>
|
||||||
|
<string name="safe_mode_title">Modo seguro ligado</string>
|
||||||
|
<string name="extension_rating" formatted="true">Ranquear: %s</string>
|
||||||
|
<string name="extension_language">Linguagem</string>
|
||||||
|
<string name="hls_playlist">Lista de reprodução HLS</string>
|
||||||
|
<string name="skip_type_ed">Terminando</string>
|
||||||
|
<string name="episode_format" formatted="true">%d %s</string>
|
||||||
|
<string name="sort_updated_old">Adicionado em (antigo para novo)</string>
|
||||||
|
<string name="skip_type_intro">Introdução</string>
|
||||||
|
<string name="no_plugins_found_error">plug-ins não foram encontrados no repositório</string>
|
||||||
|
<string name="no_repository_found_error">Repositório não encontrado, verifique o URL e tente usa uma VPN</string>
|
||||||
|
<string name="extension_description">Descrição</string>
|
||||||
|
<string name="extension_version">Versão</string>
|
||||||
|
<string name="extension_authors">Autores</string>
|
||||||
|
<string name="extension_install_first">Instale a extensão primeiro</string>
|
||||||
|
<string name="skip_type_creddits">Créditos</string>
|
||||||
|
<string name="history">Historico</string>
|
||||||
|
<string name="clear_history">Limpar historico</string>
|
||||||
|
<string name="clipboard_too_large">Tem Muito texto. Não é possível salvar no clipboard.</string>
|
||||||
|
<string name="player_pref">Player de vídeo preferido</string>
|
||||||
|
<string name="start">Começar</string>
|
||||||
|
<string name="extension_types">Suportado</string>
|
||||||
|
<string name="extension_status">Status</string>
|
||||||
|
<string name="player_settings_play_in_mpv">MPV</string>
|
||||||
|
<string name="skip_type_mixed_op">Abrindo mistura</string>
|
||||||
|
<string name="player_settings_play_in_vlc">VLC</string>
|
||||||
|
<string name="apply_on_restart">Aplicar quando reiniciar</string>
|
||||||
|
<string name="safe_mode_crash_info">Visualização info de crash</string>
|
||||||
|
<string name="audio_tracks">Faixas de áudio</string>
|
||||||
|
<string name="sort_updated_new">Adicionado em (novo para antigo)</string>
|
||||||
|
<string name="video_tracks">Faixas de video</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -576,4 +576,5 @@
|
||||||
<string name="no_plugins_found_error">V repozitáři nebyly nalezeny žádné doplňky</string>
|
<string name="no_plugins_found_error">V repozitáři nebyly nalezeny žádné doplňky</string>
|
||||||
<string name="no_repository_found_error">Repozitář nenalezen, zkontrolujte adresu URL a zkuste použít VPN</string>
|
<string name="no_repository_found_error">Repozitář nenalezen, zkontrolujte adresu URL a zkuste použít VPN</string>
|
||||||
<string name="default_account">@string/default_subtitles</string>
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
|
<string name="already_voted">Již jste hlasovali</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
<string name="sort_cancel">Abbrechen</string>
|
<string name="sort_cancel">Abbrechen</string>
|
||||||
<string name="sort_copy">Kopieren</string>
|
<string name="sort_copy">Kopieren</string>
|
||||||
<string name="sort_close">Schließen</string>
|
<string name="sort_close">Schließen</string>
|
||||||
<string name="sort_clear">Löschen</string>
|
<string name="sort_clear">Leeren</string>
|
||||||
<string name="sort_save">Speichern</string>
|
<string name="sort_save">Speichern</string>
|
||||||
<string name="player_speed">Player-Geschwindigkeit</string>
|
<string name="player_speed">Player-Geschwindigkeit</string>
|
||||||
<string name="subtitles_settings">Untertiteleinstellungen</string>
|
<string name="subtitles_settings">Untertiteleinstellungen</string>
|
||||||
|
@ -390,7 +390,7 @@
|
||||||
<string name="skip_setup">Einrichtung überspringen</string>
|
<string name="skip_setup">Einrichtung überspringen</string>
|
||||||
<string name="app_layout_subtext">Aussehen der App passend zu dem des Geräts ändern</string>
|
<string name="app_layout_subtext">Aussehen der App passend zu dem des Geräts ändern</string>
|
||||||
<string name="crash_reporting_title">Absturzmeldung</string>
|
<string name="crash_reporting_title">Absturzmeldung</string>
|
||||||
<string name="preferred_media_subtext">Was möchtest du anschauen\?</string>
|
<string name="preferred_media_subtext">Was möchten Sie sehen\?</string>
|
||||||
<string name="setup_done">Fertig</string>
|
<string name="setup_done">Fertig</string>
|
||||||
<string name="extensions">Erweiterungen</string>
|
<string name="extensions">Erweiterungen</string>
|
||||||
<string name="add_repository">Repository hinzufügen</string>
|
<string name="add_repository">Repository hinzufügen</string>
|
||||||
|
@ -546,4 +546,10 @@
|
||||||
\nWerden eine kombinierte Videopriorität von 10 haben.
|
\nWerden eine kombinierte Videopriorität von 10 haben.
|
||||||
\n
|
\n
|
||||||
\nHINWEIS: Wenn die Summe 10 oder mehr beträgt, überspringt der Player automatisch das Laden, wenn der Link geladen wird!</string>
|
\nHINWEIS: Wenn die Summe 10 oder mehr beträgt, überspringt der Player automatisch das Laden, wenn der Link geladen wird!</string>
|
||||||
|
<string name="automatic_plugin_download_mode_title">Filtermodus für Plugin-Downloads auswählen</string>
|
||||||
|
<string name="already_voted">Es wurde bereits abgestimmt</string>
|
||||||
|
<string name="no_plugins_found_error">Keine Plugins im Repository gefunden</string>
|
||||||
|
<string name="no_repository_found_error">Repository nicht gefunden, überprüfe die URL und probiere eine VPN</string>
|
||||||
|
<string name="unable_to_inflate">Die Benutzeroberfläche konnte nicht korrekt erstellt werden. Dies ist ein schwerwiegender Fehler und sollte sofort gemeldet werden. %s</string>
|
||||||
|
<string name="disable">Deaktivieren</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -552,4 +552,5 @@
|
||||||
<string name="default_account">@string/default_subtitles</string>
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
<string name="no_plugins_found_error">No se encontraron complementos en el repositorio</string>
|
<string name="no_plugins_found_error">No se encontraron complementos en el repositorio</string>
|
||||||
<string name="no_repository_found_error">Repositorio no encontrado, comprueba la URL y prueba la VPN</string>
|
<string name="no_repository_found_error">Repositorio no encontrado, comprueba la URL y prueba la VPN</string>
|
||||||
|
<string name="already_voted">Ya has votado</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
2
app/src/main/res/values-fil/strings.xml
Normal file
2
app/src/main/res/values-fil/strings.xml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources/>
|
|
@ -530,4 +530,26 @@
|
||||||
<string name="android_tv_interface_on_seek_settings">Joueur représenté - Montant de la recherche</string>
|
<string name="android_tv_interface_on_seek_settings">Joueur représenté - Montant de la recherche</string>
|
||||||
<string name="android_tv_interface_off_seek_settings">Joueur caché - Montant de la recherche</string>
|
<string name="android_tv_interface_off_seek_settings">Joueur caché - Montant de la recherche</string>
|
||||||
<string name="jsdelivr_enabled">Impossible d\'accéder à GitHub. Activation du proxy jsDelivr…</string>
|
<string name="jsdelivr_enabled">Impossible d\'accéder à GitHub. Activation du proxy jsDelivr…</string>
|
||||||
|
<string name="already_voted">Vous avez déjà voté</string>
|
||||||
|
<string name="disable">Désactivé</string>
|
||||||
|
<string name="quality_profile_help">Ici, vous pouvez modifier la façon dont les sources sont ordonnées. Si une vidéo a une priorité plus élevée, elle apparaîtra plus haut dans la sélection de la source. La somme de la priorité source et de la priorité qualité est la priorité vidéo.
|
||||||
|
\n
|
||||||
|
\nSource A : 3
|
||||||
|
\nQualité B : 7
|
||||||
|
\nLa priorité vidéo combinée sera de 10.
|
||||||
|
\n
|
||||||
|
\nREMARQUE : Si la somme est de 10 ou plus, le joueur sautera automatiquement le chargement lorsque ce lien est chargé !</string>
|
||||||
|
<string name="no_plugins_found_error">Aucun plugin trouvé dans ce dossier</string>
|
||||||
|
<string name="no_repository_found_error">Dossier non trouvé, vérifiez l\'url et essayé un VPN</string>
|
||||||
|
<string name="mobile_data">Données mobiles</string>
|
||||||
|
<string name="set_default">Définir par défaut</string>
|
||||||
|
<string name="use">Utiliser</string>
|
||||||
|
<string name="edit">Modifier</string>
|
||||||
|
<string name="profiles">Profils</string>
|
||||||
|
<string name="help">Aide</string>
|
||||||
|
<string name="profile_number">Profil %d</string>
|
||||||
|
<string name="wifi">Wi-Fi</string>
|
||||||
|
<string name="qualities">Qualités</string>
|
||||||
|
<string name="unable_to_inflate">L\'interface utilisateur n\'a pas pu être créée correctement. Il s\'agit d\'un bogue majeur qui doit être signalé immédiatement %s</string>
|
||||||
|
<string name="automatic_plugin_download_mode_title">Sélectionnez le mode pour filtrer le téléchargement des plugins</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -190,7 +190,7 @@
|
||||||
<string name="backup_success">Adatok eltárolva</string>
|
<string name="backup_success">Adatok eltárolva</string>
|
||||||
<string name="backup_failed_error_format">Hiba a biztonsági mentés során %s</string>
|
<string name="backup_failed_error_format">Hiba a biztonsági mentés során %s</string>
|
||||||
<string name="category_account">Fiókok</string>
|
<string name="category_account">Fiókok</string>
|
||||||
<string name="advanced_search_des">Szolgáltatás szerinti keresés eredmények</string>
|
<string name="advanced_search_des">Szolgáltató szerint elkülönítve adja meg a keresési eredményeket</string>
|
||||||
<string name="bug_report_settings_on">Nem küld adatokat</string>
|
<string name="bug_report_settings_on">Nem küld adatokat</string>
|
||||||
<string name="kitsu_settings">Poszterek megjelenítése Kitsu-ról</string>
|
<string name="kitsu_settings">Poszterek megjelenítése Kitsu-ról</string>
|
||||||
<string name="pref_filter_search_quality">Kiválasztott videóminőségek elrejtése keresési eredményekbe</string>
|
<string name="pref_filter_search_quality">Kiválasztott videóminőségek elrejtése keresési eredményekbe</string>
|
||||||
|
@ -198,7 +198,7 @@
|
||||||
<string name="automatic_plugin_download">Bővítmények automatikus letöltése</string>
|
<string name="automatic_plugin_download">Bővítmények automatikus letöltése</string>
|
||||||
<string name="automatic_plugin_download_summary">Automatikusan telepíti az összes még nem telepített bővítményt a hozzáadott tárolókból.</string>
|
<string name="automatic_plugin_download_summary">Automatikusan telepíti az összes még nem telepített bővítményt a hozzáadott tárolókból.</string>
|
||||||
<string name="updates_settings">Alkalmazás frissítések megjelenítése</string>
|
<string name="updates_settings">Alkalmazás frissítések megjelenítése</string>
|
||||||
<string name="updates_settings_des">Automatikusan keressen új frissítéseket indításkor</string>
|
<string name="updates_settings_des">Automatikusan keressen új frissítéseket indításkor.</string>
|
||||||
<string name="uprereleases_settings">Frissítés az előzetes kiadásokhoz (prerelease)</string>
|
<string name="uprereleases_settings">Frissítés az előzetes kiadásokhoz (prerelease)</string>
|
||||||
<string name="uprereleases_settings_des">Csak előzetesen kiadott frissítések (prerelease) keresése a teljes kiadások helyett</string>
|
<string name="uprereleases_settings_des">Csak előzetesen kiadott frissítések (prerelease) keresése a teljes kiadások helyett</string>
|
||||||
<string name="github">Github</string>
|
<string name="github">Github</string>
|
||||||
|
@ -232,30 +232,30 @@
|
||||||
<string name="episode_action_play_in_browser">Lejátszás böngészőben</string>
|
<string name="episode_action_play_in_browser">Lejátszás böngészőben</string>
|
||||||
<string name="episode_action_download_subtitle">Feliratok letöltése</string>
|
<string name="episode_action_download_subtitle">Feliratok letöltése</string>
|
||||||
<string name="reload_error">Újracsatlakozás…</string>
|
<string name="reload_error">Újracsatlakozás…</string>
|
||||||
<string name="swipe_to_seek_settings_des">Swipe balra vagy jobbra a videólejátszóban az idő vezérléséhez</string>
|
<string name="swipe_to_seek_settings_des">Húzd balra vagy jobbra a videólejátszóban az idő vezérléséhez</string>
|
||||||
<string name="swipe_to_change_settings">Csúsztassa ujját a beállítások módosításához</string>
|
<string name="swipe_to_change_settings">Csúsztassa ujját a beállítások módosításához</string>
|
||||||
<string name="swipe_to_change_settings_des">Csúsztassa az újját bal vagy jobb oldalon a fényerő vagy hangerő megváltoztatásához</string>
|
<string name="swipe_to_change_settings_des">Csúsztassa felfelé vagy lefelé a bal vagy jobb oldalon a fényerő vagy a hangerő megváltoztatásához</string>
|
||||||
<string name="backup_settings">Biztonsági mentés</string>
|
<string name="backup_settings">Biztonsági mentés</string>
|
||||||
<string name="benene_count_text_none">0 Banán a fejlesztőknek</string>
|
<string name="benene_count_text_none">0 Banán a fejlesztőknek</string>
|
||||||
<string name="swipe_to_seek_settings">Swipe to seek</string>
|
<string name="swipe_to_seek_settings">Húzás a kereséshez</string>
|
||||||
<string name="autoplay_next_settings">Következő epizód automatikus lejátszása</string>
|
<string name="autoplay_next_settings">Következő epizód automatikus lejátszása</string>
|
||||||
<string name="autoplay_next_settings_des">Következő epizód lejátszása amikor az aktuális epizód véget ér</string>
|
<string name="autoplay_next_settings_des">Következő epizód lejátszása amikor az aktuális epizód véget ér</string>
|
||||||
<string name="double_tap_to_seek_settings">Dupla koppintás to seek</string>
|
<string name="double_tap_to_seek_settings">Dupla koppintás a kereséshez</string>
|
||||||
<string name="double_tap_to_pause_settings">Dupla koppintás a szüneteltetéshez</string>
|
<string name="double_tap_to_pause_settings">Dupla koppintás a szüneteltetéshez</string>
|
||||||
<string name="double_tap_to_seek_amount_settings">Player seek amount</string>
|
<string name="double_tap_to_seek_amount_settings">Lejátszó keresési értéke (Másodpercben)</string>
|
||||||
<string name="double_tap_to_seek_settings_des">Koppintson kétszer a jobb vagy bal oldalra az előre vagy hátra ugráshoz</string>
|
<string name="double_tap_to_seek_settings_des">Koppintson kétszer a jobb vagy bal oldalra az előre vagy hátra ugráshoz</string>
|
||||||
<string name="double_tap_to_pause_settings_des">Koppintson középre a szüneteltetéshez</string>
|
<string name="double_tap_to_pause_settings_des">Koppintson kétszer középen a szüneteltetéshez</string>
|
||||||
<string name="use_system_brightness_settings">Rendszer fényerejének használata</string>
|
<string name="use_system_brightness_settings">Rendszer fényerejének használata</string>
|
||||||
<string name="use_system_brightness_settings_des">Rendszer fényerejének használata az appban a sötét átfedés helyett</string>
|
<string name="use_system_brightness_settings_des">Rendszer fényerejének használata az appban a sötét átfedés helyett</string>
|
||||||
<string name="episode_sync_settings">Előrehaladás frissítése</string>
|
<string name="episode_sync_settings">Előrehaladás frissítése</string>
|
||||||
<string name="episode_sync_settings_des">Automatikusan szinkronizálja az aktuális epizód előrehaladását</string>
|
<string name="episode_sync_settings_des">Automatikusan szinkronizálja az aktuális epizód előrehaladását</string>
|
||||||
<string name="restore_settings">Adatok visszaállítása a biztonsági mentésből</string>
|
<string name="restore_settings">Adatok visszaállítása biztonsági mentésből</string>
|
||||||
<string name="restore_success">Biztonsági mentés betöltve</string>
|
<string name="restore_success">Biztonsági mentés betöltve</string>
|
||||||
<string name="settings_info">Információ</string>
|
<string name="settings_info">Információ</string>
|
||||||
<string name="resume">Folytatás</string>
|
<string name="resume">Folytatás</string>
|
||||||
<string name="go_back_30">-30</string>
|
<string name="go_back_30">-30</string>
|
||||||
<string name="update_started">Frissítés elkezdődött</string>
|
<string name="update_started">Frissítés elkezdődött</string>
|
||||||
<string name="restore_failed_format" formatted="true">Nem sikerült visszaállítani az adatok a fájlból %s</string>
|
<string name="restore_failed_format" formatted="true">Nem sikerült visszaállítani az adatokat a %s fájlból</string>
|
||||||
<string name="backup_failed">Tárolási engedélyek hiányoznak. Kérjük próbálja újra.</string>
|
<string name="backup_failed">Tárolási engedélyek hiányoznak. Kérjük próbálja újra.</string>
|
||||||
<string name="bug_report_settings_off">Csak összeomlásokról küld adatokat</string>
|
<string name="bug_report_settings_off">Csak összeomlásokról küld adatokat</string>
|
||||||
<string name="apk_installer_settings">APK Telepítő</string>
|
<string name="apk_installer_settings">APK Telepítő</string>
|
||||||
|
@ -280,7 +280,7 @@
|
||||||
<string name="dns_pref">DNS HTTPS-en keresztül</string>
|
<string name="dns_pref">DNS HTTPS-en keresztül</string>
|
||||||
<string name="browser">Böngésző</string>
|
<string name="browser">Böngésző</string>
|
||||||
<string name="pref_category_android_tv">Android TV</string>
|
<string name="pref_category_android_tv">Android TV</string>
|
||||||
<string name="pref_category_gestures">kézmozdulatok</string>
|
<string name="pref_category_gestures">Kézmozdulatok</string>
|
||||||
<string name="skip_update">frissítés kihagyása</string>
|
<string name="skip_update">frissítés kihagyása</string>
|
||||||
<string name="pref_category_app_updates">Alkalmazásfrissítések</string>
|
<string name="pref_category_app_updates">Alkalmazásfrissítések</string>
|
||||||
<string name="category_providers">Szolgáltatók</string>
|
<string name="category_providers">Szolgáltatók</string>
|
||||||
|
@ -496,4 +496,18 @@
|
||||||
<string name="quality_hq">HQ</string>
|
<string name="quality_hq">HQ</string>
|
||||||
<string name="plugins_downloaded" formatted="true">%d letöltve</string>
|
<string name="plugins_downloaded" formatted="true">%d letöltve</string>
|
||||||
<string name="start">Start</string>
|
<string name="start">Start</string>
|
||||||
|
<string name="emulator_layout">Emulátor elrendezés</string>
|
||||||
|
<string name="add_sync">Nyomkövetés hozzáadása</string>
|
||||||
|
<string name="phone_layout">Telefon elrendezés</string>
|
||||||
|
<string name="bottom_title_settings">Poszter cím helye</string>
|
||||||
|
<string name="bottom_title_settings_des">Tegye a címet a poszter alá</string>
|
||||||
|
<string name="android_tv_interface_off_seek_settings_summary">Az átugrás mértéke, amikor a lejátszó el van rejtve</string>
|
||||||
|
<string name="legal_notice">Jogi nyilatkozat</string>
|
||||||
|
<string name="android_tv_interface_on_seek_settings">Lejátszó megjelenítve - Ugrási Érték</string>
|
||||||
|
<string name="android_tv_interface_off_seek_settings">Lejátszó elrejtve - Ugrási Érték</string>
|
||||||
|
<string name="add_site_pref">Klónozott oldal</string>
|
||||||
|
<string name="add_site_summary">Egy meglévő webhely klónjának hozzáadása, más URL-címmel</string>
|
||||||
|
<string name="tv_layout">TV elrendezés</string>
|
||||||
|
<string name="automatic">Automatikus</string>
|
||||||
|
<string name="android_tv_interface_on_seek_settings_summary">Az átugrás mértéke, amikor a lejátszó látható</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -574,4 +574,6 @@
|
||||||
<string name="automatic_plugin_download_mode_title">Pilih mode untuk memfilter unduhan plugin</string>
|
<string name="automatic_plugin_download_mode_title">Pilih mode untuk memfilter unduhan plugin</string>
|
||||||
<string name="no_plugins_found_error">Tidak ada plugin yang ditemukan di repositori</string>
|
<string name="no_plugins_found_error">Tidak ada plugin yang ditemukan di repositori</string>
|
||||||
<string name="no_repository_found_error">Repositori tidak ditemukan, periksa URL dan coba VPN</string>
|
<string name="no_repository_found_error">Repositori tidak ditemukan, periksa URL dan coba VPN</string>
|
||||||
|
<string name="already_voted">Kamu sudah voting</string>
|
||||||
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -574,4 +574,5 @@
|
||||||
<string name="automatic_plugin_download_mode_title">Seleziona la modalità per filtrare il download dei plugin</string>
|
<string name="automatic_plugin_download_mode_title">Seleziona la modalità per filtrare il download dei plugin</string>
|
||||||
<string name="default_account">@string/default_subtitles</string>
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
<string name="disable">Disabilita</string>
|
<string name="disable">Disabilita</string>
|
||||||
|
<string name="already_voted">Hai già votato</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
556
app/src/main/res/values-my/strings.xml
Normal file
556
app/src/main/res/values-my/strings.xml
Normal file
|
@ -0,0 +1,556 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="cast_format" formatted="true">သရုပ်ဆောင်များ: %s</string>
|
||||||
|
<string name="next_episode_time_day_format" formatted="true">%dရက် %ddနာရီ %ddမိနစ်</string>
|
||||||
|
<string name="next_episode_time_hour_format" formatted="true">%ddနာရီ %ddမိနစ်</string>
|
||||||
|
<string name="next_episode_time_min_format" formatted="true">%ddမိနစ်</string>
|
||||||
|
<string name="search_poster_img_des">ပိုစတာ</string>
|
||||||
|
<string name="episode_poster_img_des">အပိုင်း ပိုစတာ</string>
|
||||||
|
<string name="home_main_poster_img_des">မိန်း ပိုစတာ</string>
|
||||||
|
<string name="home_next_random_img_des">နောက် ကျပန်း</string>
|
||||||
|
<string name="go_back_img_des">နောက်သို့</string>
|
||||||
|
<string name="preview_background_img_des">နောက်ခံပုံရိပ်ကို အကြိုကြည့်ရန်</string>
|
||||||
|
<string name="rated_format" formatted="true">အဆင့်: %.1f</string>
|
||||||
|
<string name="new_update_format" formatted="true">အပ်ဒိတ်အသစ်!
|
||||||
|
\n%s -> %s</string>
|
||||||
|
<string name="filler" formatted="true">စစ်ထုတ်မှု</string>
|
||||||
|
<string name="duration_format" formatted="true">%d မိနစ်</string>
|
||||||
|
<string name="app_name">CloudStream</string>
|
||||||
|
<string name="play_with_app_name">CloudStream ဖြင့်ကြည့်ရန်</string>
|
||||||
|
<string name="title_home">ပင်မ</string>
|
||||||
|
<string name="title_search">ရှာရန်</string>
|
||||||
|
<string name="search_hint">ရှာရန်…</string>
|
||||||
|
<string name="search_hint_site" formatted="true">ရှာရန် %s…</string>
|
||||||
|
<string name="no_data">အချက်အလက်မရှိပါ</string>
|
||||||
|
<string name="episode_more_options_des">အခြားရွေးစရာများ</string>
|
||||||
|
<string name="next_episode">နောက်အပိုင်း</string>
|
||||||
|
<string name="result_tags">ကဏ္ဍများ</string>
|
||||||
|
<string name="result_share">မျှဝေမည်</string>
|
||||||
|
<string name="result_open_in_browser">ဘရောက်ဇာတွင်ဖွင့်ရန်</string>
|
||||||
|
<string name="browser">ဘရောက်ဇာ</string>
|
||||||
|
<string name="skip_loading">မစောင့်တော့ပါ</string>
|
||||||
|
<string name="type_watching">ကြည့်နေသည်</string>
|
||||||
|
<string name="type_completed">ကြည့်ပြီး</string>
|
||||||
|
<string name="type_dropped">ကြည့်ခြင်းရပ်ထားသော</string>
|
||||||
|
<string name="type_none">ဘာမျှ</string>
|
||||||
|
<string name="error_loading_links_toast">လင့်များချိတ်ဆက်ရာတွင်အချို့အယွင်း</string>
|
||||||
|
<string name="download_storage_text">ဖုန်း သိုလှောင်ရုံ</string>
|
||||||
|
<string name="filter_bookmarks">စာမှတ်များ စစ်ထုတ်မှု</string>
|
||||||
|
<string name="error_bookmarks_text">စာမှတ်များ</string>
|
||||||
|
<string name="action_remove_from_bookmarks">ဖယ်ရှားရန်</string>
|
||||||
|
<string name="action_add_to_bookmarks">ကြည့်ရှုမှုအခြေအနေသတ်မှတ်ခြင်း</string>
|
||||||
|
<string name="sort_copy">မိတ္တူကူးရန်</string>
|
||||||
|
<string name="sort_close">ပိတ်ရန်</string>
|
||||||
|
<string name="sort_clear">ရှင်းလင်းရန်</string>
|
||||||
|
<string name="sort_save">သိမ်းဆည်းရန်</string>
|
||||||
|
<string name="player_speed">ကြည့်ရှုမှုအရှိန်</string>
|
||||||
|
<string name="subs_background_color">နောက်ခံ အရောင်</string>
|
||||||
|
<string name="subs_window_color">ဝင်းဒိုး အရောင်</string>
|
||||||
|
<string name="subs_edge_type">အစွန်းနားပုံစံ</string>
|
||||||
|
<string name="subs_subtitle_elevation">စာတန်းထိုး အမြင့်</string>
|
||||||
|
<string name="subs_font">ဖောင့်</string>
|
||||||
|
<string name="subs_font_size">ဖောင့် အရွယ်အစား</string>
|
||||||
|
<string name="search_provider_text_types">အမျိုးအစားများအသုံးပြု၍ရှာရန်</string>
|
||||||
|
<string name="benene_count_text">%d အက်ပ်ဖန်တီးသူတွေကိုကျေးဇူးတင်ကြောင်းပို့မည်</string>
|
||||||
|
<string name="subs_auto_select_language">အလိုအလျောက် ဘာသာစကားရွေးချယ်ခြင်း</string>
|
||||||
|
<string name="subs_download_languages">ဒေါင်းလုဒ် လုပ်ထားသော ဘာသာစကားများ</string>
|
||||||
|
<string name="subs_hold_to_reset_to_default">မူရင်းပုံစံအတိုင်းပြန်ထားရန်ဖိထားပါ</string>
|
||||||
|
<string name="continue_watching">ဆက်လက်ကြည့်ရှုမည်</string>
|
||||||
|
<string name="action_remove_watching">ဖယ်ရှားရန်</string>
|
||||||
|
<string name="action_open_watching">ပိုမို၍</string>
|
||||||
|
<string name="action_open_play">@string/home_play</string>
|
||||||
|
<string name="vpn_torrent">ဒီဟာကတောရပ်တစ်ခုပါ ဗီပီအန်တစ်ခုသုံးဖို့အကြံပြုပါတယ်</string>
|
||||||
|
<string name="torrent_plot">ဖော်ပြချက်</string>
|
||||||
|
<string name="normal_no_plot">ဇာတ်လမ်းသွား မတွေ့ပါ</string>
|
||||||
|
<string name="torrent_no_plot">ဖော်ပြချက် မရိှပါ</string>
|
||||||
|
<string name="show_log_cat">Logcat ပြရန် 🐈</string>
|
||||||
|
<string name="test_log">Log</string>
|
||||||
|
<string name="picture_in_picture">ရုပ်ပုံထပ်</string>
|
||||||
|
<string name="player_size_settings">ကြည့်ရှုမှု စခရင်အရွယ်အစားချိန်ညိှမှု</string>
|
||||||
|
<string name="player_subtitles_settings">စာတန်းထိုးများ</string>
|
||||||
|
<string name="player_subtitles_settings_des">ကြည့်ရှုမှုစာတန်းထိုးပြုပြင်စရာများ</string>
|
||||||
|
<string name="eigengraumode_settings">Eigengravy လုပ်ဆောင်မှု</string>
|
||||||
|
<string name="swipe_to_seek_settings">ရစ်ရန်ဘယ်ညာဆွဲပါ</string>
|
||||||
|
<string name="swipe_to_seek_settings_des">သင်ရောက်နေတဲ့နေရာပြောင်းရန်ဘယ်ညာဆွဲပါ</string>
|
||||||
|
<string name="swipe_to_change_settings">ပြုပြင်စရာရိှပါက ပွတ်ဆွဲပါ</string>
|
||||||
|
<string name="autoplay_next_settings">နောက်အပိုင်းကို အလိုအလျောက် ဖွင့်ပါ</string>
|
||||||
|
<string name="double_tap_to_seek_settings">ကျော်ရန်နှစ်ချက်နှိပ်ပါ</string>
|
||||||
|
<string name="double_tap_to_pause_settings">ရပ်ရန်နှစ်ချက်နှိပ်ပါ</string>
|
||||||
|
<string name="double_tap_to_seek_amount_settings">ကျော်လိုသောပမာဏ (စက္ကန့်များ)</string>
|
||||||
|
<string name="double_tap_to_seek_settings_des">ရှေ့သို့ကျော်ရန် သို့ နောက်သို့ရစ်ရန် ဘယ် သို့ ညာ ပေါ်မှာနှစ်ချက်နှိပ်ပါ</string>
|
||||||
|
<string name="double_tap_to_pause_settings_des">ရပ်ရန် အလယ်တွင်နှစ်ချက်နှိပ်ပါ</string>
|
||||||
|
<string name="use_system_brightness_settings">ဖုန်းအလင်းအမှောင်အတိုင်းသုံးမည်</string>
|
||||||
|
<string name="use_system_brightness_settings_des">အက်ပ်ကြည့်ရှုမှုထဲမှာ ဖုန်းအလင်းအမှောင်အတိုင်းသုံးမည်</string>
|
||||||
|
<string name="episode_sync_settings">ကြည့်ရှုမှုတိုးတက်ခြင်းကိုအပ်ဒိတ်လုပ်ပါ</string>
|
||||||
|
<string name="restore_settings">အရန်သိမ်းဖိုင်မှပြန်သိုလှောင်မည်</string>
|
||||||
|
<string name="backup_settings">အရန်သိမ်းမည်</string>
|
||||||
|
<string name="restore_success">အရန်သိမ်းဖိုင်များရယူပြီး</string>
|
||||||
|
<string name="restore_failed_format" formatted="true">အရန်သိမ်းဖိုင်မှပြန်သိုလှောငးခြင်မအောင်မြင်ပါ %s</string>
|
||||||
|
<string name="backup_success">သိုလှောင်ပြီး</string>
|
||||||
|
<string name="backup_failed">သိုလှောင်ရုံခွင့်ပြုချက်မရိှပါ။ပြန်ကြိုးစားပါ။</string>
|
||||||
|
<string name="backup_failed_error_format">အရန်သိမ်းနေစဥ်အချို့အယွင်း %s</string>
|
||||||
|
<string name="library">လိုက်ဘရီ</string>
|
||||||
|
<string name="category_updates">အပ်ဒိတ်များနှင့်အရန်သိမ်းဆည်းမှု</string>
|
||||||
|
<string name="advanced_search">နက်နက်ရှိုင်းရှိုင်းရှာခြင်း</string>
|
||||||
|
<string name="advanced_search_des">သင့်ကိုဝန်ဆောင်မှုပေးသူအလိုက်ရှာဖွေမှုရလဒ်များပေးမည်</string>
|
||||||
|
<string name="bug_report_settings_off">ချို့ယွင်းမှုအကြီးစားဖြစ်မှသာဒေတာများပေးပို့ပါ</string>
|
||||||
|
<string name="show_fillers_settings">anime များအတွက်ဖြည့်စွက်အပိုင်းကိုပြရန်</string>
|
||||||
|
<string name="show_trailers_settings">ထွေလာများကိုပြရန်</string>
|
||||||
|
<string name="kitsu_settings">Kitsu မှ ပိုစတာများကိုပြရန်</string>
|
||||||
|
<string name="automatic_plugin_updates">အလိုအလျောက် ဖြည့်စွက်လုပ်ဆောင်ချက်များကိုအပ်ဒိတ်တင်ခြင်း</string>
|
||||||
|
<string name="automatic_plugin_download_mode_title">အပိုလုပ်ဆောင်ချက်များကိုစစ်ထုတ်ရန်မုဒ်ရွေးပါ</string>
|
||||||
|
<string name="updates_settings">အက်ပ်အပ်ဒိတ်များပြရန်</string>
|
||||||
|
<string name="redo_setup_process">အစီအစဥ်ချခြင်းကိုပြန်စမည်</string>
|
||||||
|
<string name="apk_installer_settings">အက်ပ်ထည့်သွင်းခြင်း</string>
|
||||||
|
<string name="apk_installer_settings_des">အချို့ဖုန်းတွေက အက်ပ်ထည့်သွင်းခြင်းလုပ်ဆောင်ချက်အသစ်ကို မပံ့ပိုးပါဘူး။အကယ်၍အလုပ်မဖြစ်ပါကသမားရိုးကျနည်းလမ်းကိုအသုံးပြုပါ။</string>
|
||||||
|
<string name="github">Github</string>
|
||||||
|
<string name="no_chromecast_support_toast">ဤဝန်ဆောင်မှုပေးသူသည် Chromecast ကိုမပံ့ပိုးပါ</string>
|
||||||
|
<string name="no_links_found_toast">လင့်များမတွေ့ပါ</string>
|
||||||
|
<string name="copy_link_toast">ကလစ်ဘုတ်သို့မိတ္တူကူးပြီး</string>
|
||||||
|
<string name="play_episode_toast">အပိုင်းကြည့်မည်</string>
|
||||||
|
<string name="season">အတွဲ</string>
|
||||||
|
<string name="no_season">အတွဲမရှိပါ</string>
|
||||||
|
<string name="episode">အပိုင်း</string>
|
||||||
|
<string name="episodes">အပိုင်းများ</string>
|
||||||
|
<string name="episodes_range">%d-%d</string>
|
||||||
|
<string name="delete_message" formatted="true">ဒါကအပြီးဖျက်ခြင်းဖြစ်ပါသည် %s
|
||||||
|
\nသင်သေချာပါသလား။</string>
|
||||||
|
<string name="resume_time_left" formatted="true">%dမိနစ်
|
||||||
|
\nကျန်ရိှသည်</string>
|
||||||
|
<string name="status_ongoing">ထုတ်လွှင့်နေဆဲ</string>
|
||||||
|
<string name="status_completed">ထုတ်လွှင့်မှုပြီးဆုံး</string>
|
||||||
|
<string name="status">အခြေအနေ</string>
|
||||||
|
<string name="year">ခုနစ်</string>
|
||||||
|
<string name="rating">အဆင့်သတ်မှတ်ချက်</string>
|
||||||
|
<string name="duration">ကြာချိန်</string>
|
||||||
|
<string name="site">ဆိုဒ်</string>
|
||||||
|
<string name="synopsis">အကျဥ်းချုပ်</string>
|
||||||
|
<string name="queued">နောက်အစီအစဥ်</string>
|
||||||
|
<string name="no_subtitles">စာတန်းထိုးမထည့်</string>
|
||||||
|
<string name="default_subtitles">ပုံသေ</string>
|
||||||
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
|
<string name="free_storage">ကျန်ရှိသော</string>
|
||||||
|
<string name="app_storage">အက်ပ်</string>
|
||||||
|
<string name="movies">ရုပ်ရှင်များ</string>
|
||||||
|
<string name="tv_series">ဇာတ်လမ်းတွဲများ</string>
|
||||||
|
<string name="cartoons">ကာတွန်းများ</string>
|
||||||
|
<string name="anime">Anime</string>
|
||||||
|
<string name="torrent">ေတာရပ်များ</string>
|
||||||
|
<string name="documentaries">မှတ်တမ်းရုပ်ရှင်များ</string>
|
||||||
|
<string name="ova">OVA</string>
|
||||||
|
<string name="asian_drama">အာရှ ဒရာမာများ</string>
|
||||||
|
<string name="livestreams">တိုက်ရိုက်ထုတ်လွှင်မှုများ</string>
|
||||||
|
<string name="nsfw">အပြာဗီဒီယိုများ</string>
|
||||||
|
<string name="others">အခြား</string>
|
||||||
|
<string name="movies_singular">ရုပ်ရှင်</string>
|
||||||
|
<string name="tv_series_singular">ဇာတ်လမ်းတွဲ</string>
|
||||||
|
<string name="ova_singular">OVA</string>
|
||||||
|
<string name="torrent_singular">တောရပ်</string>
|
||||||
|
<string name="documentaries_singular">မှတ်တမ်းရုပ်ရှင်</string>
|
||||||
|
<string name="asian_drama_singular">အာရှ ဒရာမာ</string>
|
||||||
|
<string name="live_singular">တိုက်ရိုက်ထုတ်လွှင့်မှု</string>
|
||||||
|
<string name="nsfw_singular">အပြာဗီဒီယို</string>
|
||||||
|
<string name="other_singular">ဗီဒီယို</string>
|
||||||
|
<string name="source_error">ရင်းမြစ်အချို့အယွင်း</string>
|
||||||
|
<string name="remote_error">အဝေးထိန်းချုပ်မှုအချို့အယွင်း</string>
|
||||||
|
<string name="render_error">တင်ဆက်သူ အချို့အယွင်း</string>
|
||||||
|
<string name="unexpected_error">မျှော်လင့်မထားသော အချို့အယွင်း</string>
|
||||||
|
<string name="episode_action_chromecast_episode">Chromecast အပိုင်း</string>
|
||||||
|
<string name="episode_action_chromecast_mirror">Chromecast ဖန်သားပြင်</string>
|
||||||
|
<string name="episode_action_play_in_app">အက်ပ်တွင်းဖွင့်</string>
|
||||||
|
<string name="episode_action_play_in_format">ဖွင့်ရန် %s</string>
|
||||||
|
<string name="episode_action_play_in_browser">ဘရောက်ဇာထဲမှာ ဖွင့်ရန်</string>
|
||||||
|
<string name="episode_action_copy_link">လင့်ကူးယူရန်</string>
|
||||||
|
<string name="episode_action_auto_download">အလိုအလျောက်ဒေါင်းလုဒ်</string>
|
||||||
|
<string name="episode_action_reload_links">လင့်များကို ပြန်စစ်ရန်</string>
|
||||||
|
<string name="show_hd">အရည်အသွေး အမှတ်အသား</string>
|
||||||
|
<string name="show_dub">နောက်ခံအသံ အမှတ်အသား</string>
|
||||||
|
<string name="show_sub">စာတန်း အမှတ်အသား</string>
|
||||||
|
<string name="show_title">ခေါင်းစဥ်</string>
|
||||||
|
<string name="no_update_found">အပ်ဒိတ်မရှိပါ</string>
|
||||||
|
<string name="check_for_update">အပ်ဒိတ်စစ်ရန်</string>
|
||||||
|
<string name="video_lock">လော့ခ်ခတ်ရန်</string>
|
||||||
|
<string name="video_source">ရင်းမြစ်</string>
|
||||||
|
<string name="video_skip_op">OPကိုကျော်ရန်</string>
|
||||||
|
<string name="skip_update">ဒီအပ်ဒိတ်ကိုကျော်ပါ</string>
|
||||||
|
<string name="update">အပ်ဒိတ်</string>
|
||||||
|
<string name="limit_title">ခေါင်းစဥ်အတွက်စာလုံးရေပြည့်ခြင်း</string>
|
||||||
|
<string name="limit_title_rez">ကြည့်ရှုမှု အရည်အသွေး</string>
|
||||||
|
<string name="video_buffer_size_settings">ဗီဒီယိုရှေ့ပြေးသိမ်းဆည်းမှုပမာဏ</string>
|
||||||
|
<string name="android_tv_interface_on_seek_settings_summary">ကြည့်ရှုမှုဘားမြင်တွေ့ရချိန်တွင်ပြသသောပမာဏ</string>
|
||||||
|
<string name="android_tv_interface_off_seek_settings">ဝှက်ထားသောကြည့်ရှုပြီးသောပမာဏ</string>
|
||||||
|
<string name="android_tv_interface_off_seek_settings_summary">ဝှက်ထားသည့်အခါ အသုံးပြုသည့် ရှာဖွေမှုပမာဏ</string>
|
||||||
|
<string name="video_ram_description">Android TV ကဲ့သို့သော မမ်မိုရီနည်းသော စက်ပစ္စည်းများတွင် သတ်မှတ်နှုန်း အလွန်မြင့်မားပါက ပျက်စီးမှုများ ဖြစ်စေသည်။</string>
|
||||||
|
<string name="dns_pref">DNS over HTTPS</string>
|
||||||
|
<string name="jsdelivr_proxy">raw.githubusercontent.com ပရောက်စီ</string>
|
||||||
|
<string name="jsdelivr_enabled">GitHub သို့ မရောက်ရှိနိုင်ပါ။ jsDelivr ပရောက်စီကို ဖွင့်နေသည်…</string>
|
||||||
|
<string name="add_site_pref">ကလုန်း ဆိုဒ်</string>
|
||||||
|
<string name="remove_site_pref">ဆိုဒ်ကိုဖယ်ရှားရန်</string>
|
||||||
|
<string name="add_site_summary">မတူညီသော URL တစ်ခုဖြင့် ရှိပြီးသား ဝဘ်ဆိုက်တစ်ခု၏ ပုံတူတစ်ခုကို ထည့်ပါ</string>
|
||||||
|
<string name="download_path_pref">ဒေါင်းလုဒ်လမ်းကြောင်း</string>
|
||||||
|
<string name="nginx_url_pref">NGINX ဆာဗာ URL</string>
|
||||||
|
<string name="display_subbed_dubbed_settings">Dubbed/Subbed Anime ကိုပြသပါ</string>
|
||||||
|
<string name="resize_fit">မျက်နှာပြင်နှင့် အံကိုက်</string>
|
||||||
|
<string name="resize_fill">ဆန့်သည်</string>
|
||||||
|
<string name="resize_zoom">ချဲ့သည်</string>
|
||||||
|
<string name="legal_notice">ရှင်းလင်းချက်</string>
|
||||||
|
<string name="pref_category_bypass">ISP ရှောင်လွှဲမှုများ</string>
|
||||||
|
<string name="pref_category_links">လင့်များ</string>
|
||||||
|
<string name="pref_category_app_updates">အက်ပ်အပ်ဒိတ်များ</string>
|
||||||
|
<string name="pref_category_extensions">Extensions</string>
|
||||||
|
<string name="pref_category_actions">ဆောင်ရွက်ချက်များ</string>
|
||||||
|
<string name="pref_category_cache">Cache</string>
|
||||||
|
<string name="pref_category_android_tv">Android တီဗွီ</string>
|
||||||
|
<string name="pref_category_subtitles">စာတန်းထိုးများ</string>
|
||||||
|
<string name="pref_category_defaults">ပုံသေများ</string>
|
||||||
|
<string name="pref_category_looks">ပုံပန်းသဏ္ဌာန်</string>
|
||||||
|
<string name="category_general">အထွေထွေ</string>
|
||||||
|
<string name="random_button_settings_desc">ပင်မစာမျက်နှာမှာကျပန်းခလုတ်ကိုပြပါ</string>
|
||||||
|
<string name="app_dub_sub_episode_text_format" formatted="true">%s အပိုင်း %d</string>
|
||||||
|
<string name="next_episode_format" formatted="true">အပိုင်း %d ထုတ်လွှင့်ပြသမည်</string>
|
||||||
|
<string name="result_poster_img_des">ပိုစတာ</string>
|
||||||
|
<string name="home_change_provider_img_des">ပံ့ပိုးပေးသောဝန်ဆောင်မှုပြောင်းရန်</string>
|
||||||
|
<string name="player_speed_text_format" formatted="true">အရှိန် (%.2fx)</string>
|
||||||
|
<string name="title_downloads">ဒေါင်းလုဒ်များ</string>
|
||||||
|
<string name="title_settings">ပြင်ဆင်ရန်</string>
|
||||||
|
<string name="loading">ခဏစောင့်ပါ…</string>
|
||||||
|
<string name="type_on_hold">ကြည့်ဆဲ</string>
|
||||||
|
<string name="type_plan_to_watch">ကြည့်ရန်</string>
|
||||||
|
<string name="type_re_watching">ပြန်ကြည့်နေသည်</string>
|
||||||
|
<string name="pick_subtitle">စာတန်းထိုး</string>
|
||||||
|
<string name="play_movie_button">ရုပ်ရှင်ကြည့်မည်</string>
|
||||||
|
<string name="play_trailer_button">ထွေလာ ကြည့်မည်</string>
|
||||||
|
<string name="play_livestream_button">လိုက်ခ် ကြည့်မည်</string>
|
||||||
|
<string name="play_torrent_button">တောရပ် ကြည့်မည်</string>
|
||||||
|
<string name="pick_source">ရင်းမြစ်များ</string>
|
||||||
|
<string name="reload_error">ချိတ်ဆက်မှုပြန်ကြိုးစား…</string>
|
||||||
|
<string name="go_back">နောက်သို့</string>
|
||||||
|
<string name="play_episode">အပိုင်း ကြည့်မည်</string>
|
||||||
|
<string name="download">ဒေါင်းလုဒ်</string>
|
||||||
|
<string name="downloaded">ဒေါင်းလုဒ် လုပ်ပြီး</string>
|
||||||
|
<string name="downloading">ဒေါင်းလုဒ် လုပ်နေသည်</string>
|
||||||
|
<string name="download_paused">ဒေါင်းလုဒ် ရပ်ထား</string>
|
||||||
|
<string name="download_started">ဒေါင်းလုဒ်စတင်</string>
|
||||||
|
<string name="download_failed">ဒေါင်းလုဒ် မအောင်မြင်</string>
|
||||||
|
<string name="download_canceled">ဒေါင်းလုဒ် ပယ်ဖျက်ပြီး</string>
|
||||||
|
<string name="download_done">ဒေါင်းလုဒ်ပြီးစီး</string>
|
||||||
|
<string name="update_started">အပ်ဒိတ်စတင်</string>
|
||||||
|
<string name="stream">တိုက်ရိုက်ကြည့်မည်</string>
|
||||||
|
<string name="app_dubbed_text">နောက်ခံအသံ</string>
|
||||||
|
<string name="pref_filter_search_quality">ရှာဖွေမှုရလဒ်များတွင်ရွေးချယ်ထားသောဗီဒီယိုအရည်အသွေးကိုဝှက်ထားရန်</string>
|
||||||
|
<string name="app_subbed_text">စာတန်းထိုး</string>
|
||||||
|
<string name="popup_delete_file">ဖိုင်ဖျက်ရန်</string>
|
||||||
|
<string name="popup_play_file">ဖိုင်ကို ဖွင့်ရန်</string>
|
||||||
|
<string name="popup_resume_download">ဒေါင်းလုဒ် ဆက်လုပ်ရန်</string>
|
||||||
|
<string name="popup_pause_download">ဒေါင်းလုဒ် ရပ်ရန်</string>
|
||||||
|
<string name="pref_disable_acra">အလိုအလျောက်အက်ပ်ချို့ယွင်းချက်ပေးပို့ခြင်းကိုပိတ်မည်</string>
|
||||||
|
<string name="home_more_info">ပိုမို၍</string>
|
||||||
|
<string name="search_provider_text_providers">ပ့ံပိုးပေးသောဝန်ဆောင်မှုများအသုံးပြု၍ရှာရန်</string>
|
||||||
|
<string name="home_expanded_hide">ဝုက်ရန်</string>
|
||||||
|
<string name="benene_count_text_none">ကျေးဇူးတင်ကြောင်းမပို့ရသေး</string>
|
||||||
|
<string name="home_play">ကြည့်မည်</string>
|
||||||
|
<string name="home_info">အချက်အလက်</string>
|
||||||
|
<string name="subs_subtitle_languages">စာတန်းထိုး ဘာသာစကား</string>
|
||||||
|
<string name="subs_import_text" formatted="true">ဒီမှာနေရာချခြင်းဖြင့်ဖောင့်များကိုသွင်းပါ %s</string>
|
||||||
|
<string name="sort_apply">အတည်ပြု</string>
|
||||||
|
<string name="sort_cancel">ပယ်ဖျက်ရန်</string>
|
||||||
|
<string name="subtitles_settings">စာတန်းထိုး ပြုပြင်ခြင်း</string>
|
||||||
|
<string name="subs_text_color">စာသား အရောင်</string>
|
||||||
|
<string name="subs_outline_color">အနားကွပ် အရောင်</string>
|
||||||
|
<string name="vpn_might_be_needed">ဒီပံ့ပိုးမှုကောင်းမွန်စွာအလုပ်လုပ်ရန်ဗီပီအန်တစ်ခုလိုနိုင်ပါတယ်</string>
|
||||||
|
<string name="provider_info_meta">အသေးစိတ်အချက်အလက်များပြမထားပါ။ဝဘ်ဆိုဒ်ပေါ်မှာမရှိလျှင်ကြည့်ရှု၍မရနိုင်ပါ။</string>
|
||||||
|
<string name="automatic_plugin_download">ဖြည့်စွက်လုပ်ဆောင်ချက်များကို အလိုအလျောက်ဒေါင်းလုဒ်လုပ်ခြင်း</string>
|
||||||
|
<string name="automatic_plugin_download_summary">ရီပိုစစ်ထရီများမှမထည့်သွင်းရသေးသောဖြည့်စွက်လုပ်ဆောင်ချက်များအားလုံးကိုထည့်သွင်းပါ။</string>
|
||||||
|
<string name="picture_in_picture_des">ပြန်ကြည့်ခြင်းကိုအသေးစား ကြည့်ရှုမှုတွင်ဆက်ပြပါ</string>
|
||||||
|
<string name="player_size_settings_des">အနက်ရောင်ဘောင်များကို ဖယ်ရှားရန်</string>
|
||||||
|
<string name="updates_settings_des">အက်ပ်ထဲဝင်လိုက်သည့်နှင့်အက်ပ်အပ်ဒိတ်ကိုစစ်ဆေးပါ။</string>
|
||||||
|
<string name="chromecast_subtitles_settings">Chromecast စာတန်းထိုးများ</string>
|
||||||
|
<string name="chromecast_subtitles_settings_des">Chromecast စာတန်းထိုး ပြုပြင်ရန်</string>
|
||||||
|
<string name="eigengraumode_settings_des">ကြည့်ရှုမှုပုံစံထဲမှာအရိှန်ရွေးစရာတစ်ခုထည့်ရန်</string>
|
||||||
|
<string name="swipe_to_change_settings_des">အသံအတိုးအကျယ်နှင့်အလင်းအမှောင်များကိုချိန်ညိှရန် ဘယ် သို့ ညာ ဘက်တွင် အပေါ်အောက်ဆွဲပါ</string>
|
||||||
|
<string name="autoplay_next_settings_des">ယခုကြည့်နေသောအပိုင်းပြီးပါကနောက်အပိုင်းကိုဖွင့်ပါ</string>
|
||||||
|
<string name="episode_sync_settings_des">သင့်၏အပိုင်းကြည်ရှုမှုရောက်ရှိနေရာကိုအလိုအလျောက်သိမ်းဆည်းပါ</string>
|
||||||
|
<string name="search">ရှာရန်</string>
|
||||||
|
<string name="category_account">အကောင့်များ</string>
|
||||||
|
<string name="settings_info">အချက်အလက်</string>
|
||||||
|
<string name="bug_report_settings_on">ဒေတာများမပို့ရန်</string>
|
||||||
|
<string name="android_tv_interface_on_seek_settings">ကြည့်ရှုပြီးသောအချိန်ပမာဏ</string>
|
||||||
|
<string name="video_disk_description">Android TV ကဲ့သို့သော သိုလှောင်မှုနေရာနည်းပါးသော စက်ပစ္စည်းများတွင် အလွန်မြင့်မားစွာ သတ်မှတ်ပါက ပြဿနာများ ဖြစ်လာနိုင်သည်။</string>
|
||||||
|
<string name="dns_pref_summary">ISP ပိတ်ဆို့ခြင်းကို ကျော်လွှားရန်အတွက် အသုံးဝင်သည်</string>
|
||||||
|
<string name="jsdelivr_proxy_summary">jsDelivr ကို အသုံးပြု၍ GitHub ပိတ်ဆို့ခြင်းကို ကျော်ဖြတ်သည်။ အပ်ဒိတ်များကို ရက်အနည်းငယ်ကြာအောင် နှောင့်နှေးစေနိုင်သည်။</string>
|
||||||
|
<string name="pref_category_backup">အရန်သိမ်းထားသော</string>
|
||||||
|
<string name="pref_category_gestures">လက်ဟန်များ</string>
|
||||||
|
<string name="pref_category_player_features">ကြည့်ရှုမှုလုပ်ဆောင်ချက်များ</string>
|
||||||
|
<string name="pref_category_player_layout">အပြင်အဆင်</string>
|
||||||
|
<string name="pref_category_ui_features">လုပ်ဆောင်ချက်များ</string>
|
||||||
|
<string name="random_button_settings">ကျပန်းခလုတ်</string>
|
||||||
|
<string name="uprereleases_settings">ရှေ့ပြေးအပ်ဒိတ်များကိုထည့်သွင်းပါ</string>
|
||||||
|
<string name="uprereleases_settings_des">ပုံမှန်အပ်ဒိတ်များအစား ရှေ့ပြေးအက်ဒိတ်များကိုရှာပါ</string>
|
||||||
|
<string name="lightnovel">တူညီသောအက်ပ်ရေးသားသူများ၏ ဝတ္ထုရှည်များဖတ်နိုင်သည့် အက်ပ်</string>
|
||||||
|
<string name="anim">တူညီသောအက်ပ်ရေးသားသူများ၏ Anime အက်ပ်</string>
|
||||||
|
<string name="discord">Discord ကိုဝင်ရန်</string>
|
||||||
|
<string name="benene">အက်ပ်ရေးသားသူများထံ ကျေးဇူးတင်စာပို့မည်</string>
|
||||||
|
<string name="benene_des">ပေးခဲ့သောစာအရေအတွက်</string>
|
||||||
|
<string name="app_language">အက်ပ်ဘာသာစကား</string>
|
||||||
|
<string name="subs_default_reset_toast">မူလအခြေအနေများကိုပြန်ထားပါ</string>
|
||||||
|
<string name="acra_report_toast">စိတ်မကောင်းပါ။အက်ပ်ရပ်တန့်သွားပါတယ်။အမည်မဖော်ထားတဲ့တင်ပြချက်ကို အက်ပ်ရေးသားသူများထံ ပို့မှာဖြစ်ပါတယ်</string>
|
||||||
|
<string name="season_format">%s %d%s</string>
|
||||||
|
<string name="season_short">အတွဲ</string>
|
||||||
|
<string name="episode_format" formatted="true">%d %s</string>
|
||||||
|
<string name="episode_short">အပိုင်း</string>
|
||||||
|
<string name="no_episodes_found">အပိုင်းများမတွေ့ပါ</string>
|
||||||
|
<string name="delete_file">ဖိုင်ကိုဖျက်ရန်</string>
|
||||||
|
<string name="delete">ဖျက်ရန်</string>
|
||||||
|
<string name="pause">ရပ်ရန်</string>
|
||||||
|
<string name="start">စရန်</string>
|
||||||
|
<string name="test_failed">မအောင်မြင်ပါ</string>
|
||||||
|
<string name="test_passed">ကျော်ဖြတ်ပြီး</string>
|
||||||
|
<string name="resume">ကြည့်လက်စ</string>
|
||||||
|
<string name="go_back_30">-30</string>
|
||||||
|
<string name="go_forward_30">+30</string>
|
||||||
|
<string name="used_storage">အသုံးပြုပြီးသော</string>
|
||||||
|
<string name="cartoons_singular">ကာတွန်း</string>
|
||||||
|
<string name="anime_singular">Anime</string>
|
||||||
|
<string name="storage_error">ဒေါင်းလုဒ် အချို့အယွင်း၊သိုလှောင်ရုံခွင့်ပြုချက်တွေကိုစစ်ဆေးပါ</string>
|
||||||
|
<string name="episode_action_download_mirror">ဒေါင်းလုဒ် ကြေးမုံ</string>
|
||||||
|
<string name="episode_action_download_subtitle">စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ရန်</string>
|
||||||
|
<string name="poster_ui_settings">ပိုစတာပေါ်ရှိ UI အစိတ်အပိုင်းများကို ပြောင်းပါ</string>
|
||||||
|
<string name="video_aspect_ratio_resize">ပြန်ညိှ</string>
|
||||||
|
<string name="dont_show_again">နောက်ထပ်မပြရန်</string>
|
||||||
|
<string name="watch_quality_pref">ဝိုင်ဖိုင်ဖြင့်ကြည့်စဥ်ဗီဒီယိုအရည်အသွေး</string>
|
||||||
|
<string name="watch_quality_pref_data">မိုဘိုင်းဒေတာဖြင့်ကြည့်စဥ်ဗီဒီယိုအရည်အသွေး</string>
|
||||||
|
<string name="video_buffer_length_settings">ဗီဒီယိုရှေ့ပြေးသိမ်းဆည်းမှုအကွာအဝေး</string>
|
||||||
|
<string name="video_buffer_disk_settings">ဗီဒီယိုcacheအများ</string>
|
||||||
|
<string name="video_buffer_clear_settings">ဗီဒီယို cache နှင့် ရုပ်ပုံ cache များကိူရှင်းလင်းရန်</string>
|
||||||
|
<string name="enable_nsfw_on_providers">ပံ့ပိုးပေးထားသည့် ဝန်ဆောင်မှုများပေါ်တွင် အပြာဗီဒီယို ကို ဖွင့်ပါ</string>
|
||||||
|
<string name="provider_lang_settings">ဝန်ဆောင်မှုပံ့ပိုးသူဘာသာစကား</string>
|
||||||
|
<string name="app_layout">အက်ပ်အပြင်အဆင်</string>
|
||||||
|
<string name="preferred_media_settings">ဦးစားပေးမီဒီယာ</string>
|
||||||
|
<string name="app_theme_settings">အက်ပ် အပြင်အဆင်</string>
|
||||||
|
<string name="bottom_title_settings">ပိုစတာခေါင်းစဉ်တည်နေရာ</string>
|
||||||
|
<string name="bottom_title_settings_des">ခေါင်းစဉ်ကို ပိုစတာအောက်မှာ ထားပါ</string>
|
||||||
|
<string name="phone_layout">ဖုန်းအပြင်အဆင်</string>
|
||||||
|
<string name="emulator_layout">အင်မြူလိတ်တာ အပြင်အဆင်</string>
|
||||||
|
<string name="primary_color_settings">အဓိကအရောင်</string>
|
||||||
|
<string name="recommended">အကြံပြုသည်</string>
|
||||||
|
<string name="quality_dvd">ဒီဗွီဒီ</string>
|
||||||
|
<string name="quality_4k">4K</string>
|
||||||
|
<string name="network_adress_example">ထုတ်လွှင့်ရန် လင့်ခ် နှင့်ချိတ်ပါ</string>
|
||||||
|
<string name="referer">ရည်ညွှန်းသည်</string>
|
||||||
|
<string name="next">ရှေ့သို့</string>
|
||||||
|
<string name="previous">နောက်သို့</string>
|
||||||
|
<string name="plugins_updated" formatted="true">အပ်ဒိတ်လုပ်ပြီး %d ဖြည့်စွက်များ</string>
|
||||||
|
<string name="plugins_not_downloaded" formatted="true">ဒေါင်းလုဒ်မလုပ်ရသေး: %d</string>
|
||||||
|
<string name="player_settings_play_in_browser">ဝဘ်ဘရောက်ဇာ</string>
|
||||||
|
<string name="app_not_found_error">အက်ပ်မတွေ့ပါ</string>
|
||||||
|
<string name="all_languages_preference">ဘာသာစကားအားလုံး</string>
|
||||||
|
<string name="skip_type_format" formatted="true">ကျော်ရန် %s</string>
|
||||||
|
<string name="skip_type_recap">အစမှပြန်စ</string>
|
||||||
|
<string name="skip_type_mixed_ed">ရောထားသောအဆုံးပိုင်း</string>
|
||||||
|
<string name="skip_type_mixed_op">ရောထားသောအစပိုင်း</string>
|
||||||
|
<string name="skip_type_creddits">ခရက်ဒစ်များ</string>
|
||||||
|
<string name="skip_type_intro">အစ</string>
|
||||||
|
<string name="yes">သေချာသည်</string>
|
||||||
|
<string name="apk_installer_legacy">သမားရိုးကျ</string>
|
||||||
|
<string name="apk_installer_package_installer">ထည့်သွင်းသူ</string>
|
||||||
|
<string name="delayed_update_notice">ထွက်ချိန်တွင် အက်ပ်ကို အပ်ဒိတ်လုပ်ပါမည်</string>
|
||||||
|
<string name="blank_repo_message">CloudStream တွင် မူရင်းအတိုင်း ထည့်သွင်းထားသည့်ဆိုက်များ မရှိပါ။ ရီပိုစစ်ထရီများ မှ ဆိုဒ် များကို ထည့်သွင်းရန်လိုအပ်သည်။
|
||||||
|
\n
|
||||||
|
\nSky UK Limited မှ ဦးနှောက်မဲ့ DMCA ကို ဖယ်ရှားလိုက်ခြင်းကြောင့် 🤮 ကျွန်ုပ်တို့သည် ရီပိုစစ်ထရီဆိုဒ်ကို အက်ပ်တွင် ချိတ်ဆက်၍မရပါ။
|
||||||
|
\n
|
||||||
|
\nကျွန်ုပ်တို့၏ Discord တွင်ပါဝင်ပါ သို့မဟုတ် အွန်လိုင်းတွင်ရှာဖွေပါ။</string>
|
||||||
|
<string name="view_public_repositories_button">အခြားသူများ၏ရီပိုစစ်ထရီများကိုရှာဖွေမည်</string>
|
||||||
|
<string name="tracks">အသံများ</string>
|
||||||
|
<string name="audio_tracks">အသံဖိုင်များ</string>
|
||||||
|
<string name="video_tracks">ဗီဒီယိုအသံဖိုင်များ</string>
|
||||||
|
<string name="apply_on_restart">ပြန်စတင်ချိန်မှာအသုံးပြုပါ</string>
|
||||||
|
<string name="stop">ရပ်ရန်</string>
|
||||||
|
<string name="safe_mode_title">လုံခြုံသောမုဖွင့်ရန်</string>
|
||||||
|
<string name="player_settings_play_in_app">ဖုန်းတွင်းကြည့်ရှုမှု</string>
|
||||||
|
<string name="player_pref">ဦးစားပေး ဗီဒီယိုဖွင့်စက်</string>
|
||||||
|
<string name="safe_mode_description">ပြဿနာဖြစ်စေသည့်အရာကို သင်ရှာဖွေရာတွင် အထောက်အကူဖြစ်စေရန်အတွက် ပျက်စီးမှုတစ်ခုကြောင့် အဆက်များအားလုံးကို ပိတ်ထားသည်။</string>
|
||||||
|
<string name="extension_rating" formatted="true">အဆင့်သတ်မှတ်ချက်များ: %s</string>
|
||||||
|
<string name="safe_mode_crash_info">ပျက်စီးမှုအချက်အလက်ကို ကြည့်ပါ</string>
|
||||||
|
<string name="extension_description">ဖော်ပြချက်</string>
|
||||||
|
<string name="extension_version">ဗားရှင်း</string>
|
||||||
|
<string name="extension_status">အခြေအနေ</string>
|
||||||
|
<string name="extension_size">အရွယ်အစား</string>
|
||||||
|
<string name="extension_authors">ရေးသားသူများ</string>
|
||||||
|
<string name="hls_playlist">HLS ဖွင့်စဥ်</string>
|
||||||
|
<string name="history">ကြည့်ရှုခဲ့သည်များ</string>
|
||||||
|
<string name="update_notification_failed">အက်ပ်၏ ဗားရှင်းအသစ်ကို ထည့်သွင်း၍မရပါ</string>
|
||||||
|
<string name="enable_skip_op_from_database_des">အစပိုင်း/အဆုံးပိုင်းအတွက် ကျော်နိုင်သော ပေါ့ပ်အပ်များကို ပြပါ</string>
|
||||||
|
<string name="clipboard_too_large">စာသားအလွန်များသဖြင့်ကလစ်ဘုတ်တွင် သိမ်းဆည်း၍မရပါ။</string>
|
||||||
|
<string name="category_providers">ပံ့ပိုးပေးသူများ</string>
|
||||||
|
<string name="category_ui">အပြင်အဆင်</string>
|
||||||
|
<string name="automatic">အလိုအလျောက်</string>
|
||||||
|
<string name="tv_layout">တီဗွီအပြင်အဆင်</string>
|
||||||
|
<string name="example_password">သင့်စကားဝှက်</string>
|
||||||
|
<string name="example_username">သင့်ယူဇာနိမ်း</string>
|
||||||
|
<string name="example_email">သင့်အီးမေးလ် လိပ်စာ</string>
|
||||||
|
<string name="example_ip">127.0.0.1</string>
|
||||||
|
<string name="example_site_name">သင့်ဆိုဒ်</string>
|
||||||
|
<string name="example_site_url">example.com</string>
|
||||||
|
<string name="subtitles_shadow">အရိပ်</string>
|
||||||
|
<string name="subtitles_raised">ထမြောက်မှု</string>
|
||||||
|
<string name="subtitle_offset">စာတန်းထိုးများ ထပ်တူပြုရန်</string>
|
||||||
|
<string name="subtitle_offset_extra_hint_later_format">စာတန်းထိုးများ အလွန်စောနေပါက %d ms ဒီဟာကိုသုံးပါ</string>
|
||||||
|
<string name="subtitles_example_text">The quick brown fox jumps over the lazy dog</string>
|
||||||
|
<string name="player_loaded_subtitles" formatted="true">တင်ပြီး %s</string>
|
||||||
|
<string name="player_load_subtitles">ဖိုင်မှတင်သွင်းပြီး</string>
|
||||||
|
<string name="quality_cam_hd">ရုံရိုက်</string>
|
||||||
|
<string name="quality_hq">အကြည်</string>
|
||||||
|
<string name="quality_hd">အကြည်</string>
|
||||||
|
<string name="quality_uhd">UHD</string>
|
||||||
|
<string name="quality_hdr">HDR</string>
|
||||||
|
<string name="quality_sdr">SDR</string>
|
||||||
|
<string name="quality_webrip">Web</string>
|
||||||
|
<string name="quality_workprint">WP</string>
|
||||||
|
<string name="quality_sd">SD</string>
|
||||||
|
<string name="category_player">ကြည့်ရှုမှု</string>
|
||||||
|
<string name="poster_image">ပိုစတာပုံရိပ်</string>
|
||||||
|
<string name="subtitles_remove_bloat">စာတန်းထိုးများမှ bloat ကိုဖယ်ရှားပါ</string>
|
||||||
|
<string name="subtitles_filter_lang">နှစ်သက်ရာ မီဒီယာဘာသာစကားဖြင့် စစ်ထုတ်ပါ</string>
|
||||||
|
<string name="extras">အပိုများ</string>
|
||||||
|
<string name="error_invalid_data">ဒေတာမမှန်ပါ</string>
|
||||||
|
<string name="error_invalid_url">URL မမှန်ပါ</string>
|
||||||
|
<string name="error">အချို့အယွင်း</string>
|
||||||
|
<string name="subtitles_remove_captions">စာတန်းထိုးများမှ ပိတ်ထားသော စာတန်းများကို ဖယ်ရှားပါ</string>
|
||||||
|
<string name="trailer">ထွေလာ</string>
|
||||||
|
<string name="plugin">ဖြည့်စွက်များ</string>
|
||||||
|
<string name="delete_repository_plugins">ရီပိုစစ်ထရီ ဖြည့်စွက်များအားလုံးကိုဖျက်မည်ဖြစ်သည်</string>
|
||||||
|
<string name="delete_repository">ရီပိုစစ်ထရီ ကိုဖျက်ရန်</string>
|
||||||
|
<string name="download_all_plugins_from_repo">ဤရီပိုစစ်ထရီမှ ဖြည့်စွက်များအားလုံးကို ဒေါင်းလုဒ်လုပ်မှာလား\?</string>
|
||||||
|
<string name="single_plugin_disabled" formatted="true">%s (ပိတ်ပြီး)</string>
|
||||||
|
<string name="extension_types">ထောက်ပံ့ထားသော</string>
|
||||||
|
<string name="extension_language">ဘာသာစကား</string>
|
||||||
|
<string name="extension_install_first">အဆက်များကိုအရင်သွင်းပါ</string>
|
||||||
|
<string name="player_settings_play_in_vlc">VLC</string>
|
||||||
|
<string name="player_settings_play_in_mpv">MPV</string>
|
||||||
|
<string name="player_settings_play_in_web">ဝဘ်ထဲတွင်ဖွင့်ရန်</string>
|
||||||
|
<string name="skip_type_op">အစပိုင်း</string>
|
||||||
|
<string name="skip_type_ed">အဆုံးပိုင်း</string>
|
||||||
|
<string name="clear_history">ကြည့်ရှုခဲ့သည်များကိုရှင်းရန်</string>
|
||||||
|
<string name="action_remove_from_watched">ကြည့်ပြီးသည်မှဖယ်ရှားရန်</string>
|
||||||
|
<string name="confirm_exit_dialog">သင်ထွက်ရန်သေချာပြီလား</string>
|
||||||
|
<string name="no">မသေချာပါ</string>
|
||||||
|
<string name="update_notification_downloading">အက်ပ်အပ်ဒိတ်အားဒေါင်းလုဒ်လုပ်နေသည်…</string>
|
||||||
|
<string name="update_notification_installing">အက်ပ်အပ်ဒိတ်အားသွင်းနေသည်…</string>
|
||||||
|
<string name="sort_updated_new">အပ်ဒိတ်ဖြစ်မှု (အသစ် မှ အဟောင်း)</string>
|
||||||
|
<string name="empty_library_no_accounts_message">သင့်လိုက်ဘရီသည် ဗလာဖြစ်နေသည် :(
|
||||||
|
\nအကောင့်ဝင်ပါ သို့မဟုတ် သင့်ဖုန်းလိုက်ဘရီတွင် ကြည့်စရာများထည့်ပါ။</string>
|
||||||
|
<string name="use">သုံးရန်</string>
|
||||||
|
<string name="edit">တည်းဖြတ်ရန်</string>
|
||||||
|
<string name="qualities">အရည်အသွေးများ</string>
|
||||||
|
<string name="subtitles_encoding">စာတန်းထိုး ကုဒ်လုပ်ခြင်း</string>
|
||||||
|
<string name="category_provider_test">ပံ့ပိုးပေးသူ စစ်ဆေးမှု</string>
|
||||||
|
<string name="login_format" formatted="true">%s %s</string>
|
||||||
|
<string name="login">အကောင့်ဝင်မည်</string>
|
||||||
|
<string name="switch_account">အကောင့်ပြောင်းမည်</string>
|
||||||
|
<string name="upload_sync">ချိန်ညိှခြင်း</string>
|
||||||
|
<string name="sync_total_episodes_some" formatted="true">/%d</string>
|
||||||
|
<string name="player_load_subtitles_online">အင်တာနက်မှ တင်သွင်းမည်</string>
|
||||||
|
<string name="actor_background">နောက်ခံ</string>
|
||||||
|
<string name="authenticated_user_fail" formatted="true">အကောင့်မဝင်ရောက်နိုင်ပါ %s</string>
|
||||||
|
<string name="none">ဘာမျှ</string>
|
||||||
|
<string name="min">အနည်းဆုံး</string>
|
||||||
|
<string name="subtitles_outline">အနားကွပ်</string>
|
||||||
|
<string name="home_random">ကျပန်း</string>
|
||||||
|
<string name="subtitles_depressed">ချုံ့ပြီး</string>
|
||||||
|
<string name="subtitle_offset_hint">1000 ms</string>
|
||||||
|
<string name="subtitle_offset_title">စာတန်းထိုး ကြန့်ကြာမှု</string>
|
||||||
|
<string name="subtitle_offset_extra_hint_before_format">စာတန်းထိုးများအလွန်နောက်ကျနေပါက %d ms ဒီဟာကိုသုံးပါ</string>
|
||||||
|
<string name="subtitle_offset_extra_hint_none_format">စာတန်းထိုး ကြန့်ကြာမှု သတ်မှတ်ထားခြင်းမရှိ</string>
|
||||||
|
<string name="quality_cam">ရုံရိုက်</string>
|
||||||
|
<string name="quality_cam_rip">ရုံရိုက်</string>
|
||||||
|
<string name="quality_tc">TC</string>
|
||||||
|
<string name="resolution">အရည်အသွေး</string>
|
||||||
|
<string name="skip_setup">အစီအစဥ်ချခြင်းကိုကျော်မည်</string>
|
||||||
|
<string name="crash_reporting_title">ချို့ယွင်းမှုသတင်းပေးပို့ခြင်း</string>
|
||||||
|
<string name="preferred_media_subtext">ဘာတွေကြည့်ချင်လဲ</string>
|
||||||
|
<string name="setup_done">ပြီးပြီ</string>
|
||||||
|
<string name="extensions">အဆက်များ</string>
|
||||||
|
<string name="plugin_load_fail" formatted="true">မသွင်းနိုင်ပါ %s</string>
|
||||||
|
<string name="app_layout_subtext">သင့်စက်ပစ္စည်းနှင့် ကိုက်ညီစေရန် အက်ပ်၏အသွင်အပြင်ကို ပြောင်းလဲပါ</string>
|
||||||
|
<string name="add_repository">ရီပိုစစ်ထရီထည့်ရန်</string>
|
||||||
|
<string name="is_adult">အသက်ပြည့်ပြီးသူများသာ</string>
|
||||||
|
<string name="repository_name_hint">ရီပိုစစ်ထရီအမည်</string>
|
||||||
|
<string name="repository_url_hint">ရီပိုစစ်ထရီ URL</string>
|
||||||
|
<string name="plugin_loaded">ဖြည့်စွက်များ ထည့်ပြီး</string>
|
||||||
|
<string name="provider_languages_tip">ဤဘာသာစကားများဖြင့် ဗီဒီယိုများကို ကြည့်ရှုပါ</string>
|
||||||
|
<string name="plugin_downloaded">ဖြည့်စွက်များ ဒေါင်းလုဒ်လုပ်ပြီး</string>
|
||||||
|
<string name="plugin_deleted">ဖြည့်စွက်များဖျက်ပြီး</string>
|
||||||
|
<string name="batch_download_start_format" formatted="true">ဒေါင်းလုဒ်လုပ်ခြင်း စတင်သည် %d %s…</string>
|
||||||
|
<string name="batch_download_finish_format" formatted="true">ဒေါင်းလုဒ်လုပ်ပြီး %d %s</string>
|
||||||
|
<string name="batch_download_nothing_to_download_format" formatted="true">အားလုံး %s ဒေါင်းလုဒ်လုပ်ပြီးသား</string>
|
||||||
|
<string name="no_plugins_found_error">ရီပိုစစ်ထရီထဲတွင်ဖြည့်စွက်များမတွေ့ပါ</string>
|
||||||
|
<string name="no_repository_found_error">ရီပိုစစ်ထရီမတွေ့ပါ၊URLကိုပြန်စစ်ပြီးဗီပီအန်ဖြင့်ကြိုးစားကြည့်ပါ</string>
|
||||||
|
<string name="batch_download">အသုတ်လိုက် ဒေါင်းလုဒ်</string>
|
||||||
|
<string name="plugin_singular">ဖြည့်စွက်</string>
|
||||||
|
<string name="setup_extensions_subtext">သင်အသုံးပြုလိုသောဆိုက်များစာရင်းကို ဒေါင်းလုဒ်လုပ်ပါ</string>
|
||||||
|
<string name="plugins_downloaded" formatted="true">ဒေါင်းလုဒ်လုပ်ပြီး: %d</string>
|
||||||
|
<string name="plugins_disabled" formatted="true">ပိတ်ပြီး: %d</string>
|
||||||
|
<string name="example_lang_name">ဘာသာစကားကုဒ် (en)</string>
|
||||||
|
<string name="account">အကောင့်</string>
|
||||||
|
<string name="logout">အကောင့်ထွက်မည်</string>
|
||||||
|
<string name="add_account">အကောင့်ထည့်မည်</string>
|
||||||
|
<string name="create_account">အကောင့်ဖွင့်မည်</string>
|
||||||
|
<string name="add_sync">စောင့်ကြည့်ခြင်းထည့်မည်</string>
|
||||||
|
<string name="added_sync_format" formatted="true">ထည့်ပြီး %s</string>
|
||||||
|
<string name="sync_score">အဆင့်သတ်မှတ်ထားပြီး</string>
|
||||||
|
<string name="sync_score_format" formatted="true">%d / 10</string>
|
||||||
|
<string name="sync_total_episodes_none">/\?\?</string>
|
||||||
|
<string name="authenticated_user" formatted="true">%s ချိတ်ဆက်ပြီး</string>
|
||||||
|
<string name="disable">ပိတ်ပါ</string>
|
||||||
|
<string name="normal">ပုံမှန်</string>
|
||||||
|
<string name="all">အားလုံး</string>
|
||||||
|
<string name="max">အပြည့်</string>
|
||||||
|
<string name="downloaded_file">ဖိုင်ဒေါင်းလုဒ်လုပ်ပြီး</string>
|
||||||
|
<string name="actor_main">အဓိက</string>
|
||||||
|
<string name="actor_supporting">ထောက်ပံ့သည်</string>
|
||||||
|
<string name="home_source">ရင်းမြစ်</string>
|
||||||
|
<string name="coming_soon">မကြာမီလာမည်…</string>
|
||||||
|
<string name="quality_ts">TS</string>
|
||||||
|
<string name="quality_blueray">Blu-ray</string>
|
||||||
|
<string name="resolution_and_title">အရည်အသွေးနှင့်ခေါင်းစဥ်</string>
|
||||||
|
<string name="title">ခေါင်းစဥ်</string>
|
||||||
|
<string name="error_invalid_id">အိုင်ဒီမမှန်ပါ</string>
|
||||||
|
<string name="view_public_repositories_button_short">အများမြင်နိုင်သော</string>
|
||||||
|
<string name="uppercase_all_subtitles">စာတန်းထိုးအားလုံးကို စာလုံးအကြီးပြောင်းပါ</string>
|
||||||
|
<string name="restart">ပြန်စတင်မည်</string>
|
||||||
|
<string name="action_mark_as_watched">ကြည့်ပြီးအဖြစ်မှတ်ရန်</string>
|
||||||
|
<string name="sort_by">အစီအစဥ်ချမှု</string>
|
||||||
|
<string name="sort">အစီအစဥ်</string>
|
||||||
|
<string name="sort_rating_desc">အဆင့်သတ်မှတ်ချက် (အမြင့်ဆုံးမှအနိမ့်ဆုံးသို့)</string>
|
||||||
|
<string name="sort_rating_asc">အဆင့်သတ်မှတ်ချက် (အနိမ့်ဆုံး မှ အမြင့်ဆုံးသို့)</string>
|
||||||
|
<string name="sort_updated_old">အပ်ဒိတ်ဖြစ်မှု (အဟောင် မှ အသစ်)</string>
|
||||||
|
<string name="sort_alphabetical_a">အက္ခရာစဥ်လိုက် (A မှ Z)</string>
|
||||||
|
<string name="sort_alphabetical_z">အက္ခရာစဥ်လိုက် (Z မှ A)</string>
|
||||||
|
<string name="revert">ပြောင်းပြန်</string>
|
||||||
|
<string name="subscription_in_progress_notification">စာရင်းသွင်းထားသောရှိုးများကိုအပ်ဒိတ်လုပ်နေသည်</string>
|
||||||
|
<string name="subscription_list_name">စာရင်းသွင်းပြီး</string>
|
||||||
|
<string name="subscription_new">စာရင်းသွင်းပြီး %s</string>
|
||||||
|
<string name="subscription_deleted">စာရင်းသွင်းမှုပယ်ဖျက်ပြီး %s</string>
|
||||||
|
<string name="empty_library_logged_in_message">ဤစာရင်းသည် ဗလာဖြစ်နေသည်။ အခြားတစ်ခုသို့ ပြောင်းကြည့်ပါ။</string>
|
||||||
|
<string name="safe_mode_file">Safe mode ဖိုင်ကို တွေ့ရှိခဲ့သည်။
|
||||||
|
\nဖိုင်ကိုမဖယ်ရှားမချင်း စတင်ဖွင့်စတွင် မည်သည့် extension များကိုမျှ မတင်ပါ။</string>
|
||||||
|
<string name="subscription_episode_released">အပိုင်းသစ် %d ထွက်ပြီ</string>
|
||||||
|
<string name="profile_number">ပရိုဖိုင် %d</string>
|
||||||
|
<string name="wifi">ဝိုင်ဖိုင်</string>
|
||||||
|
<string name="mobile_data">မိုဘိုင်းဒေတာ</string>
|
||||||
|
<string name="set_default">ပုံသေထားရန်</string>
|
||||||
|
<string name="profiles">ပရိုဖိုင်များ</string>
|
||||||
|
<string name="help">အကူအညီ</string>
|
||||||
|
<string name="quality_profile_help">ဤနေရာတွင် သင်သည် အရင်းအမြစ်များကို မည်ကဲ့သို့ အစီအစဥ်ချမည်ကို ပြောင်းလဲနိုင်သည်။ ဗီဒီယိုတစ်ခုတွင် ပိုမိုဦးစားပေးပါက ရင်းမြစ်ရွေးချယ်မှုတွင် ပိုမိုမြင့်မားလာမည်ဖြစ်သည်။ အရင်းအမြစ် ဦးစားပေးနှင့် အရည်အသွေး ဦးစားပေး၏ ပေါင်းစုသည် ဗီဒီယို ဦးစားပေးဖြစ်သည်။
|
||||||
|
\n
|
||||||
|
\nအရင်းအမြစ် A: 3
|
||||||
|
\nအရည်အသွေး B: 7
|
||||||
|
\nပေါင်းစပ်ဗီဒီယို ဦးစားပေး 10 ခု ရှိပါမည်။
|
||||||
|
\n
|
||||||
|
\nမှတ်ချက်- ပေါင်းလဒ်သည် 10 သို့မဟုတ် ထို့ထက်ပိုပါက ထိုလင့်ခ်ကို တင်သည့်အခါ ဗီဒီယိုဖွင့်စက်သည် အလိုအလျောက် ဒေါင်းလုဒ်ကို ကျော်သွားမည်ဖြစ်သည်</string>
|
||||||
|
<string name="profile_background_des">ပရိုဖိုင်နောက်ခံ</string>
|
||||||
|
<string name="unable_to_inflate">UI ကို မှန်ကန်စွာ ဖန်တီး၍မရပါ၊ ၎င်းသည် အဓိက ချို့ယွင်းချက်တစ်ခုဖြစ်ပြီး ချက်ချင်းသတင်းပို့သင့်သည်။ %s</string>
|
||||||
|
<string name="already_voted">သင်နဂိုတည်းကသတ်မှတ်ပြီး</string>
|
||||||
|
<string name="select_library">လိုက်ဘရီရွေးချယ်ရန်</string>
|
||||||
|
<string name="open_with">ဖြင့်ဖွင့်မည်</string>
|
||||||
|
</resources>
|
|
@ -574,4 +574,5 @@
|
||||||
<string name="disable">Uitzetten</string>
|
<string name="disable">Uitzetten</string>
|
||||||
<string name="unable_to_inflate">De gebruikersinterface kon niet correct worden gemaakt, dit is een ERNSTIG PROBLEEM en moet onmiddellijk gerapporteerd worden %s</string>
|
<string name="unable_to_inflate">De gebruikersinterface kon niet correct worden gemaakt, dit is een ERNSTIG PROBLEEM en moet onmiddellijk gerapporteerd worden %s</string>
|
||||||
<string name="default_account">@string/default_subtitles</string>
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
|
<string name="already_voted">Je hebt al gestemd</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -553,4 +553,7 @@
|
||||||
<string name="automatic_plugin_download_mode_title">Wybierz tryb filtrowania pobieranych rozszerzeń</string>
|
<string name="automatic_plugin_download_mode_title">Wybierz tryb filtrowania pobieranych rozszerzeń</string>
|
||||||
<string name="disable">Wyłączać</string>
|
<string name="disable">Wyłączać</string>
|
||||||
<string name="default_account">@string/default_subtitles</string>
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
|
<string name="no_plugins_found_error">Nie znaleziono żadnych wtyczek w repozytorium</string>
|
||||||
|
<string name="already_voted">Już oddano głos</string>
|
||||||
|
<string name="no_repository_found_error">Nie znaleziono tego repozytorium, sprawdź adres URL lub spróbuj połączyć się przez VPN</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -552,4 +552,5 @@
|
||||||
<string name="disable">Desativar</string>
|
<string name="disable">Desativar</string>
|
||||||
<string name="no_plugins_found_error">Não foram encontrados plugins no repositório</string>
|
<string name="no_plugins_found_error">Não foram encontrados plugins no repositório</string>
|
||||||
<string name="no_repository_found_error">Repositório não encontrado, verifique o URL e tente a VPN</string>
|
<string name="no_repository_found_error">Repositório não encontrado, verifique o URL e tente a VPN</string>
|
||||||
|
<string name="already_voted">Você já votou</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -248,4 +248,5 @@
|
||||||
<string name="clear_history">aoaaaaaoooghhh</string>
|
<string name="clear_history">aoaaaaaoooghhh</string>
|
||||||
<string name="sort_save">oooooh uuaagh</string>
|
<string name="sort_save">oooooh uuaagh</string>
|
||||||
<string name="action_open_play">@string/home_play</string>
|
<string name="action_open_play">@string/home_play</string>
|
||||||
|
<string name="chromecast_subtitles_settings">oouuhhh ahhooo-ahah</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
6
app/src/main/res/values-ti/strings.xml
Normal file
6
app/src/main/res/values-ti/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_dub_sub_episode_text_format" formatted="true">%s ክፋል %d</string>
|
||||||
|
<string name="next_episode_format" formatted="true">ክፋል %d በ ላይ ይወጣል</string>
|
||||||
|
<string name="cast_format" formatted="true">ተዋሳእቲ፡ %s</string>
|
||||||
|
</resources>
|
|
@ -80,14 +80,14 @@
|
||||||
<string name="normal_no_plot">Сюжет не знайдено</string>
|
<string name="normal_no_plot">Сюжет не знайдено</string>
|
||||||
<string name="torrent_no_plot">Опис не знайдено</string>
|
<string name="torrent_no_plot">Опис не знайдено</string>
|
||||||
<string name="show_log_cat">Показати Logcat 🐈</string>
|
<string name="show_log_cat">Показати Logcat 🐈</string>
|
||||||
<string name="picture_in_picture_des">Продовження відтворення в мініатюрному плеєрі поверх інших застосунків</string>
|
<string name="picture_in_picture_des">Продовжує відтворення в мініатюрному плеєрі поверх інших застосунків</string>
|
||||||
<string name="player_size_settings_des">Прибирає чорні рамки</string>
|
<string name="player_size_settings_des">Прибирає чорні рамки</string>
|
||||||
<string name="player_subtitles_settings">Субтитри</string>
|
<string name="player_subtitles_settings">Субтитри</string>
|
||||||
<string name="chromecast_subtitles_settings">Субтитри Chromecast</string>
|
<string name="chromecast_subtitles_settings">Субтитри Chromecast</string>
|
||||||
<string name="chromecast_subtitles_settings_des">Налаштування субтитрів Chromecast</string>
|
<string name="chromecast_subtitles_settings_des">Налаштування субтитрів Chromecast</string>
|
||||||
<string name="eigengraumode_settings">Режим Eigengravy</string>
|
<string name="eigengraumode_settings">Режим Eigengravy</string>
|
||||||
<string name="swipe_to_change_settings">Проведіть пальцем, щоб змінити налаштування</string>
|
<string name="swipe_to_change_settings">Проведіть пальцем, щоб змінити налаштування</string>
|
||||||
<string name="swipe_to_change_settings_des">Проведіть пальцем вгору або вниз, ліворуч або праворуч, щоб змінити яскравість чи гучність</string>
|
<string name="swipe_to_change_settings_des">Проведіть вгору або вниз з лівого або правого боку, щоб змінити яскравість чи гучність</string>
|
||||||
<string name="autoplay_next_settings_des">Відтворювати наступний епізод після закінчення поточного</string>
|
<string name="autoplay_next_settings_des">Відтворювати наступний епізод після закінчення поточного</string>
|
||||||
<string name="title_home">Головна</string>
|
<string name="title_home">Головна</string>
|
||||||
<string name="app_name">CloudStream</string>
|
<string name="app_name">CloudStream</string>
|
||||||
|
@ -121,8 +121,8 @@
|
||||||
<string name="subs_text_color">Колір тексту</string>
|
<string name="subs_text_color">Колір тексту</string>
|
||||||
<string name="subs_outline_color">Колір контуру</string>
|
<string name="subs_outline_color">Колір контуру</string>
|
||||||
<string name="autoplay_next_settings">Автовідтворення наступного епізоду</string>
|
<string name="autoplay_next_settings">Автовідтворення наступного епізоду</string>
|
||||||
<string name="swipe_to_seek_settings_des">Проведіть пальцем з боку в бік, щоб керувати своїм положенням у відео</string>
|
<string name="swipe_to_seek_settings_des">Проведіть з боку в бік, щоб керувати своїм положенням у відео</string>
|
||||||
<string name="benene_count_text">%d Бананів для розробників</string>
|
<string name="benene_count_text">%d бананів для розробників</string>
|
||||||
<string name="player_size_settings">Кнопка зміни розміру плеєра</string>
|
<string name="player_size_settings">Кнопка зміни розміру плеєра</string>
|
||||||
<string name="action_open_play">@string/home_play</string>
|
<string name="action_open_play">@string/home_play</string>
|
||||||
<string name="vpn_might_be_needed">Для коректної роботи цього постачальника може знадобитися VPN</string>
|
<string name="vpn_might_be_needed">Для коректної роботи цього постачальника може знадобитися VPN</string>
|
||||||
|
@ -133,7 +133,7 @@
|
||||||
<string name="swipe_to_seek_settings">Проведіть пальцем, щоб перемотати</string>
|
<string name="swipe_to_seek_settings">Проведіть пальцем, щоб перемотати</string>
|
||||||
<string name="double_tap_to_seek_settings">Двічі торкніться, щоб перемотати</string>
|
<string name="double_tap_to_seek_settings">Двічі торкніться, щоб перемотати</string>
|
||||||
<string name="double_tap_to_pause_settings">Двічі торкніться для паузи</string>
|
<string name="double_tap_to_pause_settings">Двічі торкніться для паузи</string>
|
||||||
<string name="double_tap_to_seek_amount_settings">Крок перемотки (Секунди)</string>
|
<string name="double_tap_to_seek_amount_settings">Крок перемотки (секунди)</string>
|
||||||
<string name="double_tap_to_pause_settings_des">Натисніть двічі посередині, щоб призупинити відтворення відео</string>
|
<string name="double_tap_to_pause_settings_des">Натисніть двічі посередині, щоб призупинити відтворення відео</string>
|
||||||
<string name="use_system_brightness_settings">Використовувати яскравість системи</string>
|
<string name="use_system_brightness_settings">Використовувати яскравість системи</string>
|
||||||
<string name="episode_sync_settings">Оновити прогрес перегляду</string>
|
<string name="episode_sync_settings">Оновити прогрес перегляду</string>
|
||||||
|
@ -150,8 +150,8 @@
|
||||||
<string name="advanced_search_des">Надає результати пошуку, розділені за постачальниками</string>
|
<string name="advanced_search_des">Надає результати пошуку, розділені за постачальниками</string>
|
||||||
<string name="bug_report_settings_off">Надсилає дані лише про збої</string>
|
<string name="bug_report_settings_off">Надсилає дані лише про збої</string>
|
||||||
<string name="bug_report_settings_on">Не надсилає даних</string>
|
<string name="bug_report_settings_on">Не надсилає даних</string>
|
||||||
<string name="show_fillers_settings">Показати заповнюючий епізод для аніме</string>
|
<string name="show_fillers_settings">Показувати філери до аніме</string>
|
||||||
<string name="show_trailers_settings">Показати трейлери</string>
|
<string name="show_trailers_settings">Показувати трейлери</string>
|
||||||
<string name="pref_filter_search_quality">Приховати вибрану якість відео в результатах пошуку</string>
|
<string name="pref_filter_search_quality">Приховати вибрану якість відео в результатах пошуку</string>
|
||||||
<string name="automatic_plugin_download">Автоматичне завантаження плагінів</string>
|
<string name="automatic_plugin_download">Автоматичне завантаження плагінів</string>
|
||||||
<string name="updates_settings">Показувати оновлення застосунку</string>
|
<string name="updates_settings">Показувати оновлення застосунку</string>
|
||||||
|
@ -214,12 +214,12 @@
|
||||||
<string name="episode_action_download_mirror">Завантажити дзеркало</string>
|
<string name="episode_action_download_mirror">Завантажити дзеркало</string>
|
||||||
<string name="check_for_update">Перевірити наявність оновлень</string>
|
<string name="check_for_update">Перевірити наявність оновлень</string>
|
||||||
<string name="video_lock">Заблокувати</string>
|
<string name="video_lock">Заблокувати</string>
|
||||||
<string name="video_skip_op">Пропустити OP</string>
|
<string name="video_skip_op">Пропускати OP</string>
|
||||||
<string name="dont_show_again">Не показувати знову</string>
|
<string name="dont_show_again">Не показувати знову</string>
|
||||||
<string name="update">Оновити</string>
|
<string name="update">Оновити</string>
|
||||||
<string name="watch_quality_pref">Бажана якість перегляду (WiFi)</string>
|
<string name="watch_quality_pref">Бажана якість перегляду (WiFi)</string>
|
||||||
<string name="show_title">Заголовок</string>
|
<string name="show_title">Заголовок</string>
|
||||||
<string name="poster_ui_settings">Перемикання елементів інтерфейсу на плакаті</string>
|
<string name="poster_ui_settings">Перемикання елементів інтерфейсу на постері</string>
|
||||||
<string name="no_update_found">Оновлення не знайдено</string>
|
<string name="no_update_found">Оновлення не знайдено</string>
|
||||||
<string name="double_tap_to_seek_settings_des">Двічі торкніться праворуч або ліворуч, щоб перемотати відео вперед або назад</string>
|
<string name="double_tap_to_seek_settings_des">Двічі торкніться праворуч або ліворуч, щоб перемотати відео вперед або назад</string>
|
||||||
<string name="use_system_brightness_settings_des">Використовуйте системну яскравість у плеєрі замість темної накладки</string>
|
<string name="use_system_brightness_settings_des">Використовуйте системну яскравість у плеєрі замість темної накладки</string>
|
||||||
|
@ -227,10 +227,10 @@
|
||||||
<string name="torrent">Торренти</string>
|
<string name="torrent">Торренти</string>
|
||||||
<string name="episode_sync_settings_des">Автоматична синхронізація прогресу поточного епізоду</string>
|
<string name="episode_sync_settings_des">Автоматична синхронізація прогресу поточного епізоду</string>
|
||||||
<string name="backup_failed">Відсутні дозволи на зберігання. Будь ласка, спробуйте ще раз.</string>
|
<string name="backup_failed">Відсутні дозволи на зберігання. Будь ласка, спробуйте ще раз.</string>
|
||||||
<string name="kitsu_settings">Показати постери від Kitsu</string>
|
<string name="kitsu_settings">Показувати постери від Kitsu</string>
|
||||||
<string name="automatic_plugin_updates">Автоматичне оновлення плагінів</string>
|
<string name="automatic_plugin_updates">Автоматичне оновлення плагінів</string>
|
||||||
<string name="automatic_plugin_download_summary">Автоматично встановлювати всі ще не встановлені плагіни з доданих репозиторіїв.</string>
|
<string name="automatic_plugin_download_summary">Автоматично встановлювати всі ще не встановлені плагіни з доданих репозиторіїв.</string>
|
||||||
<string name="updates_settings_des">Автоматично шукати нові оновлення після запуску застосунку.</string>
|
<string name="updates_settings_des">Автоматично шукає нові оновлення після запуску застосунку.</string>
|
||||||
<string name="uprereleases_settings">Оновлення до бета-версій</string>
|
<string name="uprereleases_settings">Оновлення до бета-версій</string>
|
||||||
<string name="copy_link_toast">Посилання скопійовано в буфер обміну</string>
|
<string name="copy_link_toast">Посилання скопійовано в буфер обміну</string>
|
||||||
<string name="apk_installer_settings_des">Деякі телефони не підтримують новий інсталятор пакетів. Спробуйте стару версію, якщо оновлення не встановлюються.</string>
|
<string name="apk_installer_settings_des">Деякі телефони не підтримують новий інсталятор пакетів. Спробуйте стару версію, якщо оновлення не встановлюються.</string>
|
||||||
|
@ -354,7 +354,7 @@
|
||||||
<string name="dns_pref">DNS через HTTPS</string>
|
<string name="dns_pref">DNS через HTTPS</string>
|
||||||
<string name="download_path_pref">Шлях завантаження</string>
|
<string name="download_path_pref">Шлях завантаження</string>
|
||||||
<string name="add_site_summary">Додайте клон існуючого сайту, з іншою URL-адресою</string>
|
<string name="add_site_summary">Додайте клон існуючого сайту, з іншою URL-адресою</string>
|
||||||
<string name="display_subbed_dubbed_settings">Відображати мітку Дубляж/Субтитри в аніме</string>
|
<string name="display_subbed_dubbed_settings">Відображати мітку Дубляж/Субтитри до аніме</string>
|
||||||
<string name="legal_notice">Застереження</string>
|
<string name="legal_notice">Застереження</string>
|
||||||
<string name="pref_category_extensions">Розширення</string>
|
<string name="pref_category_extensions">Розширення</string>
|
||||||
<string name="pref_category_actions">Дії</string>
|
<string name="pref_category_actions">Дії</string>
|
||||||
|
@ -382,7 +382,7 @@
|
||||||
<string name="actor_supporting">Підтримка</string>
|
<string name="actor_supporting">Підтримка</string>
|
||||||
<string name="actor_background">Фон</string>
|
<string name="actor_background">Фон</string>
|
||||||
<string name="quality_blueray">Blu-ray</string>
|
<string name="quality_blueray">Blu-ray</string>
|
||||||
<string name="subtitles_remove_captions">Видалити закриті титри з субтитрів</string>
|
<string name="subtitles_remove_captions">Видаляти закриті титри з субтитрів</string>
|
||||||
<string name="quality_dvd">DVD</string>
|
<string name="quality_dvd">DVD</string>
|
||||||
<string name="error_invalid_data">Недійсні дані</string>
|
<string name="error_invalid_data">Недійсні дані</string>
|
||||||
<string name="subtitles_filter_lang">Фільтрувати за бажаною мовою медіа</string>
|
<string name="subtitles_filter_lang">Фільтрувати за бажаною мовою медіа</string>
|
||||||
|
@ -400,7 +400,7 @@
|
||||||
<string name="quality_hd">HD</string>
|
<string name="quality_hd">HD</string>
|
||||||
<string name="quality_ts">TS</string>
|
<string name="quality_ts">TS</string>
|
||||||
<string name="quality_tc">TC</string>
|
<string name="quality_tc">TC</string>
|
||||||
<string name="subtitles_remove_bloat">Видалити роздуття субтитрів</string>
|
<string name="subtitles_remove_bloat">Видаляти роздуття субтитрів</string>
|
||||||
<string name="referer">Referer</string>
|
<string name="referer">Referer</string>
|
||||||
<string name="next">Далі</string>
|
<string name="next">Далі</string>
|
||||||
<string name="provider_languages_tip">Дивіться відео на цих мовах</string>
|
<string name="provider_languages_tip">Дивіться відео на цих мовах</string>
|
||||||
|
@ -418,7 +418,7 @@
|
||||||
<string name="batch_download_start_format" formatted="true">Почалося завантаження %d %s…</string>
|
<string name="batch_download_start_format" formatted="true">Почалося завантаження %d %s…</string>
|
||||||
<string name="batch_download_finish_format" formatted="true">Завантажено %d %s</string>
|
<string name="batch_download_finish_format" formatted="true">Завантажено %d %s</string>
|
||||||
<string name="batch_download_nothing_to_download_format" formatted="true">Всі %s вже завантажено</string>
|
<string name="batch_download_nothing_to_download_format" formatted="true">Всі %s вже завантажено</string>
|
||||||
<string name="batch_download">Пакетне завантаження</string>
|
<string name="batch_download">Завантажити пакети</string>
|
||||||
<string name="plugin_singular">плагін</string>
|
<string name="plugin_singular">плагін</string>
|
||||||
<string name="plugin">плагіни</string>
|
<string name="plugin">плагіни</string>
|
||||||
<string name="delete_repository">Видалити репозиторій</string>
|
<string name="delete_repository">Видалити репозиторій</string>
|
||||||
|
@ -451,8 +451,8 @@
|
||||||
<string name="player_settings_play_in_app">Вбудований плеєр</string>
|
<string name="player_settings_play_in_app">Вбудований плеєр</string>
|
||||||
<string name="player_settings_play_in_vlc">VLC</string>
|
<string name="player_settings_play_in_vlc">VLC</string>
|
||||||
<string name="player_settings_play_in_mpv">MPV</string>
|
<string name="player_settings_play_in_mpv">MPV</string>
|
||||||
<string name="player_settings_play_in_web">Відтворення веб-відео</string>
|
<string name="player_settings_play_in_web">Web Video Cast</string>
|
||||||
<string name="player_settings_play_in_browser">Веб-браузер</string>
|
<string name="player_settings_play_in_browser">Веббраузер</string>
|
||||||
<string name="skip_type_ed">Ендінґ</string>
|
<string name="skip_type_ed">Ендінґ</string>
|
||||||
<string name="skip_type_recap">Коротке повторення</string>
|
<string name="skip_type_recap">Коротке повторення</string>
|
||||||
<string name="skip_type_format" formatted="true">Пропустити %s</string>
|
<string name="skip_type_format" formatted="true">Пропустити %s</string>
|
||||||
|
@ -462,7 +462,7 @@
|
||||||
<string name="skip_type_intro">Вступ</string>
|
<string name="skip_type_intro">Вступ</string>
|
||||||
<string name="clear_history">Очистити історію</string>
|
<string name="clear_history">Очистити історію</string>
|
||||||
<string name="history">Історія</string>
|
<string name="history">Історія</string>
|
||||||
<string name="enable_skip_op_from_database_des">Показувати спливаючі вікна для опенінґу/ендінґу</string>
|
<string name="enable_skip_op_from_database_des">Показує спливаюче вікно для пропуску опенінґу/ендінґу</string>
|
||||||
<string name="clipboard_too_large">Забагато тексту. Не вдалося зберегти в буфер обміну.</string>
|
<string name="clipboard_too_large">Забагато тексту. Не вдалося зберегти в буфер обміну.</string>
|
||||||
<string name="action_mark_as_watched">Позначити як переглянуте</string>
|
<string name="action_mark_as_watched">Позначити як переглянуте</string>
|
||||||
<string name="confirm_exit_dialog">Ви впевнені що хочете вийти\?</string>
|
<string name="confirm_exit_dialog">Ви впевнені що хочете вийти\?</string>
|
||||||
|
@ -552,4 +552,5 @@
|
||||||
<string name="default_account">@string/default_subtitles</string>
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
<string name="no_repository_found_error">Репозиторій не знайдено, перевірте URL-адресу та спробуйте VPN</string>
|
<string name="no_repository_found_error">Репозиторій не знайдено, перевірте URL-адресу та спробуйте VPN</string>
|
||||||
<string name="no_plugins_found_error">Не знайдено жодних плагінів у репозиторії</string>
|
<string name="no_plugins_found_error">Не знайдено жодних плагінів у репозиторії</string>
|
||||||
|
<string name="already_voted">Ви вже проголосували</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -267,7 +267,7 @@
|
||||||
<string name="update">Cập nhật</string>
|
<string name="update">Cập nhật</string>
|
||||||
<string name="watch_quality_pref">Chất lượng xem ưu tiên (WiFi)</string>
|
<string name="watch_quality_pref">Chất lượng xem ưu tiên (WiFi)</string>
|
||||||
<string name="limit_title">Kí tự tối đa trên tiêu đề</string>
|
<string name="limit_title">Kí tự tối đa trên tiêu đề</string>
|
||||||
<string name="limit_title_rez">Độ phân giải trình phát video</string>
|
<string name="limit_title_rez">Nội dung trình phát video</string>
|
||||||
<string name="video_buffer_size_settings">Kích thước bộ nhớ đệm video</string>
|
<string name="video_buffer_size_settings">Kích thước bộ nhớ đệm video</string>
|
||||||
<string name="video_buffer_length_settings">Thời lượng bộ nhớ đệm</string>
|
<string name="video_buffer_length_settings">Thời lượng bộ nhớ đệm</string>
|
||||||
<string name="video_buffer_disk_settings">Lưu bộ nhớ đệm video trên ổ cứng</string>
|
<string name="video_buffer_disk_settings">Lưu bộ nhớ đệm video trên ổ cứng</string>
|
||||||
|
@ -380,8 +380,8 @@
|
||||||
<string name="quality_webrip">Web</string>
|
<string name="quality_webrip">Web</string>
|
||||||
<string name="poster_image">Ảnh áp phích</string>
|
<string name="poster_image">Ảnh áp phích</string>
|
||||||
<string name="category_player">Trình phát</string>
|
<string name="category_player">Trình phát</string>
|
||||||
<string name="resolution_and_title">Độ phân giải và Tiêu đề</string>
|
<string name="resolution_and_title">Độ phân giải và Tên nguồn</string>
|
||||||
<string name="title">Tiêu đề</string>
|
<string name="title">Tên nguồn</string>
|
||||||
<string name="resolution">Độ phân giải</string>
|
<string name="resolution">Độ phân giải</string>
|
||||||
<string name="error_invalid_id">Id không hợp lệ</string>
|
<string name="error_invalid_id">Id không hợp lệ</string>
|
||||||
<string name="error_invalid_data">Lỗi dữ liệu</string>
|
<string name="error_invalid_data">Lỗi dữ liệu</string>
|
||||||
|
@ -561,4 +561,11 @@
|
||||||
\n
|
\n
|
||||||
\nLƯU Ý: Nếu tổng là 10 hoặc nhiều hơn, trình phát sẽ tự động bỏ tải khi liên kết đó được tải!</string>
|
\nLƯU Ý: Nếu tổng là 10 hoặc nhiều hơn, trình phát sẽ tự động bỏ tải khi liên kết đó được tải!</string>
|
||||||
<string name="qualities">Các phẩm chất</string>
|
<string name="qualities">Các phẩm chất</string>
|
||||||
|
<string name="already_voted">Bạn đã bình chọn</string>
|
||||||
|
<string name="disable">Vô hiệu hoá</string>
|
||||||
|
<string name="no_repository_found_error">Không tìm thấy tiện ích, hãy kiểm tra URL và thử VPN</string>
|
||||||
|
<string name="no_plugins_found_error">Không tìm thấy plugin</string>
|
||||||
|
<string name="unable_to_inflate">Không thể khởi tạo UI, đây là một LỖI LỚN và cần được báo cáo ngay lập tức tới %s</string>
|
||||||
|
<string name="automatic_plugin_download_mode_title">Chọn chế độ để lọc plugin tải xuống</string>
|
||||||
|
<string name="default_account">@string/default_subtitles</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
1
fastlane/metadata/android/ar-SA/changelogs/2.txt
Normal file
1
fastlane/metadata/android/ar-SA/changelogs/2.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
تمت إضافة سجل التغيير!
|
|
@ -1,14 +1,10 @@
|
||||||
يتيح لك كلاود ستريم -3 بث وتنزيل الأفلام والمسلسلات التلفزيونية والأنيمي. يأتي التطبيق بدون أي إعلانات وتحليلات. و يدعم العديد من مواقع البث الاولي(التريلر) والأفلام والمزيد. وتشمل الميزات:
|
يسمح لك كلاود ستريم -3 ببث وتنزيل الأفلام, المسلسلات التلفزيونية, والأنيمي.
|
||||||
|
|
||||||
|
|
||||||
|
يأتي التطبيق بدون أي إعلانات وتحليلات و
|
||||||
|
يدعم العديد من مواقع البث الاولي(التريلر) ,والأفلام, والمزيد.
|
||||||
|
|
||||||
إشارات مرجعية
|
إشارات مرجعية
|
||||||
|
|
||||||
|
|
||||||
قم بتنزيل ودفق الأفلام والبرامج التلفزيونية والأنيمي
|
|
||||||
|
|
||||||
|
|
||||||
تنزيلات الترجمة
|
تنزيلات الترجمة
|
||||||
|
|
||||||
|
|
||||||
دعم كروم كاست
|
دعم كروم كاست
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
بث وتحميل الأفلام والأنمي والمسلسلات التلفزيونية.
|
بث وتحميل الأفلام, الأنمي, والمسلسلات التلفزيونية.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
كلاود ستريم
|
كلاودستريم
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
Mit CloudStream-3 kannst du Filme, TV-Serien und Anime streamen und herunterladen.
|
Mit CloudStream-3 kannst du Filme, TV-Serien und Anime streamen und herunterladen.
|
||||||
|
|
||||||
Die App kommt ganz ohne Werbung und Analytik aus.
|
Die App kommt ganz ohne Werbung und Analytik aus.
|
||||||
Sie unterstützt mehrere Trailer-, Filmseiten und vieles mehr. Integrierte Features:
|
Sie unterstützt zahlreiche Trailer, Filmseiten und vieles mehr, unter anderem:
|
||||||
|
|
||||||
Lesezeichen
|
Lesezeichen
|
||||||
|
|
||||||
Herunterladen und Streamen von Filmen, Fernsehsendungen und Animes
|
Herunterladen und Streaming von Filmen, Fernsehsendungen und Animes
|
||||||
|
|
||||||
Downloads von Untertiteln
|
Downloads von Untertiteln
|
||||||
|
|
||||||
|
|
1
fastlane/metadata/android/pt/changelogs/2.txt
Normal file
1
fastlane/metadata/android/pt/changelogs/2.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
- Adicionado o registo de alterações!
|
10
fastlane/metadata/android/pt/full_description.txt
Normal file
10
fastlane/metadata/android/pt/full_description.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
O CloudStream-3 permite-lhe transmitir e descarregar filmes, séries de TV e anime.
|
||||||
|
|
||||||
|
A aplicação é fornecida sem quaisquer anúncios e análises e
|
||||||
|
suporta vários sites de trailers e filmes, e muito mais, por exemplo
|
||||||
|
|
||||||
|
Marcadores
|
||||||
|
|
||||||
|
Downloads de legendas
|
||||||
|
|
||||||
|
Suporte para Chromecast
|
1
fastlane/metadata/android/pt/short_description.txt
Normal file
1
fastlane/metadata/android/pt/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Transmita e transfira filmes, séries de TV e anime.
|
1
fastlane/metadata/android/pt/title.txt
Normal file
1
fastlane/metadata/android/pt/title.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CloudStream
|
1
fastlane/metadata/android/vi/changelogs/2.txt
Normal file
1
fastlane/metadata/android/vi/changelogs/2.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
- Đã thêm Nhật ký thay đổi!
|
10
fastlane/metadata/android/vi/full_description.txt
Normal file
10
fastlane/metadata/android/vi/full_description.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
CloudStream-3 cho phép bạn xem và tải xuống phim lẻ, phim bộ và anime.
|
||||||
|
|
||||||
|
Ứng dụng không có quảng cáo hay và phân tích nào,
|
||||||
|
đồng thời hỗ trợ nhiều trang web xem phim, v.v.
|
||||||
|
|
||||||
|
Đánh dấu
|
||||||
|
|
||||||
|
Tải phụ đề
|
||||||
|
|
||||||
|
Hỗ trợ Chromecast
|
1
fastlane/metadata/android/vi/short_description.txt
Normal file
1
fastlane/metadata/android/vi/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Xem và tải xuống phim lẻ, phim bộ và anime.
|
1
fastlane/metadata/android/vi/title.txt
Normal file
1
fastlane/metadata/android/vi/title.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CloudStream
|
Loading…
Add table
Add a link
Reference in a new issue