diff --git a/README.md b/README.md index e3d033ba..8949304e 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,9 @@ + **AdFree**, No ads whatsoever + No tracking/analytics + Bookmarks -+ Download and stream movies, tv-shows and anime ++ Phone and TV support + Chromecast ++ Extension system for personal customization ### Supported languages: diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 27bd1e48..6fd4ae21 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,7 +18,7 @@ fun String.execute() = ByteArrayOutputStream().use { baot -> workingDir = projectDir commandLine = this@execute.split(Regex("\\s")) standardOutput = baot - }.exitValue == 0) + }.exitValue == 0) String(baot.toByteArray()).trim() else null } @@ -78,12 +78,18 @@ android { isDebuggable = false isMinifyEnabled = false isShrinkResources = false - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) } debug { isDebuggable = true applicationIdSuffix = ".debug" - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) } } flavorDimensions.add("state") @@ -160,10 +166,16 @@ dependencies { // implementation("androidx.leanback:leanback-paging:1.1.0-alpha09") // Exoplayer - implementation("com.google.android.exoplayer:exoplayer:2.18.2") - 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") + implementation("androidx.media3:media3-common:1.1.0") + implementation("androidx.media3:media3-exoplayer:1.1.0") + implementation("androidx.media3:media3-datasource-okhttp:1.1.0") + implementation("androidx.media3:media3-ui:1.1.0") + implementation("androidx.media3:media3-session:1.1.0") + implementation("androidx.media3:media3-cast:1.1.0") + implementation("androidx.media3:media3-exoplayer-hls:1.1.0") + implementation("androidx.media3:media3-exoplayer-dash:1.1.0") + + // 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") diff --git a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt index 9c7c319e..3cfde983 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt @@ -372,7 +372,11 @@ object CommonActivity { } // if cant focus but visible then break and let android decide - if (!next.isFocusable && next.isShown) return null + // the exception if is the view is a parent and has children that wants focus + val hasChildrenThatWantsFocus = (next as? ViewGroup)?.let { parent -> + parent.descendantFocusability == ViewGroup.FOCUS_AFTER_DESCENDANTS && parent.childCount > 0 + } ?: false + if (!next.isFocusable && next.isShown && !hasChildrenThatWantsFocus) return null // if not shown then continue because we will "skip" over views to get to a replacement if (!next.isShown) return getNextFocus(act, next, direction, depth + 1) diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index 73b3e6f5..b1f60ad7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -1,6 +1,5 @@ package com.lagradost.cloudstream3 -import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.content.ComponentName import android.content.Context @@ -12,7 +11,12 @@ import android.os.Build import android.os.Bundle import android.util.AttributeSet import android.util.Log -import android.view.* +import android.view.KeyEvent +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.annotation.IdRes @@ -20,8 +24,7 @@ import androidx.annotation.MainThread import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.animation.addListener -import androidx.core.view.ViewCompat +import androidx.core.view.children import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.fragment.app.FragmentActivity @@ -34,10 +37,14 @@ import androidx.navigation.NavOptions import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.setupWithNavController import androidx.preference.PreferenceManager +import androidx.recyclerview.widget.RecyclerView import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.google.android.gms.cast.framework.* +import com.google.android.gms.cast.framework.CastContext +import com.google.android.gms.cast.framework.Session +import com.google.android.gms.cast.framework.SessionManager +import com.google.android.gms.cast.framework.SessionManagerListener import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.navigationrail.NavigationRailView @@ -59,7 +66,11 @@ import com.lagradost.cloudstream3.CommonActivity.updateLocale import com.lagradost.cloudstream3.databinding.ActivityMainBinding import com.lagradost.cloudstream3.databinding.ActivityMainTvBinding import com.lagradost.cloudstream3.databinding.BottomResultviewPreviewBinding -import com.lagradost.cloudstream3.mvvm.* +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.mvvm.debugAssert +import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.mvvm.normalSafeApiCall +import com.lagradost.cloudstream3.mvvm.observeNullable import com.lagradost.cloudstream3.network.initClient import com.lagradost.cloudstream3.plugins.PluginManager import com.lagradost.cloudstream3.plugins.PluginManager.loadAllOnlinePlugins @@ -94,7 +105,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateT import com.lagradost.cloudstream3.ui.settings.SettingsGeneral import com.lagradost.cloudstream3.ui.setup.HAS_DONE_SETUP_KEY import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions -import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.ApkInstaller import com.lagradost.cloudstream3.utils.AppUtils.html import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable import com.lagradost.cloudstream3.utils.AppUtils.isLtr @@ -111,6 +122,8 @@ 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 +import com.lagradost.cloudstream3.utils.Event +import com.lagradost.cloudstream3.utils.IOnBackPressed import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState @@ -122,6 +135,8 @@ import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard import com.lagradost.cloudstream3.utils.UIHelper.navigate import com.lagradost.cloudstream3.utils.UIHelper.requestRW import com.lagradost.cloudstream3.utils.UIHelper.toPx +import com.lagradost.cloudstream3.utils.USER_PROVIDER_API +import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.ResponseParser import kotlinx.coroutines.sync.Mutex @@ -765,7 +780,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { return ret } - private var binding: ActivityMainBinding? = null + var binding: ActivityMainBinding? = null object TvFocus { data class FocusTarget( @@ -793,10 +808,18 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { var focusOutline: WeakReference = WeakReference(null) var lastFocus: WeakReference = WeakReference(null) private val layoutListener: View.OnLayoutChangeListener = - View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ -> - updateFocusView( - v, same = true - ) + View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> + // shitty fix for layouts + lastFocus.get()?.apply { + updateFocusView( + this, same = true + ) + postDelayed({ + updateFocusView( + lastFocus.get(), same = false + ) + }, 300) + } } private val attachListener: View.OnAttachStateChangeListener = object : View.OnAttachStateChangeListener { @@ -828,9 +851,12 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { @MainThread fun updateFocusView(newFocus: View?, same: Boolean = false) { val focusOutline = focusOutline.get() ?: return - lastFocus.get()?.apply { - removeOnLayoutChangeListener(layoutListener) - removeOnAttachStateChangeListener(attachListener) + val lastView = lastFocus.get() + val exactlyTheSame = lastView == newFocus && newFocus != null + if (!exactlyTheSame) { + lastView?.removeOnLayoutChangeListener(layoutListener) + lastView?.removeOnAttachStateChangeListener(attachListener) + (lastView?.parent as? RecyclerView)?.removeOnLayoutChangeListener(layoutListener) } val wasGone = focusOutline.isGone @@ -842,6 +868,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { if (newFocus != null) { lastFocus = WeakReference(newFocus) + val out = IntArray(2) newFocus.getLocationInWindow(out) val (screenX, screenY) = out @@ -856,10 +883,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { if (screenX == 0 && screenY == 0) { focusOutline.isVisible = false } - - newFocus.addOnLayoutChangeListener(layoutListener) - newFocus.addOnAttachStateChangeListener(attachListener) - + if (!exactlyTheSame) { + (newFocus.parent as? RecyclerView)?.addOnLayoutChangeListener(layoutListener) + newFocus.addOnLayoutChangeListener(layoutListener) + newFocus.addOnAttachStateChangeListener(attachListener) + } val start = FocusTarget( x = currentX, y = currentY, @@ -1213,6 +1241,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { navController.addOnDestinationChangedListener { _: NavController, navDestination: NavDestination, bundle: Bundle? -> // Intercept search and add a query + updateNavBar(navDestination) if (navDestination.matchDestination(R.id.navigation_search) && !nextSearchQuery.isNullOrBlank()) { bundle?.apply { this.putString(SearchFragment.SEARCH_QUERY, nextSearchQuery) @@ -1231,29 +1260,47 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { .setPopExitAnim(R.anim.nav_pop_exit) .setPopUpTo(navController.graph.startDestination, false) .build()*/ - binding?.navView?.setupWithNavController(navController) - val navRail = findViewById(R.id.nav_rail_view) - navRail?.setupWithNavController(navController) - if (isTvSettings()) { - navRail?.background?.alpha = 200 - } else { - navRail?.background?.alpha = 255 + val rippleColor = ColorStateList.valueOf(getResourceColor(R.attr.colorPrimary, 0.1f)) + + binding?.navView?.apply { + itemRippleColor = rippleColor + itemActiveIndicatorColor = rippleColor + setupWithNavController(navController) + setOnItemSelectedListener { item -> + onNavDestinationSelected( + item, + navController + ) + } } - navRail?.setOnItemSelectedListener { item -> - onNavDestinationSelected( - item, - navController - ) - } - binding?.navView?.setOnItemSelectedListener { item -> - onNavDestinationSelected( - item, - navController - ) - } - navController.addOnDestinationChangedListener { _, destination, _ -> - updateNavBar(destination) + + binding?.navRailView?.apply { + itemRippleColor = rippleColor + itemActiveIndicatorColor = rippleColor + setupWithNavController(navController) + if (isTvSettings()) { + background?.alpha = 200 + } else { + background?.alpha = 255 + } + + setOnItemSelectedListener { item -> + onNavDestinationSelected( + item, + navController + ) + } + + fun noFocus(view: View) { + view.tag = view.context.getString(R.string.tv_no_focus_tag) + (view as? ViewGroup)?.let { + for (child in it.children) { + noFocus(child) + } + } + } + noFocus(this) } loadCache() @@ -1276,11 +1323,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { true }*/ - val rippleColor = ColorStateList.valueOf(getResourceColor(R.attr.colorPrimary, 0.1f)) - binding?.navView?.itemRippleColor = rippleColor - navRail?.itemRippleColor = rippleColor - navRail?.itemActiveIndicatorColor = rippleColor - binding?.navView?.itemActiveIndicatorColor = rippleColor if (!checkWrite()) { requestRW() diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt index fd2412da..84964950 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt @@ -14,11 +14,12 @@ import androidx.viewbinding.ViewBinding import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipDrawable -import com.google.android.material.navigationrail.NavigationRailView import com.lagradost.cloudstream3.APIHolder.getId import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity +import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.HomePageList import com.lagradost.cloudstream3.LoadResponse +import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.databinding.FragmentHomeHeadBinding @@ -467,24 +468,18 @@ class HomeParentItemAdapterPreview( } homePreviewHiddenNextFocus.setOnFocusChangeListener { _, hasFocus -> - if (hasFocus) { - previewViewpager.setCurrentItem(previewViewpager.currentItem + 1, true) - homePreviewInfoBtt.requestFocus() - } + if (!hasFocus) return@setOnFocusChangeListener + previewViewpager.setCurrentItem(previewViewpager.currentItem + 1, true) + homePreviewInfoBtt.requestFocus() } homePreviewHiddenPrevFocus.setOnFocusChangeListener { _, hasFocus -> - if (hasFocus) { - previewViewpager.apply { - if (currentItem <= 0) { - findViewById(R.id.nav_rail_view)?.menu?.getItem( - 0 - )?.actionView?.requestFocus() - } else { - setCurrentItem(currentItem - 1, true) - binding.homePreviewPlayBtt.requestFocus() - } - } + if (!hasFocus) return@setOnFocusChangeListener + if (previewViewpager.currentItem <= 0) { + (activity as? MainActivity)?.binding?.navRailView?.requestFocus() + } else { + previewViewpager.setCurrentItem(previewViewpager.currentItem - 1, true) + binding.homePreviewPlayBtt.requestFocus() } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt index a00127fd..e6f93377 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt @@ -7,7 +7,6 @@ import android.graphics.drawable.AnimatedVectorDrawable import android.media.metrics.PlaybackErrorEvent import android.os.Build import android.os.Bundle -import android.support.v4.media.session.MediaSessionCompat import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -20,15 +19,14 @@ import androidx.annotation.LayoutRes import androidx.annotation.StringRes import androidx.core.view.isVisible import androidx.fragment.app.Fragment -import androidx.media.session.MediaButtonReceiver import androidx.preference.PreferenceManager import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat -import com.google.android.exoplayer2.ExoPlayer -import com.google.android.exoplayer2.PlaybackException -import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector -import com.google.android.exoplayer2.ui.AspectRatioFrameLayout -import com.google.android.exoplayer2.ui.PlayerView -import com.google.android.exoplayer2.ui.SubtitleView +import androidx.media3.common.PlaybackException +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.session.MediaSession +import androidx.media3.ui.AspectRatioFrameLayout +import androidx.media3.ui.PlayerView +import androidx.media3.ui.SubtitleView import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.canEnterPipMode @@ -38,6 +36,7 @@ import com.lagradost.cloudstream3.CommonActivity.playerEventListener import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment import com.lagradost.cloudstream3.utils.AppUtils @@ -179,15 +178,16 @@ abstract class AbstractPlayerFragment( } canEnterPipMode = isPlayingRightNow && hasPipModeSupport - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isInPIPMode) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { activity?.let { act -> - PlayerPipHelper.updatePIPModeActions(act, isPlayingRightNow) + PlayerPipHelper.updatePIPModeActions(act, isPlayingRightNow, player.getAspectRatio()) } } } private var pipReceiver: BroadcastReceiver? = null override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) { + super.onPictureInPictureModeChanged(isInPictureInPictureMode) try { isInPIPMode = isInPictureInPictureMode if (isInPictureInPictureMode) { @@ -210,9 +210,7 @@ abstract class AbstractPlayerFragment( } } val filter = IntentFilter() - filter.addAction( - ACTION_MEDIA_CONTROL - ) + filter.addAction(ACTION_MEDIA_CONTROL) activity?.registerReceiver(pipReceiver, filter) val isPlaying = player.getIsPlaying() val isPlayingValue = @@ -223,7 +221,10 @@ abstract class AbstractPlayerFragment( piphide?.isVisible = true exitedPipMode() pipReceiver?.let { - activity?.unregisterReceiver(it) + // Prevents java.lang.IllegalArgumentException: Receiver not registered + normalSafeApiCall { + activity?.unregisterReceiver(it) + } } activity?.hideSystemUI() this.view?.let { UIHelper.hideKeyboard(it) } @@ -276,18 +277,21 @@ abstract class AbstractPlayerFragment( gotoNext = true ) } + PlaybackException.ERROR_CODE_REMOTE_ERROR, PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS, PlaybackException.ERROR_CODE_TIMEOUT, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE -> { showToast( "${ctx.getString(R.string.remote_error)}\n$errorName ($code)\n$msg", gotoNext = true ) } + PlaybackException.ERROR_CODE_DECODING_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_INIT_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_OTHER, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED, PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED -> { showToast( "${ctx.getString(R.string.render_error)}\n$errorName ($code)\n$msg", gotoNext = true ) } + else -> { showToast( "${ctx.getString(R.string.unexpected_error)}\n$errorName ($code)\n$msg", @@ -296,12 +300,14 @@ abstract class AbstractPlayerFragment( } } } + is InvalidFileException -> { showToast( "${ctx.getString(R.string.source_error)}\n${exception.message}", gotoNext = true ) } + else -> { exception.message?.let { showToast( @@ -322,15 +328,8 @@ abstract class AbstractPlayerFragment( private fun playerUpdated(player: Any?) { if (player is ExoPlayer) { context?.let { ctx -> - val mediaButtonReceiver = ComponentName(ctx, MediaButtonReceiver::class.java) - MediaSessionCompat(ctx, "Player", mediaButtonReceiver, null).let { media -> - //media.setCallback(mMediaSessionCallback) - //media.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS) - val mediaSessionConnector = MediaSessionConnector(media) - mediaSessionConnector.setPlayer(player) - media.isActive = true - mMediaSessionCompat = media - } + mMediaSession?.release() + mMediaSession = MediaSession.Builder(ctx, player).build() } // Necessary for multiple combined videos @@ -340,8 +339,7 @@ abstract class AbstractPlayerFragment( } } - private var mediaSessionConnector: MediaSessionConnector? = null - private var mMediaSessionCompat: MediaSessionCompat? = null + private var mMediaSession: MediaSession? = null // this can be used in the future for players other than exoplayer //private val mMediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() { @@ -442,6 +440,7 @@ abstract class AbstractPlayerFragment( playerEventListener = null keyEventListener = null canEnterPipMode = false + mMediaSession?.release() SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged keepScreenOn(false) 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 f491f995..70e12a47 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 @@ -5,30 +5,42 @@ import android.net.Uri import android.os.Handler import android.os.Looper import android.util.Log +import android.util.Rational import android.widget.FrameLayout +import androidx.media3.common.C 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 -import com.google.android.exoplayer2.trackselection.TrackSelectionOverride -import com.google.android.exoplayer2.trackselection.TrackSelector -import com.google.android.exoplayer2.ui.SubtitleView -import com.google.android.exoplayer2.upstream.DataSource -import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory -import com.google.android.exoplayer2.upstream.DefaultHttpDataSource -import com.google.android.exoplayer2.upstream.HttpDataSource -import com.google.android.exoplayer2.upstream.cache.CacheDataSource -import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor -import com.google.android.exoplayer2.upstream.cache.SimpleCache -import com.google.android.exoplayer2.util.MimeTypes -import com.google.android.exoplayer2.video.VideoSize +import androidx.media3.common.C.* +import androidx.media3.common.Format +import androidx.media3.common.MediaItem +import androidx.media3.common.TrackSelectionOverride +import androidx.media3.common.MimeTypes +import androidx.media3.common.PlaybackException +import androidx.media3.common.Player +import androidx.media3.common.TrackGroup +import androidx.media3.common.Tracks +import androidx.media3.common.VideoSize +import androidx.media3.database.StandaloneDatabaseProvider +import androidx.media3.datasource.DataSource +import androidx.media3.datasource.DefaultDataSourceFactory +import androidx.media3.datasource.DefaultHttpDataSource +import androidx.media3.datasource.HttpDataSource +import androidx.media3.datasource.cache.CacheDataSource +import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor +import androidx.media3.datasource.cache.SimpleCache +import androidx.media3.datasource.okhttp.OkHttpDataSource +import androidx.media3.exoplayer.DefaultLoadControl +import androidx.media3.exoplayer.DefaultRenderersFactory +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.exoplayer.SeekParameters +import androidx.media3.exoplayer.source.ClippingMediaSource +import androidx.media3.exoplayer.source.ConcatenatingMediaSource +import androidx.media3.exoplayer.source.DefaultMediaSourceFactory +import androidx.media3.exoplayer.source.MergingMediaSource +import androidx.media3.exoplayer.source.SingleSampleMediaSource +import androidx.media3.exoplayer.text.TextRenderer +import androidx.media3.exoplayer.trackselection.DefaultTrackSelector +import androidx.media3.exoplayer.trackselection.TrackSelector +import androidx.media3.ui.SubtitleView import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey @@ -44,7 +56,6 @@ 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 @@ -451,6 +462,12 @@ class CS3IPlayer : IPlayer { } } + override fun getAspectRatio(): Rational? { + return exoPlayer?.videoFormat?.let { format -> + Rational(format.width, format.height) + } + } + override fun updateSubtitleStyle(style: SaveCaptionStyle) { subtitleHelper.setSubStyle(style) } 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..b830d4e0 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 @@ -3,19 +3,23 @@ package com.lagradost.cloudstream3.ui.player 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.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 androidx.media3.common.Format +import androidx.media3.common.MimeTypes +import androidx.media3.exoplayer.text.ExoplayerCuesDecoder +import androidx.media3.exoplayer.text.SubtitleDecoderFactory +import androidx.media3.extractor.text.SubtitleDecoder +import androidx.media3.extractor.text.SubtitleInputBuffer +import androidx.media3.extractor.text.SubtitleOutputBuffer +import androidx.media3.extractor.text.cea.Cea608Decoder +import androidx.media3.extractor.text.cea.Cea708Decoder +import androidx.media3.extractor.text.dvb.DvbDecoder +import androidx.media3.extractor.text.pgs.PgsDecoder +import androidx.media3.extractor.text.ssa.SsaDecoder +import androidx.media3.extractor.text.subrip.SubripDecoder +import androidx.media3.extractor.text.ttml.TtmlDecoder +import androidx.media3.extractor.text.tx3g.Tx3gDecoder +import androidx.media3.extractor.text.webvtt.Mp4WebvttDecoder +import androidx.media3.extractor.text.webvtt.WebvttDecoder import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError import org.mozilla.universalchardet.UniversalDetector diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomTextRenderer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomTextRenderer.kt index d3f4171a..514aaeab 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomTextRenderer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomTextRenderer.kt @@ -1,8 +1,8 @@ package com.lagradost.cloudstream3.ui.player import android.os.Looper -import com.google.android.exoplayer2.text.SubtitleDecoderFactory -import com.google.android.exoplayer2.text.TextOutput +import androidx.media3.exoplayer.text.SubtitleDecoderFactory +import androidx.media3.exoplayer.text.TextOutput class CustomTextRenderer( offset: Long, 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 46bf8568..c280af59 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 @@ -19,8 +19,8 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.lifecycle.ViewModelProvider import androidx.preference.PreferenceManager -import com.google.android.exoplayer2.Format.NO_VALUE -import com.google.android.exoplayer2.util.MimeTypes +import androidx.media3.common.Format.NO_VALUE +import androidx.media3.common.MimeTypes import com.hippo.unifile.UniFile import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt index ba5a4a85..3038cb8d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.ui.player import android.content.Context +import android.util.Rational import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle import com.lagradost.cloudstream3.utils.EpisodeSkip import com.lagradost.cloudstream3.utils.ExtractorLink @@ -167,6 +168,19 @@ interface IPlayer { fun getVideoTracks(): CurrentTracks + /** + * Original video aspect ratio used for PiP mode + * + * Set using: Width, Height. + * Example: Rational(16, 9) + * + * If null will default to set no aspect ratio. + * + * PiP functions calling this needs to coerce this value between 0.418410 and 2.390000 + * to prevent crashes. + */ + fun getAspectRatio(): Rational? + /** If no parameters are set it'll default to no set size, Specifying the id allows for track overrides to force the player to pick the quality. */ fun setMaxVideoSize(width: Int = Int.MAX_VALUE, height: Int = Int.MAX_VALUE, id: String? = null) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/NonFinalTextRenderer.java b/app/src/main/java/com/lagradost/cloudstream3/ui/player/NonFinalTextRenderer.java index 3b47b27a..b5ecfe8f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/NonFinalTextRenderer.java +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/NonFinalTextRenderer.java @@ -15,10 +15,10 @@ */ package com.lagradost.cloudstream3.ui.player; -import static com.google.android.exoplayer2.text.Cue.DIMEN_UNSET; -import static com.google.android.exoplayer2.text.Cue.LINE_TYPE_NUMBER; -import static com.google.android.exoplayer2.util.Assertions.checkNotNull; -import static com.google.android.exoplayer2.util.Assertions.checkState; +import static androidx.media3.common.text.Cue.DIMEN_UNSET; +import static androidx.media3.common.text.Cue.LINE_TYPE_NUMBER; +import static androidx.media3.common.util.Assertions.checkNotNull; +import static androidx.media3.common.util.Assertions.checkState; import static java.lang.annotation.ElementType.TYPE_USE; import android.os.Handler; @@ -28,25 +28,24 @@ import android.os.Message; import androidx.annotation.IntDef; import androidx.annotation.Nullable; - -import com.google.android.exoplayer2.BaseRenderer; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.Format; -import com.google.android.exoplayer2.FormatHolder; -import com.google.android.exoplayer2.RendererCapabilities; -import com.google.android.exoplayer2.source.SampleStream.ReadDataResult; -import com.google.android.exoplayer2.text.Cue; -import com.google.android.exoplayer2.text.CueGroup; -import com.google.android.exoplayer2.text.Subtitle; -import com.google.android.exoplayer2.text.SubtitleDecoder; -import com.google.android.exoplayer2.text.SubtitleDecoderException; -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.TextOutput; -import com.google.android.exoplayer2.util.Log; -import com.google.android.exoplayer2.util.MimeTypes; -import com.google.android.exoplayer2.util.Util; +import androidx.media3.common.C; +import androidx.media3.common.Format; +import androidx.media3.common.text.Cue; +import androidx.media3.common.text.CueGroup; +import androidx.media3.common.MimeTypes; +import androidx.media3.common.util.Log; +import androidx.media3.common.util.Util; +import androidx.media3.exoplayer.BaseRenderer; +import androidx.media3.exoplayer.FormatHolder; +import androidx.media3.exoplayer.RendererCapabilities; +import androidx.media3.exoplayer.source.SampleStream; +import androidx.media3.exoplayer.text.SubtitleDecoderFactory; +import androidx.media3.exoplayer.text.TextOutput; +import androidx.media3.extractor.text.Subtitle; +import androidx.media3.extractor.text.SubtitleDecoder; +import androidx.media3.extractor.text.SubtitleDecoderException; +import androidx.media3.extractor.text.SubtitleInputBuffer; +import androidx.media3.extractor.text.SubtitleOutputBuffer; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -310,7 +309,7 @@ public class NonFinalTextRenderer extends BaseRenderer implements Callback { return; } // Try and read the next subtitle from the source. - @ReadDataResult int result = readSource(formatHolder, nextInputBuffer, /* readFlags= */ 0); + @SampleStream.ReadDataResult int result = readSource(formatHolder, nextInputBuffer, /* readFlags= */ 0); if (result == C.RESULT_BUFFER_READ) { if (nextInputBuffer.isEndOfStream()) { inputStreamEnded = true; diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerPipHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerPipHelper.kt index 0fbc22f6..4bed0c9d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerPipHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerPipHelper.kt @@ -7,28 +7,22 @@ import android.app.RemoteAction import android.content.Intent import android.graphics.drawable.Icon import android.os.Build +import android.util.Rational import androidx.annotation.RequiresApi import androidx.annotation.StringRes import com.lagradost.cloudstream3.R +import kotlin.math.roundToInt class PlayerPipHelper { companion object { + @RequiresApi(Build.VERSION_CODES.O) private fun getPen(activity: Activity, code: Int): PendingIntent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - PendingIntent.getBroadcast( - activity, - code, - Intent("media_control").putExtra("control_type", code), - PendingIntent.FLAG_IMMUTABLE - ) - } else { - PendingIntent.getBroadcast( - activity, - code, - Intent("media_control").putExtra("control_type", code), - 0 - ) - } + return PendingIntent.getBroadcast( + activity, + code, + Intent(ACTION_MEDIA_CONTROL).putExtra(EXTRA_CONTROL_TYPE, code), + PendingIntent.FLAG_IMMUTABLE + ) } @RequiresApi(Build.VERSION_CODES.O) @@ -48,7 +42,7 @@ class PlayerPipHelper { } @RequiresApi(Build.VERSION_CODES.O) - fun updatePIPModeActions(activity: Activity, isPlaying: Boolean) { + fun updatePIPModeActions(activity: Activity, isPlaying: Boolean, aspectRatio: Rational?) { val actions: ArrayList = ArrayList() actions.add( getRemoteAction( @@ -87,8 +81,28 @@ class PlayerPipHelper { CSPlayerEvent.SeekForward ) ) + + // Nessecary to prevent crashing. + val mixAspectRatio = 0.41841f // ~1/2.39 + val maxAspectRatio = 2.39f // widescreen standard + val ratioAccuracy = 100000 // To convert the float to int + + // java.lang.IllegalArgumentException: setPictureInPictureParams: Aspect ratio is too extreme (must be between 0.418410 and 2.390000) + val fixedRational = aspectRatio?.toFloat()?.coerceIn(mixAspectRatio, maxAspectRatio)?.let { + Rational((it * ratioAccuracy).roundToInt(), ratioAccuracy) + } + activity.setPictureInPictureParams( - PictureInPictureParams.Builder().setActions(actions).build() + PictureInPictureParams.Builder() + .apply { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + setSeamlessResizeEnabled(true) + setAutoEnterEnabled(isPlaying) + } + } + .setAspectRatio(fixedRational) + .setActions(actions) + .build() ) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt index 8d85f176..e532d1a3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt @@ -4,8 +4,8 @@ import android.util.Log import android.util.TypedValue import android.view.ViewGroup import android.widget.FrameLayout -import com.google.android.exoplayer2.ui.SubtitleView -import com.google.android.exoplayer2.util.MimeTypes +import androidx.media3.common.MimeTypes +import androidx.media3.ui.SubtitleView import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.regexSubtitlesToRemoveBloat import com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.regexSubtitlesToRemoveCaptions 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 f62d7e73..d69c18ef 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 @@ -301,8 +301,8 @@ class ResultFragmentTv : Fragment() { resultEpisodes ) for (requestView in views) { - if (!requestView.isVisible) continue - if (requestView.requestFocus()) break + if (!requestView.isShown) continue + if (requestView.requestFocus()) break // View.FOCUS_RIGHT } } } @@ -624,7 +624,7 @@ class ResultFragmentTv : Fragment() { resultPlaySeries.setOnClickListener { viewModel.handleAction( EpisodeClickEvent( - ACTION_PLAY_EPISODE_IN_PLAYER, + ACTION_CLICK_DEFAULT, first ) ) 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 85dd9540..d76eba1e 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 @@ -70,6 +70,7 @@ val appLanguages = arrayListOf( Triple("", "español", "es"), Triple("", "فارسی", "fa"), Triple("", "français", "fr"), + Triple("", "galego", "gl"), Triple("", "हिन्दी", "hi"), Triple("", "hrvatski", "hr"), Triple("", "magyar", "hu"), diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt index 07d00b07..ffb593a0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt @@ -14,7 +14,7 @@ import android.widget.TextView import android.widget.Toast import androidx.fragment.app.Fragment import com.fasterxml.jackson.annotation.JsonProperty -import com.google.android.exoplayer2.text.Cue +import androidx.media3.common.text.Cue import com.google.android.gms.cast.TextTrackStyle import com.google.android.gms.cast.TextTrackStyle.* import com.jaredrummler.android.colorpicker.ColorPickerDialog diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt index ea8524e3..f053023d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt @@ -18,8 +18,8 @@ import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.Fragment import androidx.preference.PreferenceManager import com.fasterxml.jackson.annotation.JsonProperty -import com.google.android.exoplayer2.text.Cue -import com.google.android.exoplayer2.ui.CaptionStyleCompat +import androidx.media3.common.text.Cue +import androidx.media3.ui.CaptionStyleCompat import com.jaredrummler.android.colorpicker.ColorPickerDialog import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt index 9e8cc1d4..6b5e9ec2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt @@ -1,7 +1,7 @@ package com.lagradost.cloudstream3.utils import android.net.Uri -import com.google.android.exoplayer2.util.MimeTypes +import androidx.media3.common.MimeTypes import com.google.android.gms.cast.* import com.google.android.gms.cast.framework.CastSession import com.google.android.gms.cast.framework.media.RemoteMediaClient diff --git a/app/src/main/res/layout/chromecast_subtitle_settings.xml b/app/src/main/res/layout/chromecast_subtitle_settings.xml index 624c2201..4d3b50df 100644 --- a/app/src/main/res/layout/chromecast_subtitle_settings.xml +++ b/app/src/main/res/layout/chromecast_subtitle_settings.xml @@ -35,7 +35,7 @@ android:layout_height="match_parent" android:contentDescription="@string/preview_background_img_des" /> - - - --> - - - @@ -66,7 +65,7 @@ android:layout_height="match_parent" android:layout_rowWeight="1" android:background="?attr/primaryBlackBackground" - android:listSelector="@drawable/outline_drawable_less" + android:listSelector="@drawable/outline_drawable_forced" android:nextFocusLeft="@id/sort_subtitles" android:nextFocusRight="@id/apply_btt" android:requiresFadingEdge="vertical" @@ -95,8 +94,7 @@ android:layout_height="wrap_content" android:layout_rowWeight="1" android:layout_marginTop="10dp" - android:background="@drawable/outline_drawable_less" - android:foreground="?attr/selectableItemBackgroundBorderless" + android:foreground="@drawable/outline_drawable_forced" android:orientation="horizontal" android:paddingTop="10dp" android:paddingBottom="10dp"> @@ -140,7 +138,7 @@ android:layout_height="match_parent" android:layout_rowWeight="1" android:background="?attr/primaryBlackBackground" - android:listSelector="@drawable/outline_drawable_less" + android:listSelector="@drawable/outline_drawable_forced" android:nextFocusLeft="@id/sort_providers" android:nextFocusRight="@id/cancel_btt" android:requiresFadingEdge="vertical" diff --git a/app/src/main/res/layout/sort_bottom_footer_add_choice.xml b/app/src/main/res/layout/sort_bottom_footer_add_choice.xml index 82937ba1..63d79227 100644 --- a/app/src/main/res/layout/sort_bottom_footer_add_choice.xml +++ b/app/src/main/res/layout/sort_bottom_footer_add_choice.xml @@ -4,5 +4,6 @@ style="@style/CheckLabel" android:id="@android:id/text1" tools:text="hello" + android:foreground="@drawable/outline_drawable_forced" app:drawableStartCompat="@drawable/ic_baseline_add_24" app:drawableTint="?attr/textColor" /> \ No newline at end of file diff --git a/app/src/main/res/layout/subtitle_settings.xml b/app/src/main/res/layout/subtitle_settings.xml index 2491b254..8b3f5b2f 100644 --- a/app/src/main/res/layout/subtitle_settings.xml +++ b/app/src/main/res/layout/subtitle_settings.xml @@ -35,9 +35,8 @@ android:scaleType="centerCrop" android:src="@drawable/subtitles_preview_background" /> - - فشل التنزيل تم إلغاء التنزيل تم التنزيل - تشغيل + بث خطأ في تحميل الرابط التخزين الداخلي مدبلج @@ -71,7 +71,7 @@ معلومات تصفية الاشارات المرجعية إشارات مرجعية - حذف + ازالة إعداد حالة المشاهدة تطبيق إلغاء @@ -578,4 +578,5 @@ \nملاحظة: إذا كان المجموع 10 أو أكثر ، فسيتخطى المشغل التحميل تلقائيًا عند تحميل هذا الرابط! النوعيات خلفية الملف الشخصي + تعذر إنشاء واجهة المستخدم بشكل صحيح ، وهذا خطأ كبير ويجب الإبلاغ عنه على الفور %s diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 0543a94e..d76aa94b 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -29,7 +29,7 @@ Търсене… Търси %s… Няма данни - Още опций + Още опции Следващ епизод Жанрове Сподели @@ -124,16 +124,16 @@ Режим Eigengravy (промяна скорост на възпроизвеждане) Добавя опция за скорост в плейъра Плъзнете за преместване - Плъзнете наляво или надясно, за да контролирате времето във видеоплейъра + Плъзнете пръст от една страна на друга, за да контролирате позицията си във видеоклип Плъзнете, за да промените настройките - Плъзнете наляво или надясно, за да промените яркостта или силата на звука + Плъзнете нагоре или надолу от лявата или дясната страна, за да промените яркостта или силата на звука Автоматично пускане на следващ епизод Започнете следващия епизод, когато текущият приключи Докоснете двукратно за превъртане Докоснете два пъти за пауза - Размер на превъртане + Размер на превъртане (секунди) Докоснете два пъти от дясната или лявата страна, за да превъртите напред или назад - Докоснете в средата, за да направите пауза + Докоснете два пъти в средата, за да поставите на пауза Използвайте яркостта на системата Използвайте системна яркост в плейъра на приложението вместо тъмно наслагване Актуализирайте прогреса на гледане @@ -497,4 +497,12 @@ Приложението ще се актуализира при изход от него Започна Актуализация Премахване от гледани + Постер + Браузър + Регистър + Преминато + Неуспешен + Библиотека + Предпочитано качество за гледане (Мобилни данни) + Начало diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index cc9f0ad4..db9398ca 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -570,4 +570,5 @@ \nBudou mít celkovou prioritu videa 10. \n \nPOZNÁMKA: Pokud je součet 10 nebo vyšší, přehrávač automaticky přeskočí načítání při načtení daného odkazu! + Nepodařilo se správně vytvořit rozhraní. Toto je VÁŽNÁ CHYBA, kterou je potřeba ihned nahlásit %s diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 5e02924f..c24c0971 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -7,7 +7,7 @@ Ρυθμίσεις Άνοιγμα με CloudStream Αναζήτηση… - Πόστερ + Αφίσα Χωρίς δεδομένα Περισσότερες Επιλογές Πίσω @@ -96,9 +96,9 @@ Eigengravy Mode Προσθέτει την επιλογή ταχύτητας στο πρόγραμμα αναπαραγωγής Σύρετε για αναζήτηση - Σύρετε αριστερά ή δεξιά για να ελέγξετε τον χρόνο στην μπάρα του προγράμματος αναπαραγωγής + Σύρετε από πλευρά σε πλευρά για να ελέγξετε το σημείο του βίντεο στο οποίο βρίσκεστε Σύρετε για να αλλάξετε ρυθμίσεις - Σύρετε αριστερά ή δεξιά για να αλλάξετε τη φωτεινότητα ή την ένταση + Σύρετε πάνω ή κάτω στην αριστερή ή στη δεξιά μεριά της οθόνης για να αλλάξετε τη φωτεινότητα ή την ένταση Διπλό πάτημα για αναζήτηση Διπλό πάτημα στα αριστερά ή δεξιά για αναζήτηση προς τα μπροστά ή πίσω Αναζήτηση @@ -108,7 +108,7 @@ Αποστέλλει δεδομένα μόνο για καταρρεύσεις Δεν στέλνει δεδομένα Εμφάνιση ενημερώσεων - Αυτόματη αναζήτηση νέων ενημερώσεων + Αυτόματη αναζήτηση νέων ενημερώσεων κατά την εκκίνηση της εφαρμογής. Ενημέρωση σε προ-εκδόσεις (beta) Αναζητήστε ενημερώσεις προ-εκδόσεων (beta) αντί για σταθερές εκδόσεις (stable) GitHub @@ -121,7 +121,7 @@ Βαθμολογία: %.1f Νέα διαθέσιμη ενημέρωση! \n%s -> %s - Πάτημα στη μέση για παύση + Πατήστε δύο φορές στη μέση για παύση Χρήση φωτεινότητας συστήματος Χρήση φωτεινότητας συστήματος στο ενσωματωμένο πρόγραμμα αναπαραγωγής, αντί εφαρμογής προεπιλεγμένου σκούρου επικαλύμματος Ενημέρωση προόδου παρακολούθησης @@ -390,7 +390,7 @@ @string/home_play Δεν έχουν παρασχεθεί μεταδεδομένα από τον ιστότοπο, η φόρτωση του βίντεο θα αποτύχει αν δεν υπάρχει στον ιστότοπο. Διπλό πάτημα για παύση - Μέγεθος αναζήτησης στο πρόγραμμα αναπαραγωγής + Μέγεθος αναζήτησης στο πρόγραμμα αναπαραγωγής (σε δευτερόλεπτα) Αυτόματη ενημέρωση plugin Αυτόματη λήψη plugin DNS μέσω HTTPS @@ -464,7 +464,7 @@ Προεπιλεγμένα %s %s Μέγεθος γραμματοσειράς - @string/anime + Άνιμε Σύνδεσμοι Εμφάνιση Χαρακτηριστικά @@ -508,4 +508,8 @@ \nΣυνδέσου σε έναν λογαριασμό που έχει βιβλιοθήκη, ή πρόσθεσε σειρές στην τοπική βιβλιοθήκη σου Βρέθηκε αρχείο Ασφαλούς Λειτουργίας! \nΔεν πρόκειται να φορτωθούν extensions κατά το ξεκίνημα μέχρι να διαγραφεί το αρχείο. + Αρχείο Καταγραφής + Απέτυχε + Πέτυχε + Εκκίνηση diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bc830084..ac757b15 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -546,4 +546,5 @@ Usar Calidades Perfil del fondo + La interfaz de usuario no se ha podido crear correctamente, se trata de un GRAN BUG y debe ser reportado inmediatamente %s diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml new file mode 100644 index 00000000..8386188c --- /dev/null +++ b/app/src/main/res/values-gl/strings.xml @@ -0,0 +1,16 @@ + + + %dd %dh %dm + %dh %dm + %dm + Póster Principal + Seguinte ó azar + %s Ep %d + Elenco: %s + O episodio %d se lanzará en + Póster + Cartel + Póster do Episodio + Regresar + Cambiar provedor + diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 722352a6..f27b12fe 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -193,7 +193,7 @@ antri Tidak Ada Subtitle Default - Bebas + Tersedia Terpakai Aplikasi @@ -243,7 +243,7 @@ Jangan tunjukkan lagi Skip Update ini Update - Kualitas tontonan yang lebih diinginkan (WIFI) + Kualitas nonton yang diinginkan (WiFi) Karakter maksimal judul pemutar video Resolusi pemutar video Ukuran buffer video @@ -252,7 +252,7 @@ Membersihkan cache video dan gambar Dapat menyebabkan crash jika disetel terlalu tinggi. Jangan diubah jika perangkat anda memiliki jumlah RAM yang rendah, seperti TV Android atau ponsel lama. Dapat bermasalah pada sistem dengan ruang penyimpanan rendah, seperti Android TV, jika diatur terlalu tinggi. - DNS melalui HTTPS + DNS over HTTPS Berguna untuk melewati blok ISP Jalur download NGINX server URL @@ -260,7 +260,7 @@ Paskan dengan layar Regang Zoom - Peringatan + Disclaimer 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 @@ -364,7 +364,7 @@ Tampilkan poster dari Kitsu Pasang otomatis semua plugins yang belum terpasang, dari repositori yang telah ditambahkan. Siaran langsung - 17+ + NSFW password123 Penyedia Cache @@ -374,7 +374,7 @@ Bawaan Tampilan Fitur - Tampilkan konten 17+ + Tampilkan konten NSFW Putar Cuplikan Putar Siaran Siaran @@ -385,7 +385,7 @@ Ulang proses pemasangan %d-%d %d %s - 17+ + NSFW Lainnya Video Duplikasi Website @@ -393,7 +393,7 @@ Tautan Perbarui Aplikasi Cadangkan - Fitur Tambahan + Ekstensi Putar di CloudStream Sembunyikan kualitas video terpilih di pencarian %s %d%s @@ -464,7 +464,7 @@ Ubah tampilan aplikasi Laporkan Crash Selesai - Fitur Tambahan + Ekstensi Hapus Repositori Unduh semua situs yang ingin digunakan Ukuran @@ -485,7 +485,7 @@ Aksi Referer Ya - Pasang dulu fitur tambahan + Install ekstensi terlebih dahulu Semua Bahasa Lewati %s Pembuka @@ -546,12 +546,12 @@ Berlangganan ke %s Berhenti berlangganan di %s Episode %d telah rilis! - raw.githubusercontent.com Proksi - Tidak dapat menjangkau GitHub. Mengaktifkan proksi jsDelivr… + Proxy raw.githubusercontent.com + Tidak dapat menjangkau GitHub. Mengaktifkan proxy jsDelivr… Melewati pemblokiran GitHub menggunakan jsDelivr. Dapat menyebabkan pembaruan tertunda beberapa hari. Bypass ISP Pulihkan - Nonton dengan kualitas yang di inginkan (Data Seluler) + Kualitas nonton yang diinginkan (Data Seluler) Data seluler Bantuan Di sini anda dapat mengubah sumber yang diurutkan. Jika video memiliki prioritas lebih tinggi, video tersebut akan muncul lebih tinggi dalam pemilihan sumber. Jumlah prioritas sumber dan prioritas kualitas adalah prioritas video. @@ -569,4 +569,5 @@ Profil Kualitas Latar belakang profil + UI tidak dapat dibuat dengan benar, ini adalah BUG UTAMA dan harus segera dilaporkan %s diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 5fcc14da..5e415dc6 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -201,4 +201,7 @@ バックグラウンドをプレビュー ライブストリームの再生 プロバイダーの変更 + エピソード %d は にリリースされます + 再視聴 + ストリームトレント diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 7d4bf3e3..60b776b1 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -549,4 +549,5 @@ Pomoc Jakości Tło profilu + Nie można było poprawnie utworzyć interfejsu użytkownika, jest to POWAŻNY BŁĄD i należy go natychmiast zgłosić %s diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 0fad744c..e246c673 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -59,7 +59,7 @@ Скопіювати Закрити Зберегти - Швидкість програвача + Швидкість плеєра Колір вікна Тип контуру Шрифт @@ -80,15 +80,15 @@ Сюжет не знайдено Опис не знайдено Показати Logcat 🐈 - Продовження відтворення в мініатюрному плеєрі поверх інших програм + Продовження відтворення в мініатюрному плеєрі поверх інших застосунків Прибирає чорні рамки Субтитри Субтитри Chromecast Налаштування субтитрів Chromecast Режим Eigengravy Проведіть пальцем, щоб змінити налаштування - Проведіть пальцем вгору або вниз ліворуч або праворуч, щоб змінити яскравість або гучність - Відтворення наступного епізоду після закінчення поточного + Проведіть пальцем вгору або вниз, ліворуч або праворуч, щоб змінити яскравість чи гучність + Відтворювати наступний епізод після закінчення поточного Головна CloudStream Філер @@ -129,12 +129,12 @@ Метадані не надаються сайтом, завантаження відео не відбудеться, якщо їх немає на сайті. Картинка в картинці Налаштування субтитрів плеєра - Додає опцію швидкості в плеєрі + Додає опцію керування швидкістю в плеєрі Проведіть пальцем, щоб перемотати Двічі торкніться, щоб перемотати Двічі торкніться для паузи Крок перемотки (Секунди) - Натисніть двічі посередині, щоб призупинити + Натисніть двічі посередині, щоб призупинити відтворення відео Використовувати яскравість системи Оновити прогрес перегляду Відновлення даних з резервної копії @@ -154,7 +154,7 @@ Показати трейлери Приховати вибрану якість відео в результатах пошуку Автоматичне завантаження плагінів - Показати оновлення програми + Показувати оновлення застосунку Повторний процес налаштування Пошук лише попередніх оновлень, а не повних релізів Встановлювач APK @@ -162,7 +162,7 @@ Застосунок для легких новел від тих же розробників Застосунок для аніме від тих же розробників Дайте бананів розробникам - Мова програми + Мова застосунку Цей постачальник не має підтримки Chromecast Посилань не знайдено Переглянути епізод @@ -189,7 +189,7 @@ За замовчуванням Вільно Зайнято - Програма + Застосунок Телесеріали Мультфільми Аніме @@ -208,7 +208,7 @@ Віддалена помилка Помилка рендеринга Дзеркало Chromecast - Переглянути в програмі + Переглянути в застосунку Переглянути в %s Автозавантаження Завантажити дзеркало @@ -221,7 +221,7 @@ Заголовок Перемикання елементів інтерфейсу на плакаті Оновлення не знайдено - Двічі торкніться праворуч або ліворуч, щоб перейти вперед або назад + Двічі торкніться праворуч або ліворуч, щоб перемотати відео вперед або назад Використовуйте системну яскравість у плеєрі замість темної накладки Завантажено файл резервної копії Торренти @@ -273,7 +273,7 @@ Заповнити Збільшити Доріжки - Оновлення програми + Оновлення застосунку Кеш Жести Особливості плеєра @@ -283,19 +283,19 @@ Особливості Загальне Випадкова кнопка - Показати випадкову кнопку на Головній сторінці + Показувати кнопку на Головній сторінці, яка вибирає випадковий фільм чи серіал Мови постачальника - Макет програми + Макет застосунку Бажані медіа Авто Макет телевізора Макет телефону Макет емулятора Основний колір - Тема програми + Тема застосунку Розташування назви постера Розмістіть назву під постером - пароль123 + Пароль123 Моє круте ім\'я hello@world.com Мій крутий сайт @@ -354,7 +354,7 @@ DNS через HTTPS Шлях завантаження Додайте клон існуючого сайту, з іншою URL-адресою - Відображати Дубляж/Субтитри аніме + Відображати мітку Дубляж/Субтитри в аніме Застереження Розширення Дії @@ -368,7 +368,7 @@ %s %s Депресивний обліковий запис - Створити обліковий запис + Створити Додано %s /\?\? Оцінений @@ -401,7 +401,7 @@ TS TC Видалити роздуття субтитрів - Реферер + Referer Далі Дивіться відео на цих мовах Пропустити налаштування @@ -437,7 +437,7 @@ Усі субтитри у верхньому регістрі %s (Вимкнено) Відео доріжки - Застосувати при перезавантаженні + Застосується при перезавантаженні Переглянути інформацію про збій Рейтинг: %s Опис @@ -462,17 +462,17 @@ Вступ Очистити історію Історія - Показувати спливаючі вікна для опенінґу/кінця + Показувати спливаючі вікна для опенінґу/ендінґу Забагато тексту. Не вдалося зберегти в буфер обміну. Позначити як переглянуте Ви впевнені що хочете вийти\? Так Ні - Встановлення оновлення програми… - Не вдалося встановити нову версію програми - Старий + Встановлення оновлення застосунку… + Не вдалося встановити нову версію застосунку + Legacy Інсталятор пакетів - Програму буде оновлено після виходу + Застосунок буде оновлено після виходу Це також призведе до видалення всіх плагінів репозиторію Всі мови Назад @@ -484,44 +484,44 @@ Бажаний відеоплеєр Увімкнено безпечний режим Автори - Завантаження оновлення програми… + Завантаження оновлення застосунку… Усі розширення були вимкнені через збій, щоб допомогти вам знайти те, що стало причиною проблеми. - Програму не знайдено + Застосунок не знайдено Змішаний опенінґ Видалити з переглянутого - За оновленням (від старого до нового) - За оновленням (від нового до старого) + Оновленням (від старого до нового) + Оновленням (від нового до старого) Бібліотека Сортувати - За рейтингом (від високого до низького) + Рейтингом (від високого до низького) Сортувати за - За алфавітом (від А до Я) - За рейтингом (від низького до високого) + Алфавітом (від А до Я) + Рейтингом (від низького до високого) Ваша бібліотека порожня :( \nУвійдіть в обліковий запис бібліотеки або додайте фільми до вашої локальної бібліотеки. - За алфавітом (від Я до А) + Алфавітом (від Я до А) Виберіть бібліотеку - Відкрити з + Відкрити Браузер Цей список порожній. Спробуйте перейти до іншого. Файл безпечного режиму знайдено! \nРозширеня не завантажуються під час запуску, доки файл не буде видалено. Android TV - Плеєр сховано - обсяг пошуку - Плеєр показано - обсяг пошуку - Обсяг пошуку, який використовується, коли плеєр видимий - Обсяг пошуку, який використовується, коли гравець прихований - Не вдалося - Пройдено + Плеєр сховано - обсяг перемотки + Плеєр показано - обсяг перемотки + Обсяг перемотки, який використовується, коли плеєр видимий + Обсяг перемотки, який використовується, коли плеєр прихований + Тест провалено + Тест пройдено Перезапуск Журнал - Старт - Стоп - Тест постачальника + Почати + Зупинити + Тестування постачальників Оновлення підписаних шоу Підписано - Підписано на %s - Відписатися від %s + Ви підписалися на %s + Ви відписалися від %s Епізод %d випущено! Повернути raw.githubusercontent.com Proxy diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index f896e5c1..4b394227 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -378,7 +378,7 @@ HDR SDR Web - Áp phích + Ảnh áp phích Trình phát Độ phân giải và Tiêu đề Tiêu đề @@ -389,15 +389,15 @@ Lỗi Xoá phụ đề đã dùng Loại bỏ mã hoá phụ đề - Lọc theo ngôn ngữ + Lọc theo ngôn ngữ media được chuộng hơn Thêm Xem trước Liên kết trực tiếp Đề xuất Tiếp theo Xem video bằng các ngôn ngữ này - Trước - Bỏ qua + Trước đó + Bỏ qua cài đặt setup Chọn giao diện phù hợp với thiết bị của bạn Báo cáo sự cố Bạn muốn xem gì @@ -407,7 +407,7 @@ Tên kho lưu trữ Đường dẫn kho lưu trữ Đã tải plugin - Đã xoá plugin + Plugin đã xoá Không tải được %s 18+ Bắt đầu tải %d %s… @@ -436,7 +436,7 @@ Âm thanh Chất lượng Video Áp dụng khi khởi động lại - Bật chế độ an toàn + Chế độ an toàn được bật Đã xảy ra sự cố và chúng tôi đã tự động tắt tất cả các tiện ích mở rộng, hãy tìm và xóa tiện ích mở rộng đang gây ra sự cố. Xem thông tin sự cố Lịch sử @@ -486,13 +486,13 @@ Mở đầu Kết thúc Tóm tắt - Mở đầu tuỳ chọn - Kết thúc tuỳ chọn + Các kết thúc hỗn hợp + Các mở đầu hỗn hợp Danh đề Giới thiệu Xoá lịch sử Hiển thị nút tua nhanh cho mở đầu/kết thúc - Văn bản quá dài. Không thể lưu vào bộ nhớ tạm. + Văn bản quá dài. Không thể lưu vào khay nhớ tạm. Xoá khỏi đã xem Bạn có chắc muốn thoát\? @@ -503,11 +503,11 @@ Thư viện Trình duyệt Plugin đã tải - Mặc định - Tải lên (Mới đến Cũ) - Tải lên (Cũ đến Mới) + Di sản + Đã cập nhật (Mới đến Cũ) + Đã cập nhật (Cũ đến Mới) Thư viện của bạn đang trống :( -\nĐăng nhập vào tài khoản thư viện hoặc thêm phim vào thư viện cục bộ +\nĐăng nhập vào tài khoản thư viện hoặc thêm phim vào thư viện cục bộ. Mở với Siêu dữ liệu không có sẵn, video sẽ không được tải nếu nó không tồn tại trên trang web. PackageInstaller @@ -515,7 +515,7 @@ Xếp hạng (Cao đến Thấp) Xếp hạng (Thấp đến Cao) Chữ cái (Z đến A) - Sắp xếp + Sắp xếp theo 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 @@ -532,16 +532,33 @@ Đã đăng kí %s Tập %d đã ra mắt! Đã đăng kí - Dừng + Dừng lại Bỏ qua ISP Đã bỏ đăng ký %s Tìm thấy tệp Safe mode! -\nKhông tải bất cứ tiện ích nào khi khởi dộng cho đến khi tệp bị xoá - Trở lại +\nKhông tải bất cứ tiện ích mở rộng nào khi khởi động cho đến khi loại bỏ tệp. + Đảo ngược lại Đang cập nhật các phim đã đăng kí - Bỏ qua chặn GitHub bằng cách dùng jsDelivr. Có thể gây ra việc cập nhật bị chậm vài ngày + Bỏ qua chặn GitHub bằng cách dùng jsDelivr. Có thể gây ra việc cập nhật bị chậm vài ngày. Lượng tua thêm được sử dụng khi trình phát ẩn Lượng tua thêm Lượng tua thêm được sử dụng khi trình phát hiện lên Lượng tua thêm + Hồ sơ %d + Dữ liệu di động + Đặt mặc định + Wi-Fi + Sử dụng + Điều chỉnh + Hồ sơ + Trợ giúp + Nền hồ sơ + Tại đây bạn có thể thay đổi cách sắp xếp các nguồn. Nếu video có mức độ ưu tiên cao hơn thì video đó sẽ xuất hiện cao hơn trong lựa chọn nguồn. Tổng ưu tiên nguồn và ưu tiên chất lượng là ưu tiên video. +\n +\nNguồn A: 3 +\nChất lượng B: 7 +\nSẽ có mức độ ưu tiên video kết hợp là 10. +\n +\nLƯU Ý: Nếu tổng là 10 hoặc nhiều hơn, trình phát sẽ tự động bỏ tải khi liên kết đó được tải! + Các phẩm chất diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index dbd96827..033a5f50 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -577,4 +577,21 @@ ISP 绕过 还原 首选播放画质(移动数据) + 简介 %d + 无线网络 + 设为默认 + 使用 + 编辑 + 配置文件 + 帮助 + 移动流量 + 在这里,您可以更改源的排序方式。如果视频具有更高的优先级,它将在源选择中显示得更高。源优先级和质量优先级的总和就是视频优先级。 +\n +\n来源 A:3 +\n质量 B: 7 +\n组合视频优先级为 10。 +\n +\n注意:如果总和为 10 或更多,则加载该链接时播放器将自动跳过加载! + 质量 + 个人资料背景 diff --git a/fastlane/metadata/android/de-DE/title.txt b/fastlane/metadata/android/de-DE/title.txt new file mode 100644 index 00000000..dde89d58 --- /dev/null +++ b/fastlane/metadata/android/de-DE/title.txt @@ -0,0 +1 @@ +CloudStream diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt index e01b7d03..07c5f3ae 100644 --- a/fastlane/metadata/android/en-US/full_description.txt +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -1,14 +1,10 @@ -CloudStream-3 lets you stream and download Movies, TV-Series and Anime. The app comes without any ads and analytics. It supports multiple trailer & movie sites, and more. Features include: - +CloudStream-3 lets you stream and download Movies, TV-Series and Anime. +The app comes without any ads and analytics and +supports multiple trailer & movie sites, and more, e.g. Bookmarks - -Download and stream movies, tv-shows and anime - - -subtitle downloads - +Subtitle downloads Chromecast support diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt index 83ee1066..73078f8d 100644 --- a/fastlane/metadata/android/en-US/short_description.txt +++ b/fastlane/metadata/android/en-US/short_description.txt @@ -1 +1 @@ -Stream and download Movies, TV-Series and Anime. +Stream and download movies, TV-series and anime. diff --git a/fastlane/metadata/android/no-NO/changelogs/2.txt b/fastlane/metadata/android/no-NO/changelogs/2.txt new file mode 100644 index 00000000..6d66f546 --- /dev/null +++ b/fastlane/metadata/android/no-NO/changelogs/2.txt @@ -0,0 +1 @@ +- Endringslogg tillagt. diff --git a/fastlane/metadata/android/no-NO/full_description.txt b/fastlane/metadata/android/no-NO/full_description.txt new file mode 100644 index 00000000..ac0c64c3 --- /dev/null +++ b/fastlane/metadata/android/no-NO/full_description.txt @@ -0,0 +1,8 @@ +CloudStream-3 lar deg strømme og laste ned filmer, TV-serier, og anime. Programmet er reklamefritt, og det utføres ingen analyse. Flere førfilmer og filmsteder støttes, med mer. +Noen av funksjonene. + +Bokmerker + +Nedlasting av undertekster + +Chromecast-støtte diff --git a/fastlane/metadata/android/no-NO/short_description.txt b/fastlane/metadata/android/no-NO/short_description.txt new file mode 100644 index 00000000..80290325 --- /dev/null +++ b/fastlane/metadata/android/no-NO/short_description.txt @@ -0,0 +1 @@ +Se filmer, TV-serier og anime direkte eller last ned diff --git a/fastlane/metadata/android/no-NO/title.txt b/fastlane/metadata/android/no-NO/title.txt new file mode 100644 index 00000000..dde89d58 --- /dev/null +++ b/fastlane/metadata/android/no-NO/title.txt @@ -0,0 +1 @@ +CloudStream diff --git a/fastlane/metadata/android/pl-PL/short_description.txt b/fastlane/metadata/android/pl-PL/short_description.txt new file mode 100644 index 00000000..1c561b6e --- /dev/null +++ b/fastlane/metadata/android/pl-PL/short_description.txt @@ -0,0 +1 @@ +Streamuj i pobieraj filmy, seriale telewizyjne i anime. diff --git a/fastlane/metadata/android/pl-PL/title.txt b/fastlane/metadata/android/pl-PL/title.txt new file mode 100644 index 00000000..dde89d58 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/title.txt @@ -0,0 +1 @@ +CloudStream diff --git a/fastlane/metadata/android/uk/changelogs/2.txt b/fastlane/metadata/android/uk/changelogs/2.txt new file mode 100644 index 00000000..2c8d9f7e --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/2.txt @@ -0,0 +1 @@ +- Додано журнал змін! diff --git a/fastlane/metadata/android/uk/full_description.txt b/fastlane/metadata/android/uk/full_description.txt new file mode 100644 index 00000000..554b08ac --- /dev/null +++ b/fastlane/metadata/android/uk/full_description.txt @@ -0,0 +1,14 @@ +CloudStream-3 дозволяє транслювати та завантажувати фільми, серіали та аніме. Застосунок не містить реклами та аналітики. Підтримує безліч сайтів з трейлерами та фільмами тощо. Особливості застосунку: + + + +Закладки + + +Завантаження та трансляція фільмів, серіалів та аніме + + +завантаження субтитрів + + +Підтримка Chromecast diff --git a/fastlane/metadata/android/uk/short_description.txt b/fastlane/metadata/android/uk/short_description.txt new file mode 100644 index 00000000..b54cc950 --- /dev/null +++ b/fastlane/metadata/android/uk/short_description.txt @@ -0,0 +1 @@ +Трансляція та завантаження фільмів, серіалів та аніме. diff --git a/fastlane/metadata/android/uk/title.txt b/fastlane/metadata/android/uk/title.txt new file mode 100644 index 00000000..dde89d58 --- /dev/null +++ b/fastlane/metadata/android/uk/title.txt @@ -0,0 +1 @@ +CloudStream diff --git a/fastlane/metadata/android/zh-CN/changelogs/2.txt b/fastlane/metadata/android/zh-CN/changelogs/2.txt new file mode 100644 index 00000000..5512f16c --- /dev/null +++ b/fastlane/metadata/android/zh-CN/changelogs/2.txt @@ -0,0 +1 @@ +- 添加了更新日志! diff --git a/fastlane/metadata/android/zh-CN/full_description.txt b/fastlane/metadata/android/zh-CN/full_description.txt index 1f437a99..56519df6 100644 --- a/fastlane/metadata/android/zh-CN/full_description.txt +++ b/fastlane/metadata/android/zh-CN/full_description.txt @@ -1,14 +1,9 @@ CloudStream-3可以让你串流和下载电影、剧集和动漫。这款应用没有任何广告和分析。它支持多个预告片和电影网站等。特点包括: - - 书签 - 下载和串流电影、电视节目和动漫 - 下载字幕 - 支持投屏 diff --git a/fastlane/metadata/android/zh-CN/title.txt b/fastlane/metadata/android/zh-CN/title.txt new file mode 100644 index 00000000..dde89d58 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/title.txt @@ -0,0 +1 @@ +CloudStream diff --git a/gradle.properties b/gradle.properties index 8145fa7b..b8aa1f91 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,7 +16,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true +# android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official android.defaults.buildfeatures.buildconfig=true