diff --git a/.github/downloads.jpg b/.github/downloads.jpg
new file mode 100644
index 00000000..ca14a664
Binary files /dev/null and b/.github/downloads.jpg differ
diff --git a/.github/home.jpg b/.github/home.jpg
new file mode 100644
index 00000000..72370d3c
Binary files /dev/null and b/.github/home.jpg differ
diff --git a/.github/locales.py b/.github/locales.py
index 7d6d6b90..1c79c093 100644
--- a/.github/locales.py
+++ b/.github/locales.py
@@ -1,7 +1,6 @@
import re
import glob
import requests
-import lxml.etree as ET # builtin library doesn't preserve comments
SETTINGS_PATH = "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt"
@@ -46,18 +45,4 @@ open(SETTINGS_PATH, "w+",encoding='utf-8').write(
"\n" +
END_MARKER +
after_src
-)
-
-# Go through each values.xml file and fix escaped \@string
-for file in glob.glob(f"{XML_NAME}*/strings.xml"):
- try:
- tree = ET.parse(file)
- for child in tree.getroot():
- if child.text.startswith("\\@string/"):
- print(f"[{file}] fixing {child.attrib['name']}")
- child.text = child.text.replace("\\@string/", "@string/")
- with open(file, 'wb') as fp:
- fp.write(b'\n')
- tree.write(fp, encoding="utf-8", method="xml", pretty_print=True, xml_declaration=False)
- except ET.ParseError as ex:
- print(f"[{file}] {ex}")
+)
\ No newline at end of file
diff --git a/.github/player.jpg b/.github/player.jpg
new file mode 100644
index 00000000..f6959cf3
Binary files /dev/null and b/.github/player.jpg differ
diff --git a/.github/results.jpg b/.github/results.jpg
new file mode 100644
index 00000000..4dbc9b8d
Binary files /dev/null and b/.github/results.jpg differ
diff --git a/.github/search.jpg b/.github/search.jpg
new file mode 100644
index 00000000..784bec89
Binary files /dev/null and b/.github/search.jpg differ
diff --git a/.github/workflows/update_locales.yml b/.github/workflows/update_locales.yml
index 628e9bc9..93cdca44 100644
--- a/.github/workflows/update_locales.yml
+++ b/.github/workflows/update_locales.yml
@@ -1,4 +1,4 @@
-name: Fix locale issues
+name: Update locale lists
on:
workflow_dispatch:
@@ -9,7 +9,7 @@ on:
- master
concurrency:
- group: "locale"
+ group: "locale-list"
cancel-in-progress: true
jobs:
@@ -26,9 +26,6 @@ jobs:
- uses: actions/checkout@v2
with:
token: ${{ steps.generate_token.outputs.token }}
- - name: Install dependencies
- run: |
- pip3 install lxml
- name: Edit files
run: |
python3 .github/locales.py
@@ -38,5 +35,5 @@ jobs:
git config --local user.name "recloudstream[bot]"
git add .
# "echo" returns true so the build succeeds, even if no changed files
- git commit -m 'chore(locales): fix locale issues' || echo
+ git commit -m 'update list of locales' || echo
git push
diff --git a/README.md b/README.md
index e3d033ba..3430d626 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,12 @@
+ Download and stream movies, tv-shows and anime
+ Chromecast
+### Screenshots:
+
+


+
+
### Supported languages:
-
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 0bd56fe7..3c855d28 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -159,8 +159,6 @@ dependencies {
implementation("com.google.android.exoplayer:extension-cast:2.18.2")
implementation("com.google.android.exoplayer:extension-mediasession:2.18.2")
implementation("com.google.android.exoplayer:extension-okhttp:2.18.2")
- // Use the Jellyfin ffmpeg extension for easy ffmpeg audio decoding in exoplayer. Thank you Jellyfin <3
-// implementation("org.jellyfin.exoplayer:exoplayer-ffmpeg-extension:2.18.2+1")
//implementation("com.google.android.exoplayer:extension-leanback:2.14.0")
@@ -186,8 +184,8 @@ dependencies {
//implementation("com.github.TorrentStream:TorrentStream-Android:2.7.0")
// Downloading
- implementation("androidx.work:work-runtime:2.8.0")
- implementation("androidx.work:work-runtime-ktx:2.8.0")
+ implementation("androidx.work:work-runtime:2.7.1")
+ implementation("androidx.work:work-runtime-ktx:2.7.1")
// Networking
// implementation("com.squareup.okhttp3:okhttp:4.9.2")
diff --git a/app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt
index 92042d60..81753f6b 100644
--- a/app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt
+++ b/app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt
@@ -1,8 +1,9 @@
package com.lagradost.cloudstream3
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.lagradost.cloudstream3.mvvm.logError
+import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.SubtitleHelper
-import com.lagradost.cloudstream3.utils.TestingUtils
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Test
@@ -15,11 +16,142 @@ import org.junit.runner.RunWith
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
+ //@Test
+ //fun useAppContext() {
+ // // Context of the app under test.
+ // val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ // assertEquals("com.lagradost.cloudstream3", appContext.packageName)
+ //}
+
private fun getAllProviders(): List {
- println("Providers: ${APIHolder.allProviders.size}")
return APIHolder.allProviders //.filter { !it.usesWebView }
}
+ private suspend fun loadLinks(api: MainAPI, url: String?): Boolean {
+ Assert.assertNotNull("Api ${api.name} has invalid url on episode", url)
+ if (url == null) return true
+ var linksLoaded = 0
+ try {
+ val success = api.loadLinks(url, false, {}) { link ->
+ Assert.assertTrue(
+ "Api ${api.name} returns link with invalid Quality",
+ Qualities.values().map { it.value }.contains(link.quality)
+ )
+ Assert.assertTrue(
+ "Api ${api.name} returns link with invalid url ${link.url}",
+ link.url.length > 4
+ )
+ linksLoaded++
+ }
+ if (success) {
+ return linksLoaded > 0
+ }
+ Assert.assertTrue("Api ${api.name} has returns false on .loadLinks", success)
+ } catch (e: Exception) {
+ if (e.cause is NotImplementedError) {
+ Assert.fail("Provider has not implemented .loadLinks")
+ }
+ logError(e)
+ }
+ return true
+ }
+
+ private suspend fun testSingleProviderApi(api: MainAPI): Boolean {
+ val searchQueries = listOf("over", "iron", "guy")
+ var correctResponses = 0
+ var searchResult: List? = null
+ for (query in searchQueries) {
+ val response = try {
+ api.search(query)
+ } catch (e: Exception) {
+ if (e.cause is NotImplementedError) {
+ Assert.fail("Provider has not implemented .search")
+ }
+ logError(e)
+ null
+ }
+ if (!response.isNullOrEmpty()) {
+ correctResponses++
+ if (searchResult == null) {
+ searchResult = response
+ }
+ }
+ }
+
+ if (correctResponses == 0 || searchResult == null) {
+ System.err.println("Api ${api.name} did not return any valid search responses")
+ return false
+ }
+
+ try {
+ var validResults = false
+ for (result in searchResult) {
+ Assert.assertEquals(
+ "Invalid apiName on response on ${api.name}",
+ result.apiName,
+ api.name
+ )
+ val load = api.load(result.url) ?: continue
+ Assert.assertEquals(
+ "Invalid apiName on load on ${api.name}",
+ load.apiName,
+ result.apiName
+ )
+ Assert.assertTrue(
+ "Api ${api.name} on load does not contain any of the supportedTypes",
+ api.supportedTypes.contains(load.type)
+ )
+ when (load) {
+ is AnimeLoadResponse -> {
+ val gotNoEpisodes =
+ load.episodes.keys.isEmpty() || load.episodes.keys.any { load.episodes[it].isNullOrEmpty() }
+
+ if (gotNoEpisodes) {
+ println("Api ${api.name} got no episodes on ${load.url}")
+ continue
+ }
+
+ val url = (load.episodes[load.episodes.keys.first()])?.first()?.data
+ validResults = loadLinks(api, url)
+ if (!validResults) continue
+ }
+ is MovieLoadResponse -> {
+ val gotNoEpisodes = load.dataUrl.isBlank()
+ if (gotNoEpisodes) {
+ println("Api ${api.name} got no movie on ${load.url}")
+ continue
+ }
+
+ validResults = loadLinks(api, load.dataUrl)
+ if (!validResults) continue
+ }
+ is TvSeriesLoadResponse -> {
+ val gotNoEpisodes = load.episodes.isEmpty()
+ if (gotNoEpisodes) {
+ println("Api ${api.name} got no episodes on ${load.url}")
+ continue
+ }
+
+ validResults = loadLinks(api, load.episodes.first().data)
+ if (!validResults) continue
+ }
+ }
+ break
+ }
+ if (!validResults) {
+ System.err.println("Api ${api.name} did not load on any")
+ }
+
+ return validResults
+ } catch (e: Exception) {
+ if (e.cause is NotImplementedError) {
+ Assert.fail("Provider has not implemented .load")
+ }
+ logError(e)
+ return false
+ }
+ }
+
@Test
fun providersExist() {
Assert.assertTrue(getAllProviders().isNotEmpty())
@@ -27,7 +159,6 @@ class ExampleInstrumentedTest {
}
@Test
- @Throws(AssertionError::class)
fun providerCorrectData() {
val isoNames = SubtitleHelper.languages.map { it.ISO_639_1 }
Assert.assertFalse("ISO does not contain any languages", isoNames.isNullOrEmpty())
@@ -50,20 +181,67 @@ class ExampleInstrumentedTest {
fun providerCorrectHomepage() {
runBlocking {
getAllProviders().amap { api ->
- TestingUtils.testHomepage(api, ::println)
+ if (api.hasMainPage) {
+ try {
+ val f = api.mainPage.first()
+ val homepage =
+ api.getMainPage(1, MainPageRequest(f.name, f.data, f.horizontalImages))
+ when {
+ homepage == null -> {
+ System.err.println("Homepage provider ${api.name} did not correctly load homepage!")
+ }
+ homepage.items.isEmpty() -> {
+ System.err.println("Homepage provider ${api.name} does not contain any items!")
+ }
+ homepage.items.any { it.list.isEmpty() } -> {
+ System.err.println("Homepage provider ${api.name} does not have any items on result!")
+ }
+ }
+ } catch (e: Exception) {
+ if (e.cause is NotImplementedError) {
+ Assert.fail("Provider marked as hasMainPage, while in reality is has not been implemented")
+ }
+ logError(e)
+ }
+ }
}
}
println("Done providerCorrectHomepage")
}
+// @Test
+// fun testSingleProvider() {
+// testSingleProviderApi(ThenosProvider())
+// }
+
@Test
- fun testAllProvidersCorrect() {
+ fun providerCorrect() {
runBlocking {
- TestingUtils.getDeferredProviderTests(
- this,
- getAllProviders(),
- ::println
- ) { _, _ -> }
+ val invalidProvider = ArrayList>()
+ val providers = getAllProviders()
+ providers.amap { api ->
+ try {
+ println("Trying $api")
+ if (testSingleProviderApi(api)) {
+ println("Success $api")
+ } else {
+ System.err.println("Error $api")
+ invalidProvider.add(Pair(api, null))
+ }
+ } catch (e: Exception) {
+ logError(e)
+ invalidProvider.add(Pair(api, e))
+ }
+ }
+ if (invalidProvider.isEmpty()) {
+ println("No Invalid providers! :D")
+ } else {
+ println("Invalid providers are: ")
+ for (provider in invalidProvider) {
+ println("${provider.first}")
+ }
+ }
}
+ println("Done providerCorrect")
}
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 563c82f8..871c4f69 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -98,16 +98,6 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt
index c20786c3..4014e34d 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt
@@ -17,10 +17,8 @@ import com.lagradost.cloudstream3.syncproviders.SyncIdName
import com.lagradost.cloudstream3.ui.player.SubtitleData
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson
-import com.lagradost.cloudstream3.utils.Coroutines.mainWork
import com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf
import okhttp3.Interceptor
-import org.mozilla.javascript.Scriptable
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.absoluteValue
@@ -84,7 +82,7 @@ object APIHolder {
initMap()
return apiMap?.get(apiName)?.let { apis.getOrNull(it) }
// Leave the ?. null check, it can crash regardless
- ?: allProviders.firstOrNull { it.name == apiName }
+ ?: allProviders.firstOrNull { it?.name == apiName }
}
}
@@ -736,19 +734,6 @@ fun fixTitle(str: String): String {
.replaceFirstChar { char -> if (char.isLowerCase()) char.titlecase(Locale.getDefault()) else it }
}
}
-/**
- * Get rhino context in a safe way as it needs to be initialized on the main thread.
- * Make sure you get the scope using: val scope: Scriptable = rhino.initSafeStandardObjects()
- * Use like the following: rhino.evaluateString(scope, js, "JavaScript", 1, null)
- **/
-suspend fun getRhinoContext(): org.mozilla.javascript.Context {
- return Coroutines.mainWork {
- val rhino = org.mozilla.javascript.Context.enter()
- rhino.initSafeStandardObjects()
- rhino.optimizationLevel = -1
- rhino
- }
-}
/** https://www.imdb.com/title/tt2861424/ -> tt2861424 */
fun imdbUrlToId(url: String): String? {
@@ -1327,7 +1312,7 @@ fun LoadResponse?.isAnimeBased(): Boolean {
fun TvType?.isEpisodeBased(): Boolean {
if (this == null) return false
- return (this == TvType.TvSeries || this == TvType.Anime || this == TvType.AsianDrama)
+ return (this == TvType.TvSeries || this == TvType.Anime)
}
@@ -1351,7 +1336,6 @@ interface EpisodeResponse {
var showStatus: ShowStatus?
var nextAiring: NextAiring?
var seasonNames: List?
- fun getLatestEpisodes(): Map
}
@JvmName("addSeasonNamesString")
@@ -1420,18 +1404,7 @@ data class AnimeLoadResponse(
override var nextAiring: NextAiring? = null,
override var seasonNames: List? = null,
override var backgroundPosterUrl: String? = null,
-) : LoadResponse, EpisodeResponse {
- override fun getLatestEpisodes(): Map {
- return episodes.map { (status, episodes) ->
- val maxSeason = episodes.maxOfOrNull { it.season ?: Int.MIN_VALUE }
- .takeUnless { it == Int.MIN_VALUE }
- status to episodes
- .filter { it.season == maxSeason }
- .maxOfOrNull { it.episode ?: Int.MIN_VALUE }
- .takeUnless { it == Int.MIN_VALUE }
- }.toMap()
- }
-}
+) : LoadResponse, EpisodeResponse
/**
* If episodes already exist appends the list.
@@ -1629,17 +1602,7 @@ data class TvSeriesLoadResponse(
override var nextAiring: NextAiring? = null,
override var seasonNames: List? = null,
override var backgroundPosterUrl: String? = null,
-) : LoadResponse, EpisodeResponse {
- override fun getLatestEpisodes(): Map {
- val maxSeason =
- episodes.maxOfOrNull { it.season ?: Int.MIN_VALUE }.takeUnless { it == Int.MIN_VALUE }
- val max = episodes
- .filter { it.season == maxSeason }
- .maxOfOrNull { it.episode ?: Int.MIN_VALUE }
- .takeUnless { it == Int.MIN_VALUE }
- return mapOf(DubStatus.None to max)
- }
-}
+) : LoadResponse, EpisodeResponse
suspend fun MainAPI.newTvSeriesLoadResponse(
name: String,
diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
index d054f504..eddec15e 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
@@ -5,8 +5,6 @@ import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.content.res.Configuration
-import android.net.Uri
-import android.os.Build
import android.os.Bundle
import android.util.AttributeSet
import android.util.Log
@@ -34,7 +32,6 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.google.android.gms.cast.framework.*
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.navigationrail.NavigationRailView
-import com.google.android.material.snackbar.Snackbar
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import com.lagradost.cloudstream3.APIHolder.allProviders
import com.lagradost.cloudstream3.APIHolder.apis
@@ -58,7 +55,6 @@ import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.OAuth2Apis
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.accountManagers
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appString
-import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringPlayer
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringRepo
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringResumeWatching
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringSearch
@@ -67,9 +63,6 @@ import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
import com.lagradost.cloudstream3.ui.home.HomeViewModel
-import com.lagradost.cloudstream3.ui.player.BasicLink
-import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
-import com.lagradost.cloudstream3.ui.player.LinkGenerator
import com.lagradost.cloudstream3.ui.result.ResultViewModel2
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
import com.lagradost.cloudstream3.ui.result.setImage
@@ -86,7 +79,6 @@ import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.html
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
-import com.lagradost.cloudstream3.utils.AppUtils.isNetworkAvailable
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
import com.lagradost.cloudstream3.utils.AppUtils.loadRepository
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
@@ -94,7 +86,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
-import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
@@ -175,12 +166,7 @@ open class ResultResume(
val VLC = object : ResultResume(
VLC_PACKAGE,
- // Android 13 intent restrictions fucks up specifically launching the VLC player
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
- "org.videolan.vlc.player.result"
- } else {
- Intent.ACTION_VIEW
- },
+ "org.videolan.vlc.player.result",
"extra_position",
"extra_duration",
) {
@@ -279,8 +265,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
isWebview: Boolean
): Boolean =
with(activity) {
- // TODO MUCH BETTER HANDLING
-
// Invalid URIs can crash
fun safeURI(uri: String) = normalSafeApiCall { URI(uri) }
@@ -331,25 +315,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
} else if (safeURI(str)?.scheme == appStringSearch) {
nextSearchQuery =
URLDecoder.decode(str.substringAfter("$appStringSearch://"), "UTF-8")
-
- // Use both navigation views to support both layouts.
- // It might be better to use the QuickSearch.
- nav_view?.selectedItemId = R.id.navigation_search
- nav_rail_view?.selectedItemId = R.id.navigation_search
- } else if (safeURI(str)?.scheme == appStringPlayer) {
- val uri = Uri.parse(str)
- val name = uri.getQueryParameter("name")
- val url = URLDecoder.decode(uri.authority, "UTF-8")
-
- navigate(
- R.id.global_to_navigation_player,
- GeneratorPlayer.newInstance(
- LinkGenerator(
- listOf(BasicLink(url, name)),
- extract = true,
- )
- )
- )
+ nav_view.selectedItemId = R.id.navigation_search
} else if (safeURI(str)?.scheme == appStringResumeWatching) {
val id =
str.substringAfter("$appStringResumeWatching://").toIntOrNull()
@@ -436,7 +402,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
R.id.navigation_settings_general,
R.id.navigation_settings_extensions,
R.id.navigation_settings_plugins,
- R.id.navigation_test_providers,
).contains(destination.id)
@@ -751,29 +716,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
changeStatusBarState(isEmulatorSettings())
- // Automatically enable jsdelivr if cant connect to raw.githubusercontent.com
- if (this.getKey(getString(R.string.jsdelivr_proxy_key)) == null && isNetworkAvailable()) {
- main {
- if (checkGithubConnectivity()) {
- this.setKey(getString(R.string.jsdelivr_proxy_key), false)
- } else {
- this.setKey(getString(R.string.jsdelivr_proxy_key), true)
- val parentView: View = findViewById(android.R.id.content)
- Snackbar.make(parentView, R.string.jsdelivr_enabled, Snackbar.LENGTH_LONG)
- .let { snackbar ->
- snackbar.setAction(R.string.revert) {
- setKey(getString(R.string.jsdelivr_proxy_key), false)
- }
- snackbar.setBackgroundTint(colorFromAttribute(R.attr.primaryGrayBackground))
- snackbar.setTextColor(colorFromAttribute(R.attr.textColor))
- snackbar.setActionTextColor(colorFromAttribute(R.attr.colorPrimary))
- snackbar.show()
- }
- }
-
- }
- }
-
if (PluginManager.checkSafeModeFile()) {
normalSafeApiCall {
@@ -1147,15 +1089,4 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
// }
}
-
- suspend fun checkGithubConnectivity(): Boolean {
- return try {
- app.get(
- "https://raw.githubusercontent.com/recloudstream/.github/master/connectivitycheck",
- timeout = 5
- ).text.trim() == "ok"
- } catch (t: Throwable) {
- false
- }
- }
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Dailymotion.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Dailymotion.kt
index 4b7cb19f..125e4bcf 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Dailymotion.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Dailymotion.kt
@@ -6,7 +6,6 @@ import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
-import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import com.lagradost.cloudstream3.utils.Qualities
import java.net.URL
@@ -43,9 +42,18 @@ open class Dailymotion : ExtractorApi() {
)
val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = cookies)
.parsedSafe() ?: return
- metaData.qualities.forEach { (_, video) ->
+ metaData.qualities.forEach { (key, video) ->
video.forEach {
- getStream(it.url, this.name, callback)
+ callback.invoke(
+ ExtractorLink(
+ name,
+ "$name $key",
+ it.url,
+ "",
+ Qualities.Unknown.value,
+ true
+ )
+ )
}
}
}
@@ -67,17 +75,6 @@ open class Dailymotion : ExtractorApi() {
return null
}
- private suspend fun getStream(
- streamLink: String,
- name: String,
- callback: (ExtractorLink) -> Unit
- ) {
- return generateM3u8(
- name,
- streamLink,
- "",
- ).forEach(callback)
- }
data class Config(
val context: Context,
val dmInternalData: InternalData
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt
index 0d94eb08..7ec1fb22 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt
@@ -38,9 +38,6 @@ class DoodWsExtractor : DoodLaExtractor() {
override var mainUrl = "https://dood.ws"
}
-class DoodYtExtractor : DoodLaExtractor() {
- override var mainUrl = "https://dood.yt"
-}
open class DoodLaExtractor : ExtractorApi() {
override var name = "DoodStream"
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Evolaod.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Evolaod.kt
index 3e38b446..eddbf6df 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Evolaod.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Evolaod.kt
@@ -16,7 +16,26 @@ open class Evoload : ExtractorApi() {
override suspend fun getUrl(url: String, referer: String?): List {
- val id = url.replace("https://evoload.io/e/", "") // wanted media id
+ val lang = url.substring(0, 2)
+ val flag =
+ if (lang == "vo") {
+ " \uD83C\uDDEC\uD83C\uDDE7"
+ }
+ else if (lang == "vf"){
+ " \uD83C\uDDE8\uD83C\uDDF5"
+ } else {
+ ""
+ }
+
+ val cleaned_url = if (lang == "ht") { // if url doesn't contain a flag and the url starts with http://
+ url
+ } else {
+ url.substring(2, url.length)
+ }
+ //println(lang)
+ //println(cleaned_url)
+
+ val id = cleaned_url.replace("https://evoload.io/e/", "") // wanted media id
val csrv_token = app.get("https://csrv.evosrv.com/captcha?m412548=").text // whatever that is
val captchaPass = app.get("https://cd2.evosrv.com/html/jsx/e.jsx").text.take(300).split("captcha_pass = '")[1].split("\'")[0] //extract the captcha pass from the js response (located in the 300 first chars)
val payload = mapOf("code" to id, "csrv_token" to csrv_token, "pass" to captchaPass)
@@ -25,9 +44,9 @@ open class Evoload : ExtractorApi() {
return listOf(
ExtractorLink(
name,
- name,
+ name + flag,
link,
- url,
+ cleaned_url,
Qualities.Unknown.value,
)
)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Filesim.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Filesim.kt
index 84fd0552..bc910a7e 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Filesim.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Filesim.kt
@@ -1,25 +1,18 @@
package com.lagradost.cloudstream3.extractors
+import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
-import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
+import com.lagradost.cloudstream3.utils.AppUtils.parseJson
+import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
+import java.net.URI
-
-class Ztreamhub : Filesim() {
- override val mainUrl: String = "https://ztreamhub.com" //Here 'cause works
- override val name = "Zstreamhub"
-}
class FileMoon : Filesim() {
override val mainUrl = "https://filemoon.to"
override val name = "FileMoon"
}
-class FileMoonSx : Filesim() {
- override val mainUrl = "https://filemoon.sx"
- override val name = "FileMoonSx"
-}
-
open class Filesim : ExtractorApi() {
override val name = "Filesim"
override val mainUrl = "https://files.im"
@@ -31,27 +24,34 @@ open class Filesim : ExtractorApi() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
- val response = app.get(url, referer = mainUrl).document
- response.select("script[type=text/javascript]").map { script ->
- if (script.data().contains(Regex("eval\\(function\\(p,a,c,k,e,[rd]"))) {
- val unpackedscript = getAndUnpack(script.data())
- val m3u8Regex = Regex("file.\\\"(.*?m3u8.*?)\\\"")
- val m3u8 = m3u8Regex.find(unpackedscript)?.destructured?.component1() ?: ""
- if (m3u8.isNotEmpty()) {
- generateM3u8(
- name,
- m3u8,
- mainUrl
- ).forEach(callback)
+ with(app.get(url).document) {
+ this.select("script").forEach { script ->
+ if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
+ val data = getAndUnpack(script.data())
+ val foundData = Regex("""sources:\[(.*?)]""").find(data)?.groupValues?.get(1) ?: return@forEach
+ val fixedData = foundData.replace("file:", """"file":""")
+
+ parseJson>("[$fixedData]").forEach {
+ callback.invoke(
+ ExtractorLink(
+ name,
+ name,
+ it.file,
+ "$mainUrl/",
+ Qualities.Unknown.value,
+ URI(it.file).path.endsWith(".m3u8")
+ )
+ )
+ }
}
}
}
}
- /* private data class ResponseSource(
+ private data class ResponseSource(
@JsonProperty("file") val file: String,
@JsonProperty("type") val type: String?,
@JsonProperty("label") val label: String?
- ) */
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt
index 6a4945bb..c28a8900 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt
@@ -18,36 +18,31 @@ open class Linkbox : ExtractorApi() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
- val id = Regex("""(?:/f/|/file/|\?id=)(\w+)""").find(url)?.groupValues?.get(1)
- app.get("$mainUrl/api/file/detail?itemId=$id", referer = url)
- .parsedSafe()?.data?.itemInfo?.resolutionList?.map { link ->
- callback.invoke(
- ExtractorLink(
- name,
- name,
- link.url ?: return@map null,
- url,
- getQualityFromName(link.resolution)
- )
+ val id = Regex("""(/file/|id=)(\S+)[&/?]""").find(url)?.groupValues?.get(2)
+ app.get("$mainUrl/api/open/get_url?itemId=$id", referer=url).parsedSafe()?.data?.rList?.map { link ->
+ callback.invoke(
+ ExtractorLink(
+ name,
+ name,
+ link.url,
+ url,
+ getQualityFromName(link.resolution)
)
- }
+ )
+ }
}
- data class Resolutions(
- @JsonProperty("url") val url: String? = null,
- @JsonProperty("resolution") val resolution: String? = null,
- )
-
- data class ItemInfo(
- @JsonProperty("resolutionList") val resolutionList: ArrayList? = arrayListOf(),
+ data class RList(
+ @JsonProperty("url") val url: String,
+ @JsonProperty("resolution") val resolution: String?,
)
data class Data(
- @JsonProperty("itemInfo") val itemInfo: ItemInfo? = null,
+ @JsonProperty("rList") val rList: List?,
)
data class Responses(
- @JsonProperty("data") val data: Data? = null,
+ @JsonProperty("data") val data: Data?,
)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Sendvid.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Sendvid.kt
deleted file mode 100644
index 514b802d..00000000
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Sendvid.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.lagradost.cloudstream3.extractors
-
-import com.lagradost.cloudstream3.SubtitleFile
-import com.lagradost.cloudstream3.utils.*
-import com.lagradost.cloudstream3.app
-import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
-
-open class Sendvid : ExtractorApi() {
- override var name = "Sendvid"
- override val mainUrl = "https://sendvid.com"
- override val requiresReferer = false
- override suspend fun getUrl(
- url: String,
- referer: String?,
- subtitleCallback: (SubtitleFile) -> Unit,
- callback: (ExtractorLink) -> Unit
- ) {
- val doc = app.get(url).document
- val urlString = doc.select("head meta[property=og:video:secure_url]").attr("content")
- if (urlString.contains("m3u8")) {
- generateM3u8(
- name,
- urlString,
- mainUrl,
- ).forEach(callback)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt
index cac31328..958d63fb 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt
@@ -77,10 +77,6 @@ class StreamSB10 : StreamSB() {
override var mainUrl = "https://sbplay2.xyz"
}
-class StreamSB11 : StreamSB() {
- override var mainUrl = "https://sbbrisk.com"
-}
-
// This is a modified version of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/genoanime/src/eu/kanade/tachiyomi/animeextension/en/genoanime/extractors/StreamSBExtractor.kt
// The following code is under the Apache License 2.0 https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE
open class StreamSB : ExtractorApi() {
@@ -134,7 +130,7 @@ open class StreamSB : ExtractorApi() {
it.value.replace(Regex("(embed-|/e/)"), "")
}.first()
// val master = "$mainUrl/sources48/6d6144797752744a454267617c7c${bytesToHex.lowercase()}7c7c4e61755a56456f34385243727c7c73747265616d7362/6b4a33767968506e4e71374f7c7c343837323439333133333462353935333633373836643638376337633462333634663539343137373761333635313533333835333763376333393636363133393635366136323733343435323332376137633763373337343732363536313664373336327c7c504d754478413835306633797c7c73747265616d7362"
- val master = "$mainUrl/sources15/" + bytesToHex("||$id||||streamsb".toByteArray()) + "/"
+ val master = "$mainUrl/sources50/" + bytesToHex("||$id||||streamsb".toByteArray()) + "/"
val headers = mapOf(
"watchsb" to "sbstream",
)
@@ -160,4 +156,4 @@ open class StreamSB : ExtractorApi() {
)
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Uqload.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Uqload.kt
index 86bd9e0b..5109acc3 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Uqload.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Uqload.kt
@@ -7,10 +7,6 @@ class Uqload1 : Uqload() {
override var mainUrl = "https://uqload.com"
}
-class Uqload2 : Uqload() {
- override var mainUrl = "https://uqload.co"
-}
-
open class Uqload : ExtractorApi() {
override val name: String = "Uqload"
override val mainUrl: String = "https://www.uqload.com"
@@ -19,14 +15,30 @@ open class Uqload : ExtractorApi() {
override suspend fun getUrl(url: String, referer: String?): List? {
- with(app.get(url)) { // raised error ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED (3003) is due to the response: "error_nofile"
+ val lang = url.substring(0, 2)
+ val flag =
+ if (lang == "vo") {
+ " \uD83C\uDDEC\uD83C\uDDE7"
+ }
+ else if (lang == "vf"){
+ " \uD83C\uDDE8\uD83C\uDDF5"
+ } else {
+ ""
+ }
+
+ val cleaned_url = if (lang == "ht") { // if url doesn't contain a flag and the url starts with http://
+ url
+ } else {
+ url.substring(2, url.length)
+ }
+ with(app.get(cleaned_url)) { // raised error ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED (3003) is due to the response: "error_nofile"
srcRegex.find(this.text)?.groupValues?.get(1)?.replace("\"", "")?.let { link ->
return listOf(
ExtractorLink(
name,
- name,
+ name + flag,
link,
- url,
+ cleaned_url,
Qualities.Unknown.value,
)
)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Vido.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vido.kt
deleted file mode 100644
index 67e59281..00000000
--- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Vido.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.lagradost.cloudstream3.extractors
-import com.lagradost.cloudstream3.app
-import com.lagradost.cloudstream3.utils.ExtractorApi
-import com.lagradost.cloudstream3.utils.ExtractorLink
-import com.lagradost.cloudstream3.utils.Qualities
-import com.lagradost.cloudstream3.utils.getAndUnpack
-
-class Vido : ExtractorApi() {
- override var name = "Vido"
- override var mainUrl = "https://vido.lol"
- private val srcRegex = Regex("""sources:\s*\["(.*?)"\]""")
- override val requiresReferer = true
-
- override suspend fun getUrl(url: String, referer: String?): List? {
- val methode = app.get(url.replace("/e/", "/embed-")) // fix wiflix and mesfilms
- with(methode) {
- if (!methode.isSuccessful) return null
- //val quality = unpackedText.lowercase().substringAfter(" height=").substringBefore(" ").toIntOrNull()
- srcRegex.find(this.text)?.groupValues?.get(1)?.let { link ->
- return listOf(
- ExtractorLink(
- name,
- name,
- link,
- url,
- Qualities.Unknown.value,
- true,
- )
- )
- }
- }
- return null
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt b/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt
index bb15bc85..afe956cc 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt
@@ -49,7 +49,7 @@ inline fun debugWarning(assert: () -> Boolean, message: () -> String) {
}
}
-fun LifecycleOwner.observe(liveData: LiveData, action: (t: T) -> Unit) {
+fun LifecycleOwner.observe(liveData: LiveData, action: (t: T) -> Unit) {
liveData.observe(this) { it?.let { t -> action(t) } }
}
@@ -121,21 +121,13 @@ suspend fun suspendSafeApiCall(apiCall: suspend () -> T): T? {
}
}
-fun Throwable.getAllMessages(): String {
- return (this.localizedMessage ?: "") + (this.cause?.getAllMessages()?.let { "\n$it" } ?: "")
-}
-
-fun Throwable.getStackTracePretty(showMessage: Boolean = true): String {
- val prefix = if (showMessage) this.localizedMessage?.let { "\n$it" } ?: "" else ""
- return prefix + this.stackTrace.joinToString(
- separator = "\n"
- ) {
- "${it.fileName} ${it.lineNumber}"
- }
-}
-
fun safeFail(throwable: Throwable): Resource {
- val stackTraceMsg = throwable.getStackTracePretty()
+ val stackTraceMsg =
+ (throwable.localizedMessage ?: "") + "\n\n" + throwable.stackTrace.joinToString(
+ separator = "\n"
+ ) {
+ "${it.fileName} ${it.lineNumber}"
+ }
return Resource.Failure(false, null, null, stackTraceMsg)
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt
index 0dee57eb..3533d6a8 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt
@@ -16,7 +16,6 @@ import com.google.gson.Gson
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
import com.lagradost.cloudstream3.APIHolder.removePluginMapping
-import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
@@ -166,11 +165,11 @@ object PluginManager {
private var loadedLocalPlugins = false
private val gson = Gson()
- private suspend fun maybeLoadPlugin(context: Context, file: File) {
+ private suspend fun maybeLoadPlugin(activity: Activity, file: File) {
val name = file.name
if (file.extension == "zip" || file.extension == "cs3") {
loadPlugin(
- context,
+ activity,
file,
PluginData(name, null, false, file.absolutePath, PLUGIN_VERSION_NOT_SET)
)
@@ -200,7 +199,7 @@ object PluginManager {
// var allCurrentOutDatedPlugins: Set = emptySet()
- suspend fun loadSinglePlugin(context: Context, apiName: String): Boolean {
+ suspend fun loadSinglePlugin(activity: Activity, apiName: String): Boolean {
return (getPluginsOnline().firstOrNull {
// Most of the time the provider ends with Provider which isn't part of the api name
it.internalName.replace("provider", "", ignoreCase = true) == apiName
@@ -210,7 +209,7 @@ object PluginManager {
})?.let { savedData ->
// OnlinePluginData(savedData, onlineData)
loadPlugin(
- context,
+ activity,
File(savedData.filePath),
savedData
)
@@ -372,11 +371,11 @@ object PluginManager {
/**
* Use updateAllOnlinePluginsAndLoadThem
* */
- fun loadAllOnlinePlugins(context: Context) {
+ fun loadAllOnlinePlugins(activity: Activity) {
// Load all plugins as fast as possible!
(getPluginsOnline()).toList().apmap { pluginData ->
loadPlugin(
- context,
+ activity,
File(pluginData.filePath),
pluginData
)
@@ -399,7 +398,7 @@ object PluginManager {
* @param forceReload see afterPluginsLoadedEvent, basically a way to load all local plugins
* and reload all pages even if they are previously valid
**/
- fun loadAllLocalPlugins(context: Context, forceReload: Boolean) {
+ fun loadAllLocalPlugins(activity: Activity, forceReload: Boolean) {
val dir = File(LOCAL_PLUGINS_PATH)
removeKey(PLUGINS_KEY_LOCAL)
@@ -417,7 +416,7 @@ object PluginManager {
Log.d(TAG, "Files in '${LOCAL_PLUGINS_PATH}' folder: $sortedPlugins")
sortedPlugins?.sortedBy { it.name }?.apmap { file ->
- maybeLoadPlugin(context, file)
+ maybeLoadPlugin(activity, file)
}
loadedLocalPlugins = true
@@ -442,14 +441,14 @@ object PluginManager {
/**
* @return True if successful, false if not
* */
- private suspend fun loadPlugin(context: Context, file: File, data: PluginData): Boolean {
+ private suspend fun loadPlugin(activity: Activity, file: File, data: PluginData): Boolean {
val fileName = file.nameWithoutExtension
val filePath = file.absolutePath
currentlyLoading = fileName
Log.i(TAG, "Loading plugin: $data")
return try {
- val loader = PathClassLoader(filePath, context.classLoader)
+ val loader = PathClassLoader(filePath, activity.classLoader)
var manifest: Plugin.Manifest
loader.getResourceAsStream("manifest.json").use { stream ->
if (stream == null) {
@@ -493,22 +492,22 @@ object PluginManager {
addAssetPath.invoke(assets, file.absolutePath)
pluginInstance.resources = Resources(
assets,
- context.resources.displayMetrics,
- context.resources.configuration
+ activity.resources.displayMetrics,
+ activity.resources.configuration
)
}
plugins[filePath] = pluginInstance
classLoaders[loader] = pluginInstance
urlPlugins[data.url ?: filePath] = pluginInstance
- pluginInstance.load(context)
+ pluginInstance.load(activity)
Log.i(TAG, "Loaded plugin ${data.internalName} successfully")
currentlyLoading = null
true
} catch (e: Throwable) {
Log.e(TAG, "Failed to load $file: ${Log.getStackTraceString(e)}")
showToast(
- context.getActivity(),
- context.getString(R.string.plugin_load_fail).format(fileName),
+ activity,
+ activity.getString(R.string.plugin_load_fail).format(fileName),
Toast.LENGTH_LONG
)
currentlyLoading = null
diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt
index 742bf308..e77b2d54 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt
@@ -2,10 +2,8 @@ package com.lagradost.cloudstream3.plugins
import android.content.Context
import com.fasterxml.jackson.annotation.JsonProperty
-import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
-import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.amap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError
@@ -73,15 +71,6 @@ object RepositoryManager {
val PREBUILT_REPOSITORIES: Array by lazy {
getKey("PREBUILT_REPOSITORIES") ?: emptyArray()
}
- val GH_REGEX = Regex("^https://raw.githubusercontent.com/([A-Za-z0-9-]+)/([A-Za-z0-9_.-]+)/(.*)$")
-
- /* Convert raw.githubusercontent.com urls to cdn.jsdelivr.net if enabled in settings */
- fun convertRawGitUrl(url: String): String {
- if (getKey(context!!.getString(R.string.jsdelivr_proxy_key)) != true) return url
- val match = GH_REGEX.find(url) ?: return url
- val (user, repo, rest) = match.destructured
- return "https://cdn.jsdelivr.net/gh/$user/$repo@$rest"
- }
suspend fun parseRepoUrl(url: String): String? {
val fixedUrl = url.trim()
@@ -95,15 +84,10 @@ object RepositoryManager {
}
} else if (fixedUrl.matches("^[a-zA-Z0-9!_-]+$".toRegex())) {
suspendSafeApiCall {
- app.get("https://l.cloudstream.cf/${fixedUrl}", allowRedirects = false).let {
- it.headers["Location"]?.let { url ->
- return@suspendSafeApiCall if (!url.startsWith("https://cutt.ly/branded-domains")) url
- else null
- }
- app.get("https://cutt.ly/${fixedUrl}", allowRedirects = false).let { it2 ->
- it2.headers["Location"]?.let { url ->
- return@suspendSafeApiCall if (url.startsWith("https://cutt.ly/404")) url else null
- }
+ app.get("https://l.cloudstream.cf/${fixedUrl}").let {
+ return@let if (it.isSuccessful && !it.url.startsWith("https://cutt.ly/branded-domains")) it.url
+ else app.get("https://cutt.ly/${fixedUrl}").let let2@{ it2 ->
+ return@let2 if (it2.isSuccessful) it2.url else null
}
}
}
@@ -113,14 +97,14 @@ object RepositoryManager {
suspend fun parseRepository(url: String): Repository? {
return suspendSafeApiCall {
// Take manifestVersion and such into account later
- app.get(convertRawGitUrl(url)).parsedSafe()
+ app.get(url).parsedSafe()
}
}
private suspend fun parsePlugins(pluginUrls: String): List {
// Take manifestVersion and such into account later
return try {
- val response = app.get(convertRawGitUrl(pluginUrls))
+ val response = app.get(pluginUrls)
// Normal parsed function not working?
// return response.parsedSafe()
tryParseJson>(response.text)?.toList() ?: emptyList()
@@ -155,7 +139,7 @@ object RepositoryManager {
}
file.createNewFile()
- val body = app.get(convertRawGitUrl(pluginUrl)).okhttpResponse.body
+ val body = app.get(pluginUrl).okhttpResponse.body
write(body.byteStream(), file.outputStream())
file
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/services/SubscriptionWorkManager.kt b/app/src/main/java/com/lagradost/cloudstream3/services/SubscriptionWorkManager.kt
deleted file mode 100644
index adf5abfa..00000000
--- a/app/src/main/java/com/lagradost/cloudstream3/services/SubscriptionWorkManager.kt
+++ /dev/null
@@ -1,224 +0,0 @@
-package com.lagradost.cloudstream3.services
-
-import android.app.NotificationManager
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build
-import androidx.core.app.NotificationCompat
-import androidx.core.net.toUri
-import androidx.work.*
-import com.lagradost.cloudstream3.*
-import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
-import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
-import com.lagradost.cloudstream3.R
-import com.lagradost.cloudstream3.mvvm.safeApiCall
-import com.lagradost.cloudstream3.plugins.PluginManager
-import com.lagradost.cloudstream3.ui.result.txt
-import com.lagradost.cloudstream3.utils.AppUtils.createNotificationChannel
-import com.lagradost.cloudstream3.utils.Coroutines.ioWork
-import com.lagradost.cloudstream3.utils.DataStoreHelper
-import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllSubscriptions
-import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
-import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
-import com.lagradost.cloudstream3.utils.VideoDownloadManager.getImageBitmapFromUrl
-import kotlinx.coroutines.withTimeoutOrNull
-import java.util.concurrent.TimeUnit
-
-const val SUBSCRIPTION_CHANNEL_ID = "cloudstream3.subscriptions"
-const val SUBSCRIPTION_WORK_NAME = "work_subscription"
-const val SUBSCRIPTION_CHANNEL_NAME = "Subscriptions"
-const val SUBSCRIPTION_CHANNEL_DESCRIPTION = "Notifications for new episodes on subscribed shows"
-const val SUBSCRIPTION_NOTIFICATION_ID = 938712897 // Random unique
-
-class SubscriptionWorkManager(val context: Context, workerParams: WorkerParameters) :
- CoroutineWorker(context, workerParams) {
- companion object {
- fun enqueuePeriodicWork(context: Context?) {
- if (context == null) return
-
- val constraints = Constraints.Builder()
- .setRequiredNetworkType(NetworkType.CONNECTED)
- .build()
-
- val periodicSyncDataWork =
- PeriodicWorkRequest.Builder(SubscriptionWorkManager::class.java, 6, TimeUnit.HOURS)
- .addTag(SUBSCRIPTION_WORK_NAME)
- .setConstraints(constraints)
- .build()
-
- WorkManager.getInstance(context).enqueueUniquePeriodicWork(
- SUBSCRIPTION_WORK_NAME,
- ExistingPeriodicWorkPolicy.KEEP,
- periodicSyncDataWork
- )
-
- // Uncomment below for testing
-
-// val oneTimeSyncDataWork =
-// OneTimeWorkRequest.Builder(SubscriptionWorkManager::class.java)
-// .addTag(SUBSCRIPTION_WORK_NAME)
-// .setConstraints(constraints)
-// .build()
-//
-// WorkManager.getInstance(context).enqueue(oneTimeSyncDataWork)
- }
- }
-
- private val progressNotificationBuilder =
- NotificationCompat.Builder(context, SUBSCRIPTION_CHANNEL_ID)
- .setAutoCancel(false)
- .setColorized(true)
- .setOnlyAlertOnce(true)
- .setSilent(true)
- .setPriority(NotificationCompat.PRIORITY_DEFAULT)
- .setColor(context.colorFromAttribute(R.attr.colorPrimary))
- .setContentTitle(context.getString(R.string.subscription_in_progress_notification))
- .setSmallIcon(R.drawable.quantum_ic_refresh_white_24)
- .setProgress(0, 0, true)
-
- private val updateNotificationBuilder =
- NotificationCompat.Builder(context, SUBSCRIPTION_CHANNEL_ID)
- .setColorized(true)
- .setOnlyAlertOnce(true)
- .setAutoCancel(true)
- .setPriority(NotificationCompat.PRIORITY_DEFAULT)
- .setColor(context.colorFromAttribute(R.attr.colorPrimary))
- .setSmallIcon(R.drawable.ic_cloudstream_monochrome_big)
-
- private val notificationManager: NotificationManager =
- context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
- private fun updateProgress(max: Int, progress: Int, indeterminate: Boolean) {
- notificationManager.notify(
- SUBSCRIPTION_NOTIFICATION_ID, progressNotificationBuilder
- .setProgress(max, progress, indeterminate)
- .build()
- )
- }
-
- override suspend fun doWork(): Result {
-// println("Update subscriptions!")
- context.createNotificationChannel(
- SUBSCRIPTION_CHANNEL_ID,
- SUBSCRIPTION_CHANNEL_NAME,
- SUBSCRIPTION_CHANNEL_DESCRIPTION
- )
-
- setForeground(
- ForegroundInfo(
- SUBSCRIPTION_NOTIFICATION_ID,
- progressNotificationBuilder.build()
- )
- )
-
- val subscriptions = getAllSubscriptions()
-
- if (subscriptions.isEmpty()) {
- WorkManager.getInstance(context).cancelWorkById(this.id)
- return Result.success()
- }
-
- val max = subscriptions.size
- var progress = 0
-
- updateProgress(max, progress, true)
-
- // We need all plugins loaded.
- PluginManager.loadAllOnlinePlugins(context)
- PluginManager.loadAllLocalPlugins(context, false)
-
- subscriptions.apmap { savedData ->
- try {
- val id = savedData.id ?: return@apmap null
- val api = getApiFromNameNull(savedData.apiName) ?: return@apmap null
-
- // Reasonable timeout to prevent having this worker run forever.
- val response = withTimeoutOrNull(60_000) {
- api.load(savedData.url) as? EpisodeResponse
- } ?: return@apmap null
-
- val dubPreference =
- getDub(id) ?: if (
- context.getApiDubstatusSettings().contains(DubStatus.Dubbed)
- ) {
- DubStatus.Dubbed
- } else {
- DubStatus.Subbed
- }
-
- val latestEpisodes = response.getLatestEpisodes()
- val latestPreferredEpisode = latestEpisodes[dubPreference]
-
- val (shouldUpdate, latestEpisode) = if (latestPreferredEpisode != null) {
- val latestSeenEpisode =
- savedData.lastSeenEpisodeCount[dubPreference] ?: Int.MIN_VALUE
- val shouldUpdate = latestPreferredEpisode > latestSeenEpisode
- shouldUpdate to latestPreferredEpisode
- } else {
- val latestEpisode = latestEpisodes[DubStatus.None] ?: Int.MIN_VALUE
- val latestSeenEpisode =
- savedData.lastSeenEpisodeCount[DubStatus.None] ?: Int.MIN_VALUE
- val shouldUpdate = latestEpisode > latestSeenEpisode
- shouldUpdate to latestEpisode
- }
-
- DataStoreHelper.updateSubscribedData(
- id,
- savedData,
- response
- )
-
- if (shouldUpdate) {
- val updateHeader = savedData.name
- val updateDescription = txt(
- R.string.subscription_episode_released,
- latestEpisode,
- savedData.name
- ).asString(context)
-
- val intent = Intent(context, MainActivity::class.java).apply {
- data = savedData.url.toUri()
- flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
- }
-
- val pendingIntent =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- PendingIntent.getActivity(
- context,
- 0,
- intent,
- PendingIntent.FLAG_IMMUTABLE
- )
- } else {
- PendingIntent.getActivity(context, 0, intent, 0)
- }
-
- val poster = ioWork {
- savedData.posterUrl?.let { url ->
- context.getImageBitmapFromUrl(
- url,
- savedData.posterHeaders
- )
- }
- }
-
- val updateNotification =
- updateNotificationBuilder.setContentTitle(updateHeader)
- .setContentText(updateDescription)
- .setContentIntent(pendingIntent)
- .setLargeIcon(poster)
- .build()
-
- notificationManager.notify(id, updateNotification)
- }
-
- // You can probably get some issues here since this is async but it does not matter much.
- updateProgress(max, ++progress, false)
- } catch (_: Throwable) {
- }
- }
-
- return Result.success()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/services/VideoDownloadService.kt b/app/src/main/java/com/lagradost/cloudstream3/services/VideoDownloadService.kt
index 6151a0ed..be2fe75b 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/services/VideoDownloadService.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/services/VideoDownloadService.kt
@@ -1,22 +1,11 @@
package com.lagradost.cloudstream3.services
-import android.app.Service
+
+import android.app.IntentService
import android.content.Intent
-import android.os.IBinder
import com.lagradost.cloudstream3.utils.VideoDownloadManager
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.launch
-class VideoDownloadService : Service() {
-
- private val downloadScope = CoroutineScope(Dispatchers.Default)
-
- override fun onBind(intent: Intent?): IBinder? {
- return null
- }
-
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+class VideoDownloadService : IntentService("VideoDownloadService") {
+ override fun onHandleIntent(intent: Intent?) {
if (intent != null) {
val id = intent.getIntExtra("id", -1)
val type = intent.getStringExtra("type")
@@ -25,36 +14,10 @@ class VideoDownloadService : Service() {
"resume" -> VideoDownloadManager.DownloadActionType.Resume
"pause" -> VideoDownloadManager.DownloadActionType.Pause
"stop" -> VideoDownloadManager.DownloadActionType.Stop
- else -> return START_NOT_STICKY
- }
-
- downloadScope.launch {
- VideoDownloadManager.downloadEvent.invoke(Pair(id, state))
+ else -> return
}
+ VideoDownloadManager.downloadEvent.invoke(Pair(id, state))
}
}
-
- return START_NOT_STICKY
}
-
- override fun onDestroy() {
- downloadScope.coroutineContext.cancel()
- super.onDestroy()
- }
-}
-// override fun onHandleIntent(intent: Intent?) {
-// if (intent != null) {
-// val id = intent.getIntExtra("id", -1)
-// val type = intent.getStringExtra("type")
-// if (id != -1 && type != null) {
-// val state = when (type) {
-// "resume" -> VideoDownloadManager.DownloadActionType.Resume
-// "pause" -> VideoDownloadManager.DownloadActionType.Pause
-// "stop" -> VideoDownloadManager.DownloadActionType.Stop
-// else -> return
-// }
-// VideoDownloadManager.downloadEvent.invoke(Pair(id, state))
-// }
-// }
-// }
-//}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt
index 8ce6bae2..f17086c1 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt
@@ -45,7 +45,6 @@ abstract class AccountManager(private val defIndex: Int) : AuthAPI {
const val appString = "cloudstreamapp"
const val appStringRepo = "cloudstreamrepo"
- const val appStringPlayer = "cloudstreamplayer"
// Instantly start the search given a query
const val appStringSearch = "cloudstreamsearch"
diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt
index 0010ce25..7d9de43a 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt
@@ -759,11 +759,6 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
return data != ""
}
- /** Used to query a saved MediaItem on the list to get the id for removal */
- data class MediaListItemRoot(@JsonProperty("data") val data: MediaListItem? = null)
- data class MediaListItem(@JsonProperty("MediaList") val MediaList: MediaListId? = null)
- data class MediaListId(@JsonProperty("id") val id: Long? = null)
-
private suspend fun postDataAboutId(
id: Int,
type: AniListStatusType,
@@ -771,43 +766,19 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
progress: Int?
): Boolean {
val q =
- // Delete item if status type is None
- if (type == AniListStatusType.None) {
- val userID = getKey(accountId, ANILIST_USER_KEY)?.id ?: return false
- // Get list ID for deletion
- val idQuery = """
- query MediaList(${'$'}userId: Int = $userID, ${'$'}mediaId: Int = $id) {
- MediaList(userId: ${'$'}userId, mediaId: ${'$'}mediaId) {
- id
- }
- }
- """
- val response = postApi(idQuery)
- val listId =
- tryParseJson(response)?.data?.MediaList?.id ?: return false
- """
- mutation(${'$'}id: Int = $listId) {
- DeleteMediaListEntry(id: ${'$'}id) {
- deleted
- }
- }
- """
- } else {
- """mutation (${'$'}id: Int = $id, ${'$'}status: MediaListStatus = ${
- aniListStatusString[maxOf(
- 0,
- type.value
- )]
- }, ${if (score != null) "${'$'}scoreRaw: Int = ${score * 10}" else ""} , ${if (progress != null) "${'$'}progress: Int = $progress" else ""}) {
- SaveMediaListEntry (mediaId: ${'$'}id, status: ${'$'}status, scoreRaw: ${'$'}scoreRaw, progress: ${'$'}progress) {
- id
- status
- progress
- score
- }
+ """mutation (${'$'}id: Int = $id, ${'$'}status: MediaListStatus = ${
+ aniListStatusString[maxOf(
+ 0,
+ type.value
+ )]
+ }, ${if (score != null) "${'$'}scoreRaw: Int = ${score * 10}" else ""} , ${if (progress != null) "${'$'}progress: Int = $progress" else ""}) {
+ SaveMediaListEntry (mediaId: ${'$'}id, status: ${'$'}status, scoreRaw: ${'$'}scoreRaw, progress: ${'$'}progress) {
+ id
+ status
+ progress
+ score
+ }
}"""
- }
-
val data = postApi(q)
return data != ""
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/LocalList.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/LocalList.kt
index 7dd43fe7..0b081220 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/LocalList.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/LocalList.kt
@@ -9,7 +9,6 @@ import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.library.ListSorting
import com.lagradost.cloudstream3.ui.result.txt
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
-import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllSubscriptions
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds
import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState
@@ -75,16 +74,13 @@ class LocalList : SyncAPI {
group.value.mapNotNull {
getBookmarkedData(it.first)?.toLibraryItem(it.first.toString())
}
- } + mapOf(R.string.subscription_list_name to getAllSubscriptions().mapNotNull {
- it.toLibraryItem()
- })
+ }
}
val baseMap = WatchType.values().filter { it != WatchType.NONE }.associate {
// None is not something to display
it.stringRes to emptyList()
- } + mapOf(R.string.subscription_list_name to emptyList())
-
+ }
return SyncAPI.LibraryMetadata(
(baseMap + list).map { SyncAPI.LibraryList(txt(it.key), it.value) },
setOf(
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt
index e80a8fa5..f0340845 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt
@@ -24,6 +24,7 @@ import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
import com.lagradost.cloudstream3.ui.player.LinkGenerator
+import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
@@ -39,7 +40,6 @@ import kotlinx.android.synthetic.main.stream_input.*
import android.text.format.Formatter.formatShortFileSize
import androidx.core.widget.doOnTextChanged
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
-import com.lagradost.cloudstream3.ui.player.BasicLink
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import java.net.URI
@@ -225,7 +225,7 @@ class DownloadFragment : Fragment() {
R.id.global_to_navigation_player,
GeneratorPlayer.newInstance(
LinkGenerator(
- listOf(BasicLink(url)),
+ listOf(url),
extract = true,
referer = referer,
isM3u8 = dialog.hls_switch?.isChecked
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt
index 58c6dbe0..e6999c9e 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt
@@ -185,7 +185,7 @@ open class ParentItemAdapter(
) :
RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.home_child_more_info
- private val recyclerView: RecyclerView = itemView.home_child_recyclerview
+ val recyclerView: RecyclerView = itemView.home_child_recyclerview
fun update(expand: HomeViewModel.ExpandableHomepageList) {
val info = expand.list
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt
index e0885671..4772a7f1 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt
@@ -9,11 +9,8 @@ import android.widget.FrameLayout
import androidx.preference.PreferenceManager
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.C.*
-import com.google.android.exoplayer2.DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON
-import com.google.android.exoplayer2.DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource
-import com.google.android.exoplayer2.mediacodec.MediaCodecSelector
import com.google.android.exoplayer2.source.*
import com.google.android.exoplayer2.text.TextRenderer
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
@@ -38,13 +35,11 @@ import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle
import com.lagradost.cloudstream3.utils.EpisodeSkip
-import com.lagradost.cloudstream3.utils.AppUtils.isUsingMobileData
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.ExtractorLinkPlayList
import com.lagradost.cloudstream3.utils.ExtractorUri
import com.lagradost.cloudstream3.utils.SubtitleHelper.fromTwoLettersToLanguage
import java.io.File
-import java.time.Duration
import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSession
@@ -540,17 +535,15 @@ class CS3IPlayer : IPlayer {
OkHttpDataSource.Factory(client).setUserAgent(USER_AGENT)
}
- // Do no include empty referer, if the provider wants those they can use the header map.
- val refererMap =
- if (link.referer.isBlank()) emptyMap() else mapOf("referer" to link.referer)
val headers = mapOf(
+ "referer" to link.referer,
"accept" to "*/*",
"sec-ch-ua" to "\"Chromium\";v=\"91\", \" Not;A Brand\";v=\"99\"",
"sec-ch-ua-mobile" to "?0",
"sec-fetch-user" to "?1",
"sec-fetch-mode" to "navigate",
"sec-fetch-dest" to "video"
- ) + refererMap + link.headers // Adds the headers from the provider, e.g Authorization
+ ) + link.headers // Adds the headers from the provider, e.g Authorization
return source.apply {
setDefaultRequestProperties(headers)
@@ -673,27 +666,23 @@ class CS3IPlayer : IPlayer {
val exoPlayerBuilder =
ExoPlayer.Builder(context)
.setRenderersFactory { eventHandler, videoRendererEventListener, audioRendererEventListener, textRendererOutput, metadataRendererOutput ->
- DefaultRenderersFactory(context).apply {
-// setEnableDecoderFallback(true)
- // Enable Ffmpeg extension
-// setExtensionRendererMode(EXTENSION_RENDERER_MODE_ON)
- }.createRenderers(
- eventHandler,
- videoRendererEventListener,
- audioRendererEventListener,
- textRendererOutput,
- metadataRendererOutput
- ).map {
- if (it is TextRenderer) {
- currentTextRenderer = CustomTextRenderer(
- subtitleOffset,
- textRendererOutput,
- eventHandler.looper,
- CustomSubtitleDecoderFactory()
- )
- currentTextRenderer!!
- } else it
- }.toTypedArray()
+ DefaultRenderersFactory(context).createRenderers(
+ eventHandler,
+ videoRendererEventListener,
+ audioRendererEventListener,
+ textRendererOutput,
+ metadataRendererOutput
+ ).map {
+ if (it is TextRenderer) {
+ currentTextRenderer = CustomTextRenderer(
+ subtitleOffset,
+ textRendererOutput,
+ eventHandler.looper,
+ CustomSubtitleDecoderFactory()
+ )
+ currentTextRenderer!!
+ } else it
+ }.toTypedArray()
}
.setTrackSelector(
trackSelector ?: getTrackSelector(
@@ -858,7 +847,7 @@ class CS3IPlayer : IPlayer {
Log.i(TAG, "loadExo")
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
val maxVideoHeight = settingsManager.getInt(
- context.getString(if (context.isUsingMobileData()) com.lagradost.cloudstream3.R.string.quality_pref_mobile_data_key else com.lagradost.cloudstream3.R.string.quality_pref_key),
+ context.getString(com.lagradost.cloudstream3.R.string.quality_pref_key),
Int.MAX_VALUE
)
@@ -1204,10 +1193,10 @@ class CS3IPlayer : IPlayer {
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.socketFactory)
}
- val mime = when {
- link.isM3u8 -> MimeTypes.APPLICATION_M3U8
- link.isDash -> MimeTypes.APPLICATION_MPD
- else -> MimeTypes.VIDEO_MP4
+ val mime = if (link.isM3u8) {
+ MimeTypes.APPLICATION_M3U8
+ } else {
+ MimeTypes.VIDEO_MP4
}
val mediaItems = if (link is ExtractorLinkPlayList) {
@@ -1257,4 +1246,4 @@ class CS3IPlayer : IPlayer {
loadOfflinePlayer(context, it)
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt
index 974a5d26..690d3706 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt
@@ -4,16 +4,13 @@ import android.content.Context
import android.util.Log
import androidx.preference.PreferenceManager
import com.google.android.exoplayer2.Format
-import com.google.android.exoplayer2.text.*
-import com.google.android.exoplayer2.text.cea.Cea608Decoder
-import com.google.android.exoplayer2.text.cea.Cea708Decoder
-import com.google.android.exoplayer2.text.dvb.DvbDecoder
-import com.google.android.exoplayer2.text.pgs.PgsDecoder
+import com.google.android.exoplayer2.text.SubtitleDecoder
+import com.google.android.exoplayer2.text.SubtitleDecoderFactory
+import com.google.android.exoplayer2.text.SubtitleInputBuffer
+import com.google.android.exoplayer2.text.SubtitleOutputBuffer
import com.google.android.exoplayer2.text.ssa.SsaDecoder
import com.google.android.exoplayer2.text.subrip.SubripDecoder
import com.google.android.exoplayer2.text.ttml.TtmlDecoder
-import com.google.android.exoplayer2.text.tx3g.Tx3gDecoder
-import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder
import com.google.android.exoplayer2.text.webvtt.WebvttDecoder
import com.google.android.exoplayer2.util.MimeTypes
import com.lagradost.cloudstream3.R
@@ -22,11 +19,7 @@ import org.mozilla.universalchardet.UniversalDetector
import java.nio.ByteBuffer
import java.nio.charset.Charset
-/**
- * @param fallbackFormat used to create a decoder based on mimetype if the subtitle string is not
- * enough to identify the subtitle format.
- **/
-class CustomDecoder(private val fallbackFormat: Format?) : SubtitleDecoder {
+class CustomDecoder : SubtitleDecoder {
companion object {
fun updateForcedEncoding(context: Context) {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
@@ -146,7 +139,7 @@ class CustomDecoder(private val fallbackFormat: Format?) : SubtitleDecoder {
val inputString = getStr(inputBuffer)
if (realDecoder == null && !inputString.isNullOrBlank()) {
var str: String = inputString
- // this way we read the subtitle file and decide what decoder to use instead of relying fully on mimetype
+ // this way we read the subtitle file and decide what decoder to use instead of relying on mimetype
Log.i(TAG, "Got data from queueInputBuffer")
//https://github.com/LagradOst/CloudStream-2/blob/ddd774ee66810137ff7bd65dae70bcf3ba2d2489/CloudStreamForms/CloudStreamForms/Script/MainChrome.cs#L388
realDecoder = when {
@@ -155,31 +148,8 @@ class CustomDecoder(private val fallbackFormat: Format?) : SubtitleDecoder {
(str.startsWith(
"[Script Info]",
ignoreCase = true
- ) || str.startsWith("Title:", ignoreCase = true)) -> SsaDecoder(fallbackFormat?.initializationData)
+ ) || str.startsWith("Title:", ignoreCase = true)) -> SsaDecoder()
str.startsWith("1", ignoreCase = true) -> SubripDecoder()
- fallbackFormat != null -> {
- when (val mimeType = fallbackFormat.sampleMimeType) {
- MimeTypes.TEXT_VTT -> WebvttDecoder()
- MimeTypes.TEXT_SSA -> SsaDecoder(fallbackFormat.initializationData)
- MimeTypes.APPLICATION_MP4VTT -> Mp4WebvttDecoder()
- MimeTypes.APPLICATION_TTML -> TtmlDecoder()
- MimeTypes.APPLICATION_SUBRIP -> SubripDecoder()
- MimeTypes.APPLICATION_TX3G -> Tx3gDecoder(fallbackFormat.initializationData)
- MimeTypes.APPLICATION_CEA608, MimeTypes.APPLICATION_MP4CEA608 -> Cea608Decoder(
- mimeType,
- fallbackFormat.accessibilityChannel,
- Cea608Decoder.MIN_DATA_CHANNEL_TIMEOUT_MS
- )
- MimeTypes.APPLICATION_CEA708 -> Cea708Decoder(
- fallbackFormat.accessibilityChannel,
- fallbackFormat.initializationData
- )
- MimeTypes.APPLICATION_DVBSUBS -> DvbDecoder(fallbackFormat.initializationData)
- MimeTypes.APPLICATION_PGS -> PgsDecoder()
- MimeTypes.TEXT_EXOPLAYER_CUES -> ExoplayerCuesDecoder()
- else -> null
- }
- }
else -> null
}
Log.i(
@@ -276,6 +246,28 @@ class CustomSubtitleDecoderFactory : SubtitleDecoderFactory {
}
override fun createDecoder(format: Format): SubtitleDecoder {
- return CustomDecoder(format)
+ return CustomDecoder()
+ //return when (val mimeType = format.sampleMimeType) {
+ // MimeTypes.TEXT_VTT -> WebvttDecoder()
+ // MimeTypes.TEXT_SSA -> SsaDecoder(format.initializationData)
+ // MimeTypes.APPLICATION_MP4VTT -> Mp4WebvttDecoder()
+ // MimeTypes.APPLICATION_TTML -> TtmlDecoder()
+ // MimeTypes.APPLICATION_SUBRIP -> SubripDecoder()
+ // MimeTypes.APPLICATION_TX3G -> Tx3gDecoder(format.initializationData)
+ // MimeTypes.APPLICATION_CEA608, MimeTypes.APPLICATION_MP4CEA608 -> return Cea608Decoder(
+ // mimeType,
+ // format.accessibilityChannel,
+ // Cea608Decoder.MIN_DATA_CHANNEL_TIMEOUT_MS
+ // )
+ // MimeTypes.APPLICATION_CEA708 -> Cea708Decoder(
+ // format.accessibilityChannel,
+ // format.initializationData
+ // )
+ // MimeTypes.APPLICATION_DVBSUBS -> DvbDecoder(format.initializationData)
+ // MimeTypes.APPLICATION_PGS -> PgsDecoder()
+ // MimeTypes.TEXT_EXOPLAYER_CUES -> ExoplayerCuesDecoder()
+ // // Default WebVttDecoder
+ // else -> WebvttDecoder()
+ //}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt
index 6f40e145..dc1bbba3 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt
@@ -42,7 +42,7 @@ class DownloadedPlayerActivity : AppCompatActivity() {
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
LinkGenerator(
listOf(
- BasicLink(url)
+ url
)
)
)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt
index 86e21fd6..8d28fd9d 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt
@@ -40,7 +40,6 @@ import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer.Companion.subsProvidersIsActive
import com.lagradost.cloudstream3.utils.Qualities
-import com.lagradost.cloudstream3.utils.AppUtils.isUsingMobileData
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
@@ -84,7 +83,6 @@ const val HORIZONTAL_MULTIPLIER = 2.0f
const val DOUBLE_TAB_MAXIMUM_HOLD_TIME = 200L
const val DOUBLE_TAB_MINIMUM_TIME_BETWEEN = 200L // this also affects the UI show response time
const val DOUBLE_TAB_PAUSE_PERCENTAGE = 0.15 // in both directions
-private const val SUBTITLE_DELAY_BUNDLE_KEY = "subtitle_delay"
// All the UI Logic for the player
open class FullScreenPlayer : AbstractPlayerFragment() {
@@ -1121,20 +1119,11 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
resetRewindText()
}
- override fun onSaveInstanceState(outState: Bundle) {
- // As this is video specific it is better to not do any setKey/getKey
- outState.putLong(SUBTITLE_DELAY_BUNDLE_KEY, subtitleDelay)
- super.onSaveInstanceState(outState)
- }
-
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// init variables
setPlayBackSpeed(getKey(PLAYBACK_SPEED_KEY) ?: 1.0f)
- savedInstanceState?.getLong(SUBTITLE_DELAY_BUNDLE_KEY)?.let {
- subtitleDelay = it
- }
// handle tv controls
playerEventListener = { eventType ->
@@ -1257,8 +1246,9 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
ctx.getString(R.string.double_tap_pause_enabled_key),
false
)
+
currentPrefQuality = settingsManager.getInt(
- ctx.getString(if (ctx.isUsingMobileData()) R.string.quality_pref_mobile_data_key else R.string.quality_pref_key),
+ ctx.getString(R.string.quality_pref_key),
currentPrefQuality
)
// useSystemBrightness =
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt
index 46f2bca9..67f58195 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt
@@ -13,6 +13,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AlertDialog
import androidx.core.animation.addListener
import androidx.core.content.ContextCompat
import androidx.core.view.isGone
@@ -733,17 +734,19 @@ class GeneratorPlayer : FullScreenPlayer() {
}
val currentAudioTracks = tracks.allAudioTracks
- val trackDialog = Dialog(ctx, R.style.AlertDialogCustomBlack)
- trackDialog.setContentView(R.layout.player_select_tracks)
- trackDialog.show()
+ val trackBuilder = AlertDialog.Builder(ctx, R.style.AlertDialogCustomBlack)
+ .setView(R.layout.player_select_tracks)
+
+ val tracksDialog = trackBuilder.create()
// selectTracksDialog = tracksDialog
- val videosList = trackDialog.video_tracks_list
- val audioList = trackDialog.auto_tracks_list
+ tracksDialog.show()
+ val videosList = tracksDialog.video_tracks_list
+ val audioList = tracksDialog.auto_tracks_list
- trackDialog.video_tracks_holder.isVisible = currentVideoTracks.size > 1
- trackDialog.audio_tracks_holder.isVisible = currentAudioTracks.size > 1
+ tracksDialog.video_tracks_holder.isVisible = currentVideoTracks.size > 1
+ tracksDialog.audio_tracks_holder.isVisible = currentAudioTracks.size > 1
fun dismiss() {
if (isPlaying) {
@@ -778,7 +781,7 @@ class GeneratorPlayer : FullScreenPlayer() {
videosList.setItemChecked(which, true)
}
- trackDialog.setOnDismissListener {
+ tracksDialog.setOnDismissListener {
dismiss()
// selectTracksDialog = null
}
@@ -808,11 +811,11 @@ class GeneratorPlayer : FullScreenPlayer() {
audioList.setItemChecked(which, true)
}
- trackDialog.cancel_btt?.setOnClickListener {
- trackDialog.dismissSafe(activity)
+ tracksDialog.cancel_btt?.setOnClickListener {
+ tracksDialog.dismissSafe(activity)
}
- trackDialog.apply_btt?.setOnClickListener {
+ tracksDialog.apply_btt?.setOnClickListener {
val currentTrack = currentAudioTracks.getOrNull(audioIndexStart)
player.setPreferredAudioTrack(
currentTrack?.language, currentTrack?.id
@@ -825,7 +828,7 @@ class GeneratorPlayer : FullScreenPlayer() {
player.setMaxVideoSize(width, height, currentVideo?.id)
}
- trackDialog.dismissSafe(activity)
+ tracksDialog.dismissSafe(activity)
}
}
} catch (e: Exception) {
@@ -1142,7 +1145,7 @@ class GeneratorPlayer : FullScreenPlayer() {
val source = currentSelectedLink?.first?.name ?: currentSelectedLink?.second?.name ?: "NULL"
- val title = when (titleRez) {
+ val title = when (titleRez) {
0 -> ""
1 -> extra
2 -> source
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt
index 0b560857..1f242481 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt
@@ -5,15 +5,8 @@ import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.utils.*
import java.net.URI
-/**
- * Used to open the player more easily with the LinkGenerator
- **/
-data class BasicLink(
- val url: String,
- val name: String? = null,
-)
class LinkGenerator(
- private val links: List,
+ private val links: List,
private val extract: Boolean = true,
private val referer: String? = null,
private val isM3u8: Boolean? = null
@@ -54,7 +47,7 @@ class LinkGenerator(
offset: Int
): Boolean {
links.amap { link ->
- if (!extract || !loadExtractor(link.url, referer, {
+ if (!extract || !loadExtractor(link, referer, {
subtitleCallback(PlayerSubtitleHelper.getSubtitleData(it))
}) {
callback(it to null)
@@ -64,11 +57,11 @@ class LinkGenerator(
callback(
ExtractorLink(
"",
- link.name ?: link.url,
- unshortenLinkSafe(link.url), // unshorten because it might be a raw link
+ link,
+ unshortenLinkSafe(link), // unshorten because it might be a raw link
referer ?: "",
Qualities.Unknown.value, isM3u8 ?: normalSafeApiCall {
- URI(link.url).path?.substringAfterLast(".")?.contains("m3u")
+ URI(link).path?.substringAfterLast(".")?.contains("m3u")
} ?: false
) to null
)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt
index affbcbb4..59a46264 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt
@@ -7,13 +7,13 @@ import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.mvvm.logError
fun RecyclerView?.setLinearListLayout(isHorizontal: Boolean = true) {
- if (this == null) return
+ if(this == null) return
this.layoutManager =
this.context?.let { LinearListLayout(it).apply { if (isHorizontal) setHorizontal() else setVertical() } }
?: this.layoutManager
}
-open class LinearListLayout(context: Context?) :
+class LinearListLayout(context: Context?) :
LinearLayoutManager(context) {
fun setHorizontal() {
@@ -24,8 +24,7 @@ open class LinearListLayout(context: Context?) :
orientation = VERTICAL
}
- private fun getCorrectParent(focused: View?): View? {
- if (focused == null) return null
+ private fun getCorrectParent(focused: View): View? {
var current: View? = focused
val last: ArrayList = arrayListOf(focused)
while (current != null && current !is RecyclerView) {
@@ -55,17 +54,10 @@ open class LinearListLayout(context: Context?) :
linearSmoothScroller.targetPosition = position
startSmoothScroll(linearSmoothScroller)
}*/
+
override fun onInterceptFocusSearch(focused: View, direction: Int): View? {
val dir = if (orientation == HORIZONTAL) {
- if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) {
- // This scrolls the recyclerview before doing focus search, which
- // allows the focus search to work better.
-
- // Without this the recyclerview focus location on the screen
- // would change when scrolling between recyclerviews.
- (focused.parent as? RecyclerView)?.focusSearch(direction)
- return null
- }
+ if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) return null
if (direction == View.FOCUS_RIGHT) 1 else -1
} else {
if (direction == View.FOCUS_RIGHT || direction == View.FOCUS_LEFT) return null
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt
index 5a3e28b4..68dd1c0e 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt
@@ -15,28 +15,24 @@ import android.view.ViewGroup
import android.widget.AbsListView
import android.widget.ArrayAdapter
import android.widget.ImageView
-import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager
-import androidx.recyclerview.widget.RecyclerView
import com.discord.panels.OverlappingPanelsLayout
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipDrawable
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
-import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.DubStatus
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.mvvm.*
-import com.lagradost.cloudstream3.services.SubscriptionWorkManager
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
@@ -532,25 +528,6 @@ open class ResultFragment : ResultTrailerPlayer() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- result_cast_items?.layoutManager = object : LinearListLayout(view.context) {
- override fun onRequestChildFocus(
- parent: RecyclerView,
- state: RecyclerView.State,
- child: View,
- focused: View?
- ): Boolean {
- // Make the cast always focus the first visible item when focused
- // from somewhere else. Otherwise it jumps to the last item.
- return if (parent.focusedChild == null) {
- scrollToPosition(this.findFirstCompletelyVisibleItemPosition())
- true
- } else {
- super.onRequestChildFocus(parent, state, child, focused)
- }
- }
- }.apply {
- this.orientation = RecyclerView.HORIZONTAL
- }
result_cast_items?.adapter = ActorAdaptor()
updateUIListener = ::updateUI
@@ -873,7 +850,7 @@ open class ResultFragment : ResultTrailerPlayer() {
}
observe(viewModel.page) { data ->
- if (data == null) return@observe
+ if(data == null) return@observe
when (data) {
is Resource.Success -> {
val d = data.value
@@ -927,36 +904,6 @@ open class ResultFragment : ResultTrailerPlayer() {
updateList(d.actors ?: emptyList())
}
- observeNullable(viewModel.subscribeStatus) { isSubscribed ->
- result_subscribe?.isVisible = isSubscribed != null
- if (isSubscribed == null) return@observeNullable
-
- val drawable = if (isSubscribed) {
- R.drawable.ic_baseline_notifications_active_24
- } else {
- R.drawable.baseline_notifications_none_24
- }
-
- result_subscribe?.setImageResource(drawable)
- }
-
- result_subscribe?.setOnClickListener {
- val isSubscribed =
- viewModel.toggleSubscriptionStatus() ?: return@setOnClickListener
-
- val message = if (isSubscribed) {
- // Kinda icky to have this here, but it works.
- SubscriptionWorkManager.enqueuePeriodicWork(context)
- R.string.subscription_new
- } else {
- R.string.subscription_deleted
- }
-
- val name = (viewModel.page.value as? Resource.Success)?.value?.title
- ?: txt(R.string.no_data).asStringNull(context) ?: ""
- showToast(activity, txt(message, name), Toast.LENGTH_SHORT)
- }
-
result_open_in_browser?.isVisible = d.url.startsWith("http")
result_open_in_browser?.setOnClickListener {
val i = Intent(ACTION_VIEW)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
index 2f232995..b38e1765 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt
@@ -322,7 +322,9 @@ class ResultFragmentPhone : ResultFragment() {
// it?.dismiss()
//}
builder.setCanceledOnTouchOutside(true)
+
builder.show()
+
builder
}
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt
index 71ecb0e9..2bd8ff0f 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt
@@ -176,7 +176,8 @@ class ResultFragmentTv : ResultFragment() {
loadingDialog = null
}
loadingDialog = loadingDialog ?: context?.let { ctx ->
- val builder = BottomSheetDialog(ctx)
+ val builder =
+ BottomSheetDialog(ctx)
builder.setContentView(R.layout.bottom_loading)
builder.setOnDismissListener {
loadingDialog = null
@@ -186,7 +187,9 @@ class ResultFragmentTv : ResultFragment() {
// it?.dismiss()
//}
builder.setCanceledOnTouchOutside(true)
+
builder.show()
+
builder
}
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt
index 46a8c9f6..6817af6a 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt
@@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.ui.result
import android.app.Activity
import android.content.*
import android.net.Uri
-import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
@@ -17,7 +16,6 @@ import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.getId
import com.lagradost.cloudstream3.APIHolder.unixTime
-import com.lagradost.cloudstream3.APIHolder.unixTimeMS
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.CommonActivity.getCastSession
import com.lagradost.cloudstream3.CommonActivity.showToast
@@ -27,7 +25,6 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.getMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.isMovie
import com.lagradost.cloudstream3.metaproviders.SyncRedirector
import com.lagradost.cloudstream3.mvvm.*
-import com.lagradost.cloudstream3.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
import com.lagradost.cloudstream3.ui.APIRepository
@@ -416,9 +413,6 @@ class ResultViewModel2 : ViewModel() {
private val _episodeSynopsis: MutableLiveData = MutableLiveData(null)
val episodeSynopsis: LiveData = _episodeSynopsis
- private val _subscribeStatus: MutableLiveData = MutableLiveData(null)
- val subscribeStatus: LiveData = _subscribeStatus
-
companion object {
const val TAG = "RVM2"
private const val EPISODE_RANGE_SIZE = 20
@@ -820,42 +814,6 @@ class ResultViewModel2 : ViewModel() {
}
}
- /**
- * @return true if the new status is Subscribed, false if not. Null if not possible to subscribe.
- **/
- fun toggleSubscriptionStatus(): Boolean? {
- val isSubscribed = _subscribeStatus.value ?: return null
- val response = currentResponse ?: return null
- if (response !is EpisodeResponse) return null
-
- val currentId = response.getId()
-
- if (isSubscribed) {
- DataStoreHelper.removeSubscribedData(currentId)
- } else {
- val current = DataStoreHelper.getSubscribedData(currentId)
-
- DataStoreHelper.setSubscribedData(
- currentId,
- DataStoreHelper.SubscribedData(
- currentId,
- current?.bookmarkedTime ?: unixTimeMS,
- unixTimeMS,
- response.getLatestEpisodes(),
- response.name,
- response.url,
- response.apiName,
- response.type,
- response.posterUrl,
- response.year
- )
- )
- }
-
- _subscribeStatus.postValue(!isSubscribed)
- return !isSubscribed
- }
-
private fun startChromecast(
activity: Activity?,
result: ResultEpisode,
@@ -1126,12 +1084,7 @@ class ResultViewModel2 : ViewModel() {
1L
}
- // Component no longer safe to use in A13 for VLC
- // https://code.videolan.org/videolan/vlc-android/-/issues/2776
- // This will likely need to be updated once VLC fixes their documentation.
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
- component = VLC_COMPONENT
- }
+ component = VLC_COMPONENT
putExtra("from_start", !resume)
putExtra("position", position)
@@ -1469,128 +1422,85 @@ class ResultViewModel2 : ViewModel() {
meta: SyncAPI.SyncResult?,
syncs: Map? = null
): Pair {
- //if (meta == null) return resp to false
+ if (meta == null) return resp to false
var updateEpisodes = false
val out = resp.apply {
Log.i(TAG, "applyMeta")
- if (meta != null) {
- duration = duration ?: meta.duration
- rating = rating ?: meta.publicScore
- tags = tags ?: meta.genres
- plot = if (plot.isNullOrBlank()) meta.synopsis else plot
- posterUrl = posterUrl ?: meta.posterUrl ?: meta.backgroundPosterUrl
- actors = actors ?: meta.actors
+ duration = duration ?: meta.duration
+ rating = rating ?: meta.publicScore
+ tags = tags ?: meta.genres
+ plot = if (plot.isNullOrBlank()) meta.synopsis else plot
+ posterUrl = posterUrl ?: meta.posterUrl ?: meta.backgroundPosterUrl
+ actors = actors ?: meta.actors
- if (this is EpisodeResponse) {
- nextAiring = nextAiring ?: meta.nextAiring
- }
-
- val realRecommendations = ArrayList()
- val apiNames = apis.filter {
- it.name.contains("gogoanime", true) ||
- it.name.contains("9anime", true)
- }.map {
- it.name
- }
-
- meta.recommendations?.forEach { rec ->
- apiNames.forEach { name ->
- realRecommendations.add(rec.copy(apiName = name))
- }
- }
-
- recommendations = recommendations?.union(realRecommendations)?.toList()
- ?: realRecommendations
+ if (this is EpisodeResponse) {
+ nextAiring = nextAiring ?: meta.nextAiring
}
for ((k, v) in syncs ?: emptyMap()) {
syncData[k] = v
}
- argamap(
- {
- if (this !is AnimeLoadResponse) return@argamap
- // already exist, no need to run getTracker
- if (this.getAniListId() != null && this.getMalId() != null) return@argamap
+ val realRecommendations = ArrayList()
+ // TODO: fix
+ val apiNames = apis.filter {
+ it.name.contains("gogoanime", true) ||
+ it.name.contains("9anime", true)
+ }.map {
+ it.name
+ }
- val res = APIHolder.getTracker(
- listOfNotNull(
- this.engName,
- this.name,
- this.japName
- ).filter { it.length > 2 }
- .distinct(), // the reason why we filter is due to not wanting smth like " " or "?"
- TrackerType.getTypes(this.type),
- this.year
+ meta.recommendations?.forEach { rec ->
+ apiNames.forEach { name ->
+ realRecommendations.add(rec.copy(apiName = name))
+ }
+ }
+
+ recommendations = recommendations?.union(realRecommendations)?.toList()
+ ?: realRecommendations
+
+ argamap({
+ addTrailer(meta.trailers)
+ }, {
+ if (this !is AnimeLoadResponse) return@argamap
+ val map =
+ Kitsu.getEpisodesDetails(
+ getMalId(),
+ getAniListId(),
+ isResponseRequired = false
)
-
- val ids = arrayOf(
- AccountManager.malApi.idPrefix to res?.malId?.toString(),
- AccountManager.aniListApi.idPrefix to res?.aniId
- )
-
- if (ids.any { (id, new) ->
- val current = syncData[id]
- new != null && current != null && current != new
- }
- ) {
- // getTracker fucked up as it conflicts with current implementation
- return@argamap
- }
-
- // set all the new data, prioritise old correct data
- ids.forEach { (id, new) ->
- new?.let {
- syncData[id] = syncData[id] ?: it
- }
- }
-
- // set posters, might fuck up due to headers idk
- posterUrl = posterUrl ?: res?.image
- backgroundPosterUrl = backgroundPosterUrl ?: res?.cover
- },
- {
- if (meta == null) return@argamap
- addTrailer(meta.trailers)
- }, {
- if (this !is AnimeLoadResponse) return@argamap
- val map =
- Kitsu.getEpisodesDetails(
- getMalId(),
- getAniListId(),
- isResponseRequired = false
- )
- if (map.isNullOrEmpty()) return@argamap
- updateEpisodes = DubStatus.values().map { dubStatus ->
- val current =
- this.episodes[dubStatus]?.mapIndexed { index, episode ->
- episode.apply {
- this.episode = this.episode ?: (index + 1)
- }
- }?.sortedBy { it.episode ?: 0 }?.toMutableList()
- if (current.isNullOrEmpty()) return@map false
- val episodeNumbers = current.map { ep -> ep.episode!! }
- var updateCount = 0
- map.forEach { (episode, node) ->
- episodeNumbers.binarySearch(episode).let { index ->
- current.getOrNull(index)?.let { currentEp ->
- current[index] = currentEp.apply {
- updateCount++
- this.description = this.description ?: node.description?.en
- this.name = this.name ?: node.titles?.canonical
- this.episode =
- this.episode ?: node.num ?: episodeNumbers[index]
- this.posterUrl =
- this.posterUrl ?: node.thumbnail?.original?.url
- }
+ if (map.isNullOrEmpty()) return@argamap
+ updateEpisodes = DubStatus.values().map { dubStatus ->
+ val current =
+ this.episodes[dubStatus]?.mapIndexed { index, episode ->
+ episode.apply {
+ this.episode = this.episode ?: (index + 1)
+ }
+ }?.sortedBy { it.episode ?: 0 }?.toMutableList()
+ if (current.isNullOrEmpty()) return@map false
+ val episodeNumbers = current.map { ep -> ep.episode!! }
+ var updateCount = 0
+ map.forEach { (episode, node) ->
+ episodeNumbers.binarySearch(episode).let { index ->
+ current.getOrNull(index)?.let { currentEp ->
+ current[index] = currentEp.apply {
+ updateCount++
+ val currentBack = this
+ this.description = this.description ?: node.description?.en
+ this.name = this.name ?: node.titles?.canonical
+ this.episode =
+ this.episode ?: node.num ?: episodeNumbers[index]
+ this.posterUrl =
+ this.posterUrl ?: node.thumbnail?.original?.url
}
}
}
- this.episodes[dubStatus] = current
- updateCount > 0
- }.any { it }
- })
+ }
+ this.episodes[dubStatus] = current
+ updateCount > 0
+ }.any { it }
+ })
}
return out to updateEpisodes
}
@@ -1717,16 +1627,6 @@ class ResultViewModel2 : ViewModel() {
postResume()
}
- private fun postSubscription(loadResponse: LoadResponse) {
- if (loadResponse.isEpisodeBased()) {
- val id = loadResponse.getId()
- val data = DataStoreHelper.getSubscribedData(id)
- DataStoreHelper.updateSubscribedData(id, data, loadResponse as? EpisodeResponse)
- val isSubscribed = data != null
- _subscribeStatus.postValue(isSubscribed)
- }
- }
-
private fun postEpisodeRange(indexer: EpisodeIndexer?, range: EpisodeRange?) {
if (range == null || indexer == null) {
return
@@ -1863,7 +1763,6 @@ class ResultViewModel2 : ViewModel() {
) {
currentResponse = loadResponse
postPage(loadResponse, apiRepository)
- postSubscription(loadResponse)
if (updateEpisodes)
postEpisodes(loadResponse, updateFillers)
}
@@ -2225,7 +2124,7 @@ class ResultViewModel2 : ViewModel() {
autostart: AutoResume?,
loadTrailers: Boolean = true,
) =
- ioSafe {
+ viewModelScope.launchSafe {
_page.postValue(Resource.Loading(url))
_episodes.postValue(ResourceSome.Loading())
@@ -2243,7 +2142,7 @@ class ResultViewModel2 : ViewModel() {
"This provider does not exist"
)
)
- return@ioSafe
+ return@launchSafe
}
@@ -2254,15 +2153,21 @@ class ResultViewModel2 : ViewModel() {
api
)
}
-
+ // TODO: fix
+ // val validUrlResource = safeApiCall {
+ // SyncRedirector.redirect(
+ // url,
+ // api.mainUrl.replace(NineAnimeProvider().mainUrl, "9anime")
+ // .replace(GogoanimeProvider().mainUrl, "gogoanime")
+ // )
+ // }
if (validUrlResource !is Resource.Success) {
if (validUrlResource is Resource.Failure) {
_page.postValue(validUrlResource)
}
- return@ioSafe
+ return@launchSafe
}
-
val validUrl = validUrlResource.value
val repo = APIRepository(api)
currentRepo = repo
@@ -2272,11 +2177,11 @@ class ResultViewModel2 : ViewModel() {
_page.postValue(data)
}
is Resource.Success -> {
- if (!isActive) return@ioSafe
+ if (!isActive) return@launchSafe
val loadResponse = ioWork {
applyMeta(data.value, currentMeta, currentSync).first
}
- if (!isActive) return@ioSafe
+ if (!isActive) return@launchSafe
val mainId = loadResponse.getId()
preferDubStatus = getDub(mainId) ?: preferDubStatus
@@ -2304,7 +2209,7 @@ class ResultViewModel2 : ViewModel() {
updateFillers = showFillers,
apiRepository = repo
)
- if (!isActive) return@ioSafe
+ if (!isActive) return@launchSafe
handleAutoStart(activity, autostart)
}
is Resource.Loading -> {
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt
index 1ef3cb55..f9627e46 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt
@@ -157,28 +157,6 @@ class SettingsAccount : PreferenceFragmentCompat() {
)
dialog.dismissSafe()
}
-
- val displayedItems = listOf(
- dialog.login_username_input,
- dialog.login_email_input,
- dialog.login_server_input,
- dialog.login_password_input
- ).filter { it.isVisible }
-
- displayedItems.foldRight(displayedItems.firstOrNull()) { item, previous ->
- item?.id?.let { previous?.nextFocusDownId = it }
- previous?.id?.let { item?.nextFocusUpId = it }
- item
- }
-
- displayedItems.firstOrNull()?.let {
- dialog.create_account?.nextFocusDownId = it.id
- it.nextFocusUpId = dialog.create_account.id
- }
- dialog.apply_btt?.id?.let {
- displayedItems.lastOrNull()?.nextFocusDownId = it
- }
-
dialog.text1?.text = api.name
if (api.storesPasswordInPlainText) {
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt
index 4aa859aa..649aa634 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt
@@ -57,49 +57,47 @@ fun getCurrentLocale(context: Context): String {
val appLanguages = arrayListOf(
/* begin language list */
Triple("", "العربية", "ar"),
- Triple("", "български", "bg"),
+ Triple("", "български език", "bg"),
Triple("", "বাংলা", "bn"),
- Triple("\uD83C\uDDE7\uD83C\uDDF7", "português brasileiro", "bp"),
+ Triple("\uD83C\uDDE7\uD83C\uDDF7", "Brazilian Portuguese", "bp"),
Triple("", "čeština", "cs"),
Triple("", "Deutsch", "de"),
- Triple("", "Ελληνικά", "el"),
+ Triple("", "ελληνικά", "el"),
Triple("", "English", "en"),
Triple("", "Esperanto", "eo"),
- Triple("", "español", "es"),
+ Triple("", "Español", "es"),
Triple("", "فارسی", "fa"),
Triple("", "français", "fr"),
Triple("", "हिन्दी", "hi"),
- Triple("", "hrvatski", "hr"),
+ Triple("", "hrvatski jezik", "hr"),
Triple("", "magyar", "hu"),
- Triple("\uD83C\uDDEE\uD83C\uDDE9", "Bahasa Indonesia", "in"),
- Triple("", "italiano", "it"),
- Triple("\uD83C\uDDEE\uD83C\uDDF1", "עברית", "iw"),
- Triple("", "日本語 (にほんご)", "ja"),
+ Triple("\uD83C\uDDEE\uD83C\uDDE9", "Indonesian", "in"),
+ Triple("", "Italiano", "it"),
+ Triple("\uD83C\uDDEE\uD83C\uDDF1", "עִברִית", "iw"),
Triple("", "ಕನ್ನಡ", "kn"),
- Triple("", "македонски", "mk"),
+ Triple("", "македонски јазик", "mk"),
Triple("", "മലയാളം", "ml"),
- Triple("", "bahasa Melayu", "ms"),
Triple("", "Nederlands", "nl"),
- Triple("", "norsk nynorsk", "nn"),
- Triple("", "norsk bokmål", "no"),
- Triple("", "polski", "pl"),
- Triple("\uD83C\uDDF5\uD83C\uDDF9", "português", "pt"),
- Triple("\uD83E\uDD8D", "mmmm... monke", "qt"),
- Triple("", "română", "ro"),
- Triple("", "русский", "ru"),
+ Triple("", "Norsk nynorsk", "nn"),
+ Triple("", "Norsk", "no"),
+ Triple("", "język polski", "pl"),
+ Triple("\uD83C\uDDF5\uD83C\uDDF9", "Português", "pt"),
+ Triple("🦍", "mmmm... monke", "qt"),
+ Triple("", "Română", "ro"),
+ Triple("", "Русский", "ru"),
Triple("", "slovenčina", "sk"),
Triple("", "Soomaaliga", "so"),
Triple("", "svenska", "sv"),
Triple("", "தமிழ்", "ta"),
- Triple("", "Tagalog", "tl"),
+ Triple("", "Wikang Tagalog", "tl"),
Triple("", "Türkçe", "tr"),
- Triple("", "українська", "uk"),
+ Triple("", "Українська", "uk"),
Triple("", "اردو", "ur"),
Triple("", "Tiếng Việt", "vi"),
- Triple("", "中文", "zh"),
- Triple("\uD83C\uDDF9\uD83C\uDDFC", "文言", "zh-rTW"),
+ Triple("", "中文 (Zhōngwén)", "zh"),
+ Triple("\uD83C\uDDF9\uD83C\uDDFC", "Chinese Traditional", "zh-rTW"),
/* end language list */
-).sortedBy { it.second.lowercase() } //ye, we go alphabetical, so ppl don't put their lang on top
+).sortedBy { it.second } //ye, we go alphabetical, so ppl don't put their lang on top
class SettingsGeneral : PreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -159,6 +157,9 @@ class SettingsGeneral : PreferenceFragmentCompat() {
getPref(R.string.locale_key)?.setOnPreferenceClickListener { pref ->
val tempLangs = appLanguages.toMutableList()
+ //if (beneneCount > 100) {
+ // tempLangs.add(Triple("\uD83E\uDD8D", "mmmm... monke", "mo"))
+ //}
val current = getCurrentLocale(pref.context)
val languageCodes = tempLangs.map { (_, _, iso) -> iso }
val languageNames = tempLangs.map { (emoji, name, iso) ->
@@ -315,12 +316,6 @@ class SettingsGeneral : PreferenceFragmentCompat() {
} ?: emptyList()
}
- settingsManager.edit().putBoolean(getString(R.string.jsdelivr_proxy_key), getKey(getString(R.string.jsdelivr_proxy_key), false) ?: false).apply()
- getPref(R.string.jsdelivr_proxy_key)?.setOnPreferenceChangeListener { _, newValue ->
- setKey(getString(R.string.jsdelivr_proxy_key), newValue)
- return@setOnPreferenceChangeListener true
- }
-
getPref(R.string.download_path_key)?.setOnPreferenceClickListener {
val dirs = getDownloadDirs()
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt
index e10a5a1a..33d41934 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt
@@ -113,30 +113,6 @@ class SettingsPlayer : PreferenceFragmentCompat() {
return@setOnPreferenceClickListener true
}
- getPref(R.string.quality_pref_mobile_data_key)?.setOnPreferenceClickListener {
- val prefValues = Qualities.values().map { it.value }.reversed().toMutableList()
- prefValues.remove(Qualities.Unknown.value)
-
- val prefNames = prefValues.map { Qualities.getStringByInt(it) }
-
- val currentQuality =
- settingsManager.getInt(
- getString(R.string.quality_pref_mobile_data_key),
- Qualities.values().last().value
- )
-
- activity?.showBottomDialog(
- prefNames.toList(),
- prefValues.indexOf(currentQuality),
- getString(R.string.watch_quality_pref_data),
- true,
- {}) {
- settingsManager.edit().putInt(getString(R.string.quality_pref_mobile_data_key), prefValues[it])
- .apply()
- }
- return@setOnPreferenceClickListener true
- }
-
getPref(R.string.player_pref_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.player_pref_names)
val prefValues = resources.getIntArray(R.array.player_pref_values)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt
index 42a864a6..3b01508d 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt
@@ -2,8 +2,6 @@ package com.lagradost.cloudstream3.ui.settings
import android.os.Bundle
import android.view.View
-import androidx.navigation.NavOptions
-import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.lagradost.cloudstream3.*
@@ -18,7 +16,6 @@ import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
-import com.lagradost.cloudstream3.utils.UIHelper.navigate
class SettingsProviders : PreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -59,20 +56,6 @@ class SettingsProviders : PreferenceFragmentCompat() {
return@setOnPreferenceClickListener true
}
- getPref(R.string.test_providers_key)?.setOnPreferenceClickListener {
- // Somehow animations do not work without this.
- val options = NavOptions.Builder()
- .setEnterAnim(R.anim.enter_anim)
- .setExitAnim(R.anim.exit_anim)
- .setPopEnterAnim(R.anim.pop_enter)
- .setPopExitAnim(R.anim.pop_exit)
- .build()
-
- this@SettingsProviders.findNavController()
- .navigate(R.id.navigation_test_providers, null, options)
- true
- }
-
getPref(R.string.prefer_media_type_key)?.setOnPreferenceClickListener {
val names = enumValues().sorted().map { it.name }
val default =
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestFragment.kt
deleted file mode 100644
index 34cd67cd..00000000
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestFragment.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.lagradost.cloudstream3.ui.settings.testing
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.coordinatorlayout.widget.CoordinatorLayout
-import androidx.fragment.app.activityViewModels
-import com.lagradost.cloudstream3.R
-import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
-import com.lagradost.cloudstream3.mvvm.observe
-import com.lagradost.cloudstream3.mvvm.observeNullable
-import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
-import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
-import kotlinx.android.synthetic.main.fragment_testing.*
-import kotlinx.android.synthetic.main.view_test.*
-
-
-class TestFragment : Fragment() {
-
- private val testViewModel: TestViewModel by activityViewModels()
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- setUpToolbar(R.string.category_provider_test)
- super.onViewCreated(view, savedInstanceState)
-
- provider_test_recycler_view?.adapter = TestResultAdapter(
- mutableListOf()
- )
-
- testViewModel.init()
- if (testViewModel.isRunningTest) {
- provider_test?.setState(TestView.TestState.Running)
- }
-
- observe(testViewModel.providerProgress) { (passed, failed, total) ->
- provider_test?.setProgress(passed, failed, total)
- }
-
- observeNullable(testViewModel.providerResults) {
- normalSafeApiCall {
- val newItems = it.sortedBy { api -> api.first.name }
- (provider_test_recycler_view?.adapter as? TestResultAdapter)?.updateList(
- newItems
- )
- }
- }
-
- provider_test?.setOnPlayButtonListener { state ->
- when (state) {
- TestView.TestState.Stopped -> testViewModel.stopTest()
- TestView.TestState.Running -> testViewModel.startTest()
- TestView.TestState.None -> testViewModel.startTest()
- }
- }
-
- if (isTrueTvSettings()) {
- tests_play_pause?.isFocusableInTouchMode = true
- tests_play_pause?.requestFocus()
- }
-
- provider_test?.playPauseButton?.setOnFocusChangeListener { _, hasFocus ->
- if (hasFocus) {
- provider_test_appbar?.setExpanded(true, true)
- }
- }
-
- fun focusRecyclerView() {
- // Hack to make it possible to focus the recyclerview.
- if (isTrueTvSettings()) {
- provider_test_recycler_view?.requestFocus()
- provider_test_appbar?.setExpanded(false, true)
- }
- }
-
- provider_test?.setOnMainClick {
- testViewModel.setFilterMethod(TestViewModel.ProviderFilter.All)
- focusRecyclerView()
- }
- provider_test?.setOnFailedClick {
- testViewModel.setFilterMethod(TestViewModel.ProviderFilter.Failed)
- focusRecyclerView()
- }
- provider_test?.setOnPassedClick {
- testViewModel.setFilterMethod(TestViewModel.ProviderFilter.Passed)
- focusRecyclerView()
- }
- }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- return inflater.inflate(R.layout.fragment_testing, container, false)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestResultAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestResultAdapter.kt
deleted file mode 100644
index d04e2379..00000000
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestResultAdapter.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.lagradost.cloudstream3.ui.settings.testing
-
-import android.app.AlertDialog
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.core.content.ContextCompat
-import androidx.recyclerview.widget.RecyclerView
-import com.lagradost.cloudstream3.MainAPI
-import com.lagradost.cloudstream3.R
-import com.lagradost.cloudstream3.mvvm.getAllMessages
-import com.lagradost.cloudstream3.mvvm.getStackTracePretty
-import com.lagradost.cloudstream3.utils.AppUtils
-import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
-import com.lagradost.cloudstream3.utils.TestingUtils
-import kotlinx.android.synthetic.main.provider_test_item.view.*
-
-class TestResultAdapter(override val items: MutableList>) :
- AppUtils.DiffAdapter>(items) {
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
- return ProviderTestViewHolder(
- LayoutInflater.from(parent.context)
- .inflate(R.layout.provider_test_item, parent, false),
- )
- }
-
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- when (holder) {
- is ProviderTestViewHolder -> {
- val item = items[position]
- holder.bind(item.first, item.second)
- }
- }
- }
-
- inner class ProviderTestViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
- private val languageText: TextView = itemView.lang_icon
- private val providerTitle: TextView = itemView.main_text
- private val statusText: TextView = itemView.passed_failed_marker
- private val failDescription: TextView = itemView.fail_description
- private val logButton: ImageView = itemView.action_button
-
- private fun String.lastLine(): String? {
- return this.lines().lastOrNull { it.isNotBlank() }
- }
-
- fun bind(api: MainAPI, result: TestingUtils.TestResultProvider) {
- languageText.text = getFlagFromIso(api.lang)
- providerTitle.text = api.name
-
- val (resultText, resultColor) = if (result.success) {
- R.string.test_passed to R.color.colorTestPass
- } else {
- R.string.test_failed to R.color.colorTestFail
- }
-
- statusText.setText(resultText)
- statusText.setTextColor(ContextCompat.getColor(itemView.context, resultColor))
-
- val stackTrace = result.exception?.getStackTracePretty(false)?.ifBlank { null }
- val messages = result.exception?.getAllMessages()?.ifBlank { null }
- val fullLog =
- result.log + (messages?.let { "\n\n$it" } ?: "") + (stackTrace?.let { "\n\n$it" } ?: "")
-
- failDescription.text = messages?.lastLine() ?: result.log.lastLine()
-
- logButton.setOnClickListener {
- val builder: AlertDialog.Builder =
- AlertDialog.Builder(it.context, R.style.AlertDialogCustom)
- builder.setMessage(fullLog)
- .setTitle(R.string.test_log)
- .show()
- }
- }
- }
-
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestView.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestView.kt
deleted file mode 100644
index 26513f4a..00000000
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestView.kt
+++ /dev/null
@@ -1,119 +0,0 @@
-package com.lagradost.cloudstream3.ui.settings.testing
-
-import android.content.Context
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.TextView
-import androidx.annotation.DrawableRes
-import androidx.annotation.StringRes
-import androidx.cardview.widget.CardView
-import androidx.core.content.ContextCompat
-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.AppUtils.animateProgressTo
-
-class TestView @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0
-) : CardView(context, attrs) {
- enum class TestState(@StringRes val stringRes: Int, @DrawableRes val icon: Int) {
- None(R.string.start, R.drawable.ic_baseline_play_arrow_24),
-
- // Paused(R.string.resume, R.drawable.ic_baseline_play_arrow_24),
- Stopped(R.string.restart, R.drawable.ic_baseline_play_arrow_24),
- Running(R.string.stop, R.drawable.pause_to_play),
- }
-
- var mainSection: View? = null
- var testsPassedSection: View? = null
- var testsFailedSection: View? = null
-
- var mainSectionText: TextView? = null
- var mainSectionHeader: TextView? = null
- var testsPassedSectionText: TextView? = null
- var testsFailedSectionText: TextView? = null
- var totalProgressBar: ContentLoadingProgressBar? = null
-
- var playPauseButton: MaterialButton? = null
- var stateListener: (TestState) -> Unit = {}
-
- private var state = TestState.None
-
- init {
- LayoutInflater.from(context).inflate(R.layout.view_test, this, true)
-
- mainSection = findViewById(R.id.main_test_section)
- testsPassedSection = findViewById(R.id.passed_test_section)
- testsFailedSection = findViewById(R.id.failed_test_section)
-
- mainSectionHeader = findViewById(R.id.main_test_header)
- mainSectionText = findViewById(R.id.main_test_section_progress)
- testsPassedSectionText = findViewById(R.id.passed_test_section_progress)
- testsFailedSectionText = findViewById(R.id.failed_test_section_progress)
-
- totalProgressBar = findViewById(R.id.test_total_progress)
- playPauseButton = findViewById(R.id.tests_play_pause)
-
- attrs?.let {
- val typedArray = context.obtainStyledAttributes(it, R.styleable.TestView)
- val headerText = typedArray.getString(R.styleable.TestView_header_text)
- mainSectionHeader?.text = headerText
- typedArray.recycle()
- }
-
- playPauseButton?.setOnClickListener {
- val newState = when (state) {
- TestState.None -> TestState.Running
- TestState.Running -> TestState.Stopped
- TestState.Stopped -> TestState.Running
- }
- setState(newState)
- }
- }
-
- fun setOnPlayButtonListener(listener: (TestState) -> Unit) {
- stateListener = listener
- }
-
- fun setState(newState: TestState) {
- state = newState
- stateListener.invoke(newState)
- playPauseButton?.setText(newState.stringRes)
- playPauseButton?.icon = ContextCompat.getDrawable(context, newState.icon)
- }
-
- fun setProgress(passed: Int, failed: Int, total: Int?) {
- val totalProgress = passed + failed
- mainSectionText?.text = "$totalProgress / ${total?.toString() ?: "?"}"
- testsPassedSectionText?.text = passed.toString()
- testsFailedSectionText?.text = failed.toString()
-
- totalProgressBar?.max = (total ?: 0) * 1000
- totalProgressBar?.animateProgressTo(totalProgress * 1000)
-
- totalProgressBar?.isVisible = !(totalProgress == 0 || (total ?: 0) == 0)
- if (totalProgress == total) {
- setState(TestState.Stopped)
- }
- }
-
- fun setMainHeader(@StringRes header: Int) {
- mainSectionHeader?.setText(header)
- }
-
- fun setOnMainClick(listener: OnClickListener) {
- mainSection?.setOnClickListener(listener)
- }
-
- fun setOnPassedClick(listener: OnClickListener) {
- testsPassedSection?.setOnClickListener(listener)
- }
-
- fun setOnFailedClick(listener: OnClickListener) {
- testsFailedSection?.setOnClickListener(listener)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestViewModel.kt
deleted file mode 100644
index 2e05baff..00000000
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestViewModel.kt
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.lagradost.cloudstream3.ui.settings.testing
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import com.lagradost.cloudstream3.APIHolder
-import com.lagradost.cloudstream3.MainAPI
-import com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf
-import com.lagradost.cloudstream3.utils.TestingUtils
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.cancel
-
-class TestViewModel : ViewModel() {
- data class TestProgress(
- val passed: Int,
- val failed: Int,
- val total: Int
- )
-
- enum class ProviderFilter {
- All,
- Passed,
- Failed
- }
-
- private val _providerProgress = MutableLiveData(null)
- val providerProgress: LiveData = _providerProgress
-
- private val _providerResults =
- MutableLiveData>>(
- emptyList()
- )
-
- val providerResults: LiveData>> =
- _providerResults
-
- private var scope: CoroutineScope? = null
- val isRunningTest
- get() = scope != null
-
- private var filter = ProviderFilter.All
- private val providers = threadSafeListOf>()
- private var passed = 0
- private var failed = 0
- private var total = 0
-
- private fun updateProgress() {
- _providerProgress.postValue(TestProgress(passed, failed, total))
- postProviders()
- }
-
- private fun postProviders() {
- synchronized(providers) {
- val filtered = when (filter) {
- ProviderFilter.All -> providers
- ProviderFilter.Passed -> providers.filter { it.second.success }
- ProviderFilter.Failed -> providers.filter { !it.second.success }
- }
- _providerResults.postValue(filtered)
- }
- }
-
- fun setFilterMethod(filter: ProviderFilter) {
- if (this.filter == filter) return
- this.filter = filter
- postProviders()
- }
-
- private fun addProvider(api: MainAPI, results: TestingUtils.TestResultProvider) {
- synchronized(providers) {
- val index = providers.indexOfFirst { it.first == api }
- if (index == -1) {
- providers.add(api to results)
- if (results.success) passed++ else failed++
- } else {
- providers[index] = api to results
- }
- updateProgress()
- }
- }
-
- fun init() {
- val apis = APIHolder.allProviders
- total = apis.size
- updateProgress()
- }
-
- fun startTest() {
- scope = CoroutineScope(Dispatchers.Default)
-
- val apis = APIHolder.allProviders
- total = apis.size
- failed = 0
- passed = 0
- providers.clear()
- updateProgress()
-
- TestingUtils.getDeferredProviderTests(scope ?: return, apis, ::println) { api, result ->
- addProvider(api, result)
- }
- }
-
- fun stopTest() {
- scope?.cancel()
- scope = null
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt
index a76b62fd..00dee9b2 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt
@@ -1,11 +1,8 @@
package com.lagradost.cloudstream3.utils
-import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Activity.RESULT_CANCELED
-import android.app.NotificationChannel
-import android.app.NotificationManager
import android.content.*
import android.content.pm.PackageManager
import android.database.Cursor
@@ -20,7 +17,6 @@ import android.os.*
import android.provider.MediaStore
import android.text.Spanned
import android.util.Log
-import android.view.animation.DecelerateInterpolator
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
@@ -29,7 +25,6 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import androidx.core.text.toSpanned
-import androidx.core.widget.ContentLoadingProgressBar
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.navigation.fragment.findNavController
@@ -184,36 +179,6 @@ object AppUtils {
touchSlopField.set(recyclerView, touchSlop * f) // "8" was obtained experimentally
}
- fun ContentLoadingProgressBar?.animateProgressTo(to: Int) {
- if (this == null) return
- val animation: ObjectAnimator = ObjectAnimator.ofInt(
- this,
- "progress",
- this.progress,
- to
- )
- animation.duration = 500
- animation.setAutoCancel(true)
- animation.interpolator = DecelerateInterpolator()
- animation.start()
- }
-
- fun Context.createNotificationChannel(channelId: String, channelName: String, description: String) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val importance = NotificationManager.IMPORTANCE_DEFAULT
- val channel =
- NotificationChannel(channelId, channelName, importance).apply {
- this.description = description
- }
-
- // Register the channel with the system.
- val notificationManager: NotificationManager =
- this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
- notificationManager.createNotificationChannel(channel)
- }
- }
-
@SuppressLint("RestrictedApi")
fun getAllWatchNextPrograms(context: Context): Set {
val COLUMN_WATCH_NEXT_ID_INDEX = 0
@@ -491,12 +456,6 @@ object AppUtils {
}
}
- fun Context.isNetworkAvailable(): Boolean {
- val manager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
- val activeNetworkInfo = manager.activeNetworkInfo
- return activeNetworkInfo != null && activeNetworkInfo.isConnected || manager.allNetworkInfo?.any { it.isConnected } ?: false
- }
-
fun splitQuery(url: URL): Map {
val queryPairs: MutableMap = LinkedHashMap()
val query: String = url.query
@@ -776,13 +735,8 @@ object AppUtils {
return networkInfo.any {
conManager.getNetworkCapabilities(it)
?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true
- } &&
- !networkInfo.any {
- conManager.getNetworkCapabilities(it)
- ?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true
- }
}
-
+ }
private fun Activity?.cacheClass(clazz: String?) {
clazz?.let { c ->
@@ -826,4 +780,4 @@ object AppUtils {
}
return currentAudioFocusRequest
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt
index 516cd990..281c9c44 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt
@@ -1,13 +1,16 @@
package com.lagradost.cloudstream3.utils
import com.fasterxml.jackson.annotation.JsonProperty
-import com.lagradost.cloudstream3.*
-import com.lagradost.cloudstream3.APIHolder.unixTimeMS
+import com.lagradost.cloudstream3.APIHolder.capitalize
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
+import com.lagradost.cloudstream3.DubStatus
+import com.lagradost.cloudstream3.SearchQuality
+import com.lagradost.cloudstream3.SearchResponse
+import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.ui.WatchType
@@ -17,7 +20,6 @@ const val VIDEO_POS_DUR = "video_pos_dur"
const val VIDEO_WATCH_STATE = "video_watch_state"
const val RESULT_WATCH_STATE = "result_watch_state"
const val RESULT_WATCH_STATE_DATA = "result_watch_state_data"
-const val RESULT_SUBSCRIBED_STATE_DATA = "result_subscribed_state_data"
const val RESULT_RESUME_WATCHING = "result_resume_watching_2" // changed due to id changes
const val RESULT_RESUME_WATCHING_OLD = "result_resume_watching"
const val RESULT_RESUME_WATCHING_HAS_MIGRATED = "result_resume_watching_migrated"
@@ -40,37 +42,6 @@ object DataStoreHelper {
return this
}
- /**
- * Used to display notifications on new episodes and posters in library.
- **/
- data class SubscribedData(
- @JsonProperty("id") override var id: Int?,
- @JsonProperty("subscribedTime") val bookmarkedTime: Long,
- @JsonProperty("latestUpdatedTime") val latestUpdatedTime: Long,
- @JsonProperty("lastSeenEpisodeCount") val lastSeenEpisodeCount: Map,
- @JsonProperty("name") override val name: String,
- @JsonProperty("url") override val url: String,
- @JsonProperty("apiName") override val apiName: String,
- @JsonProperty("type") override var type: TvType? = null,
- @JsonProperty("posterUrl") override var posterUrl: String?,
- @JsonProperty("year") val year: Int?,
- @JsonProperty("quality") override var quality: SearchQuality? = null,
- @JsonProperty("posterHeaders") override var posterHeaders: Map? = null,
- ) : SearchResponse {
- fun toLibraryItem(): SyncAPI.LibraryItem? {
- return SyncAPI.LibraryItem(
- name,
- url,
- id?.toString() ?: return null,
- null,
- null,
- null,
- latestUpdatedTime,
- apiName, type, posterUrl, posterHeaders, quality, this.id
- )
- }
- }
-
data class BookmarkedData(
@JsonProperty("id") override var id: Int?,
@JsonProperty("bookmarkedTime") val bookmarkedTime: Long,
@@ -92,7 +63,7 @@ object DataStoreHelper {
null,
null,
null,
- latestUpdatedTime,
+ null,
apiName, type, posterUrl, posterHeaders, quality, this.id
)
}
@@ -104,7 +75,9 @@ object DataStoreHelper {
@JsonProperty("apiName") override val apiName: String,
@JsonProperty("type") override var type: TvType? = null,
@JsonProperty("posterUrl") override var posterUrl: String?,
+
@JsonProperty("watchPos") val watchPos: PosDur?,
+
@JsonProperty("id") override var id: Int?,
@JsonProperty("parentId") val parentId: Int?,
@JsonProperty("episode") val episode: Int?,
@@ -231,41 +204,6 @@ object DataStoreHelper {
return getKey("$currentAccount/$RESULT_WATCH_STATE_DATA", id.toString())
}
- fun getAllSubscriptions(): List {
- return getKeys("$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA")?.mapNotNull {
- getKey(it)
- } ?: emptyList()
- }
-
- fun removeSubscribedData(id: Int?) {
- if (id == null) return
- AccountManager.localListApi.requireLibraryRefresh = true
- removeKey("$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA", id.toString())
- }
-
- /**
- * Set new seen episodes and update time
- **/
- fun updateSubscribedData(id: Int?, data: SubscribedData?, episodeResponse: EpisodeResponse?) {
- if (id == null || data == null || episodeResponse == null) return
- val newData = data.copy(
- latestUpdatedTime = unixTimeMS,
- lastSeenEpisodeCount = episodeResponse.getLatestEpisodes()
- )
- setKey("$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA", id.toString(), newData)
- }
-
- fun setSubscribedData(id: Int?, data: SubscribedData) {
- if (id == null) return
- setKey("$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA", id.toString(), data)
- AccountManager.localListApi.requireLibraryRefresh = true
- }
-
- fun getSubscribedData(id: Int?): SubscribedData? {
- if (id == null) return null
- return getKey("$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA", id.toString())
- }
-
fun setViewPos(id: Int?, pos: Long, dur: Long) {
if (id == null) return
if (dur < 30_000) return // too short
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt
index b03c9fb7..1ad3639b 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt
@@ -52,7 +52,7 @@ data class ExtractorLinkPlayList(
)
-open class ExtractorLink constructor(
+open class ExtractorLink(
open val source: String,
open val name: String,
override val url: String,
@@ -62,24 +62,7 @@ open class ExtractorLink constructor(
override val headers: Map = mapOf(),
/** Used for getExtractorVerifierJob() */
open val extractorData: String? = null,
- open val isDash: Boolean = false,
) : VideoDownloadManager.IDownloadableMinimum {
- /**
- * Old constructor without isDash, allows for backwards compatibility with extensions.
- * Should be removed after all extensions have updated their cloudstream.jar
- **/
- constructor(
- source: String,
- name: String,
- url: String,
- referer: String,
- quality: Int,
- isM3u8: Boolean = false,
- headers: Map = mapOf(),
- /** Used for getExtractorVerifierJob() */
- extractorData: String? = null
- ) : this(source, name, url, referer, quality, isM3u8, headers, extractorData, false)
-
override fun toString(): String {
return "ExtractorLink(name=$name, url=$url, referer=$referer, isM3u8=$isM3u8)"
}
@@ -246,7 +229,6 @@ val extractorApis: MutableList = arrayListOf(
StreamSB8(),
StreamSB9(),
StreamSB10(),
- StreamSB11(),
SBfull(),
// Streamhub(), cause Streamhub2() works
Streamhub2(),
@@ -272,7 +254,6 @@ val extractorApis: MutableList = arrayListOf(
// WatchSB(), 'cause StreamSB.kt works
Uqload(),
Uqload1(),
- Uqload2(),
Evoload(),
Evoload1(),
VoeExtractor(),
@@ -284,7 +265,6 @@ val extractorApis: MutableList = arrayListOf(
OkRu(),
OkRuHttps(),
Okrulink(),
- Sendvid(),
// dood extractors
DoodCxExtractor(),
@@ -296,7 +276,6 @@ val extractorApis: MutableList = arrayListOf(
DoodShExtractor(),
DoodWatchExtractor(),
DoodWfExtractor(),
- DoodYtExtractor(),
AsianLoad(),
@@ -344,8 +323,6 @@ val extractorApis: MutableList = arrayListOf(
Filesim(),
FileMoon(),
- FileMoonSx(),
- Vido(),
Linkbox(),
Acefile(),
SpeedoStream(),
@@ -387,7 +364,6 @@ val extractorApis: MutableList = arrayListOf(
Cda(),
Dailymotion(),
ByteShare(),
- Ztreamhub()
)
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstallerService.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstallerService.kt
index dcb1e047..1625981e 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstallerService.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstallerService.kt
@@ -14,7 +14,6 @@ import androidx.core.app.NotificationCompat
import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.app
-import com.lagradost.cloudstream3.utils.AppUtils.createNotificationChannel
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import kotlinx.coroutines.delay
@@ -48,12 +47,24 @@ class PackageInstallerService : Service() {
.setSmallIcon(R.drawable.rdload)
}
+ private fun createNotificationChannel() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val importance = NotificationManager.IMPORTANCE_DEFAULT
+ val channel =
+ NotificationChannel(UPDATE_CHANNEL_ID, UPDATE_CHANNEL_NAME, importance).apply {
+ description = UPDATE_CHANNEL_DESCRIPTION
+ }
+
+ // Register the channel with the system
+ val notificationManager: NotificationManager =
+ this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+ notificationManager.createNotificationChannel(channel)
+ }
+ }
+
override fun onCreate() {
- this.createNotificationChannel(
- UPDATE_CHANNEL_ID,
- UPDATE_CHANNEL_NAME,
- UPDATE_CHANNEL_DESCRIPTION
- )
+ createNotificationChannel()
startForeground(UPDATE_NOTIFICATION_ID, baseNotification.build())
}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/TestingUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/TestingUtils.kt
deleted file mode 100644
index 66e1e504..00000000
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/TestingUtils.kt
+++ /dev/null
@@ -1,267 +0,0 @@
-package com.lagradost.cloudstream3.utils
-
-import com.lagradost.cloudstream3.*
-import com.lagradost.cloudstream3.mvvm.logError
-import kotlinx.coroutines.*
-import org.junit.Assert
-
-object TestingUtils {
- open class TestResult(val success: Boolean) {
- companion object {
- val Pass = TestResult(true)
- val Fail = TestResult(false)
- }
- }
-
- class TestResultSearch(val results: List) : TestResult(true)
- class TestResultLoad(val extractorData: String) : TestResult(true)
-
- class TestResultProvider(success: Boolean, val log: String, val exception: Throwable?) :
- TestResult(success)
-
- @Throws(AssertionError::class, CancellationException::class)
- suspend fun testHomepage(
- api: MainAPI,
- logger: (String) -> Unit
- ): TestResult {
- if (api.hasMainPage) {
- try {
- val f = api.mainPage.first()
- val homepage =
- api.getMainPage(1, MainPageRequest(f.name, f.data, f.horizontalImages))
- when {
- homepage == null -> {
- logger.invoke("Homepage provider ${api.name} did not correctly load homepage!")
- }
- homepage.items.isEmpty() -> {
- logger.invoke("Homepage provider ${api.name} does not contain any items!")
- }
- homepage.items.any { it.list.isEmpty() } -> {
- logger.invoke("Homepage provider ${api.name} does not have any items on result!")
- }
- }
- } catch (e: Throwable) {
- if (e is NotImplementedError) {
- Assert.fail("Provider marked as hasMainPage, while in reality is has not been implemented")
- } else if (e is CancellationException) {
- throw e
- }
- logError(e)
- }
- }
- return TestResult.Pass
- }
-
- @Throws(AssertionError::class, CancellationException::class)
- private suspend fun testSearch(
- api: MainAPI
- ): TestResult {
- val searchQueries = listOf("over", "iron", "guy")
- val searchResults = searchQueries.firstNotNullOfOrNull { query ->
- try {
- api.search(query).takeIf { !it.isNullOrEmpty() }
- } catch (e: Throwable) {
- if (e is NotImplementedError) {
- Assert.fail("Provider has not implemented search()")
- } else if (e is CancellationException) {
- throw e
- }
- logError(e)
- null
- }
- }
-
- return if (searchResults.isNullOrEmpty()) {
- Assert.fail("Api ${api.name} did not return any valid search responses")
- TestResult.Fail // Should not be reached
- } else {
- TestResultSearch(searchResults)
- }
-
- }
-
-
- @Throws(AssertionError::class, CancellationException::class)
- private suspend fun testLoad(
- api: MainAPI,
- result: SearchResponse,
- logger: (String) -> Unit
- ): TestResult {
- try {
- Assert.assertEquals(
- "Invalid apiName on SearchResponse on ${api.name}",
- result.apiName,
- api.name
- )
-
- val loadResponse = api.load(result.url)
-
- if (loadResponse == null) {
- logger.invoke("Returned null loadResponse on ${result.url} on ${api.name}")
- return TestResult.Fail
- }
-
- Assert.assertEquals(
- "Invalid apiName on LoadResponse on ${api.name}",
- loadResponse.apiName,
- result.apiName
- )
- Assert.assertTrue(
- "Api ${api.name} on load does not contain any of the supportedTypes: ${loadResponse.type}",
- api.supportedTypes.contains(loadResponse.type)
- )
-
- val url = when (loadResponse) {
- is AnimeLoadResponse -> {
- val gotNoEpisodes =
- loadResponse.episodes.keys.isEmpty() || loadResponse.episodes.keys.any { loadResponse.episodes[it].isNullOrEmpty() }
-
- if (gotNoEpisodes) {
- logger.invoke("Api ${api.name} got no episodes on ${loadResponse.url}")
- return TestResult.Fail
- }
-
- (loadResponse.episodes[loadResponse.episodes.keys.firstOrNull()])?.firstOrNull()?.data
- }
- is MovieLoadResponse -> {
- val gotNoEpisodes = loadResponse.dataUrl.isBlank()
- if (gotNoEpisodes) {
- logger.invoke("Api ${api.name} got no movie on ${loadResponse.url}")
- return TestResult.Fail
- }
-
- loadResponse.dataUrl
- }
- is TvSeriesLoadResponse -> {
- val gotNoEpisodes = loadResponse.episodes.isEmpty()
- if (gotNoEpisodes) {
- logger.invoke("Api ${api.name} got no episodes on ${loadResponse.url}")
- return TestResult.Fail
- }
- loadResponse.episodes.firstOrNull()?.data
- }
- is LiveStreamLoadResponse -> {
- loadResponse.dataUrl
- }
- else -> {
- logger.invoke("Unknown load response: ${loadResponse.javaClass.name}")
- return TestResult.Fail
- }
- } ?: return TestResult.Fail
-
- return TestResultLoad(url)
-
-// val loadTest = testLoadResponse(api, load, logger)
-// if (loadTest is TestResultLoad) {
-// testLinkLoading(api, loadTest.extractorData, logger).success
-// } else {
-// false
-// }
-// if (!validResults) {
-// logger("Api ${api.name} did not load on the first search results: ${smallSearchResults.map { it.name }}")
-// }
-
-// return TestResult(validResults)
- } catch (e: Throwable) {
- if (e is NotImplementedError) {
- Assert.fail("Provider has not implemented load()")
- }
- throw e
- }
- }
-
- @Throws(AssertionError::class, CancellationException::class)
- private suspend fun testLinkLoading(
- api: MainAPI,
- url: String?,
- logger: (String) -> Unit
- ): TestResult {
- Assert.assertNotNull("Api ${api.name} has invalid url on episode", url)
- if (url == null) return TestResult.Fail // Should never trigger
-
- var linksLoaded = 0
- try {
- val success = api.loadLinks(url, false, {}) { link ->
- logger.invoke("Video loaded: ${link.name}")
- Assert.assertTrue(
- "Api ${api.name} returns link with invalid url ${link.url}",
- link.url.length > 4
- )
- linksLoaded++
- }
- if (success) {
- logger.invoke("Links loaded: $linksLoaded")
- return TestResult(linksLoaded > 0)
- } else {
- Assert.fail("Api ${api.name} returns false on loadLinks() with $linksLoaded links loaded")
- }
- } catch (e: Throwable) {
- when (e) {
- is NotImplementedError -> {
- Assert.fail("Provider has not implemented loadLinks()")
- }
- else -> {
- logger.invoke("Failed link loading on ${api.name} using data: $url")
- throw e
- }
- }
- }
- return TestResult.Pass
- }
-
- fun getDeferredProviderTests(
- scope: CoroutineScope,
- providers: List,
- logger: (String) -> Unit,
- callback: (MainAPI, TestResultProvider) -> Unit
- ) {
- providers.forEach { api ->
- scope.launch {
- var log = ""
- fun addToLog(string: String) {
- log += string + "\n"
- logger.invoke(string)
- }
- fun getLog(): String {
- return log.removeSuffix("\n")
- }
-
- val result = try {
- addToLog("Trying ${api.name}")
-
- // Test Homepage
- val homepage = testHomepage(api, logger).success
- Assert.assertTrue("Homepage failed to load", homepage)
-
- // Test Search Results
- val searchResults = testSearch(api)
- Assert.assertTrue("Failed to get search results", searchResults.success)
- searchResults as TestResultSearch
-
- // Test Load and LoadLinks
- // Only try the first 3 search results to prevent spamming
- val success = searchResults.results.take(3).any { searchResponse ->
- addToLog("Testing search result: ${searchResponse.url}")
- val loadResponse = testLoad(api, searchResponse, ::addToLog)
- if (loadResponse !is TestResultLoad) {
- false
- } else {
- testLinkLoading(api, loadResponse.extractorData, ::addToLog).success
- }
- }
-
- if (success) {
- logger.invoke("Success ${api.name}")
- TestResultProvider(true, getLog(), null)
- } else {
- logger.invoke("Error ${api.name}")
- TestResultProvider(false, getLog(), null)
- }
- } catch (e: Throwable) {
- TestResultProvider(false, getLog(), e)
- }
- callback.invoke(api, result)
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt
index 2902b76b..a629dad9 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt
@@ -20,7 +20,6 @@ import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
-import com.bumptech.glide.load.model.GlideUrl
import com.fasterxml.jackson.annotation.JsonProperty
import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
@@ -214,7 +213,7 @@ object VideoDownloadManager {
}
private val cachedBitmaps = hashMapOf()
- fun Context.getImageBitmapFromUrl(url: String, headers: Map? = null): Bitmap? {
+ private fun Context.getImageBitmapFromUrl(url: String): Bitmap? {
try {
if (cachedBitmaps.containsKey(url)) {
return cachedBitmaps[url]
@@ -222,14 +221,12 @@ object VideoDownloadManager {
val bitmap = GlideApp.with(this)
.asBitmap()
- .load(GlideUrl(url) { headers ?: emptyMap() })
- .into(720, 720)
+ .load(url).into(720, 720)
.get()
-
if (bitmap != null) {
cachedBitmaps[url] = bitmap
}
- return bitmap
+ return null
} catch (e: Exception) {
logError(e)
return null
@@ -429,7 +426,7 @@ object VideoDownloadManager {
}
private const val reservedChars = "|\\?*<\":>+[]/\'"
- fun sanitizeFilename(name: String, removeSpaces: Boolean = false): String {
+ fun sanitizeFilename(name: String, removeSpaces: Boolean= false): String {
var tempName = name
for (c in reservedChars) {
tempName = tempName.replace(c, ' ')
@@ -1615,7 +1612,7 @@ object VideoDownloadManager {
.mapIndexed { index, any -> DownloadQueueResumePackage(index, any) }
.toTypedArray()
setKey(KEY_RESUME_QUEUE_PACKAGES, dQueue)
- } catch (t: Throwable) {
+ } catch (t : Throwable) {
logError(t)
}
}
diff --git a/app/src/main/res/drawable/baseline_network_ping_24.xml b/app/src/main/res/drawable/baseline_network_ping_24.xml
deleted file mode 100644
index 1caae667..00000000
--- a/app/src/main/res/drawable/baseline_network_ping_24.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/baseline_notifications_none_24.xml b/app/src/main/res/drawable/baseline_notifications_none_24.xml
deleted file mode 100644
index cf589c6d..00000000
--- a/app/src/main/res/drawable/baseline_notifications_none_24.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/baseline_text_snippet_24.xml b/app/src/main/res/drawable/baseline_text_snippet_24.xml
deleted file mode 100644
index c1f3654b..00000000
--- a/app/src/main/res/drawable/baseline_text_snippet_24.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_cloudstream_monochrome_big.xml b/app/src/main/res/drawable/ic_cloudstream_monochrome_big.xml
deleted file mode 100644
index 4b8964f8..00000000
--- a/app/src/main/res/drawable/ic_cloudstream_monochrome_big.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/bottom_selection_dialog_direct.xml b/app/src/main/res/layout/bottom_selection_dialog_direct.xml
index cf31ba1f..0d179ebb 100644
--- a/app/src/main/res/layout/bottom_selection_dialog_direct.xml
+++ b/app/src/main/res/layout/bottom_selection_dialog_direct.xml
@@ -1,34 +1,34 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ android:id="@+id/text1"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="10dp"
+ android:textStyle="bold"
+ android:textSize="20sp"
+ android:textColor="?attr/textColor"
+ android:layout_width="match_parent"
+ android:layout_rowWeight="1"
+ tools:text="Test"
+ android:layout_height="wrap_content" />
+ android:nextFocusRight="@id/cancel_btt"
+ android:nextFocusLeft="@id/apply_btt"
+
+ android:id="@+id/listview1"
+ android:layout_marginBottom="60dp"
+ android:paddingTop="10dp"
+ android:requiresFadingEdge="vertical"
+ tools:listitem="@layout/sort_bottom_single_choice_no_checkmark"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_rowWeight="1" />
diff --git a/app/src/main/res/layout/fragment_home_head.xml b/app/src/main/res/layout/fragment_home_head.xml
index 603621f7..0ee50042 100644
--- a/app/src/main/res/layout/fragment_home_head.xml
+++ b/app/src/main/res/layout/fragment_home_head.xml
@@ -1,6 +1,7 @@
+
@@ -145,16 +148,17 @@
+ app:drawableTint="?attr/white"
+ android:background="?android:attr/selectableItemBackground"
+ android:contentDescription="@string/home_more_info"/>
@@ -180,9 +184,9 @@
+ android:layout_height="wrap_content">
+ app:drawableTint="?attr/white"
+ android:contentDescription="@string/home_more_info"/>
diff --git a/app/src/main/res/layout/fragment_result.xml b/app/src/main/res/layout/fragment_result.xml
index a481ed6b..afbf735d 100644
--- a/app/src/main/res/layout/fragment_result.xml
+++ b/app/src/main/res/layout/fragment_result.xml
@@ -129,9 +129,9 @@
+ android:layout_height="wrap_content">
@@ -515,8 +516,8 @@
android:visibility="gone" />
ملصق
@@ -103,7 +103,7 @@
مزيد من المعلومات
قد تكون هناك حاجة إلى VPN لكي يعمل هذا المزود بشكل صحيح
هذا المزود هو تورنت ، يوصى باستخدام شبكة ظاهرية خاصة
- لا يتم توفير البيانات الوصفية بواسطة الموقع، وسيفشل تحميل الفيديو إذا لم يكن موجودًا في الموقع.
+ لا يتم توفير البيانات الوصفية بواسطة الموقع ، وسيفشل تحميل الفيديو إذا لم يكن موجودًا في الموقع.
الوصف
لم يتم العثور على وصف
لم يتم العثور على وصف
@@ -119,16 +119,16 @@
وضع إيغنغرافي
يضيف خيار السرعة في المُشغل
السحب لتقديم
- اسحب من جانب إلى آخر للتحكم في موضعك في مقطع فيديو
+ إسحب إلى اليسار أو اليمين للتحكم في الوقت في مُشغل الفيديو
السحب لتغيير الإعدادات
- مرر لأعلى أو لأسفل على الجانب الأيسر أو الأيمن لتغيير السطوع أو مستوى الصوت
+ إسحب على الجانب الأيسر أو الأيمن لتغيير السطوع أو مستوى الصوت
تشغيل الحلقة التالية تلقائيًا
تبدأ الحلقة التالية عندما تنتهي الحالية
النقر مرتان للتقديم للأمام أو للخلف
الضغط مرتان لإيقاف مؤقت
- التحكم في مدى تقديم المُشغل(ثوان)
+ التحكم في مدى تقديم المُشغل
إضغط مرتين على الجانب الأيمن أو الأيسر للتقديم للأمام أو للخلف
- اضغط مرتين في المنتصف للتوقف
+ إضغط في الوسط لإيقاف مؤقت
استخدم سطوع النظام
استخدم سطوع النظام في مُشغل التطبيق بدلاً من التراكب الداكن
تحديث تقدم المشاهدة
@@ -155,7 +155,7 @@
تحديث الإضافات تلقائيًا
تنزيل الإضافات تلقائيًا
التحديث التلقائي
- ابحث تلقائيا عن التحديثات الجديدة بعد بدء التطبيق.
+ البحث تلقائيًا عن التحديثات الجديدة عند البداية
التحديث إلى الاصدارات التجريبية (بيتا)
البحث عن التحديثات التجريبية بدلاً من الإصدارات الكاملة فقط
غيت هاب
@@ -170,7 +170,7 @@
تم نسخ الرابط إلى الحافظة
تشغيل الحلقة
إعادة التعيين إلى القيمة الافتراضية
- عذرا، تعطل التطبيق. سيتم إرسال تقرير خطأ مجهول إلى المطورين
+ عذرا ، تعطل التطبيق. سيتم إرسال تقرير خطأ مجهول إلى المطورين
موسم
لا موسم
حلقة
@@ -218,8 +218,8 @@
فيلم
مسلسل
كرتون
- أنيمي
- أوفا
+ أنمي
+ اوفا
تورنت
وثائقي
دراما آسيوية
@@ -259,15 +259,15 @@
لا تظهر مرة أخرى
تخطي هذا التحديث
تحديث
- جودة المشاهدة المفضلة (WiFi)
+ جودة المشاهدة المفضلة
أقصى عدد لحروف عنوان مُشغل الفيديو
أبعاد مُشغل الفيديو
حجم ذاكرة التخزين المؤقت للفيديو
طول التخزين المؤقت
التخزين المؤقت للفيديو على القرص
مسح التخزين المؤقت للصورة والفيديو
- يتسبب في حدوث أعطال إذا تم ضبطه على مستوى مرتفع جدا على الأجهزة ذات الذاكرة المنخفضة، مثل تلفزيون أندرويد.
- يسبب مشاكل إذا تم ضبطه على مستوى مرتفع جدا على الأجهزة ذات مساحة التخزين المنخفضة، مثل تلفزيون أندرويد.
+ يتسبب في حدوث أعطال إذا تم ضبطه على مستوى مرتفع جدا على الأجهزة ذات الذاكرة المنخفضة ، مثل Android TV.
+ يسبب مشاكل إذا تم ضبطه على مستوى مرتفع جدا على الأجهزة ذات مساحة التخزين المنخفضة ، مثل Android TV.
إستخدام DNS بدلا من HTTPS
مفيد لتجاوز حجب مزود خدمة الإنترنت
موقع بديل (نسخة)
@@ -284,7 +284,7 @@
Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk.
عام
زر العشوائي
- يظهر الزر على الصفحة الرئيسية والذي يمكنه اختيار فيلم عشوائي أو مسلسل تلفزيوني من الصفحة الرئيسية
+ إظهار زر العشوائي على الصفحة الرئيسية
لغات المزود
واجهة التطبيق
المحتوى المفضل
@@ -342,7 +342,7 @@
الكل
الحد الاقصي
الحد الأدنى
- @string/none
+ \@string/none
الخطوط المحيطة
النمط المنخفض
ظل
@@ -360,7 +360,7 @@
https://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog
-->
نصٌّ حكيمٌ لهُ سِرٌّ قاطِعٌ وَذُو شَأنٍ عَظيمٍ مكتوبٌ على ثوبٍ أخضرَ ومُغلفٌ بجلدٍ أزرق
- مُوصى به
+ مُوصي به
تم تحميل %s
إختيار ملف
تحميل من الانترنت
@@ -538,27 +538,4 @@
المكتبة
تم العثور على ملف الوضع الآمن!
\nلا يتم تحميل أي ملحقات عند بدء التشغيل حتى تتم إزالة الملف.
- مدة التقديم عنما يكون المشغل مخفيا
- مدة التقديم - المشغل مخفي
- تلفزيون أندرويد
- مدة التقديم عنما يكون المشغل مرئيا
- مدة التقديم- المشغل المرئي
- فشل
- نجح
- إختبار المزود
- إعادة التشغيل
- سجل
- بَدأ
- إيقاف
- تحديث العروض التي تم الاشتراك فيها
- إلغاء الاشتراك من %s
- تم إصدار الحلقة %d!
- مشترك
- مشترك في %s
- تجاوز مزود خدمة الإنترنت
- استرجاع
- فشل الوصول إلى GitHub ، وتمكين وكيل jsdelivr.
- باستخدام jsdelivr ، يمكن تجاوز حظر GitHub. قد يؤخر التحديثات لبضعة أيام.
- وكيل raw.githubusercontent.com
- جودة المشاهدة المفضلة (بيانات الجوال)
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 301242cd..f1f512a1 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%s еп. %d
Актьори: %s
@@ -106,7 +105,7 @@
Продължете да гледате
Премахване
Повече информация
- @string/home_play
+ \@string/home_play
Може да е необходим VPN, за да работи правилно този доставчик
Този доставчик е торент, препоръчва се VPN
Метаданните не се предоставят от сайта, зареждането на видео ще бъде неуспешно, ако не съществува на сайта.
@@ -224,8 +223,8 @@
Филм
Серия
Анимационен филм
- @string/anime
- @string/ova
+ \@string/anime
+ \@string/ova
Торент
Документален филм
Азиатска драма
@@ -498,4 +497,4 @@
Приложението ще се актуализира при изход от него
Започна Актуализация
Премахване от гледани
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml
index 71d5d6d0..7e0448d6 100644
--- a/app/src/main/res/values-bn/strings.xml
+++ b/app/src/main/res/values-bn/strings.xml
@@ -1,4 +1,4 @@
-
+
পোস্টার
ক্লাউডস্ট্রিম দিয়ে চালান
@@ -143,9 +143,9 @@
হালনাগাদ ও ব্যাকআপ
অ্যাপ এর হালনাগাদ দেখান
খুঁজতে সোয়াইপ করুন
- @string/result_poster_img_des
- @string/home_play
+ \@string/result_poster_img_des
+ \@string/home_play
আগাতে ডবল ট্যাপ করুন
আইজেনগ্রাভি মোড
আপডেট শুরু হয়েছে
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-bp/strings.xml b/app/src/main/res/values-bp/strings.xml
index 13b34872..2c2e1303 100644
--- a/app/src/main/res/values-bp/strings.xml
+++ b/app/src/main/res/values-bp/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%s Ep %d
@@ -11,7 +10,7 @@
%dm
Poster
- @string/result_poster_img_des
+ \@string/result_poster_img_des
Episode Poster
Main Poster
Next Random
@@ -109,7 +108,7 @@
Continue Assistindo
Remover
Mais Info
- @string/home_play
+ \@string/home_play
Uma VPN pode ser necessária para esse fornecedor funcionar corretamente
Esse fornecedor é um torrent, uma VPN é recomendada
Metadados não são oferecidas pelo site, o carregamento do video pode falhar se ele não existir no site.
@@ -223,8 +222,8 @@
Filme
Série
Desenho Animado
- @string/anime
- @string/ova
+ \@string/anime
+ \@string/ova
Torrent
Documentário
Drama Asiático
@@ -429,4 +428,4 @@
Começa o próximo episódio quando o atual termina
Ativar NSFW em fornecedores compatíveis
Fornecedores
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 1501a5d9..214cb86d 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%s Ep %d
@@ -104,7 +103,7 @@
Pokračovat ve sledování
Odebrat
Další informace
- @string/home_play
+ \@string/home_play
Aby tento poskytovatel fungoval správně, budete možná potřebovat VPN
Tento poskytovatel je torrent, je doporučená VPN
Web neposkytnul žádná metadata, načítání videa selže, pokud na webu neexistuje.
@@ -123,14 +122,14 @@
Rychlostní režim
Přidá do přehrávače možnost rychlosti
Přejet pro posun
- Přejeďte prstem ze strany na stranu pro ovládání své pozice ve videu
+ Přejeďte prstem vlevo nebo vpravo pro ovládání času v přehrávači
Přejet pro změnu nastavení
- Přejeďte prstem nahoru nebo dolů na levé nebo pravé straně pro změnu jasu nebo hlasitosti
+ Přejeďte prstem na levé nebo pravé straně pro změnu jasu nebo hlasitosti
Dvojité klepnutí pro posun
Dvojité klepnutí pro pozastavení
- Množství času k posunu (sekundy)
+ Množství času k posunu
Klepněte dvakrát vpravo nebo vlevo pro posun vpřed nebo vzad
- Klepněte dvakrát doprostřed pro pozastavení
+ Klepněte doprostřed pro pozastavení
Použít systémový jas
V přehrávači použít systémov překrytí
Aktualizovat postup sledování
@@ -152,7 +151,7 @@
Nebude odesílat žádná data
Zobrazit výplňové epizody u anime
Zobrazit aktualizace aplikace
- Při spuštění aplikace automaticky zkontrolovat nové aktualizace.
+ Při spuštění automaticky zkontrolovat nové aktualizace
Aktualizovat na předběžná vydání
Kontrolovat aktualizace předběžných vydání, místo normálních plných vydání
GitHub
@@ -212,8 +211,8 @@
Film
Seriál
Animovaný
- Anime
- OVA
+ \@string/anime
+ \@string/ova
Torrent
Dokument
Asijské drama
@@ -246,7 +245,7 @@
Již nezobrazovat
Přeskočit tuto aktualizace
Aktualizovat
- Upřednostněná kvalita sledování (WiFi)
+ Upřednostněná kvalita sledování
Maximální počet znaků v názvu přehrávače
Rozlišení přehrávače
Velikost vyrovnávací paměti videa
@@ -267,7 +266,7 @@
Jakékoli právní otázky týkající se obsahu této aplikace je třeba řešit se samotnými hostiteli a poskytovateli souborů, protože s nimi nejsme nijak spojeni. V případě porušení autorských práv se obraťte přímo na odpovědné strany nebo na webové stránky, na kterých se streamování odehrává. Aplikace je určena výhradně pro vzdělávací a osobní účely. CloudStream 3 v aplikaci nehostuje žádný obsah a nemá žádnou kontrolu nad tím, jaká média jsou v aplikaci umístěna nebo odstraněna. CloudStream 3 funguje jako jakýkoli jiný vyhledávač, například Google. Služba CloudStream 3 nehostuje, nenahrává ani nespravuje žádná videa, filmy ani obsah. Pouze vyhledává, agreguje a zobrazuje odkazy v pohodlném, uživatelsky přívětivém rozhraní. Pouze shromažďuje webové stránky třetích stran, které jsou veřejně přístupné prostřednictvím jakéhokoli běžného webového prohlížeče. Je odpovědností uživatele, aby se vyvaroval jakýchkoli akcí, které by mohly porušovat zákony platné v jeho lokalitě. Použijte CloudStream 3 na vlastní nebezpečí.
Obecné
Náhodné tlačítko
- Zobrazit na domovské stránce tlačítko, kterým lze vybrat náhodný film nebo seriál z domovské stránky
+ Zobrazit na domovské stránce náhodné tlačítko
Jazyk poskytovatelů
Rozložení aplikace
Preferovaná média
@@ -531,27 +530,4 @@
Odstranit repozitář
Nestaženo: %d
Ne
- Skrytý přehrávač - doba hledání
- Množství vyhledávané doby při skrytém přehrávači
- Zobrazený přehrávač - doba hledání
- Android TV
- Množství vyhledávané doby při zobrazeném přehrávači
- Protokol
- Test poskytovatele
- Neúspěšné
- Úspěšné
- Restart
- Spustit
- Zastavit
- Aktualizace odebíraných pořadů
- Přihlášeno k odběru %s
- Odhlášen odběr od %s
- Byla vydána epizoda %d!
- Odebíráno
- Proxy raw.githubusercontent.com
- Nepodařilo se připojit ke GitHubu, povolování proxy jsdelivr.
- Upřednostněná kvalita sledování (mobilní data)
- Vrátit zpět
- Pomocí jsdelivr lze obejít blokování GitHubu. Může dojít ke zpoždění aktualizací o několik dní.
- Obcházení ISP
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 8fbcc2d0..e190aa9c 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -1,4 +1,4 @@
-
+
%s Ep %d
Besetzung: %s
@@ -41,7 +41,7 @@
Suche %s…
Keine Daten vorhanden
Mehr Optionen
- Nächste Episode
+ Nächste Epsisode
Genres
Teilen
In Browser öffnen
@@ -53,7 +53,7 @@
Abgebrochen
Geplant
Nichts
- Erneut schauen
+ Erneut anschauen
Film abspielen
Livestream abspielen
Torrent streamen
@@ -115,7 +115,7 @@
Weiterschauen
Entfernen
Mehr Infos
- @string/home_play
+ \@string/home_play
Damit dieser Anbieter korrekt funktioniert, ist möglicherweise ein VPN erforderlich
Dieser Anbieter bietet Torrents an, ein VPN wird dringend empfohlen
Metadaten werden nicht von der Website bereitgestellt, das Laden des Videos schlägt fehl, wenn sie auf der Website nicht vorhanden sind.
@@ -136,14 +136,14 @@
Wischen zum vor- und zurückspulen
Nach links oder rechts wischen, um die Zeit im Videoplayer zu steuern
Wischen, um Einstellungen zu ändern
- Links oder rechts nach oben oder unten wischen, um die Helligkeit oder Lautstärke zu ändern
+ Links oder rechts wischen, um die Helligkeit oder Lautstärke zu ändern
Nächste Episode automatisch abspielen
Nächste Episode wird gestartet, sobald die aktuelle Episode endet
Doppeltippen zum vor- und zurückspulen
Doppeltippen zum Pausieren
- Zeit für vor- und zurückspulen im Player (Sekunden)
+ Zeit für vor- und zurückspulen im Player
Zweimal auf die rechte oder linke Seite tippen, um vor- oder zurückzuspulen
- Doppelt in die Mitte tippen, um zu pausieren
+ In die Mitte tippen, um zu pausieren
Systemhelligkeit verwenden
Systemhelligkeit anstelle eines dunklen Overlay im Player verwenden
Episodenfortschritt aktualisieren
@@ -166,7 +166,7 @@
Ausgewählte Videoqualität bei Suchergebnissen ausblenden
Automatische Plugin-Updates
App-Updates anzeigen
- Automatisches Suchen nach neuen Updates nach dem Start
+ Automatisches Suchen nach neuen Updates beim Start
Auf Vorabversionen updaten
Suche nach Vorabversionen statt nur nach Vollversionen
Github
@@ -212,7 +212,7 @@
Keine Untertitel
Standard
Frei
- Belegt
+ Benutzt
App
Filme
TV-Serien
@@ -246,7 +246,7 @@
In Browser wiedergeben
Link kopieren
Auto-Download
- Alternativer Download
+ Download-Mirror
Links neu laden
Untertitel herunterladen
Qualitätsanzeige
@@ -263,7 +263,7 @@
Nicht mehr anzeigen
Update ignorieren
Update
- Bevorzugte Videoqualität (WLAN)
+ Bevorzugte Auflösung
Videoplayertitel max. Zeichen
Videoplayer Auflösung
Videopuffergröße
@@ -284,9 +284,9 @@
Strecken
Vergrößern
Haftungsausschluss
- Allgemein
+ General
Zufalls-Button
- Zeigt einen Zufallsbutton auf der Startseite an, mit welchem eine Serie oder ein Film von der Website zufällig ausgewählt wird
+ Zufallsbutton auf der Startseite anzeigen
Anbieter-Sprachen
App-Layout
Bevorzugte Medien
@@ -460,11 +460,11 @@
Automatische Installation aller noch nicht installierten Plugins aus hinzugefügten Repositories.
Einrichtungsvorgang wiederholen
APK-Installer
- Einige Telefone unterstützen den neuen Package-Installer nicht. Benutze die Legacy-Option, wenn sich die Updates nicht installieren lassen.
+ Einige Telefone unterstützen das neue Installationsprogramm für Pakete nicht. Benutze die Legacy-Option, wenn sich die Updates nicht installieren lassen.
%s %d%s
Links
App-Updates
- Sicherung
+ Back-Up
Erweiterungen
Wartung
Cache
@@ -506,27 +506,4 @@
Diese Liste scheint leer zu sein. Versuche, zu einer anderen Liste zu wechseln.
Datei für abgesicherten Modus gefunden!
\nBeim Start werden keine Erweiterungen geladen, bis die Datei entfernt wird.
- Player ausgeblendet - Betrag zum vor- und zurückspulen
- Der Betrag, welcher verwendet wird, wenn der Player eingeblendet ist
- Der Betrag, welcher verwendet wird, wenn der Player ausgeblendet ist
- Android-TV
- Player eingeblendet - Betrag zum vor- und zurückspulen
- Fehlgeschlagen
- Erfolgreich
- Anbieter-Test
- Stopp
- Log
- Start
- Neustarten
- Bevorzugte Videoqualität (mobile Daten)
- Umgehung der GitHub Sperre mit jsdelivr. Kann zu einigen Tagen Verzögerung bei Updates führen.
- %s abonniert
- %s deabonniert
- Episode %d erschienen!
- raw.githubusercontent.com Proxy
- GitHub kann nicht erreicht werden, der jsdelivr-Proxy wird aktiviert.
- Abonnierte Serien werden aktualisiert
- Rückgängig
- Abonniert
- ISP-Umgehungen
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index f07ce43c..0d0b7fb2 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
CloudStream
Αρχική
Αναζήτηση
@@ -151,7 +150,7 @@
Επεισόδια
%d-%d
%d %s
- Σ
+ Κ
E
Δεν βρέθηκαν επεισόδια
Διαγραφή αρχείου
@@ -388,7 +387,7 @@
Κλείσιμο
Εκκαθάριση
Γλώσσα υποτίτλων
- @string/home_play
+ \@string/home_play
Δεν έχουν παρασχεθεί μεταδεδομένα από τον ιστότοπο, η φόρτωση του βίντεο θα αποτύχει αν δεν υπάρχει στον ιστότοπο.
Διπλό πάτημα για παύση
Μέγεθος αναζήτησης στο πρόγραμμα αναπαραγωγής
@@ -453,7 +452,7 @@
Ανάμεικτοι τίτλοι τέλους
-30
Κριτική
- @string/ova
+ \@string/ova
Ενημερώσεις εφαρμογής
Αντίγραφο ασφαλείας
Extensions
@@ -465,7 +464,7 @@
Προεπιλεγμένα
%s %s
Μέγεθος γραμματοσειράς
- @string/anime
+ \@string/anime
Σύνδεσμοι
Εμφάνιση
Χαρακτηριστικά
@@ -509,4 +508,4 @@
\nΣυνδέσου σε έναν λογαριασμό που έχει βιβλιοθήκη, ή πρόσθεσε σειρές στην τοπική βιβλιοθήκη σου
Βρέθηκε αρχείο Ασφαλούς Λειτουργίας!
\nΔεν πρόκειται να φορτωθούν extensions κατά το ξεκίνημα μέχρι να διαγραφεί το αρχείο.
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml
index 5eac8686..09e6941d 100644
--- a/app/src/main/res/values-eo/strings.xml
+++ b/app/src/main/res/values-eo/strings.xml
@@ -1,4 +1,4 @@
-
+
Reen
Hejmo
@@ -78,4 +78,4 @@
Rapido (%.2fx)
Serĉi…
Elŝuti
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 06c20aa5..d253e256 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -1,4 +1,4 @@
-
+
Extensiones
Descargue la lista de sitios que quiera utilizar
@@ -24,7 +24,7 @@
Ocultar la calidad de video en los resultados de búsqueda
Diseño
Diseño
- Calidad de visualización preferida (WiFi)
+ Calidad de visualización preferida
Reproductor de video preferido
Diseño para emulador
Diseño de la aplicación
@@ -51,10 +51,10 @@
Elevado
Use esto si los subtítulos se muestran %d ms muy pronto
Use esto si los subtítulos se muestran %d ms tarde
- Desliza el dedo de lado a lado para controlar la posición en un video
+ Desliza el dedo hacia la izquierda o hacia la derecha para controlar el tiempo en el reproductor de video
Filtrar por idioma de medios preferido
Eliminar Closed Captions (CC) de los subtítulos
- Cantidad de búsquedas del reproductor (segundos)
+ Cantidad de tiempo de búsqueda en el reproductor (en segundos)
Use el brillo del sistema en el reproductor de la app en lugar de una superposición oscura
Resolución del reproductor de video
MPV
@@ -194,7 +194,7 @@
Continuar Viendo
Remover
Más info
- @string/home_play
+ \@string/home_play
Una VPN puede ser necesaria para que este proveedor funcione correctamente
Este proveedor es un torrent, se recomienda una VPN
El sitio no proporciona los metadatos, la carga del video fallará si no existe en el sitio.
@@ -205,16 +205,16 @@
Modo Eigengravy
Deslice para avanzar/retroceder
Deslice para cambiar la configuración
- Deslice hacia arriba o hacia abajo en el lado izquierdo o derecho para cambiar el brillo o el volumen
+ Deslice el dedo hacia la izquierda o hacia la derecha para cambiar el brillo o el volumen
Toca dos veces para buscar
Tocar dos veces para pausar
Toque dos veces en el lado derecho o izquierdo para buscar hacia adelante o hacia atrás
- Toque dos veces en el medio para hacer una pausa
+ Toque en el medio para pausar
Usar brillo del sistema
Restaurar datos desde el backup
Hacer copia de los datos (backup)
Archivo de backup cargado
- Busque automáticamente nuevas actualizaciones después de iniciar la aplicación.
+ Buscar automáticamente nuevas actualizaciones al inicio
Rehacer el proceso de configuración inicial
Mostrar episodio de relleno para Anime
Reproducir Episodio
@@ -306,7 +306,7 @@
Aspecto
Características
Botón de Al azar
- Muestra un botón de reproducción \"al azar\" en la página de inicio para poelículas y series
+ Muestra un botón de reproducción \"al azar\" en la página de inicio
cuenta
Cerrar sesión
Cambiar cuenta
@@ -363,8 +363,8 @@
Película
Serie
Dibujo animado
- Anime
- OVA
+ \@string/anime
+ \@string/ova
Torrent
Documental
Drama asiático
@@ -506,27 +506,8 @@
\nInicia sesión en una cuenta de biblioteca o añade series desde tu biblioteca local
¡Se encontró un archivo en modo seguro!
\nNo cargar ninguna extensión al inicio hasta que se elimine el archivo.
- Reproductor visible - buscar cantidad
- Reproductor oculto - buscar cantidad
+ Jugadora mostrada - buscar cantidad
+ Jugadora oculta - buscar cantidad
Android TV
- Tiempo de búsqueda usado (en segundos) cuando el reproductor está visible
- Tiempo de búsqueda usado (en segundos) cuando el reproductor está oculto
- Parar
- Falló
- Registro
- Empezar
- Aprobado
- Prueba del proveedor
- Reiniciar
- Suscrito
- Suscrito a %s
- Darse de baja de %s
- Actualizando los programas suscritos
- ¡Episodio %d publicado!
- Proxy raw.githubusercontent.com
- No se ha podido acceder a GitHub, activando el proxy jsdelivr.
- Con jsdelivr, se puede omitir el bloqueo de GitHub. Puede retrasar las actualizaciones unos días.
- Revertir
- ISP Bypasses
- Calidad de visualización preferida (Datos móviles)
-
+ La cantidad de búsqueda utilizada cuando la jugadora es visible.
+
\ No newline at end of file
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index e4c23628..a34c5a05 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -1,4 +1,4 @@
-
+
حذف
مکث
@@ -23,14 +23,4 @@
هیچکدام
عنوان
تاریخچه
- پوستر
- پوستر
- پوستر قسمت
- %dروز %dساعت %dدقیقه
- %s قسمت %d
- بازیگران: %s
- قسمت %d پخش خواهد شد
- %dساعت %dدقیقه
- %dدقیقه
- پوستر اصلی
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index b96ff0cd..f0e112a8 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -1,18 +1,17 @@
-
-
-
+
+
CloudStream
Accueil
Rechercher
Téléchargements
Paramètres
Rechercher…
- Affiche
+ Miniature
Aucune Donnée
Plus d\'options
Retour
Épisode suivant
- Affiche
+ Miniature
Genres
Partager
Ouvrir dans le navigateur
@@ -30,7 +29,7 @@
Sous-titres
Réessayer la connection…
Retour
- Affiche de l\'épisode
+ Miniature de l\'Épisode
Lire l\'Épisode
Télécharger
@@ -52,10 +51,10 @@
Désactiver le rapport de bug automatique
Plus d\'informations
Cacher
- Affiche principale
+ Poster principal
Lecture
- Infos
- Aléatoire suivant
+ Info
+ Suivant Aléatoire
Changer le fournisseur
Filtrer les marques-pages
Marque-pages
@@ -131,7 +130,7 @@
Nouvelle mise à jour trouvée !
\n%s -> %s
Épisode spécial
- Qualité de visionnage préférée (WiFi)
+ Qualité de visionnage préférée
Taille de la mémoire cache
Étendre
Non-responsabilité
@@ -212,7 +211,7 @@
Arrière plan
Source
Aléatoire
- Bientôt disponible…
+ À venir …
Image de l\'affiche
%s Connecté
Définir le statut de visionage
@@ -241,7 +240,7 @@
Continuer à regarder
Retirer
Plus d\'informations
- @string/home_play
+ \@string/home_play
Un VPN peut être nécessaire pour que ce fournisseur fonctionne correctement
Ce fournisseur est un torrent, un VPN est recommandé
Les métadonnées ne sont pas fournies par le site, le chargement de la vidéo échouera si elles n\'existent pas sur le site.
@@ -386,8 +385,8 @@
4K
Web
-30
- @string/anime
- @string/ova
+ \@string/anime
+ \@string/ova
NSFW
%s %s
Filtrez par langue préférée
@@ -491,37 +490,4 @@
L\'application sera mise à jour dès la fin de la session
Plugin Téléchargé
Retirer de la vue
- Bibliothèque
- Navigateur
- Trier
- Note (basse à haute)
- Note (haut à bas)
- Alphabétique (A à Z)
- On dirait que votre bibliothèque est vide :(
-\nConnectez-vous à un compte ou ajoutez des séries à votre bibliothèque locale
- Il semble que cette liste soit vide, essayez d\'en choisir une autre
- Android TV
- Trié par
- Alphabétique (Z à A)
- Sélectionnez la bibliothèque
- Ouvrir avec
- Mis à jour (Nouveau vers ancien)
- Mis à jour (ancien vers nouveau)
- Fichier du mode sans échec trouvé !
-\nAucune extension ne sera chargée au démarrage avant que le fichier ne soit enlevé.
- Arrêter
- Revenir à
- Enregistrer
- Qualité de visionnage préférée (données mobiles)
- Abonné à %s
- Démarrer
- Test des fournisseurs
- Réussi
- Désabonné de %s
- Redémarrer
- Abonné
- raw.githubusercontent.com Proxy
- Contournements de FAI
- L\'épisode %d est sorti !
- Échouer
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index 833b76f4..f33a2336 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
रफ्तार (%.2fx)
नया अपडेट आया है!
@@ -147,4 +146,4 @@
%dh %dm
%dm
विज्ञापन
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index b4931377..0f3e36bc 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%d %s | %s
%s • %s
@@ -120,7 +119,7 @@
Nastavite s gledanjem
Makni
Više informacija
- @string/home_play
+ \@string/home_play
Za ispravan rad ovog pružatelja usluga može biti potreban VPN
Ovaj pružatelj usluga je torrent, preporučuje se VPN
Stranica ne daje metapodatke, učitavanje videozapisa neće uspjeti ako ne postoji na stranici.
@@ -139,16 +138,16 @@
Eigengravy način
Dodaje opciju brzine u playeru
Prijeđi prstom za traženje
- Prijeđite prstom ulijevo ili udesno kako biste kontrolirali player
+ Prijeđi prstom ulijevo ili udesno za kontrolu vremena u videoplayeru
Klizni za promjenu postavki
- Kliznite prstom ulijevo ili udesno za promjenu svjetline ili glasnoće
+ Prijeđi prstom ulijevo ili udesno za promjenu svjetline ili glasnoće
Automatski započni sljedeću epizodu
Započne sljedeću epizodu kad trenutna završi
Dodirni dvaput za traženje
Dodirni dvaput za pauziranje
- Iznos preskakanja u playeru (Sekunde)
+ Iznos preskakanja u playeru
Dvaput dodirni desnu ili lijevu stranu ekrana za pomicanje naprijed ili natrag
- Dodirnite dvaput u sredinu zaslona za pauziranje
+ Dodirni u sredinu zaslona za pauziranje
Koristi svijetlinu u sustavu
Koristi svjetlinu sustava u playeru aplikacija umjesto tamnog preklopa
Ažuriraj napredak gledanja
@@ -174,7 +173,7 @@
Sakrij odabranu kvalitetu videozapisa u rezultatima pretraživanja
Automatsko ažuriranje dodataka
Prikaži ažuriranja aplikacije
- Automatski traži nova ažuriranja nakon pokretanja aplikacije
+ Automatski traži nova ažuriranja pri pokretanju aplikacije
Ažuriranje na predizdanja
Tražite ažuriranja prije izdanja umjesto samo potpunih izdanja
Github
@@ -239,8 +238,8 @@
Film
Serija
Crtić
- Anime
- OVA
+ \@string/anime
+ \@string/ova
Torrent
Dokumentarac
Azijska drama
@@ -300,7 +299,7 @@
Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk.
Općenito
Random gumb
- Prikazuje gumb na početnoj stranici koji može odabrati nasumični film ili TV seriju s početne stranice
+ Prikaži random gumb na početnoj stranici
Jezici pružatelja usluga
Izgled aplikacije
Preferirani mediji
@@ -532,27 +531,4 @@
Čini se da je ova lista prazna, pokušajte se prebaciti na drugu
Pronađena datoteka sigurnog načina rada!
\nNe učitavaju se ekstenzije pri pokretanju dok se datoteka ne ukloni.
- Prikazan player- iznos preskakanja
- Količina preskakanja koja se koristi kada je player vidljiv
- Player skriven - Količina preskakanja
- Količina preskakanja koja se koristi kada je player skriven
- Android TV
- Prošlo
- Restart
- Log
- Početak
- Neuspješno
- Stop
- Test pružatelja usluga
- Ažuriram pretplaćene serije
- Epizoda %d izbačena!
- Pretplaćeno
- Pretplaćen na %s
- Otkazana pretplata sa %s
- Vraćanje
- ISP zaobilaznice
- raw.githubusercontent.com Proxy
- Neuspješno dohvaćanje GitHuba, omogućavanje jsdelivr proxyja.
- Koristeći jsdelivr, GitHub blokiranje se može zaobići. Može odgoditi ažuriranja za nekoliko dana.
- Preferirana kvaliteta gledanja (podatkovna mobilna mreža)
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 1389dff0..5b42fd6a 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -1,4 +1,4 @@
-
+
Stáblista: %s
%dn %dó%dp
@@ -57,7 +57,7 @@
Megnyitás böngészőben
Betöltés kihagyása
Poster
- @string/result_poster_img_des
+ \@string/result_poster_img_des
Nézés
Befejezve
Később megnézés
@@ -111,7 +111,7 @@
Betűtípusok importálása %s
Eltávolítás
Több információ
- @string/home_play
+ \@string/home_play
VPN szükséges lehet ehhez a szolgáltató megfelelő működéséhez
Ez a szolgáltató torrent, VPN ajánlott
Leírás
@@ -172,11 +172,11 @@
OVA
Egyebek
Sorozat
- @string/anime
+ \@string/anime
Forráshiba
NSFW
Rajzfilm
- @string/ova
+ \@string/ova
Élőadás
NSFW
Videó
@@ -275,4 +275,4 @@
Minőségi jelzés
Szinkroncímke
Alcímke
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index 02234c49..d54e4fa9 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%s Ep %d
Pemeran: %s
@@ -36,7 +35,7 @@
Skip Loading
Loading…
Sedang Menonton
- Tertunda
+ Tertahan
Selesai
Dihentikan
Rencana untuk Menonton
@@ -102,7 +101,7 @@
Lanjutkan Menonton
Hapus
Info lebih lanjut
- @string/home_play
+ \@string/home_play
Sebuah VPN mungkin diperlukan agar provider ini bisa bekerja dengan benar
Provider ini adalah sebuah torrent, VPN direkomendasikan
Metadata tidak disediakan oleh situs, loading video akan gagal jika tidak ada di situs.
@@ -121,14 +120,14 @@
Mode Eigengravy
Menambahkan opsi kecepatan di pemutar
Geser untuk mengubah waktu
- Geser dari sisi ke sisi untuk mengontrol posisi dalam video
+ Geser ke kiri atau kanan untuk mengontrol waktu di pemutar video
Geser untuk mengubah pengaturan
- Geser ke atas atau ke bawah di sisi kiri atau kanan untuk mengubah kecerahan atau volume
+ Geser ke sisi kiri atau kanan untuk mengubah pencerahan atau volume
Tekan dua kali untuk mengubah waktu
Tekan dua kali untuk menjeda
- Jumlah pengubah waktu pemutar (Detik)
+ Jumlah pengubah waktu pemutar
Tekan dua kali di sisi kanan atau kiri untuk mengubah waktu ke depan atau ke belakang
- Tekan dua kali di tengah untuk menjeda
+ Tekan di tengah untuk menjeda
Gunakan pencerahan sistem
Gunakan pencerahan sistem di pemutar aplikasi dari pada hamparan gelap
Update progres tontonan
@@ -150,7 +149,7 @@
Tidak mengirim data
Tampilkan episode filler untuk anime
Tampilkan update aplikasi
- Secara otomatis mencari update terbaru setelah aplikasi dibuka.
+ Secara otomatis mencari update terbaru saat aplikasi dibuka
Update ke prarilis
Hanya mencari update prarilis daripada rilis penuh
Github
@@ -210,8 +209,8 @@
Movie
Seri
Kartun
- Anime
- OVA
+ \@string/anime
+ \@string/ova
Torrent
Film Dokumenter
Drama Asia
@@ -244,7 +243,7 @@
Jangan tunjukkan lagi
Skip Update ini
Update
- Kualitas tontonan yang lebih diinginkan (WIFI)
+ Kualitas tontonan yang lebih diinginkan
Karakter maksimal judul pemutar video
Resolusi pemutar video
Ukuran buffer video
@@ -265,7 +264,7 @@
Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk.
Umum
Tombol Acak
- Tampilkan tombol di halaman utama yang dapat memilih seri film atau TV acak dari halaman utama
+ Tampilkan tombol acak di Beranda
Bahasa provider
Tata Letak Aplikasi
Media yang lebih diinginkan
@@ -388,7 +387,7 @@
%d %s
17+
Lainnya
- Video
+ Vidio
Duplikasi Website
Duplikasi website yang telah ada, dengan alamat berbeda
Tautan
@@ -396,7 +395,7 @@
Cadangkan
Fitur Tambahan
Putar di CloudStream
- Sembunyikan kualitas video terpilih di pencarian
+ Sembunyikan kualitas vidio terpilih di pencarian
%s %d%s
Siaran langsung
Hapus Website
@@ -445,7 +444,7 @@
Peringkat: %s
Pembuat
Bahasa
- Pemutar video utama
+ Pemutar vidio utama
Pemutar Bawaan
VLC
MPV
@@ -476,7 +475,7 @@
Hapus teks tertutup dari subtitel
Hapus karakter sampah dari subtitel
Audio Trek
- Video Trek
+ Vidio Trek
Dukungan
Daftar putar HLS
Penginstal APK
@@ -530,27 +529,4 @@
Yahh daftar ini kosong, coba ganti ke yang lain
Mode aman file ditemukan!
\nTidak memuat ekstensi pada startup sampai berkas dihapus.
- Sembunyikan Pemutaran - Geser
- Pemutar terlihat - Geser
- Geser untuk menghilangkan
- Geser untuk menghilangkan
- Android TV
- Log
- Berhasil
- Tes provider
- Berhenti
- Mulai
- Mulai lagi
- Gagal
- Memperbarui acara langganan
- Berlangganan
- Berlangganan ke %s
- Berhenti berlangganan di %s
- Episode %d telah rilis!
- raw.githubusercontent.com Proksi
- Gagal mencapai GitHub, mengaktifkan proksi jsdelivr.
- Mengunakan jsdelivers, bisa melewati pemblokiran GitHub. Mungkin dapat menyebabkan pembaruan tertunda dalam beberapa hari.
- Bypass ISP
- Pulihkan
- Nonton dengan kualitas yang di inginkan (Data Seluler)
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index eca60da1..9dbc627f 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%s Ep %d
Cast: %s
@@ -109,7 +108,7 @@
Continua a guardare
Rimuovi
Più info
- @string/home_play
+ \@string/home_play
Potrebbe essere necessaria una VPN per far funzionare correttamente questo provider
Questo provider è un torrent, si raccomanda una VPN
I metadati non sono forniti dal sito, il caricamento del video fallirà se non esiste sul sito.
@@ -266,7 +265,7 @@
Non mostrare di nuovo
Salta questo aggiornamento
Aggiorna
- Qualità di visualizzazione preferita (WiFi)
+ Risoluzione preferita
Limita i caratteri del titolo nel player
Risoluzione video player
Dimensione cache video
@@ -529,27 +528,4 @@
Sembra che questa lista sia vuota, prova a passare a un\'altra
File \"safe mode\" trovato!
\nAll\'avvio non sarà caricata alcuna estensione finchè il file non verrà rimosso.
- Quantità di ricerca usata quando il player è nascosto
- TV Android
- Quantità di ricerca usata quando il player è visibile
- Player visibile - Quantità di ricerca
- Player nascosto - Quantità di ricerca
- Registro
- Avvia
- Test del provider
- Riavvia
- Ferma
- Superato
- Fallito
- Proxy raw.githubusercontent.com
- Disiscritto da %s
- Iscritto
- Iscritto a %s
- Impossibile contattare GitHub, abilitazione proxy jsdelivr avviata.
- Bypassa il blocco di GitHub utilizzando jsdelivr, potrebbe causare un ritardo di alcuni giorni.
- Baypass ISP
- Ripristina
- Aggiornando shows a cui sei iscritto
- L\'episodio %d è stato rilasciato!
- Qualità di visualizzazione preferita (Dati mobili)
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml
index b24f0c60..11cf77ce 100644
--- a/app/src/main/res/values-iw/strings.xml
+++ b/app/src/main/res/values-iw/strings.xml
@@ -1,4 +1,4 @@
-
+
הרקע של ההצגה לפני
צוות שחקנים: %s
@@ -116,7 +116,7 @@
כתוביות כרומקאסט
ממשיך ניגון בנגן מינימלי מעל ישומים אחרים
כתוביות
- @string/home_play
+ \@string/home_play
היסטוריה
מורשת
לא
@@ -164,8 +164,8 @@
משומש
סדרת טלוויזיה
סדרות/סרטים מצוירים
- @string/anime
- @string/ova
+ \@string/אנימה
+ \@string/אנימציית וידאו מקורית
דרמה אסייתית
כרומקאסט את הפרק
כרומקאסט את המראה
@@ -506,4 +506,4 @@
אלפביתי (ת\' עד א\')
פתח עם
נראה שהרשימה הזו ריקה, נסו לעבור לרשימה אחרת
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
deleted file mode 100644
index 20641b20..00000000
--- a/app/src/main/res/values-ja/strings.xml
+++ /dev/null
@@ -1,185 +0,0 @@
-
-
- %d分
- ダウンロード
- 検索
- 設定
- シェア
- 映画
- ホーム
- ライブラリ
- 再生
- %d日 %d時間%d分
- %d時間%d分
- 検索…
- ダウンロード
- 情報
- シーズン
- 予告編
- シリーズ
- エピソード
- 再生速度 (%.2fx)
- 次のエピソード
- 適用
- アカウント
- カートゥーン
- TVシリーズ
- トレント
- ドキュメンタリー
- OVA
- アジアドラマ
- ライブ配信
- 映画
- その他
- カートゥーン
- トレント
- ドキュメンタリー
- アジアドラマ
- ライブ配信
- NSFW
- キャンセル
- アニメ
- ロック
- ソース
- NSFW
- 履歴を削除
- 視聴中コンテンツ
- 全般
- 動画
- プレーヤー
- 懐う
- 予告編を再生
- エピソード
- 視聴
- ジャンル
- 映画を再生
- 字幕
- CloudStream
- CloudStreamで再生
- ブラウザ
- 完成
- 放置
- 保留
- ローディング…
- ブラウザで開く
- シーズン
- 残り
-\n%d分
- 再生エピソード
- ダウンロード済
- バックアップ
- ソース
- 履歴
- ポスター
- なし
- コピー
- 閉じる
- 保存
- 消去
- %sエピ%d
- 出演者:%s
- ポスター
- エピソードポスター
- 主要ポスター
- 次のランダム
- 戻り
- 視聴率 %.1f
- 新しいアップデートを発見!
-\n%s -> %s
- %d分
- %sを検索…
- ソース
- ろくごうきじ
- 接続を再試行…
- 戻り
- 削除
- 詳細情報
- 閉じる
- アップデート・バックアップ
- アプリ言語
- GitHub(ギットハブ)
- -30
- +30
- 免責
- 拡張機能
- アプリ更新
- 提供者
- 字幕
- 特徴
- デフォルト
- 自動
- 任意
- 拡張機能
- リンク
- Android TV
- ログイン
- ログアウト
- 最大
- 最小
- なし
- 次
- 18+
- 否
- で開く
- エピソード
- 時間
- 概要
- サイト
- 使用
- アプリ
- 詳細情報
- 削除
- ピクチャーインピクチャー
- 字幕
- 情報
- 一時停止
- 再生エピソード
- 削除
- 開始
- 状態
- 年
- 再開
- 失敗
- 合格
- 空き
- 完成
- 進行中
- デフォルト
- ウェブブラウザ
- VLC
- MPV
- 言語
- 作成者
- サイズ
- 状態
- バージョン
- 視聴率 %s
- 視聴率
- デフォルト
- ダウンロード失敗
- ダウンロード開始
- ダウンロード完了
- ダウンロード終了
- ストリーム
- アップデート開始
- シーズンなし
- 字幕なし
- アスペクト比
- ロードをスキップする
- その他のオプション
- データなし
- ダウンロード中
- ブックマーク
- 内部記憶装置
- ダウンロードが一時停止
- メタデータはこのサイトでは提供されません。メタデータがサイト上に存在しない場合、ビデオの読み込みに失敗します。
- 記述
- Logcat 🐈を表示
- ログ
- 検索
- Discordに参加
- アップデート
- アップデートを確認
- 作品名
- アプリのアップデートをインストール中…
-
diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml
index 4b7b6869..efe0a1d8 100644
--- a/app/src/main/res/values-kn/strings.xml
+++ b/app/src/main/res/values-kn/strings.xml
@@ -1,128 +1,3 @@
-
+
- %sಎಪಿ%d
- ಕ್ಯಾಸ್ಟ್:%s
- ಹಿಂದೆ ಹೋಗು
- ಫಿಲ್ಲರ್
- ಹುಡುಕು
- ಡೌನ್ಲೋಡ್
- ಫಾಂಟ್
- ಪೂರೈಕೆದಾರರನ್ನು ಬಳಸಿಕೊಂಡು ಹುಡುಕಿ
- ಪ್ರಕಾರಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಹುಡುಕಿ
- ಯಾವುದೇ ಬೆನೆನ್ಸ್ ನೀಡಿಲ್ಲ
- ಸ್ವಯಂ-ಆಯ್ಕೆ ಭಾಷೆ
- ಹೆಚ್ಚಿನ ಮಾಹಿತಿ
- \@ಸ್ಟ್ರಿಂಗ್/ಹೋಮ್_ಪ್ಲೇ
- ಈ ಪೂರೈಕೆದಾರರು ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡಲು VPN ಬೇಕಾಗಬಹುದು
- ಕಪ್ಪು ಗಡಿಗಳನ್ನು ತೆಗೆದುಹಾಕಿ
- ಸಂಚಿಕೆ%d ಬಿಡುಗಡೆಯಾಗಲಿದೆ
- %dh %dm
- ಪೋಸ್ಟರ್
- ಪೋಸ್ಟರ್
- ಸಂಚಿಕೆ ಪೋಸ್ಟರ್
- ಮೇನ್ ಪೋಸ್ಟರ್
- ಅಪ್ಡೇಟ್ ಪ್ರಾರಂಭವಾಗಿದೆ
- ಲೋಡಿಂಗ್ ಲಿಂಕ್ ಎರರ್ ಬಂದಿದೆ
- ಇಂಟರ್ನಲ್ ಸ್ಟೋರೇಜ್
- ಡಬ್
- ಸಬ್
- ಸ್ವಯಂಚಾಲಿತ ದೋಷ ವರದಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ
- ಹೈಡ್
- ಪ್ಲೇ
- ಮಾಹಿತಿ
- ಸೆಟ್ ವಾಚ್ ಸ್ಟೇಟಸ್
- ಅನ್ವಯಿಸು
- ರದ್ದುಮಾಡು
- ಸಬ್ ಟೈಟಲ್ಸ್ ಎಲೆವಷನ್
- ಫಾಂಟ್ ಸೈಜ್
- ಸಬ್ ಟೈಟಲ್ಸ್ ಭಾಷೆ
- ತೆಗೆದುಹಾಕಿ
- ಈ ಪೂರೈಕೆದಾರರು ಟೊರೆಂಟ್ ಆಗಿದೆ, VPN ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ
- ಯಾವುದೇ ಪ್ಲಾಟ್ ಕಂಡುಬಂದಿಲ್ಲ
- ಲಾಗ್ಕ್ಯಾಟ್ 🐈 ತೋರಿಸಿ
- ಲಾಗ್
- ಚಿತ್ರದಲ್ಲಿ-ಚಿತ್ರದಲ್ಲಿ
- ಪ್ಲೇಯರ್ ಮರುಗಾತ್ರಗೊಳಿಸಿ ಬಟನ್
- ಸಬ್ ಟೈಟಲ್ಸ್
- ಪ್ಲೇಯರ್ ಸಬ್ ಟೈಟಲ್ಸ್ ಸೆಟ್ಟಿಂಗ್ಗಳು
- ಕ್ರೋಮ್ ಕ್ಯಾಸ್ಟ್ ಸಬ್ ಟೈಟಲ್ಸ್ ಸೆಟ್ಟಿಂಗ್ಸ್
- ಹಿಂದೆ ಹೋಗು
- ಡೌನ್ಲೋಡ್ ವಿರಾಮಗೊಳಿಸಿ
- ಬುಕ್ಮಾರ್ಕ್
- ಬ್ಯಾಕ್ ಗ್ರೌಂಡ್ ಕಲರ್
- %d ಡೇವ್ಗಳಿಗೆ ಬೆನೆನೆಸ್ ನೀಡಲಾಗಿದೆ
- ಡೀಫಾಲ್ಟ್ಗೆ ಮರುಹೊಂದಿಸಲು ಹಿಡಿದುಕೊಳ್ಳಿ
- ಸೈಟ್ನಿಂದ ಮೆಟಾಡೇಟಾವನ್ನು ಒದಗಿಸಲಾಗಿಲ್ಲ, ಅದು ಸೈಟ್ನಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲದಿದ್ದರೆ ವೀಡಿಯೊ ಲೋಡಿಂಗ್ ವಿಫಲಗೊಳ್ಳುತ್ತದೆ.
- ಇತರ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಮೇಲೆ ಚಿಕಣಿ ಪ್ಲೇಯರ್ನಲ್ಲಿ ಪ್ಲೇಬ್ಯಾಕ್ ಅನ್ನು ಮುಂದುವರಿಸುತ್ತದೆ
- ಕ್ರೋಮ್ ಕ್ಯಾಸ್ಟ್ ಸಬ್ ಟೈಟಲ್ಸ್
- ರೇಟೆಡ್:%.1f
- ತೆಗೆದುಹಾಕಿ
- ಡೌನ್ಲೋಡ್ ಅನ್ನು ಪುನರಾರಂಭಿಸಿ
- ಕ್ಲೋಸ್
- ಕ್ಲಿಯರ್
- ಸೇವ್
- ಸಬ್ ಟೈಟಲ್ಸ್ ಸೆಟ್ಟಿಂಗ್ಸ್
- ಫೈಲ್ ಪ್ಲೇ
- ಟೆಕ್ಸ್ಟ್ ಕಲರ್
- ಔಟ್ ಲೈನ್ ಕಲರ್
- ವಿಂಡೋ ಕಲರ್
- ಎಡ್ಜ್ ಟೈಪ್
- ಪ್ರೊವೈಡರ್ ಬದಲಾಯಿಸಿ
- %dಮಿನ
- ವಿವರಣೆ
- ಸ್ಪೀಡ್(%.2fx)
- ಹೋಂ
- ಸಬ್ ಟೈಟಲ್ಸ್
- ಸೆಟ್ಟಿಂಗ್ಸ್
- ಬುಕ್ಮಾರ್ಕ್ಗಳನ್ನು ಫಿಲ್ಟರ್ ಮಾಡಿ
- ಹುಡುಕು…
- ಚಲನಚಿತ್ರವನ್ನು ಪ್ಲೇ ಮಾಡಿ
- ಪ್ರಿವ್ಯೂ ಹಿನ್ನೆಲೆ
- ಮುಂದಿನ ಸಂಚಿಕೆ
- ಕ್ಲೌಡ್ ಸ್ಟ್ರೀಮ್
- ಡೌನ್ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ
- ಸ್ಟ್ರೀಮ್
- ಶೇರ್
- ಫೈಲ್ ಅಳಿಸಿ
- ಹೆಚ್ಚಿನ ಮಾಹಿತಿ
- ಹೊಸ ಅಪ್ಡೇಟ್ ಬಂದಿದೆ
-\n%s-%s
- ಲೋಡಿಂಗ್…
- ಡೌನ್ಲೋಡ್ ಭಾಷೆಗಳನ್ನು ಮಾಡಿ
- ಲೈವ್ಸ್ಟ್ರೀಮ್ ಪ್ಲೇ ಮಾಡಿ
- ಕ್ಲೌಡ್ ಸ್ಟ್ರೀಮ್ ಇದರೊಂದಿಗೆ ಪ್ಲೇ ಮಾಡಿ
- ವೀಕ್ಷಿಸಲು ಯೋಜನೆ
- ಸಂಚಿಕೆಯನ್ನು ಪ್ಲೇ ಮಾಡಿ
- ಕಂಟಿನ್ಯೂ ವಾಟಚಿಂಗ್
- ಯಾವುದೇ ವಿವರಣೆ ಕಂಡುಬಂದಿಲ್ಲ
- ಸ್ಟ್ರೀಮ್ ಟೊರೆಂಟ್
- ಡೌನ್ಲೋಡ್
- ಕಾಪಿ
- ನೋ ಡೇಟಾ
- ಪ್ಲೇಯರ್ ಸ್ಪೀಡ್
- %d %dh %dm
- ಹುಡುಕು %s…
- ಹೆಚ್ಚಿನ ಆಯ್ಕೆ
- ಫಾಂಟ್ಗಳನ್ನು ಇರಿಸುವ ಮೂಲಕ ಆಮದು ಮಾಡಿ %s
- %dm
- ಪ್ರಕಾರಗಳು
- ಬ್ರೌಸರ್ ತೆರೆಯಿರಿ
- ಆನ್-ಹೋಲ್ಡ್
- ನನ್
- ಸಂಪರ್ಕವನ್ನು ಮರುಪ್ರಯತ್ನಿಸಿ…
- ಡೌನ್ಲೋಡ್ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ
- ಡೌನ್ಲೋಡ್ ವಿಫಲವಾಗಿದೆ
- ಡೌನ್ಲೋಡ್ ಮುಗಿದಿದೆ
- ಬ್ರೌಸರ್
- ಸ್ಕಿಪ್ ಲೋಡಿಂಗ್
- ವಾಚಿಂಗ್
- ಪೂರ್ಣಗೊಂಡಿದೆ
- ಕೈಬಿಡಲಾಯಿತು
- ಪುನಃ ವೀಕ್ಷಿಸುತ್ತಿದೆ
- ಟ್ರೈಲರ್ ಪ್ಲೇ ಮಾಡಿ
- ಮೂಲಗಳು
- ಡೌನ್ಲೋಡ್ ಮಾಡಲಾಗಿದೆ
- ಡೌನ್ಲೋಡ್ ಪ್ರಾರಂಭವಾಗಿದೆ
- ಡೌನ್ಲೋಡ್ ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ
- ಮುಂದಿನ ರಾಂಡಮ್
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml
index 811a09c5..7251d0d7 100644
--- a/app/src/main/res/values-mk/strings.xml
+++ b/app/src/main/res/values-mk/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
Брзина (%.2fx)
Оценето: %.1f
@@ -214,4 +213,4 @@
Сенка
Подигнат
Историја
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml
index d430d7cc..b6ad3a80 100644
--- a/app/src/main/res/values-ml/strings.xml
+++ b/app/src/main/res/values-ml/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
വേഗം (%.2fx)
റേറ്റിംഗ്: %.1f
@@ -170,4 +169,4 @@
ഔചിത്യ വീഡിയോ ക്വാളിറ്റി
ചരിത്രം
കണ്ടതാണെന്ന് അടയാളപ്പെടുത്തുക
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml
deleted file mode 100644
index c757504a..00000000
--- a/app/src/main/res/values-ms/strings.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 766bcdc7..c2561914 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%s Ep %d
Cast: %s
@@ -10,7 +9,7 @@
%dm
Poster
- Poster
+ \@string/result_poster_img_des
Aflevering Poster
Hoofdposter
Volgende willekeurig
@@ -110,7 +109,7 @@
Doorgaan met kijken
Verwijder
Meer Info
- @string/home_play
+ \@string/home_play
Een VPN kan nodig zijn om deze provider correct te laten werken
Deze provider is een torrent, een VPN wordt aanbevolen
Metadata wordt niet geleverd door de site, het laden van video\'s zal mislukken als deze niet op de site bestaat.
@@ -129,14 +128,14 @@
Eigengravy Modus
Voegt een snelheidsoptie toe in de speler
Swipe to seek
- Veeg naar links of rechts om de tijd in de videospeler te regelen
+ Veeg naar links of rechts om de tijd in de videoplayer te regelen
Veeg om instellingen te wijzigen
Veeg naar links of rechts om de helderheid of het volume te wijzigen
Dubbeltik om te zien
Dubbeltik om te pauzeren
- Videospeler aantal zoeken
+ Speler zoeken bedrag
Tik twee keer aan de rechter- of linkerkant om vooruit of achteruit te zoeken
- Tik twee keer in het midden om te pauzeren
+ Tik in het midden om te pauzeren
Systeemhelderheid gebruiken
Gebruik systeemhelderheid in de app-speler in plaats van een donkere overlay
Kijkvoortgang bijwerken
@@ -223,8 +222,8 @@
Film
Serie
Tekenfilm
- @string/anime
- @string/ova
+ \@string/anime
+ \@string/ova
Torrent
Documentaire
Aziatisch drama
@@ -406,7 +405,4 @@
Start de volgende episode wanneer deze afgelopen is
Volgende episode automatisch afspelen
De update is gestart
- Bibliotheek
- Browser
- Logboek
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-nn/strings.xml b/app/src/main/res/values-nn/strings.xml
index 43738665..b5132028 100644
--- a/app/src/main/res/values-nn/strings.xml
+++ b/app/src/main/res/values-nn/strings.xml
@@ -1,4 +1,4 @@
-
+
Fleire val
Heim
@@ -183,4 +183,4 @@
Varigheit
Direktesendingar
Programoppdateringar
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml
index fddd4919..41bf704d 100644
--- a/app/src/main/res/values-no/strings.xml
+++ b/app/src/main/res/values-no/strings.xml
@@ -1,8 +1,8 @@
-
+
Plakat
- @string/result_poster_img_des
+ \@string/result_poster_img_des
Episode Plakat
Main Plakat
Neste tilfeldig
@@ -412,7 +412,7 @@
Slå av/på grensesnittselementer på plakat
Hopp over denne oppdateringen
Forårsaker tilfeldige krasj hvis satt for høyt. Ikke endre dette hvis du ikke har lite minne.
- @string/home_play
+ \@string/home_play
Sikkerhetskopier data
Data lagret
Kunne ikke logge inn på %s
@@ -422,11 +422,11 @@
Sensurerbart
Vev
Lenke til strøm
- @string/anime
+ \@string/anime
Skjul valgt videokvalitet i søkeresultater
Lastet inn sikkerhetkopifil
Oppdateringer og sikkerhetskopi
- @string/ova
+ \@string/ova
Avslutt\?
Sensurerbart
Alle %s er allerede nedlastet
@@ -492,4 +492,4 @@
Oppdatering startet
Programtillegg nedlastet
Programmet vil oppgraderes når du avslutter det
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index a2a07dd7..c709f124 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
Prędkość (%.2fx)
Ocena: %.1f
Znaleziono nową aktualizację!
@@ -255,7 +254,7 @@
Nie pokazuj ponownie
Pomiń tę aktualizację
Aktualizacja
- Domyślna jakość (WiFi)
+ Domyślna jakość
Maksymalna ilość znaków w tytule odtwarzacza
Rozdzielczość odtwarzacza wideo
Rozmiar bufora wideo
@@ -374,7 +373,7 @@
Pomiń setup
Dostosuj wygląd aplikacji do urządzenia
Zgłaszanie błędów
- Co chciałbyś obejrzeć
+ Co chciałbyś obejrzeć\?
Gotowe
Rozszerzenia
Dodaj repozytorium
@@ -456,7 +455,7 @@
Instalator APK
Niektóre telefony nie obsługują nowego instalatora pakietów. Wypróbuj tryb legacy, jeśli aktualizacje nie zostaną zainstalowane.
password123
- @string/ova
+ \@string/ova
MojaFajnaWitryna
MyCoolUsername
127.0.0.1
@@ -464,9 +463,9 @@
przyklad.pl
/\?\?
Instalator pakietów
- @string/home_play
+ \@string/home_play
hello@world.com
- @string/anime
+ \@string/anime
Opening
Ending
Mixed opening
@@ -510,27 +509,4 @@
Wygląda na to, że ta lista jest pusta, spróbuj przełączyć się na inną
Znaleziono plik trybu bezpiecznego.
\nRozszerzenia nie zostaną wczytane, dopóki plik nie zostanie usunięty.
- Używana ilość przewijania, gdy widoczny jest odtwarzacz
- Ukryty odtwarzacz - ilość przewijania
- Android TV
- Pokazany odtwarzacz — ilość przewijania
- Używana ilość przewijania, gdy ukryty jest odtwarzacz
- Dziennik
- Uruchom ponownie
- Rozpocznij
- Nie powiodło się
- Ukończone powodzeniem
- Serwer pośredniczący raw.githubusercontent.com
- Obejścia ISP
- Test dostawcy
- Zatrzymaj
- Przywróć
- Aktualizowanie subskrybowanych programów
- Zasubskrybowano
- Zasubskrybowano %s
- Anulowano subskrypcję %s
- Został wydany odcinek %d!
- Obchodzi blokadę GitHuba za pomocą jsdelivr, może spowodować opóźnienie aktualizacji o kilka dni.
- Nie udało się połączyć z GitHub, włączono serwer pośredniczący jsdelivr.
- Domyślna jakość (dane mobilne)
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index dd722f62..9353664e 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -1,65 +1,65 @@
-
+
%s Ep %d
%dh %dm
%dm
- O episódio %d será lançado em
+ Episódio %d será lançado em
Poster
- Pôster do episódio
- Poster
- Pôster Principal
+ Capa do Episódio
+ \@string/result_poster_img_des
+ Capa Principal
Próximo Aleatório
Voltar
- Alterar Provedor
+ Trocar Provedor
%dd %dh %dm
Fonte
Resolução
Extras
- Visualizar plano de fundo
+ Preview Background
Velocidade (%.2fx)
Classificado: %.1f
Nova atualização encontrada!
\n%s -> %s
- Preenchimento
+ Enchimento
CloudStream
- Assistir com o CloudStream
+ Reproduzir com CloudStream
Início
- Pesquisar
- Downloads
- Configurações
+ Pesquisa
+ Transferências
+ Opções
Procurar…
- Pesquisar %s…
- Sem dados
- Mais opções
+ Procurar em %s…
+ Sem Dados
+ Mais Opções
Próximo episódio
- Gêneros
- Compartilhar
- Abrir no navegador
- Pular carregamento
+ Géneros
+ Partilhar
+ Abrir no Navegador
+ Saltar Carga
Carregando…
Assistindo
- Em espera
+ Em Espera
Concluído
- Desistido
- Pretendo assistir
- Nenhum
- Reassistindo
- Reproduzir filme
- Reproduzir transmissão ao vivo
+ Abandonado
+ Planeio Assistir
+ Nenhuma
+ Assistindo de Novo
+ Reproduzir Filme
+ Reproduzir Livestream
Transmitir Torrent
Fontes
Legendas
- Tentar conexão novamente…
- Voltar
- Reproduzir episódio
- Download
- Baixado
- Baixando
- Download Pausado
- Download Iniciado
- Falha no Download
- Download cancelado
- Download concluído
+ Voltar a tentar ligação…
+ Voltar Atrás
+ Reproduzir Episódio
+ Transferir
+ Transferido
+ A Transferir
+ Transferência em Pausa
+ Transferência Iniciada
+ Transferência Falhou
+ Transferência Cancelada
+ Transferência Completa
Stream
Erro a Carregar Links
Armazenamento Interno
@@ -123,16 +123,16 @@
Modo Eigengravy
Acrescenta uma opção de velocidade no player
Deslize para andar
- Deslize para os lados para controlar a posição em um vídeo
+ Deslize para a esq. ou dir. para controlar o tempo no player
Deslize para mudar as configurações
- Deslize para cima ou para baixo, no lado esquerdo ou direito, para ajustar brilho ou volume
+ Deslize do lado esq. ou dir. para ajustar brilho ou volume
Reproduzir automaticamente próximo episódio
Começa o próximo episódio quando o atual termina
Toque duplo para avançar
Toque duplo para pôr em pausa
- Tempo de busca no player (Segundos)
+ Segundos avançados no player
Toque duplo no lado esq. ou dir. para andar para trás ou para a frente
- Toque duas vezes no meio para pausar
+ Toque no meio para pôr em pausa
Usar brilho da sistema
Usar brilho do sistema no player em vez de uma sobreposição escura
Atualizar progresso
@@ -142,7 +142,7 @@
Arquivo de backup carregado
Falha ao restaurar dados do ficheiro %s
Dados guardados com sucesso
- Permissão de armazenamento não encontrada, por favor tente novamente.
+ Permissões de armazenamento em falta, por favor tente de novo
Erro no backup de %s
Procurar
Contas
@@ -158,7 +158,7 @@
Esconder qualidades de vídeo selecionadas nos resultados da Pesquisa
Atualizações de plugin automáticas
Mostrar atualizações da app
- Procurar automaticamente por novas atualizações depois de iniciar o app.
+ Procurar novas atualizações automaticamente ao iniciar
Atualizar para pré-lançamentos
Procura atualizações de pré-lançamento em vez de só lançamentos oficiais
Github
@@ -250,15 +250,15 @@
Não mostrar de novo
Saltar esta Atualização
Atualizar
- Qualidade Preferida (WiFi)
- Máximo de caracteres do título no player de video
+ Qualidade Preferida
+ Máximo de caracteres do título de vídeos
Resolução do player de vídeo
Tamanho do buffer do vídeo
Comprimento do buffer do vídeo
Cache do vídeo em disco
Limpar cache de vídeo e imagem
- Causará travamentos em dispositivos com pouca memória se definido muito alto , como uma Android TV.
- Pode causar problemas em sistemas com pouco espaço de armazenamento se definido muito alto, como uma Android TV.
+ Causará travamentos aleatórios se definido muito alto. Não mude se tiver pouca memória RAM, como um Android TV ou um telefone antigo
+ Pode causar problemas em sistemas com pouco espaço de armazenamento se definido muito alto, como em dispositivos Android TV
DNS sobre HTTPS
Útil para contornar bloqueios do fornecedor de internet
Clonar site
@@ -273,7 +273,7 @@
Aviso Legal
Geral
Botão Aleatório
- Mostra o botão Aleatório na página inicial, que pode escolher aleatoriamente um filme ou série
+ Mostra o botão Aleatório na página inicial
Idioma dos fornecedores
Layout da App
Mídia preferida
@@ -363,7 +363,7 @@
Plugin Carregado
Plugin Apagado
Falha ao carregar %s
- Download iniciado %d %s…
+ Iniciada a transferência %d %s
Transferido %d %s com sucesso
Tudo %s já transferido
Transferência em batch
@@ -375,158 +375,10 @@
Transferido: %d
Desativado: %d
Não transferido: %d
- O CloudStream não possui sites instalados por padrão. Você precisa instalar os sites a partir de repositórios.
-\n
-\nDevido a uma restrição sem sentido de direitos autorais (DMCA) pela Sky UK Limited 🤮 não podemos vincular o site do repositório no aplicativo.
-\n
-\nJunte-se ao nosso Discord ou pesquise online.
+ Adicionar um repositório para instalar extensões de sites
Ver repositórios da comunidade
Lista pública
Todas as legendas em maiúsculas
Transferir todos os plugins deste repositório\?
%s (Desativado)
- Instalador APK
- %d min
- Assistir Trailer
- Marcar como visto/não visto
- Reproduzir
- Instalar automaticamente todos os plugins ainda não instalados dos repositórios adicionados.
- Baixar extensões automaticamente
- Refazer o processo de configuração
- -30
- Vídeo
- +30
- %s %d%s
- Elenco: %s
- Atualização iniciada
- Log
- Alguns aparelhos não suportam o novo instalador de pacotes. Use a opção legado caso não esteja conseguindo atualizar.
- %d-%d
- %d %s
- Iniciar
- Falha
- Sucesso
- Biblioteca
- Navegar
- Aplicativo de Anime pelos mesmos desenvolvedores
- Ova
- Anime
- Player visível - Procurar valor
- Instalando atualização do app…
- Você tem certeza que deseja sair\?
- Versão
- Encerramento
- Limpar histórico
- Abertura
- Não
- Ordenar por
- Sim
- Baixando atualização do app…
- Episódio %d lançado!
- Créditos
- Descrição
- Tamanho
- Parar
- Modo seguro ligado
- Histórico
- Ordenar
- Player interno
- Autores
- Suportado
- Idioma
- Instalar a extensão primeiro
- Playlist HLS
- Player de vídeo preferido
- Estado
- Gestos
- Faixas
- WP
- Cam
- Abertura
- Selecionar Biblioteca
- Usando jsdelivr o bloqueio do GitHub pode ser contornado. Pode atrasar atualizações em alguns dias.
- VLC
- Todas as linguagens
- Atualizado (Novo para Antigo)
- Inscrito
- HDR
- Reiniciar
- Navegador Web
- Atualizado (Antigo para Novo)
- Web Video Cast
- DVD
- Instalador de pacotes
- MPV
- Remover dos assistidos
- Não foi possível instalar a nova versão do aplicativo
- Inscrição cancelada em %s
- Final misto
- Avaliações (Decrescente)
- Aplicar ao reiniciar
- Referente
- Player oculto - Quantidade de Busca
- raw.githubusercontent.com Proxy
- Blu-ray
- Aparência
- 1000 ms
- SDR
- 18+
- Abrir com
- Teste de provedor
- UHD
- Ver informações sobre falha
- Aplicativo não encontrado
- Reverter
- Link para transmitir
- Plugins baixados
- %d plugins atualizados
- Pular %s
- Abertura mista
- Alfabético (Z a A)
- Parece que esta lista está vazia, tente trocar para outra
- Inscrito em %s
- 4K
- Faixas de vídeo
- O aplicativo será atualizado ao sair
- Atualizando shows inscritos
- Alfabético (A a Z)
- Avaliações (Crescente)
- Parece que a sua biblioteca está vazia :(
-\nFaça login em uma conta de biblioteca ou adicione shows à sua biblioteca local
- Arquivo de modo de segurança encontrado!
-\nNenhuma extensão será carregada na inicialização do app até que o arquivo seja removido.
- Contorno do provedor de serviço de internet (ISP)
- Links
- Recursos do Player
- Recursos
- Atualizações de aplicativos
- Qualidade Preferida (Dados Móveis)
- Quantidade de busca (em segundos) usada quando o player de video está visível
- Quantidade de busca (em segundos) usada quando o player de video está oculto
- Falha ao conectar com GitHub, ativando proxy jsdelivr.
- Cache
- Android TV
- Legendas
- %s %s
- TS
- Cam
- Cam
- HQ
- HD
- TC
- Web
- Nota: %s
- Legado
- Todas as extensões foram desativadas devido a uma falha para ajudá-lo a encontrar a que está causando o problema.
- Recapitular
- Mostrar pop-ups para pular abertura/encerramento
- Muito texto. Não é possível salvar na área de transferência.
- Marcar como assistido
- Backup
- Extensões
- Ações
- Layout
- Configurações padrão
- SD
- Faixas de áudio
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-qt/strings.xml b/app/src/main/res/values-qt/strings.xml
index eee28785..24c51a05 100644
--- a/app/src/main/res/values-qt/strings.xml
+++ b/app/src/main/res/values-qt/strings.xml
@@ -1,15 +1,15 @@
-
+
aauugghhaauuh
ooh
oouuh
- ouuhhuhooh ooh
+ ouuhhhooh ooh
aaaghhoh aauugghh
- haaooh ooo
+ haaooh
aaaaaah
oooohhoouuh
- aaaaoouuuhahhh ahh
+ aaaaaoouuhahhh ahh
oooohh aauuh
ahhhaaaghh aaaaa
ahaauugghh
@@ -172,80 +172,28 @@
oouuh haa
oohahaha hahha ooooohaha
oohahaha hahha ooooohaha haaoou
- u ahhu uuuh hau uaohuau
+ u ahhu uuuh hau uaohuau
aahuuouhh ouh hhhah hhaohuhha
a auoo ohauh
- uhaauauau ahuuouaha
+ uhaauauau ahuuouaha
auuuha h a ahuhaaaa
- uaoh uhu uahaaaaoo
- uauhah u aao u oah
- h u ahahh aoou ha
+ uaoh uhu uahaaaaoo
+ uauhah u aao u oah
+ h u ahahh aoou ha
haoooo aaoou uou ah
oahuouooaouoa ouuhh
o ouou uhauuuoaah h
ou aouhouo aaooao hh
- hhauhohhuu au aaohu
- uhuoh o a ohahuhohoa hah
+ hhauhohhuu au aaohu
+ uhuoh o a ohahuhohoa hah
ua hu ouo o aoau hah ah
- ah huu oouhhau aoaoaaohoo ha
- a ahu uoo uoahuo uo
+ ah huu oouhhau aoaoaaohoo ha
+ a ahu uoo uoahuo uo
uo u ohouao
uuoouhh hhuhuuh ouhoaao hau aouo
- uha uh huo uooaah u
+ uha uh huo uooaah u
u ooah uo ahauao huhuu hauu h
a ou oh ouhuouhoaaha
aaooohhouhhha hauauuu
- aaaaaaa uuuuuu
-\n%s -> %s
- %s aaou %d
- oouaaahh %s
- aaaaaaugh ouh %d uuoogahaaah ooua-h-ha
- %daaa %duuu %dhhhg
- %daaaaaaauuhh %doouuahaaha
- %dmmmm...
- aaaaaaaaaaaaahh (%.2foouo)
- aghaaaooo-ough %.1f
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaooooohhuhuhuhuhuhhuhuhhhaaagaha-agagaoooo
- %d ooaaaugha
- oooooh aaah aauuuggghauuh
- aaoohhu %s aoouu
- oooaaaauhgaaaa
- aaaaaah-ooooooooouuagh
- auugggguuuuuuhhh uuuu hhhhhhhhuhggghggg
- ggaaaahhhhhhh gaauuuuuuuaaaau
- aaauuuuggggguu
- ooo aagg hhhh
- ooo aagg hhhh
- uuuuhhhoouuooog ooaaahhhh
- uuu ugggg
- ooo guggg ooh
- auuuooohaaaaagh
- uuuuuuuh aaaoo o
- ooooooouuuua aa aaagh agh
- AAAAUUUOH
- aoughoooaaaa
- oooouuuh
- ahaough aaouuuuh-h
- auughooo
- ooooooa aauoh
- aaaaagh oouoo aaaaaaa
- aaaaaagh uuohuoh
- aaaaaauo agghhhhhhaoouu
- uuuuuuuuh
- ouaaahh
- ooough aaoough aooou %s aaaa
- ouooooouuuu oooooo
- aaaaaaaaaaahhhgh-aooohoooo
- aau aooooghaao
- aagh aaaaaaaaaaaa oooh, aaough, ooga oguuu aaaaaaaaaaa ooooooohghh a-a-aaauo
- %dmmmmmm..
-\naaaaooughugh
- aooohuohaaaa ooooagh
- oooooogh-aaaaaogh
- guuuaaaahhhhhhhaaa
- woooaaahh ahahaaaauu 🦍
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOOOGGAGHAGHAAA
- aoaaaaaoooghhh
- oooooh uuaagh
- @string/home_play
-
+ aaaaaaa uuuuuu\n%s -> %s
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index aa443783..982546bc 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%s Ep %d
Distribuție: %s
@@ -10,7 +9,7 @@
%dm
Poster
- Poster
+ \@string/result_poster_img_des
Poster Episod
Poster Principal
Următorul la Întâmplare
@@ -107,7 +106,7 @@
Continuați să urmăriți
Eliminați
Mai multe informații
- @string/home_play
+ \@string/home_play
Există probabilitatea necesitații unui VPN pentru ca acest furnizor să funcționeze corespunzător
Acest furnizor este un torrent, se recomandă un VPN
Metadatele nu sunt furnizate de către site, există posibilitatea ca încărcarea videoclipului să eșueze.
@@ -143,7 +142,7 @@
Fișier de rezervă încărcat
Imposibilitatea de a restaura datele din %s
Date stocate
- Permisiunea de arhivare lipșe, vă rugăm să încercați din nou.
+ Permisiuni de arhivare lipsă, vă rugăm să încercați din nou
Eroare de backup %s
Căutare
Conturi și credite
@@ -155,7 +154,7 @@
Nu trimiteți niciun fel de date
Afișează etichetele [filler] pentru anime
Arată trailerul
- Arată afișele de la Kitsu
+ Arată posterele de la Kitsu
Afișați actualizările aplicației
Căutați automat noi actualizări la pornire
Actualizați la prerelease
@@ -385,8 +384,4 @@
Începe următorul episod când se termină episodul curent
Ascundeți calitatea video selectată în rezultatele căutării
Redare Livestream
- Librărie
- Log
- Browser
- Joacă cu CloudStream
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 9d8f6895..29e98598 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -1,4 +1,4 @@
-
+
История
Нет
@@ -25,8 +25,8 @@
Серия %d будет выпущен в
Плакат
Плакат
- Плакат эпизода
- Главный плакат
+ Постер Эпизода
+ Главный постер
Следующий случайный
Вернуться
Изменить поставщика
@@ -61,11 +61,11 @@
Нет
Пересмотрю
Смотреть фильм
- Смотреть трейлер
- Смотреть Livestream
+ Воспроизвести трейлер
+ Воспроизвести Livestream
Источники
Субтитры
- Смотреть эпизод
+ Воспроизвести эпизод
Повторная попытка подключение…
Вернуться
Скачано
@@ -90,7 +90,7 @@
Скорость проигрыватель
Воспроизвести Эпизод
%dд %dч %dм
- %d мин.
+ %d мин
Dub
Sub
Установите смотреть состояние
@@ -114,7 +114,7 @@
Шрифт
Размер шрифта
Удалить файл
- Воспроизвести файл
+ Проиграть файл
Внутренняя память
Продолжить Скачать
Остановить скачивание
@@ -142,10 +142,10 @@
Добавляет опцию скорости в проигрывателе
Проведите пальцем для поиска
Проведите пальцем для изменения настроек
- Проведите вверх или вниз по левой или правой стороне, чтобы изменить яркость или громкость
+ Проведите пальцем по левой или правой стороне для изменения яркости или громкости
Автопроиграть следующего серия
Поток торрент
- Проведите пальцем из стороны в сторону, чтобы управлять свое место в видеоролике
+ Проведите пальцем влево или вправо, чтобы управлять временем в видеоплеере
Начните следующий серию, когда закончится текущий
Загружена резервная копия
Не удалось восстановить данные из %s
@@ -159,7 +159,7 @@
Автоматическое обновление плагинов
Автоматическая загрузка плагинов
Показать обновления приложения
- Автоматически проверять обновления при старте приложения.
+ Автоматически проверять обновления при старте
Обновится до пре-релиза
APK установщик
Github
@@ -213,7 +213,7 @@
NSFW
NSFW
Фильм
- Сериал
+ Серия
Торрент
Документальный
Азиатская драма
@@ -227,7 +227,7 @@
Использовано
Двойное нажатие для паузы
Коснитесь дважды правой или левой стороны для поиска вперед или назад
- Нажмите дважды в центре, чтобы сделать паузу
+ Нажмите в центре для паузы
Использовать системную яркость
Автоматически синхронизировать текущий прогресс эпизода
Ошибка резервного копирования %s
@@ -318,7 +318,7 @@
Титры
Отметить как просмотренное
Разрешение видеоплеера
- Предпочтительное качество видео (WiFi)
+ Желаемое качество видео
Максимум символов
Длинна буфера
Кеш видео на диске
@@ -363,7 +363,7 @@
Расширения
URL репозитория
Плагин загружен
- @string/home_play
+ \@string/home_play
Перемотка двойным нажатием
/\?\?
/%d
@@ -408,8 +408,8 @@
Съешь ещё этих мягких французских булок, да выпей же чаю
Рекомендуется
Загружено %s
- Аниме
- OVA
+ \@нить/аниме
+ \@нить/ova
Этикетка Dub
Сайт
Функции
@@ -472,7 +472,7 @@
Скачайте список сайтов, который вы хотите использовать
Отображать Аниме с Дубляжом/Субтитрами
Включить NSFW на поддерживаемых провайдерах
- Удалять скрытые субтитры из субтитров
+ Убрать скрытые субтитры из субтитров
Дополнительно
Изменить вид интерфейса, чтобы соответствовать устройству
Аудио дорожки
@@ -493,7 +493,7 @@
Фильтровать по предпочитаемому языку медиа
Неверный ID
Ссылка на стрим
- Показывает кнопку на главной странице, с помощью которой можно выбрать случайный фильм или сериал с главной страницы
+ Отображать рандомную кнопку на Главной странице
Рандомная кнопка
Legacy (старый)
Веб видеокаст
@@ -501,32 +501,5 @@
Перезагрузить ссылки
Предпочтительные медиа
Опущенные
- Объем перемотки плеера (секундах)
- Объем перемотка, используемый, когда плеер виден
- Плеер показан - Перемотки объем
- Плеер спрятан - Перемотки объем
- Удалять лишнее из субтитров
- Местоположение ползунка, когда игрок скрыт
- Android TV
- Второго планa
- Смешанный опенинг
- Смешанный конец
- Тест провайдер
- Журнал
- Запустить
- Выполнено
- Неудачный
- Прекратить
- Перезапустить
- Вернуться
- Подписался на %s
- Предпочтительное качество видео (Мобильный интернет)
- raw.githubusercontent.com Прокси-сервер
- Не удалось подключиться к GitHub. Будет выполнен прокси jsdelivr.
- Эпизод %d выпущен!
- Обходы провайдера
- Обновление подписки на фильмы и сериалы
- Обход ограничения доступа к GitHub с помощью jsdelivr может задержать обновления на несколько дней.
- Подписные
- Отказались от подписки на %s
-
+ Объем перемотки плеера
+
\ No newline at end of file
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index a1afd6d9..97039233 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -1,4 +1,4 @@
-
+
Našla sa nová aktualizácia!
\n%s -> %s
@@ -17,7 +17,7 @@
%dd %dh %dm
%dm
%d min
- Plagát
+ \@string/result_poster_img_des
Plagát epizódy
Hlavný plagát
Prehrať s CloudStream
@@ -99,9 +99,9 @@
Tento poskytovateľ je torrent, odporúča sa VPN
Importovať písma ich umiestnením do %s
Viac informácií
- @string/home_play
+ \@string/home_play
Pokračovať v sledovaní
Na správne fungovanie tohto poskytovateľa môže byť potrebná VPN
Stránka neposkytla žiadne metadáta, načítanie videa zlyhá, ak na stránke neexistuje.
Popis
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-so/strings.xml b/app/src/main/res/values-so/strings.xml
index ce7d557a..b944b6b3 100644
--- a/app/src/main/res/values-so/strings.xml
+++ b/app/src/main/res/values-so/strings.xml
@@ -1,4 +1,4 @@
-
+
Metalaya: %s
%dm %ds %dd
@@ -487,4 +487,4 @@
Bilowga
Bilow isku qasan
Qoraalka dhamaadka
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 0b7ba89e..32336b66 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
Betygsatt: %.1f
Hastighet (%.2fx)
Ny uppdatering hittad!
@@ -34,7 +33,7 @@
Undertexter
Försök ansluta igen…
Gå tillbaka
- @string/result_poster_img_des
+ \@string/result_poster_img_des
Spela Avsnitt
Ladda ner
Intern lagring
@@ -45,7 +44,7 @@
Inaktivera automatisk felrapportering
Mer information
Hide
- @string/result_poster_img_des
+ \@string/result_poster_img_des
Spela upp
Info
Nästa
@@ -236,7 +235,7 @@
Episod %d kommer släppas om
%d min
Visa trailers
- @string/home_play
+ \@string/home_play
OVA
%d-%d
%d %s
@@ -245,7 +244,7 @@
%dm
\nåterstår
NSFW
- @string/ova
+ \@string/ova
Torrent
NSFW
+30
@@ -274,7 +273,7 @@
Asiatiska draman
Andra
Tecknade serier
- @string/anime
+ \@string/anime
Dokumentär
Asiatisk drama
Video
@@ -369,4 +368,4 @@
Titta på videor på dessa språk
Föregående
Spår
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml
index 4370e760..b2334c5f 100644
--- a/app/src/main/res/values-ta/strings.xml
+++ b/app/src/main/res/values-ta/strings.xml
@@ -1,4 +1,4 @@
-
+
தேடுக
தேடல் %s…
@@ -107,4 +107,4 @@
இடைநிறுத்துவதற்கு இருமுறை தட்டவும்
Chromecast வசன அமைப்புகள்
இருண்ட மேலடுக்குக்குப் பதிலாக ஆப் பிளேயரில் சிஸ்டம் பிரகாசத்தைப் பயன்படுத்தவும்
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-tl/strings.xml b/app/src/main/res/values-tl/strings.xml
index cf3b1263..9e5b29d4 100644
--- a/app/src/main/res/values-tl/strings.xml
+++ b/app/src/main/res/values-tl/strings.xml
@@ -1,12 +1,11 @@
-
-
-
+
+
%s Ep %d
Poster
- @string/result_poster_img_des
+ \@string/result_poster_img_des
Episode Poster
Main Poster
Next Random
@@ -264,4 +263,4 @@
Magdagdag ng Account
Kasaysayan
I-tanda bilang napanood na
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 74754008..807716d8 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%d %s | %s
%s • %s
@@ -24,9 +23,9 @@
Bölüm Posteri
Ana Poster
Sonraki Rastgele
- @string/play_episode
+ \@string/play_episode
Geri git
- @string/home_change_provider_img_des
+ \@string/home_change_provider_img_des
Change Provider
Preview Background
@@ -47,7 +46,7 @@
Veri yok
Daha fazla seçenek
Sonraki bölüm
- @string/synopsis
+ \@string/synopsis
Türler
Paylaş
Tarayıcıda aç
@@ -118,47 +117,47 @@
Hiç muz verilmedi
Otomatik seçilecek dil
İndirilecek diller
- Altyazı dili
- Sıfırlamak için basılı tut
+ Alt yazı dili
+ Varsayılana döndürmek için basılı tut
Fontları içe aktarmak için %s konumuna yerleştirin
İzlemeye devam et
Kaldır
Daha fazla bilgi
- @string/home_play
+ \@string/home_play
Bu sağlayıcının düzgün çalışması için bir VPN gerekebilir
- Bu sağlayıcı torrent kullanıyor, bir VPN önerilir
+ Bu sağlayıcı bir torrent. VPN önerilir
Metadata site tarafından sağlanmamış, veri site\'de bulunmuyorsa video yüklenmesi başarısız olacak.
Açıklama
Konu bulunamadı
Açıklama bulunamadı
- Logcat\'i görüntüle 🐈
- Görüntü içinde görüntü
- İçerik diğer uygulamaların üzerinde küçük bir pencerede oynatılmaya devam eder
+ Logcat\'i göster 🐈
+ Resim-içinde-resim
+ Diğer uygulamaların üzerinde minyatür bir oynatıcıda oynatmaya devam eder
Oynatıcı yeniden boyutlandırma butonu
- Siyah sınır çizgilerini kaldır
- Alt yazılar
+ Siyah sınırları kaldır
+ Alt yazı
Oynatıcı alt yazı ayarları
- Chromecast alt yazıları
+ Chromecast alt yazı
Chromecast alt yazı ayarları
- Eigengrau modu
- Oynatıcıya hız seçeneği ekler
- Atlamak için kaydır
- Zamanı ayarlamak için yanlardan kaydır
+ Eigengravy modu
+ Oynatıcıya bir hız seçeneği ekle
+ Gözlemek için kaydır
+ Zamanı ayarlamak için sağa veya sola kaydır
Ayarları değiştirmek için kaydır
- Sol ve sağ taraftan yukarı kaydırarak ekran parlaklığı ve sesi ayarla
+ Sol ve sağ taraftan kaydırarak parlaklık ve sesi ayarla
Sonraki bölümü otomatik oynat
Mevcut bölüm bittiğinde sonraki bölüme başla
- Çift dokunarak atla
- İki kez dokunarak duraklat
- Atlanacak süre (Saniye)
- İleri ve geri atlamak için sağa ve sola iki kez dokun
- Durdurmak için ekranın ortasına çift dokun
+ Gözlemek için çift tıkla
+ Durdurmak için çift tıkla
+ Oynatıcı gözleme miktarı
+ İleri ve geri atlamak için sağa ve sola çift tıkla
+ Durdurmak için ortaya tıkla
Sistem parlaklığını kullan
- Oynatıcıyı karartmak yerine sistem parlaklığını kullan
+ Oynatıcıda karanlık kaplama yerine sistem parlaklığını kullan
İzleme ilerlemesini güncelle
Mevcut bölüm ilerlemesini otomatik güncelle
- Verileri yedekten geri yükle
- Verileri yedekle
+ Yedekten geri yükle
+ Verileri yedekleyin
Yedek dosyası yüklendi
Geri yükleme başarısız oldu: %s
Başarıyla yedeklendi
@@ -166,21 +165,21 @@
%s yedeklenirken hata
Ara
Hesaplar
- Güncellemeler ve yedekleme
+ Güncellemeler ve yedek
Bilgi
Gelişmiş arama
- Arama sonuçlarını sağlayıcıya göre ayırır
+ Sağlayıcılara göre ayrılmış arama sonuçlarını ver
Yalnızca çökmelerle ilgili verileri gönderir
- Veri göndermez
- Anime için filler bölümleri göster
+ Hiç veri göndermez
+ Anime için filler bölümleri gösterir
Fragmanları göster
Kitsu\'dan posterleri göster
- Seçilen video kalitelerini arama sonuçlarında gösterme
+ Seçilen video kalitelerini arama sonuçlarında gizle
Otomatik eklenti güncellemeleri
Uygulama güncellemelerini göster
- Uygulama başlatıldıktan sonra güncellemeleri otomatik olarak kontrol et.
- Deneysel sürümlere güncelle
- Yalnızca tam sürümler yerine deneysel güncellemeleri de ara
+ Başlangıçta yeni güncellemeleri otomatik olarak ara
+ Ön sürümlere güncelle
+ Sadece tam sürümler yerine ön sürüm güncellemelerini de ara
GitHub
Aynı geliştiriciler tarafından LightNovel uygulaması
Aynı geliştiriciler tarafından anime uygulaması
@@ -192,8 +191,8 @@
Bağlantı bulunamadı
Bağlantı panoya kopyalandı
Bölümü oynat
- Varsayılan değere sıfırla
- Üzgünüz, uygulama çöktü. Geliştiricilere anonim bir hata raporu gönderilecek
+ Varsayılana sıfırla
+ Üzgünüz, uygulama çöktü. Geliştiricilere isimsiz bir hata raporu gönderilecek
Sezon
%s %d%s
Sezon yok
@@ -206,13 +205,13 @@
Bölüm bulunamadı
Dosyayı sil
Sil
- @string/sort_cancel
+ \@string/sort_cancel
Durdur
Sürdür
-30
+30
- %s tamamen silinecek
-\nEmin misiniz\?
+ %s dosyası tamamen silinecek
+\nEmins misiniz\?
%dm
\nkaldı
Devam ediyor
@@ -237,21 +236,21 @@
Torrentler
Belgeseller
OVA
- Asya dizileri
+ Asya dramaları
Canlı yayınlar
- +18
+ NSFW
Diğerleri
Film
Dizi
Çizgi film
- @string/anime
- @string/ova
+ \@string/anime
+ \@string/ova
Torrent
Belgesel
- Asya dizisi
+ Asya draması
Canlı yayın
- +18
+ NSFW
Video
Kaynak hatası
Sunucu hatası
@@ -260,10 +259,10 @@
İndirme hatası, depolama izinlerini kontrol edin
Bölümü Chromecast ile yayınla
Bağlantıyı Chromecast ile yayınla
- Burada oynat
- %s üzerinden oynat
+ Uygulamada oynat
+ %s\'deda oynat
Tarayıcıda oynat
- Bağlantıyı kopyala
+ Linki kopyala
Otomatik indir
Şu kaynaktan indir
Bağlantıları yenile
@@ -282,22 +281,22 @@
Kilitle
Yeniden boyutlandır
Kaynak
- Jeneriği geç
+ OP\'yi geç
Bir daha gösterme
Bu güncellemeyi atla
Güncelle
- Tercih edilen görüntü kalitesi (WiFi)
- Video oynatıcı başlığı karakter üst sınırı
- Oynatıcının çözünürlüğü
+ Tercih edilen izleme kalitesi
+ Oynatıcıdaki maksimum başlık karakter sayısı
+ Oynatıcının üst tarafındaki öğeler
Video arabelleği boyutu
Video arabelleği uzunluğu
- Hafızadaki video önbelleği
+ Diskteki video önbelleği
Video ve resim önbelleğini temizle
- Çok yükseğe ayarlanırsa düşük belleğe sahip cihazlarda çökmelere neden olur (örn. Android TV).
- Çok yükseğe ayarlanırsa düşük depolama alanına sahip sistemlerde sorunlara neden olur (örn. Android TV).
- HTTPS üzerinden DNS (DoH)
- İnternet Servis Sağlayıcısı (İSS) kısıtlamalarını aşmak için kullanışlıdır
- Siteyi kopyala
+ Android TV gibi düşük belleğe sahip cihazlarda çok yükseğe ayarlanırsa çökmelere neden olur.
+ Çok yükseğe ayarlanırsa, Android TV cihazları gibi düşük depolama alanına sahip sistemlerde sorunlara neden olabilir.
+ HTTPS üzerinden DNS
+ ISP bloklarını atlatmak için kullanışlıdır
+ Klon site
Siteyi kaldır
Farklı bir URL ile mevcut bir sitenin klonunu ekleyin
İndirme konumu
@@ -306,16 +305,16 @@
Ekrana sığdır
Uzat
Yakınlaştır
- Yasal Uyarı
+ Disclaimer
legal_notice_key
Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk.
Genel
- Rastgele İçerik
- Ana sayfada rastgele bir film veya dizi seçen bir tuş gösterir
+ Rastgele butonu
+ Ana sayfada rastgele butonunu göster
Sağlayıcı dilleri
Uygulama düzeni
Tercih edilen medya
- Desteklenen sağlayıcılarda +18 içeriği etkinleştir
+ Desteklenen sağlayıcılarda NSFW\'yi etkinleştir
Alt yazı kodlaması
Sağlayıcılar
Düzen
@@ -337,7 +336,7 @@
hello@world.com
127.0.0.1
MyCoolSite
- ornek.com
+ example.com
Dil kodu (tr)
Hiçbiri
Normal
Hepsi
Maksimum
Minimum
- @string/none
+ \@string/none
Dış hat
Çökmüş
Gölge
@@ -377,7 +376,7 @@
Alt yazı senkronu
1000 ms
Alt yazı gecikmesi
- Alt yazılar %d ms erken görüntüleniyorsa bunu kullanın
+ Alt yazılar %d ms erken gözüküyorsa bunu kullanın
Alt yazılar %d ms geç gözüküyorsa bunu kullanın
Alt yazı gecikmesi yok
Pijamalı hasta yağız şoföre çabucak güvendi
Önerilen
- %s eklendi
+ %s yüklendi
Dosyadan yükle
İnternetten yükle
İndirilen dosya
@@ -423,10 +422,10 @@
Geçersiz veri
Geçersiz URL
Hata
- Alt yazılardan seçmeli alt yazıyı (CC) kaldır
+ Alt yazılardan seçmeli alt yazıyı kaldır
Alt yazılardaki şişkinliği kaldır
Tercih edilen medya diline göre filtrele
- Ek içerikler
+ Ekstralar
Fragman
Yayına bağlan
Yönlendiren
@@ -434,7 +433,7 @@
Videoları bu dillerde izle
Geri
Kurulumu atla
- Cihazınıza uygun uygulama görünümünü seçin
+ Cihazınıza uygun görünümü seçin
Çökme raporları
Ne izlemek istiyorsunuz
Bitti
@@ -446,7 +445,7 @@
Eklenti silindi
%s yüklenemedi
+18
- %d %s indirilmeye başlandı…
+ %d %s … indirilmeye başlandı
%d %s indirildi
%s\'nin tamamı zaten indirildi
Toplu indir
@@ -478,7 +477,7 @@
Çökme bilgisini göster
Puan: %s
Açıklama
- Sürüm
+ Versiyon
Durum
Boyut
Geliştiriciler
@@ -500,14 +499,14 @@
Fragmanı oynat
Eklenen depolardan henüz yüklenmemiş tüm eklentileri otomatik olarak yükleyin.
Güncelleme başladı
- Bazı cihazlar yeni paket yükleyiciyi desteklemez.. Güncellemeler yüklenmezse eski seçeneği deneyin.
+ Bazı cihazlar yeni paket yükleyiciyi desteklemez.. Güncellemele yüklenmezse eski seçeneği deneyin.
Eklentileri otomatik olarak indir
APK indirici
- Bağlantılar
+ Linkler
Uygulama güncellemeleri
Yedek
Oynatıcı özellikleri
- Alt yazılar
+ Altyazılar
Düzen
Varsayılanlar
Eklentiler
@@ -532,22 +531,22 @@
İzlenenlerden kaldır
Karışık son
Karışık başlangıç
- Katkıda Bulunanlar
+ Kredi
Giriş
Eklenti İndirildi
- Eylemler
- Açılış/bitiş için atlama açılır pencerelerini göster
+ Aksiyonlar
+ Açma/bitiş için atlama açılır pencerelerini göster
Çok fazla metin. Panoya kaydedilemiyor.
Kütüphane
Tarayıcı
Görünüşe göre kütüphaneniz boş :(
-\nBir kütüphane hesabına giriş yapın veya yerel kütüphanenize içerik ekleyin
+\nBir kütüphane hesabına giriş yapın veya yerel kütüphanenize gösteri ekleyin
Güvenli mod dosyası bulundu!
\nDosya kaldırılana kadar başlangıçta herhangi bir uzantı yüklenmiyor.
Sırala
Sırala
- Güncellenme (Yeniden Eskiye)
- Güncellenme (Eskiden Yeniye)
+ Güncel (Yeniden Eskiye)
+ Güncel (Eskiden Yeniye)
Alfabetik (A\'dan Z’ye)
Alfabetik (Z - A)
Kütüphane Seçin
@@ -555,27 +554,4 @@
Görünüşe göre bu liste boş, başka bir listeye geçmeyi deneyin
Derecelendirme (Yüksekten Düşüğe)
Derecelendirme (Düşükten Yükseğe)
- Yeniden başlat
- Oynatıcı gizlenmişken atlanacak süre
- İSS Kısıtlamaları
- GitHub\'a ulaşılamadı, jsdelivr vekil sunucusu etkinleştiriliyor.
- Başlat
- Başarılı oldu
- raw.githubusercontent.com vekil sunucusu (proxy)
- Tercih edilen görüntü kalitesi (Mobil veri)
- Oynatıcı görünürken atlanacak süre
- Oynatıcı gizli durumdayken atlanacak süre miktarı
- jsdelivr kullanarak GitHub kısıtlamasını aşar. Güncellemeler birkaç gün gecikebilir.
- Android TV
- Yeni bölüm %d yayınlandı!
- Sağlayıcıyı kontrol et
- Başarısız oldu
- Durdur
- Geri al
- Abone olunan gösteriler güncelleniyor
- Abone olunan
- %s kanalına abone olundu
- %s kanalı aboneliğinden çıkıldı
- Günlük
- Oynatıcı görünür durumdayken atlanacak süre miktarı
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index bd062394..82baa6b4 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -1,13 +1,13 @@
-
+
Постер
- Постер до епізоду
+ Постер епізоду
Завантаження скасовано
Змінити постачальника
Назад
Рейтинг: %.1f
Актори: %s
- Епізод %d вийде через
+ Епізод %d буде випущено через
Poster
%s Еп. %d
%dд %dгод %dхв
@@ -15,16 +15,16 @@
%dхв
Головний постер
Наступний випадковий
- Попередній перегляд фону
+ Перегляд фону
Швидкість (%.2fx)
- Знайдено нове оновлення!
+ Нове оновлення знайдено!
\n%s -> %s
Пошук
Завантаження
%d хв
- Налаштування
+ Параметри
Пошук…
- Пошук на %s…
+ Пошук %s…
Дані відсутні
Більше опцій
Наступний епізод
@@ -37,7 +37,7 @@
Покинуто
Переглянути фільм
Переглянути трейлер
- Трансляція через торрент
+ Переглянути торрент
Повторити підключення…
Назад
Переглянути епізод
@@ -87,13 +87,13 @@
Налаштування субтитрів Chromecast
Режим Eigengravy
Проведіть пальцем, щоб змінити налаштування
- Проведіть пальцем вгору або вниз ліворуч або праворуч, щоб змінити яскравість або гучність
+ Проведіть пальцем ліворуч або праворуч, щоб змінити яскравість або гучність
Відтворення наступного епізоду після закінчення поточного
Головна
CloudStream
Філер
Програти в CloudStream
- Трансляція
+ Потік
Переглядаю
Поділитися
Відкладено
@@ -121,10 +121,10 @@
Колір тексту
Колір контуру
Автовідтворення наступного епізоду
- Проведіть пальцем з боку в бік, щоб керувати своїм положенням у відео
+ Проведіть пальцем ліворуч або праворуч, щоб керувати часом у відеоплеєрі
%d Бананів для розробників
Кнопка зміни розміру плеєра
- @string/home_play
+ \@string/home_play
Для коректної роботи цього постачальника може знадобитися VPN
Метадані не надаються сайтом, завантаження відео не відбудеться, якщо їх немає на сайті.
Картинка в картинці
@@ -133,8 +133,8 @@
Проведіть пальцем, щоб перемотати
Двічі торкніться, щоб перемотати
Двічі торкніться для паузи
- Крок перемотки (Секунди)
- Натисніть двічі посередині, щоб призупинити
+ Крок перемотки
+ Натисніть посередині, щоб поставити на паузу
Використовувати яскравість системи
Оновити прогрес перегляду
Відновлення даних з резервної копії
@@ -217,7 +217,7 @@
Пропустити OP
Не показувати знову
Оновити
- Бажана якість перегляду (WiFi)
+ Бажана якість перегляду
Заголовок
Перемикання елементів інтерфейсу на плакаті
Оновлення не знайдено
@@ -230,7 +230,7 @@
Показати постери від Kitsu
Автоматичне оновлення плагінів
Автоматично встановлювати всі ще не встановлені плагіни з доданих репозиторіїв.
- Автоматично шукати нові оновлення після запуску застосунку.
+ Автоматичний пошук нових оновлень при запуску
Оновлення до бета-версій
Посилання скопійовано в буфер обміну
Деякі телефони не підтримують новий інсталятор пакетів. Спробуйте стару версію, якщо оновлення не встановлюються.
@@ -255,7 +255,7 @@
Документальні фільми
NSFW
Фільм
- OVA
+ \@string/ova
Торрент
Мітка якості
NSFW
@@ -283,7 +283,7 @@
Особливості
Загальне
Випадкова кнопка
- Показує кнопку на Головній сторінці, яка може вибрати випадковий фільм або серіал на Головній сторінці
+ Показати випадкову кнопку на Головній сторінці
Мови постачальника
Макет програми
Бажані медіа
@@ -506,27 +506,4 @@
Схоже, цей список порожній, спробуйте перейти до іншого
Файл безпечного режиму знайдено!
\nРозширеня не завантажуються під час запуску, доки файл не буде видалено.
- Android TV
- Плеєр сховано - обсяг пошуку
- Плеєр показано - обсяг пошуку
- Обсяг пошуку, який використовується, коли плеєр видимий
- Обсяг пошуку, який використовується, коли гравець прихований
- Не вдалося
- Пройдено
- Перезапуск
- Журнал
- Старт
- Стоп
- Тест постачальника
- Оновлення підписаних шоу
- Підписано
- Підписано на %s
- Відписатися від %s
- Епізод %d випущено!
- Повернути
- raw.githubusercontent.com Proxy
- Не вдалося зв\'язатися з GitHub, увімкнувши проксі-сервер jsdelivr.
- Обходи ISP
- За допомогою jsdelivr можна обійти блокування GitHub. Можлива затримка оновлень на кілька днів.
- Бажана якість перегляду (Мобільні дані)
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml
index c19c6472..f733addc 100644
--- a/app/src/main/res/values-ur/strings.xml
+++ b/app/src/main/res/values-ur/strings.xml
@@ -1,4 +1,4 @@
-
+
کاسٹ: %s
قسط %d جاری کیا جائے گا
@@ -230,7 +230,7 @@
سلسلہ
کارٹون
انیمی
- اووا
+ \@string/اووا
ٹورینٹ
دستاویزی فلم
ایشیائی ڈرامے
@@ -356,4 +356,4 @@
%d / 10
اٹھایا
اگر سب ٹائٹلز %d ms بہت جلد دکھائے جائیں تو اسے استعمال کریں
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index 520cfaa4..db647b5d 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%s Tập %d
@@ -11,7 +10,7 @@
%dm
Poster
- Ảnh bìa
+ \@string/result_poster_img_des
Episode Poster
Main Poster
Next Random
@@ -111,7 +110,7 @@
Tiếp tục xem
Loại bỏ
Thông tin thêm
- @string/home_play
+ \@string/home_play
Bạn có thể sẽ cần sử dụng VPN để xem phim này
Phim này được chiếu dưới dạng Torrent. Hãy sử dụng VPN để xem
Thông tin phim
@@ -230,7 +229,7 @@
Phim Bộ
Hoạt Hình
Anime
- @string/ova
+ \@string/ova
Torrent
Phim Tài Liệu
Truyền Hình Châu Á
@@ -261,18 +260,18 @@
Kiểm tra cập nhật
Khóa
Thu Phóng
- Nguồn
- Bỏ qua OP
+ Tuỳ chọn
+ Tua nhanh
Không hiện lại
- Bỏ qua bản cập nhật này
+ Bỏ qua
Cập nhật
- Chất lượng xem ưu tiên (WiFi)
+ Tự động chọn chất lượng phim
Kí tự tối đa trên tiêu đề
- Độ phân giải trình phát video
- Kích thước bộ nhớ đệm video
+ Định dạng trình phát
+ Dung lượng video cache
Thời lượng bộ nhớ đệm
- Lưu bộ nhớ đệm video trên ổ cứng
- Xoá bộ nhớ đệm hình ảnh và video
+ Dung lượng video cache
+ Xoá hình ảnh và video
Sẽ gây lỗi nếu đặt quá cao trên máy có dung lượng ram thấp như Android TV.
Sẽ gây lỗi nếu đặt quá cao trên máy có dung lượng lưu trữ thấp như Android TV.
DNS over HTTPS
@@ -520,9 +519,4 @@
Có vẻ như danh sách này trống, hãy thử chuyển sang danh sách khác
Chữ cái (A đến Z)
Chọn Thư viện
- Nhật ký
- Chất lượng xem ưu tiên (Dữ liệu di động)
- Thất bại
- Thành công
- Bắt đầu
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 3364ea86..a8341d46 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%d %s | %s
%s • %s
@@ -20,13 +19,13 @@
%dm
封面
- 封面
+ \@string/result_poster_img_des
劇集封面
主封面
隨機下一個
- @string/play_episode
+ \@string/play_episode
返回
- @string/home_change_provider_img_des
+ \@string/home_change_provider_img_des
更改片源
預覽背景
@@ -47,7 +46,7 @@
無資料
更多選項
下一集
- @string/synopsis
+ \@string/synopsis
類型
分享
在瀏覽器中打開
@@ -124,7 +123,7 @@
繼續觀看
移除
更多資訊
- @string/home_play
+ \@string/home_play
此片源可能需要 VPN 才能正常使用
此片源是種子,建議使用 VPN
站點不提供元數據,如果站點上不存在元數據,影片載入將失敗。
@@ -206,7 +205,7 @@
未找到劇集
刪除文件
刪除
- @string/sort_cancel
+ \@string/sort_cancel
暫停
繼續
-30
@@ -245,8 +244,8 @@
電影
電視劇
卡通
- @string/anime
- @string/ova
+ \@string/anime
+ \@string/ova
種子
紀錄片
亞洲劇
@@ -369,7 +368,7 @@
全部
最大
最小
- @string/none
+ \@string/none
輪廓
凹陷
陰影
@@ -534,5 +533,4 @@
預設
外觀
功能
- 瀏覽器
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 44b93430..c57e3ca1 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -1,6 +1,5 @@
-
-
-
+
+
%d %s | %s
%s • %s
@@ -24,9 +23,9 @@
剧集封面
主封面
随机下一个
- @string/play_episode
+ \@string/play_episode
返回
- @string/home_change_provider_img_des
+ \@string/home_change_provider_img_des
更改片源
预览背景
@@ -47,7 +46,7 @@
无数据
更多选项
下一集
- @string/synopsis
+ \@string/synopsis
类型
分享
在浏览器中打开
@@ -124,7 +123,7 @@
继续观看
移除
更多信息
- @string/home_play
+ \@string/home_play
此片源可能需要 VPN 才能正常使用
此片源为种子文件,建议使用 VPN
站点不提供元数据,如果站点上不存在元数据,视频加载将失败。
@@ -143,14 +142,14 @@
倍速模式
在播放器中添加播放速度选项
滑动控制进度
- 左右滑动以控制视频中的位置
+ 左右滑动控制播放进度
滑动更改设置
上下滑动修改亮度或音量
自动播放下一集
播放完毕后播放下一集
双击控制进度
双击暂停
- 双击控制进度时间 (秒)
+ 双击控制进度时间
在左右侧双击快进或快退
双击中间暂停
使用系统亮度
@@ -179,7 +178,7 @@
自动更新插件
自动下载插件
显示应用更新
- 启动应用后自动搜索更新。
+ 启动时自动搜索更新
更新至预览版
搜索预览版更新替代仅搜索完整版本
Github
@@ -207,7 +206,7 @@
未找到剧集
删除文件
删除
- @string/sort_cancel
+ \@string/sort_cancel
暂停
继续
-30
@@ -246,8 +245,8 @@
电影
电视剧
卡通
- 动漫
- OVA
+ \@string/anime
+ \@string/ova
种子
纪录片
亚洲剧
@@ -287,7 +286,7 @@
不再显示
跳过此更新
更新
- 首选播放画质(WiFi)
+ 首选播放画质
视频播放器标题最多字符
视频播放器标题
视频缓冲大小
@@ -312,7 +311,7 @@
Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk.
通用
随机按钮
- 在主页上显示按钮,可以从主页上随机选择电影或电视剧
+ 在主页中显示随机按钮
片源语言
应用布局
首选类型
@@ -370,7 +369,7 @@
全部
最大
最小
- @string/none
+ \@string/none
轮廓
凹陷
阴影
@@ -555,27 +554,4 @@
看来您的库是空的 :(
\n登录库账户或添加节目到您的本地库
看来此列表是空的,请尝试切换到另一个
- 播放器显示 - 快进快退秒数
- 播放器可见时使用的快进快退秒数
- 播放器隐藏 - 快进快退秒数
- 播放器隐藏时使用的快进快退秒数
- Android TV
- 失败
- 片源测试
- 重启
- 停止
- 正在更新订阅节目
- 已订阅
- 已订阅 %s
- 已取消订阅 %s
- 开始
- 第 %d 集已发布!
- 成功
- 日志
- raw.githubusercontent.com 代理
- 连接 Github 失败,正在启用 jsdelivr 代理。
- 使用 jsdelivr,可以绕过 GitHub 的封锁。可能会延迟几天的更新。
- ISP 绕过
- 还原
- 首选播放画质(移动数据)
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 95094311..fc718008 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -1,7 +1,7 @@
-
+
@@ -13,10 +13,6 @@
- ?attr/colorPrimary
-
-
-
-
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 7dd4c989..61ff0c2b 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -82,7 +82,4 @@
#515151
#FFFFFF
#622C00
-
- #48E484
- #ea596e
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 911c0d07..778f34c9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -13,10 +13,8 @@
fast_forward_button_time
benene_count
subtitle_settings_key
- test_providers_key
subtitle_settings_chromecast_key
quality_pref_key
- quality_pref_mobile_data_key
player_pref_key
prefer_limit_title_key
prefer_limit_title_rez_key
@@ -44,7 +42,6 @@
random_button_key
provider_lang_key
dns_key
- jsdelivr_proxy_key
download_path_key
Cloudstream
app_layout_key
@@ -198,7 +195,6 @@
No Plot Found
No Description Found
Show Logcat 🐈
- Log
Picture-in-picture
Continues playback in a miniature player on top of other apps
Player resize button
@@ -210,17 +206,17 @@
Eigengravy Mode
Adds a speed option in the player
Swipe to seek
- Swipe from side to side to control your position in a video
+ Swipe left or right to control time in the videoplayer
Swipe to change settings
- Slide up or down on the left or right side to change brightness or volume
+ Swipe on the left or right side to change brightness or volume
Autoplay next episode
Start the next episode when the current one ends
Double tap to seek
Double tap to pause
- Player seek amount (Seconds)
+ Player seek amount
Tap twice on the right or left side to seek forwards or backwards
- Tap twice in the middle to pause
+ Tap in the middle to pause
Use system brightness
Use system brightness in the app player instead of a dark
overlay
@@ -251,7 +247,7 @@
Automatically download plugins
Automatically install all not yet installed plugins from added repositories.
Show app updates
- Automatically search for new updates after starting the app.
+ Automatically search for new updates on start
Redo setup process
Update to prereleases
Search for prerelease updates instead of full releases only
@@ -286,9 +282,6 @@
Delete
@string/sort_cancel
Pause
- Start
- Failed
- Passed
Resume
-30
+30
@@ -324,8 +317,8 @@
Movie
Series
Cartoon
- Anime
- OVA
+ @string/anime
+ @string/ova
Torrent
Documentary
Asian Drama
@@ -365,8 +358,7 @@
Don\'t show again
Skip this Update
Update
- Preferred watch quality (WiFi)
- Preferred watch quality (Mobile Data)
+ Preferred watch quality
Video player title max chars
Video player resolution
Video buffer size
@@ -381,9 +373,6 @@
Causes problems if set too high on devices with low storage space, such as Android TV.
DNS over HTTPS
Useful for bypassing ISP blocks
- raw.githubusercontent.com Proxy
- Failed to reach GitHub, enabling jsdelivr proxy.
- Using jsdelivr, GitHub blocking can be bypassed. May delay updates by a few days.
Clone site
Remove site
Add a clone of an existing site, with a different URL
@@ -411,7 +400,6 @@
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
CloudStream 3 at your own risk.
- ISP Bypasses
Links
App updates
Backup
@@ -428,14 +416,13 @@
Features
General
Random Button
- Shows button on Homepage which can choose a random movie or TV series from the Homepage
+ Show random button on Homepage
Provider languages
App Layout
Preferred media
Enable NSFW on supported providers
Subtitle encoding
Providers
- Provider test
Layout
Auto
TV layout
@@ -592,8 +579,6 @@
Audio tracks
Video tracks
Apply on Restart
- Restart
- Stop
Safe mode on
All extensions were turned off due to a crash to help you find the one causing trouble.
View crash info
@@ -651,10 +636,4 @@
Looks like your library is empty :(\nLogin to a library account or add shows to your local library
Looks like this list is empty, try switching to another one
Safe mode file found!\nNot loading any extensions on startup until file is removed.
- Revert
- Updating subscribed shows
- Subscribed
- Subscribed to %s
- Unsubscribed from %s
- Episode %d released!
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index b9648162..78c62c69 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -40,6 +40,7 @@
- ?attr/textColor
- ?attr/grayTextColor
+ - ?attr/grayTextColor
- ?attr/grayTextColor
- ?attr/textColor
diff --git a/app/src/main/res/xml/settings_player.xml b/app/src/main/res/xml/settings_player.xml
index 2d2905ea..0e5bd84f 100644
--- a/app/src/main/res/xml/settings_player.xml
+++ b/app/src/main/res/xml/settings_player.xml
@@ -15,10 +15,6 @@
android:icon="@drawable/ic_baseline_hd_24"
android:key="@string/quality_pref_key"
android:title="@string/watch_quality_pref" />
-
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ android:icon="@drawable/ic_baseline_language_24"
+ android:key="@string/provider_lang_key"
+ android:title="@string/provider_lang_settings" />
+ android:key="@string/prefer_media_type_key"
+ android:title="@string/preferred_media_settings"
+ android:icon="@drawable/ic_baseline_play_arrow_24" />
+ android:key="@string/display_sub_key"
+ android:title="@string/display_subbed_dubbed_settings"
+ android:icon="@drawable/ic_outline_voice_over_off_24" />
-
-
-
+ android:key="@string/enable_nsfw_on_providers_key"
+ android:title="@string/enable_nsfw_on_providers"
+ android:icon="@drawable/ic_baseline_extension_24"
+ android:summary="@string/apply_on_restart"
+ app:defaultValue="false"/>
\ No newline at end of file
diff --git a/app/src/main/res/xml/settins_general.xml b/app/src/main/res/xml/settins_general.xml
index c4900bca..726f3fd0 100644
--- a/app/src/main/res/xml/settins_general.xml
+++ b/app/src/main/res/xml/settins_general.xml
@@ -6,6 +6,18 @@
android:title="@string/app_language"
android:icon="@drawable/ic_baseline_language_24" />
+
+
+
+
-
-
-
-
-
-
-
-
-
-