diff --git a/README.md b/README.md index c2492c5d821..05dc88586d3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # CloudStream +⚠️ **DISCLAIMER: This application is an EXPERIMENT.** +**The developer is NOT responsible for any improper or dangerous use of this application.** +⛔ **Usage while driving is STRICTLY PROHIBITED.** + +**Always prioritize safe driving and adhere to local traffic laws.** +**This software is provided "as is", without warranty of any kind.** + + **⚠️ Warning: By default, this app doesn't provide any video sources; you have to install extensions to add functionality to the app.** [![Discord](https://invidget.switchblade.xyz/5Hus6fM)](https://discord.gg/5Hus6fM) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8b2ed743622..a94d049d4de 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -63,9 +63,20 @@ android { minSdk = libs.versions.minSdk.get().toInt() targetSdk = libs.versions.targetSdk.get().toInt() versionCode = 67 - versionName = "4.6.2" + versionName = "4.6.19" resValue("string", "commit_hash", getGitCommitHash()) + + resourceConfigurations.addAll( + listOf( + "en", "af", "am", "apc", "ar", "ars", "as", "az", "be", "bg", "bn", "ca", "ckb", "cs", + "de", "el", "eo", "es", "fa", "fil", "fr", "gl", "hi", "hr", "hu", "in", "it", "iw", + "ja", "kn", "ko", "lt", "lv", "mk", "ml", "ms", "mt", "my", "ne", "nl", "nn", "no", + "or", "pl", "pt", "pt-rBR", "ro", "ru", "sk", "so", "sv", "ta", "ti", "tl", "tr", + "uk", "ur", "vi", "zh", "zh-rTW" + ) + ) + manifestPlaceholders["target_sdk_version"] = libs.versions.targetSdk.get() @@ -152,7 +163,15 @@ android { resValues = true } + + namespace = "com.lagradost.cloudstream3" + + sourceSets { + getByName("main") { + res.srcDirs("src/main/res", "src/main/res-car") + } + } } dependencies { @@ -171,6 +190,7 @@ dependencies { implementation(libs.fragment.ktx) implementation(libs.bundles.lifecycle) implementation(libs.bundles.navigation) + implementation(libs.car.app) // Design & UI implementation(libs.preference.ktx) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9e1bc9ac978..5ab1ff2db93 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ - + @@ -22,6 +22,10 @@ android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" /> + + + + + + + + + + + + @@ -111,7 +127,7 @@ --> @@ -231,6 +247,15 @@ android:foregroundServiceType="dataSync" android:exported="false" /> + + + + + + + ? = null @@ -1161,7 +1165,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa @Suppress("DEPRECATION_ERROR") override fun onCreate(savedInstanceState: Bundle?) { - app.initClient(this) + val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) val errorFile = filesDir.resolve("last_error") diff --git a/app/src/main/java/com/lagradost/cloudstream3/services/CSCarAppService.kt b/app/src/main/java/com/lagradost/cloudstream3/services/CSCarAppService.kt new file mode 100644 index 00000000000..bc10bc4133e --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/services/CSCarAppService.kt @@ -0,0 +1,16 @@ +package com.lagradost.cloudstream3.services + +import androidx.car.app.CarAppService +import androidx.car.app.Session +import androidx.car.app.validation.HostValidator +import com.lagradost.cloudstream3.ui.car.CarSession + +class CSCarAppService : CarAppService() { + override fun createHostValidator(): HostValidator { + return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR + } + + override fun onCreateSession(): Session { + return CarSession() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt index 42f68067b8c..dafd8141041 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt @@ -36,8 +36,15 @@ import com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding import com.lagradost.cloudstream3.utils.UIHelper.openActivity import com.lagradost.cloudstream3.utils.UIHelper.setNavigationBarColorCompat +import android.content.Context +import com.lagradost.cloudstream3.CloudStreamApp + class AccountSelectActivity : FragmentActivity(), BiometricCallback { + override fun attachBaseContext(base: Context?) { + super.attachBaseContext(CloudStreamApp.updateBaseContextLocale(base)) + } + val accountViewModel: AccountViewModel by viewModels() @SuppressLint("NotifyDataSetChanged") diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/AboutMeScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/AboutMeScreen.kt new file mode 100644 index 00000000000..7e4c98a2780 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/AboutMeScreen.kt @@ -0,0 +1,98 @@ +package com.lagradost.cloudstream3.ui.car + +import android.net.Uri +import androidx.car.app.AppManager +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.SurfaceCallback +import androidx.car.app.SurfaceContainer +import androidx.car.app.model.Action +import androidx.car.app.model.ActionStrip +import androidx.car.app.model.CarIcon +import androidx.car.app.model.Template +import androidx.car.app.navigation.model.NavigationTemplate +import androidx.core.graphics.drawable.IconCompat +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.media3.common.MediaItem +import androidx.media3.common.Player +import androidx.media3.exoplayer.ExoPlayer +import com.lagradost.cloudstream3.R + +class AboutMeScreen(carContext: CarContext) : Screen(carContext), DefaultLifecycleObserver, SurfaceCallback { + + private var player: ExoPlayer? = null + + init { + lifecycle.addObserver(this) + } + + override fun onCreate(owner: LifecycleOwner) { + super.onCreate(owner) + try { + player = ExoPlayer.Builder(carContext).build().apply { + val audioAttributes = androidx.media3.common.AudioAttributes.Builder() + .setUsage(androidx.media3.common.C.USAGE_MEDIA) + .setContentType(androidx.media3.common.C.AUDIO_CONTENT_TYPE_MOVIE) + .build() + setAudioAttributes(audioAttributes, true) + + repeatMode = Player.REPEAT_MODE_ONE + volume = 1.0f + // android.resource://package/id + val uri = Uri.parse("android.resource://${carContext.packageName}/${R.raw.aboutme}") + setMediaItem(MediaItem.fromUri(uri)) + prepare() + playWhenReady = true + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun onDestroy(owner: LifecycleOwner) { + player?.release() + player = null + super.onDestroy(owner) + } + + override fun onStart(owner: LifecycleOwner) { + super.onStart(owner) + carContext.getCarService(AppManager::class.java).setSurfaceCallback(this) + player?.play() + } + + override fun onStop(owner: LifecycleOwner) { + player?.pause() + carContext.getCarService(AppManager::class.java).setSurfaceCallback(null) + super.onStop(owner) + } + + override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) { + val surface = surfaceContainer.surface + if (surface != null) { + player?.setVideoSurface(surface) + } + } + + + + override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) { + player?.clearVideoSurface() + } + + override fun onGetTemplate(): Template { + val backAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, androidx.appcompat.R.drawable.abc_ic_ab_back_material)).build()) + .setOnClickListener { screenManager.pop() } + .build() + + return NavigationTemplate.Builder() + .setActionStrip( + ActionStrip.Builder() + .addAction(backAction) + .build() + ) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/BookmarksScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/BookmarksScreen.kt new file mode 100644 index 00000000000..6f70f191384 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/BookmarksScreen.kt @@ -0,0 +1,104 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.CarIcon +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import com.lagradost.cloudstream3.R +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import com.lagradost.cloudstream3.TvType +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import kotlinx.coroutines.delay +import coil3.SingletonImageLoader +import coil3.request.ImageRequest +import coil3.asDrawable + +class BookmarksScreen(carContext: CarContext) : Screen(carContext), androidx.lifecycle.DefaultLifecycleObserver { + private var itemList: ItemList? = null + + init { + lifecycle.addObserver(this) + } + + override fun onStart(owner: androidx.lifecycle.LifecycleOwner) { + loadBookmarks() + } + + private fun loadBookmarks(retryCount: Int = 0) { + CoroutineScope(Dispatchers.IO).launch { + withContext(Dispatchers.Main) { + itemList = null + invalidate() + } + try { + // Fetch only Favorites (Heart icon) + val favorites = com.lagradost.cloudstream3.utils.DataStoreHelper.getAllFavorites() + .sortedByDescending { it.favoritesTime } + + val builder = ItemList.Builder() + if (favorites.isEmpty()) { + builder.setNoItemsMessage(CarStrings.get(R.string.car_no_favorites_found)) + } else { + favorites.forEach { item -> + builder.addItem( + Row.Builder() + .setTitle(item.name) + .setOnClickListener { + val type = item.type + if (type == TvType.TvSeries || + type == TvType.Anime || + type == TvType.Cartoon || + type == TvType.OVA || + type == TvType.AsianDrama || + type == TvType.Documentary) { + screenManager.push(TvSeriesDetailScreen(carContext, item)) + } else { + screenManager.push(DetailsScreen(carContext, item)) + } + } + .build() + ) + } + } + + val builtList = builder.build() + withContext(Dispatchers.Main) { + itemList = builtList + invalidate() + } + } catch (e: Exception) { + if (retryCount < 3) { + delay(3000) + loadBookmarks(retryCount + 1) + } else { + withContext(Dispatchers.Main) { + itemList = ItemList.Builder() + .addItem( + Row.Builder() + .setTitle("${CarStrings.get(R.string.car_error)}: ${e.message}") + .setOnClickListener { loadBookmarks() } + .build() + ) + .build() + invalidate() + } + } + } + } + } + + override fun onGetTemplate(): Template { + return ListTemplate.Builder() + .setSingleList(itemList ?: ItemList.Builder().setNoItemsMessage(CarStrings.get(R.string.car_loading)).build()) + .setTitle(CarStrings.get(R.string.car_favorites)) + .setHeaderAction(Action.BACK) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarHelper.kt new file mode 100644 index 00000000000..78615a7e113 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarHelper.kt @@ -0,0 +1,87 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.model.CarColor +import androidx.car.app.model.ForegroundCarColorSpan +import androidx.car.app.model.Pane +import androidx.car.app.model.Row +import android.text.SpannableString +import android.text.Spanned +import com.lagradost.cloudstream3.LoadResponse +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.utils.DataStoreHelper +import com.lagradost.cloudstream3.utils.DataStoreHelper.FavoritesData + +object CarHelper { + + fun toggleFavorite( + carContext: CarContext, + fullDetails: LoadResponse?, + isFavorite: Boolean, + onFavoriteChanged: (Boolean) -> Unit + ) { + val details = fullDetails ?: return + val api = getApiFromNameNull(details.apiName) ?: return + val id = details.url.replace(api.mainUrl, "").replace("/", "").hashCode() + + if (isFavorite) { + DataStoreHelper.removeFavoritesData(id) + onFavoriteChanged(false) + androidx.car.app.CarToast.makeText(carContext, CarStrings.get(R.string.car_removed_from_favorites), androidx.car.app.CarToast.LENGTH_SHORT).show() + } else { + val favoritesData = FavoritesData( + favoritesTime = System.currentTimeMillis(), + id = id, + latestUpdatedTime = System.currentTimeMillis(), + name = details.name, + url = details.url, + apiName = details.apiName, + type = details.type, + posterUrl = details.posterUrl, + year = details.year, + quality = null, + posterHeaders = details.posterHeaders, + plot = details.plot, + score = details.score, + tags = details.tags + ) + DataStoreHelper.setFavoritesData(id, favoritesData) + onFavoriteChanged(true) + androidx.car.app.CarToast.makeText(carContext, CarStrings.get(R.string.car_added_to_favorites), androidx.car.app.CarToast.LENGTH_SHORT).show() + } + } + + fun addPlotAndCast(paneBuilder: Pane.Builder, details: LoadResponse) { + // Plot Row + if (!details.plot.isNullOrEmpty()) { + paneBuilder.addRow( + Row.Builder() + .setTitle(CarStrings.get(R.string.car_plot)) + .addText(details.plot!!) + .build() + ) + } + + // Cast Row + if (!details.actors.isNullOrEmpty()) { + val castList = details.actors!!.groupBy { it.roleString }.flatMap { it.value }.take(5).joinToString(", ") { it.actor.name } + if (castList.isNotEmpty()) { + val s = SpannableString(castList) + s.setSpan( + ForegroundCarColorSpan.create(CarColor.SECONDARY), + 0, + s.length, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + + paneBuilder.addRow( + Row.Builder() + .setTitle(CarStrings.get(R.string.car_cast)) + .addText(s) + .build() + ) + } + } + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarSession.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarSession.kt new file mode 100644 index 00000000000..0207176830b --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarSession.kt @@ -0,0 +1,31 @@ +package com.lagradost.cloudstream3.ui.car + +import android.content.Intent +import android.util.Log +import androidx.car.app.Screen +import androidx.car.app.Session +import androidx.lifecycle.coroutineScope +import com.lagradost.cloudstream3.plugins.PluginManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +class CarSession : Session() { + companion object { + private const val TAG = "CarSession" + } + + init { + lifecycle.coroutineScope.launch(Dispatchers.IO) { + try { + @Suppress("DEPRECATION_ERROR") + PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_loadAllOnlinePlugins(carContext) + } catch (e: Exception) { + Log.e(TAG, "Error loading plugins", e) + } + } + } + + override fun onCreateScreen(intent: Intent): Screen { + return MainCarScreen(carContext) + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarStrings.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarStrings.kt new file mode 100644 index 00000000000..3d27aab57f4 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/CarStrings.kt @@ -0,0 +1,51 @@ +package com.lagradost.cloudstream3.ui.car + +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import androidx.annotation.StringRes +import androidx.preference.PreferenceManager +import com.lagradost.cloudstream3.R +import java.util.Locale + +/** + * Singleton helper for Android Auto localization. + * Wraps Android Resources to support overriding the language based on app settings, + * independent of the system locale. + */ +object CarStrings { + private var resources: Resources? = null + + /** + * Initialize the helper with the application context. + * Call this in Application.onCreate(). + */ + fun init(context: Context) { + // Read user preference + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + val localeCode = prefs.getString(context.getString(R.string.locale_key), null) + + // If a specific locale is set (e.g. "it"), force it. + // Otherwise, use system default. + if (!localeCode.isNullOrEmpty()) { + val locale = Locale(localeCode) + val config = Configuration(context.resources.configuration) + config.setLocale(locale) + resources = context.createConfigurationContext(config).resources + } else { + resources = context.resources + } + } + + /** + * Get a localized string by Resource ID. + */ + fun get(@StringRes id: Int, vararg args: Any): String { + val res = resources ?: throw IllegalStateException("CarStrings not initialized! Call init() in Application.onCreate()") + return if (args.isEmpty()) { + res.getString(id) + } else { + res.getString(id, *args) + } + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/CategoryScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/CategoryScreen.kt new file mode 100644 index 00000000000..0c0cc4daf65 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/CategoryScreen.kt @@ -0,0 +1,108 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.CarIcon +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import androidx.core.graphics.drawable.toBitmap +import coil3.asDrawable +import coil3.request.ImageRequest +import coil3.size.Scale +import coil3.size.Precision +import coil3.SingletonImageLoader +import com.lagradost.cloudstream3.HomePageList +import com.lagradost.cloudstream3.R +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch + +class CategoryScreen( + carContext: CarContext, + private val homePageList: HomePageList +) : Screen(carContext) { + + private val scope = CoroutineScope(Dispatchers.IO + Job()) + private val iconCache = mutableMapOf() + private val loadingUrls = mutableSetOf() + + private fun loadIcon(imageUrl: String) { + if (loadingUrls.contains(imageUrl)) return + loadingUrls.add(imageUrl) + + scope.launch { + try { + val request = ImageRequest.Builder(carContext) + .data(imageUrl) + .size(256, 256) + .build() + val result = SingletonImageLoader.get(carContext).execute(request) + val bitmap = result.image?.asDrawable(carContext.resources)?.toBitmap() + if (bitmap != null) { + val icon = CarIcon.Builder(IconCompat.createWithBitmap(bitmap)).build() + synchronized(iconCache) { + iconCache[imageUrl] = icon + } + invalidate() + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + loadingUrls.remove(imageUrl) + } + } + } + + override fun onGetTemplate(): Template { + val listBuilder = ItemList.Builder() + + homePageList.list.forEach { item -> + val imageUrl = item.posterUrl + + // Check cache or trigger load + val icon = if (!imageUrl.isNullOrEmpty()) { + synchronized(iconCache) { + iconCache[imageUrl] + } ?: run { + loadIcon(imageUrl) + CarIcon.Builder(IconCompat.createWithResource(carContext, R.mipmap.ic_launcher)).build() + } + } else { + CarIcon.Builder(IconCompat.createWithResource(carContext, R.mipmap.ic_launcher)).build() + } + + // Use Row with LARGE image for maximum visibility in a list + val row = Row.Builder() + .setTitle(if (item.name.isNullOrEmpty()) "Untitled" else item.name) + .setImage(icon, Row.IMAGE_TYPE_LARGE) + .setOnClickListener { + val type = item.type + if (type == com.lagradost.cloudstream3.TvType.TvSeries || + type == com.lagradost.cloudstream3.TvType.Anime || + type == com.lagradost.cloudstream3.TvType.Cartoon || + type == com.lagradost.cloudstream3.TvType.OVA || + type == com.lagradost.cloudstream3.TvType.AsianDrama || + type == com.lagradost.cloudstream3.TvType.Documentary) { + screenManager.push(TvSeriesDetailScreen(carContext, item)) + } else if (type == com.lagradost.cloudstream3.TvType.Live) { + screenManager.push(PlayerCarScreen(carContext, item = item)) + } else { + screenManager.push(DetailsScreen(carContext, item)) + } + } + .build() + listBuilder.addItem(row) + } + + return ListTemplate.Builder() + .setTitle(homePageList.name) + .setHeaderAction(Action.BACK) + .setSingleList(listBuilder.build()) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/DetailsScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/DetailsScreen.kt new file mode 100644 index 00000000000..58d8d45d0e1 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/DetailsScreen.kt @@ -0,0 +1,270 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.CarColor +import androidx.car.app.model.Pane +import androidx.car.app.model.PaneTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import com.lagradost.cloudstream3.SearchResponse +import com.lagradost.cloudstream3.TvSeriesLoadResponse +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.TvType +import com.lagradost.cloudstream3.newTvSeriesSearchResponse +import com.lagradost.cloudstream3.ui.player.DownloadedPlayerActivity +import android.content.Intent +import android.net.Uri +import android.util.Log +import android.text.SpannableString +import android.text.Spanned +import androidx.car.app.model.CarIcon +import androidx.car.app.model.ForegroundCarColorSpan +import androidx.core.graphics.drawable.IconCompat +import androidx.core.graphics.drawable.toBitmap +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import coil3.asDrawable +import coil3.request.ImageRequest +import coil3.SingletonImageLoader +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.LoadResponse +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.ui.APIRepository +import com.lagradost.cloudstream3.utils.DataStoreHelper +import com.lagradost.cloudstream3.ui.result.ResultViewModel2 +import com.lagradost.cloudstream3.utils.DataStoreHelper.FavoritesData +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.MovieLoadResponse + +class DetailsScreen( + carContext: CarContext, + private val item: SearchResponse +) : Screen(carContext) { + + private var fullDetails: LoadResponse? = null + private var isLoading = true + private var errorMessage: String? = null + + private var posterBitmap: android.graphics.Bitmap? = null + private var isFavorite: Boolean = false + private val scope = CoroutineScope(Dispatchers.IO + Job()) + + // Selected source for playback + private var selectedSource: ExtractorLink? = null + + init { + loadData() + } + + private fun loadData() { + scope.launch { + try { + // Load Image + if (!item.posterUrl.isNullOrEmpty()) { + try { + val request = ImageRequest.Builder(carContext) + .data(item.posterUrl) + .data(item.posterUrl) + .size(600, 900) // Higher resolution for hero image + .build() + val result = SingletonImageLoader.get(carContext).execute(request) + posterBitmap = result.image?.asDrawable(carContext.resources)?.toBitmap() + } catch (e: Exception) { + e.printStackTrace() + } + } + + // Load Details + val api = getApiFromNameNull(item.apiName) + if (api != null) { + val repo = APIRepository(api) + when (val result = repo.load(item.url)) { + is Resource.Success -> { + fullDetails = result.value + + // Redirect if Type Mismatch (e.g. Provider reported Movie, but it's a Series) + // We check if the response is structurally a Series (has episodes etc) + // This fixes providers that return "Movie" type but provide series data. + if (result.value is TvSeriesLoadResponse) { + val detectedType = result.value.type + // If the provider says "Movie" but sends TvSeriesLoadResponse, force TvSeries type + val isTv = detectedType == TvType.TvSeries || + detectedType == TvType.Anime || + detectedType == TvType.Cartoon || + detectedType == TvType.OVA || + detectedType == TvType.AsianDrama || + detectedType == TvType.Documentary + + val finalType = if (isTv) detectedType else TvType.TvSeries + + val correctItem = api.newTvSeriesSearchResponse( + name = result.value.name, + url = result.value.url, + type = finalType, + ) { + this.posterUrl = result.value.posterUrl ?: item.posterUrl + } + withContext(Dispatchers.Main) { + screenManager.pop() + screenManager.push(TvSeriesDetailScreen(carContext, correctItem)) + } + return@launch + } + + // Check ID logic matches standard + val id = result.value.url.replace(api.mainUrl, "").replace("/", "").hashCode() + isFavorite = DataStoreHelper.getFavoritesData(id) != null + isLoading = false + } + is Resource.Failure -> { + errorMessage = result.errorString + isLoading = false + } + is Resource.Loading -> {} + } + } else { + errorMessage = CarStrings.get(R.string.car_provider_not_found) + isLoading = false + } + } catch (e: Exception) { + errorMessage = e.message + isLoading = false + } + invalidate() + } + } + + override fun onGetTemplate(): Template { + val paneBuilder = Pane.Builder() + + if (isLoading) { + paneBuilder.setLoading(true) + } else { + buildContent(paneBuilder) + } + + buildActions(paneBuilder) + + return PaneTemplate.Builder(paneBuilder.build()) + .setTitle(fullDetails?.name ?: item.name) + .setHeaderAction(Action.BACK) + .build() + } + + private fun buildContent(paneBuilder: Pane.Builder) { + val details = fullDetails + + // Header: Title + paneBuilder.addRow( + Row.Builder() + .setTitle(details?.name ?: item.name) + .build() + ) + + // Set Hero Image on the Pane itself for maximum size + posterBitmap?.let { + paneBuilder.setImage(CarIcon.Builder(IconCompat.createWithBitmap(it)).build()) + } ?: run { + paneBuilder.setImage(CarIcon.Builder(IconCompat.createWithResource(carContext, R.mipmap.ic_launcher)).build()) + } + + if (details != null) { + // Meta Row: Year • Rating • Duration + val metaStringBuilder = StringBuilder() + details.year?.let { metaStringBuilder.append("$it") } + + // Add Score if available + val score = details.score + if (score != null) { + if (metaStringBuilder.isNotEmpty()) metaStringBuilder.append(" • ") + metaStringBuilder.append(String.format("%.1f/10", score.toDouble(10))) + } + + details.duration?.let { + if (metaStringBuilder.isNotEmpty()) metaStringBuilder.append(" • ") + metaStringBuilder.append("${it}m") + } + + if (metaStringBuilder.isNotEmpty()) { + paneBuilder.addRow( + Row.Builder() + .setTitle(metaStringBuilder.toString()) + .build() + ) + } + + // Plot and Cast + CarHelper.addPlotAndCast(paneBuilder, details) + } else if (errorMessage != null) { + paneBuilder.addRow(Row.Builder().setTitle("${CarStrings.get(R.string.car_error)}: $errorMessage").build()) + } + } + + private fun buildActions(paneBuilder: Pane.Builder) { + // Play Button: White background with Black Icon + val playIcon = IconCompat.createWithResource(carContext, android.R.drawable.ic_media_play) + .setTint(android.graphics.Color.BLACK) + + val playAction = Action.Builder() + .setIcon(CarIcon.Builder(playIcon).build()) + .setBackgroundColor(CarColor.createCustom(android.graphics.Color.WHITE, android.graphics.Color.WHITE)) + .setOnClickListener { + screenManager.push(PlayerCarScreen( + carContext = carContext, + item = item, + preSelectedSource = selectedSource + )) + } + .build() + + // Source Selection Button + val sourceIcon = IconCompat.createWithResource(carContext, R.drawable.ic_baseline_source_24) + + val sourceActionTitle = if (selectedSource != null) { + selectedSource!!.name + } else { + CarStrings.get(R.string.car_source) + } + + val sourceAction = Action.Builder() + .setIcon(CarIcon.Builder(sourceIcon).build()) + .setTitle(sourceActionTitle) + .setOnClickListener { + val details = fullDetails + val dataUrl = when (details) { + is MovieLoadResponse -> details.dataUrl + else -> details?.url + } + if (dataUrl != null && details != null) { + screenManager.push( + SourceSelectionScreen( + carContext = carContext, + apiName = details.apiName, + dataUrl = dataUrl, + currentSourceUrl = selectedSource?.url, + onSourceSelected = { source -> + selectedSource = source + invalidate() + } + ) + ) + } + } + .build() + + paneBuilder.addAction(playAction) + paneBuilder.addAction(sourceAction) + } + + private fun toggleFavorite() { + CarHelper.toggleFavorite(carContext, fullDetails, isFavorite) { newStatus -> + isFavorite = newStatus + invalidate() + } + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/DownloadsScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/DownloadsScreen.kt new file mode 100644 index 00000000000..424d3bbb116 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/DownloadsScreen.kt @@ -0,0 +1,213 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import com.lagradost.cloudstream3.utils.VideoDownloadHelper +import com.lagradost.cloudstream3.utils.VideoDownloadManager +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.utils.DataStore.getKey +import com.lagradost.cloudstream3.utils.DataStore.getKeys +import com.lagradost.cloudstream3.utils.DataStoreHelper +import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE +import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE +import com.lagradost.cloudstream3.utils.DataStore.getFolderName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import com.lagradost.cloudstream3.isEpisodeBased + +class DownloadsScreen( + carContext: CarContext, + private val parentId: Int? = null, + private val headerName: String? = null +) : Screen(carContext) { + private val scope = CoroutineScope(Dispatchers.IO) + private var itemList: ItemList? = null + + init { + loadContent() + } + + private fun loadContent() { + if (parentId != null) { + loadEpisodes(parentId) + } else { + loadHeaders() + } + } + + private fun loadEpisodes(id: Int) { + scope.launch { + val context = carContext + val children = context.getKeys(DOWNLOAD_EPISODE_CACHE) + .mapNotNull { context.getKey(it) } + .filter { it.parentId == id } + .filter { + val info = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(context, it.id) + (info?.fileLength ?: 0L) > 0 + } + .sortedWith(compareBy({ it.season }, { it.episode })) + + val builder = ItemList.Builder() + + if (children.isEmpty()) { + builder.setNoItemsMessage(CarStrings.get(R.string.car_no_episodes_found)) + } else { + children.forEach { episode -> + val name = "S${episode.season}:E${episode.episode} - ${episode.name ?: CarStrings.get(R.string.car_episode)}" + builder.addItem( + Row.Builder() + .setTitle(name) + .setOnClickListener { + playEpisode(episode.id, id) + } + .build() + ) + } + } + + val builtList = builder.build() + withContext(Dispatchers.Main) { + itemList = builtList + invalidate() + } + } + } + + private fun loadHeaders() { + scope.launch { + val headers = carContext.getKeys(DOWNLOAD_HEADER_CACHE) + .mapNotNull { carContext.getKey(it) } + .sortedBy { it.name } + + val builder = ItemList.Builder() + + // Filter and find valid items + val validHeaders = headers.filter { header -> + val context = carContext + val id = header.id + + // Get all children (episodes or movies) for this header + val children = context.getKeys(DOWNLOAD_EPISODE_CACHE) + .mapNotNull { context.getKey(it) } + .filter { it.parentId == id } + + // Check if AT LEAST ONE child is valid (> 0 bytes) + children.any { child -> + val info = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(context, child.id) + (info?.fileLength ?: 0L) > 0 + } + } + + if (validHeaders.isEmpty()) { + builder.setNoItemsMessage(CarStrings.get(R.string.car_no_downloads_found)) + } else { + validHeaders.forEach { header -> + val lastWatched = DataStoreHelper.getLastWatched(header.id) + val subtitle = if (lastWatched != null && lastWatched.season != null && lastWatched.episode != null) { + "S${lastWatched.season}E${lastWatched.episode}" + } else { + null + } + + val rowBuilder = Row.Builder() + .setTitle(header.name) + .setOnClickListener { + onHeaderClick(header) + } + + if (subtitle != null) { + rowBuilder.addText(subtitle) + } + + builder.addItem(rowBuilder.build()) + } + } + + val builtList = builder.build() + withContext(Dispatchers.Main) { + itemList = builtList + invalidate() + } + } + } + + private fun playEpisode(episodeId: Int, parentId: Int) { + scope.launch { + val context = carContext + val fileInfo = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(context, episodeId) + if (fileInfo?.path == null) { + withContext(Dispatchers.Main) { + androidx.car.app.CarToast.makeText(carContext, CarStrings.get(R.string.car_file_not_found), androidx.car.app.CarToast.LENGTH_SHORT).show() + } + return@launch + } + + // Get saved resume position + val savedPos = DataStoreHelper.getViewPos(episodeId) + val startTime = savedPos?.position ?: 0L + + withContext(Dispatchers.Main) { + screenManager.push( + PlayerCarScreen( + carContext = carContext, + fileUri = fileInfo.path.toString(), + videoId = episodeId, + parentId = parentId, + startTime = startTime + ) + ) + } + } + } + + private fun onHeaderClick(header: VideoDownloadHelper.DownloadHeaderCached) { + scope.launch { + val context = carContext + val id = header.id + + // Get children + val children = context.getKeys(DOWNLOAD_EPISODE_CACHE) + .mapNotNull { context.getKey(it) } + .filter { it.parentId == id } + .filter { + val info = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(context, it.id) + (info?.fileLength ?: 0L) > 0 + } + + if (children.isEmpty()) { + withContext(Dispatchers.Main) { + androidx.car.app.CarToast.makeText(carContext, CarStrings.get(R.string.car_no_valid_episode), androidx.car.app.CarToast.LENGTH_SHORT).show() + } + return@launch + } + + if (header.type.isEpisodeBased()) { + // Series: Always go to episode list + withContext(Dispatchers.Main) { + screenManager.push(DownloadsScreen(carContext, id, header.name)) + } + } else { + // Movie: Just pick the first/only one + val episodeId = children.firstOrNull()?.id + if (episodeId != null) { + playEpisode(episodeId, id) + } + } + } + } + + override fun onGetTemplate(): Template { + return ListTemplate.Builder() + .setTitle(headerName ?: CarStrings.get(R.string.car_downloads)) + .setHeaderAction(Action.BACK) + .setSingleList(itemList ?: ItemList.Builder().setNoItemsMessage(CarStrings.get(R.string.car_loading)).build()) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/EpisodeDetailScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/EpisodeDetailScreen.kt new file mode 100644 index 00000000000..84060f26909 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/EpisodeDetailScreen.kt @@ -0,0 +1,155 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.CarColor +import androidx.car.app.model.CarIcon +import androidx.car.app.model.Pane +import androidx.car.app.model.PaneTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import androidx.core.graphics.drawable.toBitmap +import coil3.asDrawable +import coil3.request.ImageRequest +import coil3.SingletonImageLoader +import com.lagradost.cloudstream3.Episode +import com.lagradost.cloudstream3.TvSeriesLoadResponse +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos +import com.lagradost.cloudstream3.utils.ExtractorLink +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch + +class EpisodeDetailScreen( + carContext: CarContext, + private val seriesDetails: TvSeriesLoadResponse, + private val episode: Episode, + private val playlist: List +) : Screen(carContext) { + + private val scope = CoroutineScope(Dispatchers.IO + Job()) + private var posterBitmap: android.graphics.Bitmap? = null + private var isLoadingImage = true + + // Selected source for playback + private var selectedSource: ExtractorLink? = null + + init { + loadImage() + } + + private fun loadImage() { + scope.launch { + // Try episode poster first, then series poster + val url = episode.posterUrl ?: seriesDetails.posterUrl + if (!url.isNullOrEmpty()) { + try { + val request = ImageRequest.Builder(carContext) + .data(url) + .size(600, 900) + .build() + val result = SingletonImageLoader.get(carContext).execute(request) + posterBitmap = result.image?.asDrawable(carContext.resources)?.toBitmap() + } catch (e: Exception) { + e.printStackTrace() + } + } + isLoadingImage = false + invalidate() + } + } + + override fun onGetTemplate(): Template { + val paneBuilder = Pane.Builder() + + // Title Row + val title = "${episode.episode}. ${episode.name ?: "${CarStrings.get(R.string.car_episode)} ${episode.episode}"}" + paneBuilder.addRow( + Row.Builder() + .setTitle(title) + .addText("${CarStrings.get(R.string.car_season)} ${episode.season ?: "?"}") + .build() + ) + + // Image + posterBitmap?.let { + paneBuilder.setImage(CarIcon.Builder(IconCompat.createWithBitmap(it)).build()) + } ?: run { + // Fallback icon if no image loaded yet or error + paneBuilder.setImage(CarIcon.Builder(IconCompat.createWithResource(carContext, R.mipmap.ic_launcher)).build()) + } + + // Description Row + if (!episode.description.isNullOrEmpty()) { + paneBuilder.addRow( + Row.Builder() + .setTitle(CarStrings.get(R.string.car_plot)) + .addText(episode.description!!) + .build() + ) + } + + // Play Button action + val playIcon = IconCompat.createWithResource(carContext, android.R.drawable.ic_media_play) + .setTint(android.graphics.Color.BLACK) + + val playAction = Action.Builder() + .setIcon(CarIcon.Builder(playIcon).build()) + .setBackgroundColor(CarColor.createCustom(android.graphics.Color.WHITE, android.graphics.Color.WHITE)) + .setOnClickListener { + // Get saved position for resume + val startTime = getViewPos(episode.data.hashCode())?.position ?: 0L + screenManager.push( + PlayerCarScreen( + carContext = carContext, + loadResponse = seriesDetails, + selectedEpisode = episode, + playlist = playlist, + startTime = startTime, + preSelectedSource = selectedSource + ) + ) + } + .build() + + // Source Selection Button + val sourceIcon = IconCompat.createWithResource(carContext, R.drawable.ic_baseline_source_24) + + val sourceActionTitle = if (selectedSource != null) { + selectedSource!!.name + } else { + CarStrings.get(R.string.car_source) + } + + val sourceAction = Action.Builder() + .setIcon(CarIcon.Builder(sourceIcon).build()) + .setTitle(sourceActionTitle) + .setOnClickListener { + screenManager.push( + SourceSelectionScreen( + carContext = carContext, + apiName = seriesDetails.apiName, + dataUrl = episode.data, + currentSourceUrl = selectedSource?.url, + onSourceSelected = { source -> + selectedSource = source + invalidate() + } + ) + ) + } + .build() + + paneBuilder.addAction(playAction) + paneBuilder.addAction(sourceAction) + + return PaneTemplate.Builder(paneBuilder.build()) + .setTitle(seriesDetails.name) // Header Title is Series Name + .setHeaderAction(Action.BACK) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/EpisodeListScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/EpisodeListScreen.kt new file mode 100644 index 00000000000..44c3fe6baa3 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/EpisodeListScreen.kt @@ -0,0 +1,98 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.ActionStrip +import androidx.car.app.model.CarIcon +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import com.lagradost.cloudstream3.TvSeriesLoadResponse +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos + +class EpisodeListScreen( + carContext: CarContext, + private val details: TvSeriesLoadResponse, + private val isExpressMode: Boolean = false +) : Screen(carContext) { + + private val availableSeasons: List = details.episodes.mapNotNull { it.season }.distinct().sorted() + private var currentSeasonIndex: Int = 0 // Index in availableSeasons list + + override fun onGetTemplate(): Template { + if (availableSeasons.isEmpty()) { + return ListTemplate.Builder() + .setTitle(details.name) + .setHeaderAction(Action.BACK) + .setSingleList(ItemList.Builder().addItem(Row.Builder().setTitle(CarStrings.get(R.string.car_no_episodes_found)).build()).build()) + .build() + } + + val currentSeason = availableSeasons[currentSeasonIndex] + val seasonEpisodes = details.episodes.filter { it.season == currentSeason }.sortedBy { it.episode } + + val listBuilder = ItemList.Builder() + + seasonEpisodes.forEach { episode -> + val title = "${episode.episode}. ${episode.name ?: "${CarStrings.get(R.string.car_episode)} ${episode.episode}"}" + val rowBuilder = Row.Builder() + .setTitle(title) + .setOnClickListener { + if (isExpressMode) { + // Get saved position for resume + val startTime = getViewPos(episode.data.hashCode())?.position ?: 0L + screenManager.push( + PlayerCarScreen( + carContext = carContext, + loadResponse = details, + selectedEpisode = episode, + playlist = seasonEpisodes, + startTime = startTime + ) + ) + } else { + screenManager.push( + EpisodeDetailScreen( + carContext = carContext, + seriesDetails = details, + episode = episode, + playlist = seasonEpisodes + ) + ) + } + } + + episode.description?.let { + // Truncate to avoid huge texts, though AA handles some wrapping + val desc = if (it.length > 100) it.substring(0, 97) + "..." else it + rowBuilder.addText(desc) + } + + listBuilder.addItem(rowBuilder.build()) + } + + val seasonAction = Action.Builder() + .setTitle("${CarStrings.get(R.string.car_season)} $currentSeason") + .setOnClickListener { + // Cycle through seasons + currentSeasonIndex = (currentSeasonIndex + 1) % availableSeasons.size + invalidate() + } + .build() + + return ListTemplate.Builder() + .setTitle("${details.name} - ${CarStrings.get(R.string.car_season)} $currentSeason") + .setHeaderAction(Action.BACK) + .setSingleList(listBuilder.build()) + .setActionStrip( + ActionStrip.Builder() + .addAction(seasonAction) + .build() + ) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/HistoryScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/HistoryScreen.kt new file mode 100644 index 00000000000..2e7d92e484b --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/HistoryScreen.kt @@ -0,0 +1,218 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import android.util.Log +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds +import com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched +import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos +import com.lagradost.cloudstream3.utils.VideoDownloadHelper +import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.ui.APIRepository +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.TvSeriesLoadResponse +import com.lagradost.cloudstream3.SearchResponse +import com.lagradost.cloudstream3.newMovieSearchResponse +import com.lagradost.cloudstream3.newTvSeriesSearchResponse +import com.lagradost.cloudstream3.isMovieType +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import kotlinx.coroutines.delay + +class HistoryScreen(carContext: CarContext) : Screen(carContext), DefaultLifecycleObserver { + private val scope = CoroutineScope(Dispatchers.IO) + private var itemList: ItemList? = null + + init { + lifecycle.addObserver(this) + } + + override fun onStart(owner: LifecycleOwner) { + loadHistory() + } + + private fun loadHistory(retryCount: Int = 0) { + scope.launch { + withContext(Dispatchers.Main) { + itemList = null + invalidate() + } + try { + // Strict logic copied from HomeViewModel.getResumeWatching() + val resumeWatchingResult = withContext(Dispatchers.IO) { + val ids = getAllResumeStateIds() + Log.d("HistoryDebug", "Loading history. IDs found: ${ids?.size ?: 0}") + ids?.mapNotNull { id -> + getLastWatched(id) + }?.sortedBy { -it.updateTime }?.mapNotNull { resume -> + val data = getKey( + DOWNLOAD_HEADER_CACHE, + resume.parentId.toString() + ) + if (data == null) { + Log.e("HistoryDebug", "MISSING HEADER for parentId: ${resume.parentId}") + return@mapNotNull null + } + Log.d("HistoryDebug", "Found HEADER for parentId: ${resume.parentId} -> ${data.name}") + + Pair(resume, data) + } + } + + val builder = ItemList.Builder() + + if (resumeWatchingResult.isNullOrEmpty()) { + builder.setNoItemsMessage(CarStrings.get(R.string.car_no_continue_watching)) + } else { + resumeWatchingResult.forEach { (resume, cachedData) -> + val title = cachedData.name + val subtitle = if (resume.episode != null && resume.season != null) { + "S${resume.season}E${resume.episode} (${cachedData.apiName})" + } else { + cachedData.apiName + } + + builder.addItem( + Row.Builder() + .setTitle(title) + .addText(subtitle) + .setOnClickListener { + playResumeItem(resume, cachedData) + } + .build() + ) + } + } + + val builtList = builder.build() + withContext(Dispatchers.Main) { + itemList = builtList + invalidate() + } + } catch (e: Exception) { + if (retryCount < 3) { + delay(3000) + loadHistory(retryCount + 1) + } else { + withContext(Dispatchers.Main) { + itemList = ItemList.Builder() + .addItem( + Row.Builder() + .setTitle("Errore: ${e.message}") + .setOnClickListener { loadHistory() } + .build() + ) + .build() + invalidate() + } + } + } + } + } + + private fun playResumeItem(resume: VideoDownloadHelper.ResumeWatching, cachedData: VideoDownloadHelper.DownloadHeaderCached) { + scope.launch { + withContext(Dispatchers.Main) { + androidx.car.app.CarToast.makeText(carContext, CarStrings.get(R.string.car_resuming, cachedData.name), androidx.car.app.CarToast.LENGTH_LONG).show() + } + + val api = getApiFromNameNull(cachedData.apiName) ?: return@launch + val repo = APIRepository(api) + + val loadResult = when(val result = repo.load(cachedData.url)) { + is Resource.Success -> result.value + else -> null + } ?: return@launch + + if (loadResult is TvSeriesLoadResponse) { + // Find the specific episode to resume + // resume.episodeId should match episode.data.hashCode() used by PlayerCarScreen + val episodeToResume = loadResult.episodes.find { episode -> + // Promiscuous check: try multiple ways to match the episode + // Note: Episode class does not have an 'id' field, so we skip direct ID check + val urlHashMatch = episode.data.hashCode() == resume.episodeId + val numberMatch = episode.episode == resume.episode && episode.season == resume.season + + urlHashMatch || numberMatch + } + + if (episodeToResume != null) { + val startTime = getViewPos(resume.episodeId)?.position ?: 0L + val seasonEpisodes = loadResult.episodes.filter { it.season == episodeToResume.season } + + withContext(Dispatchers.Main) { + screenManager.push( + PlayerCarScreen( + carContext = carContext, + loadResponse = loadResult, + selectedEpisode = episodeToResume, + playlist = seasonEpisodes, + startTime = startTime + ) + ) + } + } else { + // Fallback to episode list if episode not found + withContext(Dispatchers.Main) { + screenManager.push(EpisodeListScreen(carContext, loadResult, isExpressMode = true)) + } + } + } else { + val startTime = getViewPos(resume.episodeId)?.position ?: 0L + + // Prepare SearchResponse item for PlayerCarScreen + val item: SearchResponse = if (cachedData.type.isMovieType()) { + api.newMovieSearchResponse( + name = cachedData.name, + url = cachedData.url, + type = cachedData.type, + ) { + this.posterUrl = cachedData.poster + } + } else { + api.newTvSeriesSearchResponse( + name = cachedData.name, + url = cachedData.url, + type = cachedData.type, + ) { + this.posterUrl = cachedData.poster + } + } + + withContext(Dispatchers.Main) { + screenManager.push( + PlayerCarScreen( + carContext = carContext, + item = item, + loadResponse = loadResult, + selectedEpisode = null, + startTime = startTime + ) + ) + } + } + } + } + + override fun onGetTemplate(): Template { + val list = itemList ?: ItemList.Builder().setNoItemsMessage(CarStrings.get(R.string.car_loading)).build() + + return ListTemplate.Builder() + .setTitle(CarStrings.get(R.string.car_history)) + .setHeaderAction(Action.BACK) + .setSingleList(list) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/LibraryCarScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/LibraryCarScreen.kt new file mode 100644 index 00000000000..50dbb980a26 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/LibraryCarScreen.kt @@ -0,0 +1,44 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.utils.DataStoreHelper +import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData +import com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +class LibraryCarScreen(carContext: CarContext) : Screen(carContext) { + + override fun onGetTemplate(): Template { + return ListTemplate.Builder() + .setSingleList( + ItemList.Builder() + .addItem( + Row.Builder() + .setTitle(CarStrings.get(R.string.car_bookmarks)) + .setOnClickListener { screenManager.push(BookmarksScreen(carContext)) } + .setBrowsable(true) + .build() + ) + .addItem( + Row.Builder() + .setTitle(CarStrings.get(R.string.car_history)) + .setOnClickListener { screenManager.push(HistoryScreen(carContext)) } + .setBrowsable(true) + .build() + ) + .build() + ) + .setTitle(CarStrings.get(R.string.car_library)) + .setHeaderAction(Action.BACK) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/MainCarScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/MainCarScreen.kt new file mode 100644 index 00000000000..14177dc66ff --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/MainCarScreen.kt @@ -0,0 +1,213 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.ActionStrip +import androidx.car.app.model.CarIcon +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.SectionedItemList +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.HomePageList +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.ui.APIRepository +import com.lagradost.cloudstream3.utils.DataStoreHelper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class MainCarScreen(carContext: CarContext) : Screen(carContext), DefaultLifecycleObserver { + private var homePageLists: List = emptyList() + private var isLoading = true + private var errorMessage: String? = null + private var currentApiName: String = "" + + companion object { + private const val LOADING_DELAY_MS = 500L + private const val MAX_LOADING_ATTEMPTS = 20 + } + + init { + lifecycle.addObserver(this) + } + + override fun onResume(owner: LifecycleOwner) { + super.onResume(owner) + // Reload data on resume to catch provider changes + loadData() + } + + private fun loadData() { + isLoading = true + errorMessage = null + currentApiName = DataStoreHelper.currentHomePage ?: "" + invalidate() + + CoroutineScope(Dispatchers.IO).launch { + try { + var api = getApiFromNameNull(currentApiName) + var attempts = 0 + // Retry waiting for plugins to load + while (api == null && attempts < MAX_LOADING_ATTEMPTS) { + delay(LOADING_DELAY_MS) + api = getApiFromNameNull(currentApiName) + attempts++ + } + + if (api == null) { + errorMessage = "${CarStrings.get(R.string.car_provider_not_found)}: $currentApiName" + isLoading = false + invalidate() + return@launch + } + + val repo = APIRepository(api) + when (val result = repo.getMainPage(1, null)) { + is Resource.Success -> { + homePageLists = result.value.filterNotNull().flatMap { it.items } + isLoading = false + } + is Resource.Failure -> { + errorMessage = result.errorString ?: CarStrings.get(R.string.car_loading_content) + isLoading = false + } + is Resource.Loading -> {} + } + } catch (e: Exception) { + errorMessage = e.message + isLoading = false + } + invalidate() + } + } + + override fun onGetTemplate(): Template { + return ListTemplate.Builder() + .setTitle(carContext.getString(R.string.app_name)) + .addSectionedList( + SectionedItemList.create( + buildMenuSection(), + CarStrings.get(R.string.car_menu) + ) + ) + .addSectionedList( + SectionedItemList.create( + buildContentSection(), + CarStrings.get(R.string.car_home_content) + ) + ) + .setActionStrip(buildActionStrip()) + .build() + } + + private fun buildMenuSection(): ItemList { + val menuListBuilder = ItemList.Builder() + + menuListBuilder.addItem( + createMenuRow( + title = CarStrings.get(R.string.car_favorites), + iconRes = R.drawable.ic_baseline_favorite_24, + screen = { BookmarksScreen(carContext) } + ) + ) + + menuListBuilder.addItem( + createMenuRow( + title = CarStrings.get(R.string.car_history), + iconRes = android.R.drawable.ic_menu_recent_history, + screen = { HistoryScreen(carContext) } + ) + ) + + menuListBuilder.addItem( + createMenuRow( + title = CarStrings.get(R.string.car_downloads), + iconRes = android.R.drawable.stat_sys_download, + screen = { DownloadsScreen(carContext) } + ) + ) + + menuListBuilder.addItem( + Row.Builder() + .setTitle(CarStrings.get(R.string.car_provider)) + .addText("${CarStrings.get(R.string.car_current)}: $currentApiName") + .setImage(CarIcon.Builder(IconCompat.createWithResource(carContext, android.R.drawable.ic_menu_manage)).build()) + .setOnClickListener { screenManager.push(ProviderCarScreen(carContext)) } + .setBrowsable(true) + .build() + ) + + menuListBuilder.addItem( + createMenuRow( + title = CarStrings.get(R.string.car_about_me), + iconRes = android.R.drawable.ic_menu_info_details, + screen = { AboutMeScreen(carContext) } + ) + ) + + return menuListBuilder.build() + } + + private fun createMenuRow(title: String, iconRes: Int, screen: () -> Screen): Row { + return Row.Builder() + .setTitle(title) + .setImage(CarIcon.Builder(IconCompat.createWithResource(carContext, iconRes)).build()) + .setOnClickListener { screenManager.push(screen()) } + .setBrowsable(true) + .build() + } + + private fun buildContentSection(): ItemList { + val contentListBuilder = ItemList.Builder() + + if (isLoading) { + contentListBuilder.addItem(Row.Builder().setTitle(CarStrings.get(R.string.car_loading)).setBrowsable(false).build()) + } else if (errorMessage != null) { + contentListBuilder.addItem(Row.Builder().setTitle("${CarStrings.get(R.string.car_error)}: $errorMessage").setBrowsable(false).build()) + } else if (homePageLists.isEmpty()) { + contentListBuilder.addItem(Row.Builder().setTitle(CarStrings.get(R.string.car_no_content_from_provider)).setBrowsable(false).build()) + } else { + homePageLists.forEach { homePageList -> + contentListBuilder.addItem( + Row.Builder() + .setTitle(homePageList.name) + .setOnClickListener { + screenManager.push(CategoryScreen(carContext, homePageList)) + } + .setBrowsable(true) + .build() + ) + } + } + return contentListBuilder.build() + } + + private fun buildActionStrip(): ActionStrip { + return ActionStrip.Builder() + .addAction( + Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, android.R.drawable.ic_menu_search)).build()) + .setOnClickListener { + screenManager.push(SearchCarScreen(carContext)) + } + .build() + ) + .addAction( + Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_refresh)).build()) + .setOnClickListener { + loadData() + } + .build() + ) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/PlayerCarScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/PlayerCarScreen.kt new file mode 100644 index 00000000000..76cc34e1980 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/PlayerCarScreen.kt @@ -0,0 +1,704 @@ +package com.lagradost.cloudstream3.ui.car + +import android.view.Surface +import androidx.car.app.AppManager +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.SurfaceCallback +import androidx.car.app.SurfaceContainer +import androidx.car.app.model.Action +import androidx.car.app.model.ActionStrip +import androidx.car.app.model.CarColor +import androidx.car.app.model.Template +import androidx.car.app.navigation.model.NavigationTemplate +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import androidx.media3.common.AudioAttributes +import androidx.media3.common.C +import androidx.media3.common.MediaItem +import androidx.media3.common.MimeTypes +import androidx.media3.common.Player +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.session.MediaSession +import androidx.car.app.model.CarIcon +import androidx.core.graphics.drawable.IconCompat +import com.lagradost.cloudstream3.R +import androidx.media3.common.MediaMetadata +import android.net.Uri +import coil3.request.ImageRequest +import coil3.SingletonImageLoader +import coil3.asDrawable +import androidx.core.graphics.drawable.toBitmap +import androidx.media3.common.C.VIDEO_SCALING_MODE_SCALE_TO_FIT +import androidx.media3.common.C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.SearchResponse +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.ui.APIRepository +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE +import com.lagradost.cloudstream3.utils.VideoDownloadHelper +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey +import com.lagradost.cloudstream3.utils.DataStoreHelper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import android.util.Log +import com.lagradost.cloudstream3.utils.DataStore +import com.lagradost.cloudstream3.utils.DataStore.getKey +import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE +import com.lagradost.cloudstream3.Episode + +import com.lagradost.cloudstream3.LoadResponse +import com.lagradost.cloudstream3.TvSeriesLoadResponse +import com.lagradost.cloudstream3.AnimeLoadResponse +import com.lagradost.cloudstream3.MovieLoadResponse +import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual +import com.lagradost.cloudstream3.TvType +import kotlinx.coroutines.delay + +class PlayerCarScreen( + carContext: CarContext, + val item: SearchResponse? = null, + val loadResponse: LoadResponse? = null, + val selectedEpisode: Episode? = null, + val playlist: List? = null, + val startTime: Long = 0L, + val fileUri: String? = null, + val videoId: Int? = null, + val parentId: Int? = null, + val preSelectedSource: ExtractorLink? = null +) : Screen(carContext), SurfaceCallback { + + private var activeEpisode: Episode? = selectedEpisode + private val scope = CoroutineScope(Dispatchers.IO + Job()) + private var player: ExoPlayer? = null + private var surface: Surface? = null + private var mediaSession: MediaSession? = null + private var isPlaying = true + + private var resizeMode = VIDEO_SCALING_MODE_SCALE_TO_FIT + + private var currentEpisodeId: Int? = null + private var currentParentId: Int? = null + private var saveProgressJob: Job? = null + private var showSeekControls = false + + init { + lifecycle.addObserver(object : LifecycleEventObserver { + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + when (event) { + Lifecycle.Event.ON_START -> { + carContext.getCarService(AppManager::class.java).setSurfaceCallback(this@PlayerCarScreen) + player?.playWhenReady = true + } + Lifecycle.Event.ON_STOP -> { + player?.playWhenReady = false + saveProgress() + carContext.getCarService(AppManager::class.java).setSurfaceCallback(null) + } + Lifecycle.Event.ON_DESTROY -> { + mediaSession?.release() + mediaSession = null + player?.release() + player = null + scope.cancel() + } + else -> {} + } + } + }) + + if (fileUri != null) { + currentEpisodeId = videoId + currentParentId = parentId + + // Fix: Populate selectedEpisode metadata for Downloads so saveProgress works correctly + if (this.activeEpisode == null) { + scope.launch(Dispatchers.IO) { + try { + val cachedEp = carContext.getKey( + DOWNLOAD_EPISODE_CACHE, + videoId.toString() + ) + if (cachedEp != null) { + @Suppress("DEPRECATION_ERROR") + val ep = Episode( + data = "", // URL not available in cache, but ID is used from videoId so acceptable + name = cachedEp.name, + season = cachedEp.season, + episode = cachedEp.episode, + posterUrl = cachedEp.poster + ) + this@PlayerCarScreen.activeEpisode = ep + Log.d("PlayerCarScreen", "Populated activeEpisode from Download: S${cachedEp.season} E${cachedEp.episode}") + } + } catch (e: Exception) { + Log.e("PlayerCarScreen", "Error loading download metadata", e) + } + withContext(Dispatchers.Main) { + startPlayback(fileUri) + } + } + } else { + scope.launch { startPlayback(fileUri) } + } + } else { + loadMedia(item?.url) + } + } + + override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) { + val newSurface = surfaceContainer.surface + if (newSurface != null) { + surface = newSurface + player?.setVideoSurface(newSurface) + } + } + + override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) { + surface = null + player?.setVideoSurface(null) + } + + private fun loadMedia(url: String?) { + updateStatus(CarStrings.get(R.string.car_loading)) + scope.launch { + val data = getLoadResponse() + + if (data == null) { + if (item?.type == TvType.Live) { + Log.d("PlayerCarScreen", "Details load failed, attempting direct playback for Live content") + withContext(Dispatchers.Main) { + startPlayback(item!!.url) + } + return@launch + } + showToast(CarStrings.get(R.string.car_unable_to_load_details)) + return@launch + } + + resolveIds(data) + loadLinks(data) + } + } + + private suspend fun getLoadResponse(): LoadResponse? { + // If we already have the LoadResponse (passed from Details), use it. + // Otherwise, fetch it using item.url + return if (loadResponse != null) { + loadResponse + } else if (item != null) { + val apiName = item.apiName + val api = getApiFromNameNull(apiName) ?: return null + val repo = APIRepository(api) + try { + when(val result = repo.load(item.url)) { + is Resource.Success -> result.value + else -> null + } + } catch (e: Exception) { + Log.e("PlayerCarScreen", "Error loading details for ${item.url}", e) + null + } + } else { + null + } + } + + private fun resolveIds(data: LoadResponse) { + val apiName = data.apiName + val api = getApiFromNameNull(apiName) ?: return + + // Resolve IDs for syncing BEFORE starting playback + // This ensures IDs are available for saveProgress() calls during playback + val mainUrl = api.mainUrl + val idFromUrl = data.url.replace(mainUrl, "").replace("/", "").hashCode() + + // Priority: 1. Item ID (if available from Home/Search and valid) + // 2. Data URL Hashcode (using strict cleaning logic) + currentParentId = item?.id ?: idFromUrl + saveHeaderCache(data) + + if (data is TvSeriesLoadResponse && activeEpisode != null) { + currentEpisodeId = activeEpisode!!.data.hashCode() + } else { + // For movies, we use the parent ID + currentEpisodeId = currentParentId + } + + Log.d("PlayerCarScreen", "Resolved IDs (STRICT) - Name: ${data.name} | Parent: $currentParentId | Episode: $currentEpisodeId | Type: ${data.javaClass.simpleName} | ItemID: ${item?.id} | IdFromUrl: $idFromUrl") + } + + private suspend fun loadLinks(data: LoadResponse) { + val apiName = data.apiName + val api = getApiFromNameNull(apiName) ?: return + val links = mutableListOf() + try { + val urlToLoad = when { + activeEpisode != null -> activeEpisode!!.data + data is com.lagradost.cloudstream3.TvSeriesLoadResponse -> { + // Auto-select first episode if none selected + data.episodes.firstOrNull()?.data + } + data is com.lagradost.cloudstream3.AnimeLoadResponse -> { + // Auto-select first episode from first available category + data.episodes.values.flatten().firstOrNull()?.data + } + data is com.lagradost.cloudstream3.MovieLoadResponse -> { + data.dataUrl + } + else -> data.url + } + + if (urlToLoad == null) { + showToast(CarStrings.get(R.string.car_no_playable_content)) + return + } + + // Use pre-selected source if provided, otherwise load and auto-select best + if (preSelectedSource != null) { + startPlayback(preSelectedSource) + } else { + // Load links using the API + val success = api.loadLinks(urlToLoad, false, {}, { link -> + links.add(link) + }) + + if(links.isNotEmpty()) { + val bestLink = links.sortedByDescending { it.quality }.first() + startPlayback(bestLink) + } else { + showToast(CarStrings.get(R.string.car_no_link_found)) + } + } + } catch (e: Exception) { + showToast("${CarStrings.get(R.string.car_error_loading_links)}: ${e.message}") + e.printStackTrace() + } + } + + private fun saveHeaderCache(data: LoadResponse? = null) { + try { + Log.d("PlayerCarScreen", "saveHeaderCache called. Item: ${item?.url}, Data: ${data?.url}, ParentID: $currentParentId") + + val url = item?.url ?: data?.url ?: return + val apiName = item?.apiName ?: data?.apiName ?: return + val name = item?.name ?: data?.name ?: return + val type = item?.type ?: data?.type ?: TvType.Movie + val poster = item?.posterUrl ?: data?.posterUrl + + val api = getApiFromNameNull(apiName) + val mainUrl = api?.mainUrl ?: "" + val id = url.replace(mainUrl, "").replace("/", "").hashCode() + + val header = VideoDownloadHelper.DownloadHeaderCached( + apiName = apiName, + url = url, + type = type, + name = name, + poster = poster, + id = id, + cacheTime = System.currentTimeMillis() + ) + Log.e("PlayerCarScreen", "Saving Header Cache: ID=$id, ParentID=$currentParentId, Name=${name}, Type=${header.type}") + setKey(DOWNLOAD_HEADER_CACHE, id.toString(), header) + // Ensure parentId is also covered if different + currentParentId?.let { parentId -> + if (parentId != id) { + setKey(DOWNLOAD_HEADER_CACHE, parentId.toString(), header.copy(id = parentId)) + Log.e("PlayerCarScreen", "Saved extra copy for ParentID: $parentId") + } + } + } catch (e: Exception) { + Log.e("PlayerCarScreen", "Error saving header cache", e) + } + } + + private fun saveProgress() { + val p = player ?: return + val pos = p.currentPosition + val dur = p.duration + + Log.d("PlayerCarScreen", "saveProgress - Pos: $pos, Dur: $dur, IsPlaying: $isPlaying") + + if (item?.type == TvType.Live) { + Log.d("PlayerCarScreen", "Skipping saveProgress for Live content") + return + } + + if (dur <= 0) return + + // 1. Save detailed position (setViewPos) + // Only if we have a valid ID. For Movies, currentEpisodeId might be enough. + // For Episodes, we need the specific episode ID. + if (currentEpisodeId != null) { + DataStoreHelper.setViewPos(currentEpisodeId, pos, dur) + Log.d("PlayerCarScreen", "Called setViewPos for EpisodeID: $currentEpisodeId") + } else { + Log.d("PlayerCarScreen", "Skipping setViewPos (EpisodeID is null)") + } + + // 2. Save "Last Watched" for Continue Watching list + // This requires parentId. + if (currentParentId != null) { + // Logic to check if finished (95% rule) + val percentage = pos * 100L / dur + if (percentage > 95) { + // Mark as finished / remove from resume + DataStoreHelper.removeLastWatched(currentParentId) + Log.d("PlayerCarScreen", "Removed Last Watched (Finished)") + } else { + // Update resume state + val epNum = activeEpisode?.episode + val seasonNum = activeEpisode?.season + + DataStoreHelper.setLastWatched( + parentId = currentParentId, + episodeId = currentEpisodeId, + episode = epNum, + season = seasonNum, + isFromDownload = false, + updateTime = System.currentTimeMillis() + ) + Log.d("PlayerCarScreen", "Set Last Watched for ParentID: $currentParentId") + } + } else { + Log.d("PlayerCarScreen", "Skipping setLastWatched (ParentID is null)") + } + } + + @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) + private suspend fun startPlayback(link: Any) { + val url = when(link) { + is ExtractorLink -> link.url + is String -> link + else -> return + } + + withContext(Dispatchers.Main) { + updateStatus(CarStrings.get(R.string.car_starting_playback)) + if (player == null) { + player = ExoPlayer.Builder(carContext).build().apply { + val audioAttributes = AudioAttributes.Builder() + .setUsage(C.USAGE_MEDIA) + .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE) + .build() + setAudioAttributes(audioAttributes, true) + } + } + player?.let { p -> + // Wrap in ForwardingPlayer to intercept commands + val forwardingPlayer = object : androidx.media3.common.ForwardingPlayer(p) { + override fun seekToNext() { + Log.d("PlayerCarScreen", "ForwardingPlayer seekToNext") + scope.launch { loadNextEpisode() } + } + + override fun seekToPrevious() { + Log.d("PlayerCarScreen", "ForwardingPlayer seekToPrevious") + seekBack() + } + } + + // Initialize MediaSession with ForwardingPlayer + if (mediaSession == null) { + mediaSession = MediaSession.Builder(carContext, forwardingPlayer) + .setCallback(object : MediaSession.Callback { + override fun onConnect( + session: MediaSession, + controller: MediaSession.ControllerInfo + ): MediaSession.ConnectionResult { + val availableCommands = androidx.media3.common.Player.Commands.Builder() + .add(androidx.media3.common.Player.COMMAND_PLAY_PAUSE) + .add(androidx.media3.common.Player.COMMAND_STOP) + .add(androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT) + .add(androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS) + .build() + + return MediaSession.ConnectionResult.AcceptedResultBuilder(session) + .setAvailablePlayerCommands(availableCommands) + .build() + } + }) + .build() + } + + p.addListener(object : Player.Listener { + override fun onIsPlayingChanged(isPlaying: Boolean) { + this@PlayerCarScreen.isPlaying = isPlaying + invalidate() + + this@PlayerCarScreen.saveProgressJob?.cancel() + if (isPlaying) { + this@PlayerCarScreen.saveProgressJob = scope.launch { + while(true) { + kotlinx.coroutines.delay(10_000) + withContext(Dispatchers.Main) { + saveProgress() + } + } + } + } else { + saveProgress() + } + } + }) + + surface?.let { p.setVideoSurface(it) } + p.videoScalingMode = resizeMode + + // Create MediaMetadata + val metadataBuilder = MediaMetadata.Builder() + .setTitle(item?.name ?: activeEpisode?.name ?: "Video") + .setDisplayTitle(item?.name ?: activeEpisode?.name ?: "Video") + .setArtist(activeEpisode?.name ?: item?.apiName ?: "Cloudstream") + + // Try to load artwork + val posterUrl = activeEpisode?.posterUrl ?: item?.posterUrl + if (!posterUrl.isNullOrEmpty()) { + try { + val request = ImageRequest.Builder(carContext) + .data(posterUrl) + .size(512, 512) + .build() + val result = SingletonImageLoader.get(carContext).execute(request) + val bitmap = result.image?.asDrawable(carContext.resources)?.toBitmap() + if (bitmap != null) { + metadataBuilder.setArtworkData( + bitmap.let { + val stream = java.io.ByteArrayOutputStream() + it.compress(android.graphics.Bitmap.CompressFormat.PNG, 100, stream) + stream.toByteArray() + }, + MediaMetadata.PICTURE_TYPE_FRONT_COVER + ) + } + } catch (e: Exception) { + Log.e("PlayerCarScreen", "Failed to load artwork for metadata", e) + } + } + + val mediaItemBuilder = MediaItem.Builder() + .setUri(url) + .setMediaMetadata(metadataBuilder.build()) + + if (link is ExtractorLink && link.isM3u8) { + mediaItemBuilder.setMimeType(MimeTypes.APPLICATION_M3U8) + } + + p.setMediaItem(mediaItemBuilder.build()) + p.prepare() + if (startTime > 0L) { + p.seekTo(startTime) + } + p.play() + updateStatus(CarStrings.get(R.string.car_playing)) + + // Start periodic save loop + // startSaveLoop() + } + } + } + + private fun startSaveLoop() { + saveProgressJob?.cancel() + saveProgressJob = scope.launch { + Log.d("PlayerCarScreen", "Starting Save Loop") + while (true) { + delay(15_000) // Save every 15 seconds + if (isPlaying) { + withContext(Dispatchers.Main) { + saveProgress() + } + } + } + } + } + + private fun showToast(msg: String) { + androidx.car.app.CarToast.makeText(carContext, msg, androidx.car.app.CarToast.LENGTH_LONG).show() + } + + // Using a minimal Navigation Template to get the surface + // Using a minimal Navigation Template to get the surface + override fun onGetTemplate(): Template { + val playPauseAction = Action.Builder() + .setIcon( + CarIcon.Builder( + IconCompat.createWithResource( + carContext, + if (isPlaying) R.drawable.ic_baseline_pause_24 else R.drawable.ic_baseline_play_arrow_24 + ) + ).build() + ) + .setOnClickListener { + if (isPlaying) { + player?.pause() + saveProgress() // Save immediately when pausing + } else { + player?.play() + } + } + .build() + + val actionStripBuilder = ActionStrip.Builder() + + if (showSeekControls) { + // SEEK MODE: [Back (to menu)], [-10], [Play], [+30] + + val backToMenuAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_baseline_arrow_back_24)).build()) + .setOnClickListener { + showSeekControls = false + invalidate() + } + .build() + + val seekBackAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.go_back_30)).build()) + .setOnClickListener { seekBack() } + .build() + + val seekForwardAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.go_forward_30)).build()) + .setOnClickListener { seekForward() } + .build() + + val resizeAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_baseline_aspect_ratio_24)).build()) + .setOnClickListener { + resizeMode = if (resizeMode == VIDEO_SCALING_MODE_SCALE_TO_FIT) { + VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING + } else { + VIDEO_SCALING_MODE_SCALE_TO_FIT + } + player?.videoScalingMode = resizeMode + showToast(if (resizeMode == VIDEO_SCALING_MODE_SCALE_TO_FIT) CarStrings.get(R.string.car_fit_to_screen) else CarStrings.get(R.string.car_fill_screen)) + } + .build() + + actionStripBuilder.addAction(backToMenuAction) + .addAction(seekBackAction) + .addAction(seekForwardAction) + .addAction(resizeAction) + + } else { + // DEFAULT MODE: [Back (Exit)], [Play], [Resize], [Seek Controls] + + val exitAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_baseline_arrow_back_24)).build()) + .setOnClickListener { screenManager.pop() } + .build() + + + + val seekBackAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.go_back_30)).build()) + .setOnClickListener { + seekBack() + } + .build() + + val openSeekAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_baseline_tune_24)).build()) + .setOnClickListener { + showSeekControls = true + invalidate() + } + .build() + + val nextAction = Action.Builder() + .setIcon(CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_baseline_skip_next_24)).build()) + .setOnClickListener { + scope.launch { loadNextEpisode() } + } + .setEnabled(playlist != null && activeEpisode != null && playlist.indexOf(activeEpisode) < playlist.size - 1) + .build() + + actionStripBuilder.addAction(exitAction) + .addAction(playPauseAction) + .addAction(nextAction) + .addAction(openSeekAction) + } + + return NavigationTemplate.Builder() + .setActionStrip(actionStripBuilder.build()) + .setBackgroundColor(CarColor.createCustom(android.graphics.Color.BLACK, android.graphics.Color.BLACK)) + .build() + } + + private fun seekBack() { + player?.let { p -> + val newPos = p.currentPosition - 30_000 // -30 seconds + p.seekTo(if (newPos < 0) 0 else newPos) + updateStatus("-30s") + } + } + + private suspend fun loadNextEpisode() { + if (playlist == null || activeEpisode == null) { + showToast("No playlist available") + return + } + + + // Fix: Episode class does not have 'id'. Use 'data' or calculate hash. + val currentIndex = playlist.indexOfFirst { it.data == activeEpisode!!.data } // Comparing by data url is safest + if (currentIndex != -1 && currentIndex < playlist.size - 1) { + val nextEp = playlist[currentIndex + 1] + activeEpisode = nextEp + // Generate a consistent ID from the data URL, similar to how it's done elsewhere + val nextId = nextEp.data.hashCode() + currentEpisodeId = nextId + + showToast("Loading: ${nextEp.name}") + + // Re-use logic to load media + withContext(Dispatchers.Main) { + // Determine if we have a direct URL (download) or need to fetch links + val downloadEp = carContext.getKey( + DOWNLOAD_EPISODE_CACHE, + nextId.toString() + ) + + if (downloadEp != null) { + // Verify file exists? For now assume yes if cached. + // We need the file URI. The original PlayerCarScreen invocation usually gets a fileUri passed in. + // But here we are switching. We might need to find the file path. + // Simplified: If in download mode, try to find the download. + // If streaming, just fetch links. + // For now, assume streaming or that loadMedia handles it via APIRepository if needed. + // But wait, loadMedia takes a URL. Episode.data is the url for load(). + + loadMedia(nextEp.data) + } else { + loadMedia(nextEp.data) + } + } + } else { + showToast("No more episodes") + } + } + + private fun seekForward() { + player?.let { p -> + val newPos = p.currentPosition + 30_000 // +30 seconds + val duration = p.duration + p.seekTo(if (newPos > duration) duration else newPos) + updateStatus("+30s") + } + } + + private fun updateStatus(status: String) { + if(status != "Playing") { + showToast(status) + } + } + + +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/ProviderCarScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/ProviderCarScreen.kt new file mode 100644 index 00000000000..e2f86a2f4e4 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/ProviderCarScreen.kt @@ -0,0 +1,42 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.APIHolder.apis +import com.lagradost.cloudstream3.utils.DataStoreHelper + +class ProviderCarScreen(carContext: CarContext) : Screen(carContext) { + override fun onGetTemplate(): Template { + val listBuilder = ItemList.Builder() + + // Filter APIs mostly for simplicity, or show all + val current = DataStoreHelper.currentHomePage + + apis.forEach { api -> + val row = Row.Builder() + .setTitle(api.name) + .setOnClickListener { + DataStoreHelper.currentHomePage = api.name + screenManager.pop() // Go back to Home which will reload + } + + if (api.name == current) { + row.addText(CarStrings.get(R.string.car_selected)) + } + + listBuilder.addItem(row.build()) + } + + return ListTemplate.Builder() + .setSingleList(listBuilder.build()) + .setTitle(CarStrings.get(R.string.car_select_provider)) + .setHeaderAction(Action.BACK) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/SearchCarScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/SearchCarScreen.kt new file mode 100644 index 00000000000..03742ed5ff0 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/SearchCarScreen.kt @@ -0,0 +1,119 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.CarIcon +import androidx.car.app.model.ItemList +import androidx.car.app.model.Row +import androidx.car.app.model.SearchTemplate +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.ui.APIRepository +import com.lagradost.cloudstream3.utils.DataStoreHelper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.launch +import androidx.car.app.CarToast +import coil3.request.ImageRequest +import coil3.SingletonImageLoader +import coil3.asDrawable +import androidx.core.graphics.drawable.toBitmap + + +class SearchCarScreen(carContext: CarContext) : Screen(carContext) { + + private var itemList: ItemList? = null + private var searchJob: Job? = null + + private val searchCallback = object : SearchTemplate.SearchCallback { + override fun onSearchTextChanged(searchText: String) { + // Optional: Implement autocomplete here + } + + override fun onSearchSubmitted(searchText: String) { + performSearch(searchText) + } + } + + private fun performSearch(query: String) { + searchJob?.cancel() + searchJob = CoroutineScope(Dispatchers.IO).launch { + val apiName = DataStoreHelper.currentHomePage ?: return@launch + val api = getApiFromNameNull(apiName) ?: return@launch + val repo = APIRepository(api) + + // Check if search requires page + when(val result = repo.search(query, 1)) { + is Resource.Success -> { + val builder = ItemList.Builder() + val items = result.value.items + if (items.isEmpty()) { + builder.setNoItemsMessage(CarStrings.get(R.string.car_no_results_found)) + } + + // Text-only results + items.map { item -> + val image = try { + if (!item.posterUrl.isNullOrEmpty()) { + val request = ImageRequest.Builder(carContext) + .data(item.posterUrl) + .size(128, 128) + .build() + val result = SingletonImageLoader.get(carContext).execute(request) + val bitmap = result.image?.asDrawable(carContext.resources)?.toBitmap() + if (bitmap != null) { + CarIcon.Builder(IconCompat.createWithBitmap(bitmap)).build() + } else null + } else null + } catch (e: Exception) { + null + } ?: CarIcon.Builder(IconCompat.createWithResource(carContext, R.mipmap.ic_launcher)).build() + + builder.addItem( + Row.Builder() + .setTitle(item.name) + .setImage(image, Row.IMAGE_TYPE_LARGE) + .setOnClickListener { + val type = item.type + if (type == com.lagradost.cloudstream3.TvType.TvSeries || + type == com.lagradost.cloudstream3.TvType.Anime || + type == com.lagradost.cloudstream3.TvType.Cartoon || + type == com.lagradost.cloudstream3.TvType.OVA || + type == com.lagradost.cloudstream3.TvType.AsianDrama || + type == com.lagradost.cloudstream3.TvType.Documentary) { + screenManager.push(TvSeriesDetailScreen(carContext, item)) + } else { + screenManager.push(DetailsScreen(carContext, item)) + } + } + .build() + ) + } + + itemList = builder.build() + invalidate() + } + is Resource.Failure -> { + // Handle error + } + else -> {} + } + } + } + + override fun onGetTemplate(): Template { + return SearchTemplate.Builder(searchCallback) + .setSearchHint("${CarStrings.get(R.string.car_search)}...") + .setHeaderAction(Action.BACK) + .setShowKeyboardByDefault(true) + .setItemList(itemList ?: ItemList.Builder().build()) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/SourceSelectionScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/SourceSelectionScreen.kt new file mode 100644 index 00000000000..ba49f0f6e4a --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/SourceSelectionScreen.kt @@ -0,0 +1,132 @@ +package com.lagradost.cloudstream3.ui.car + +import android.graphics.Color +import androidx.car.app.CarContext +import androidx.car.app.CarToast +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.CarIcon +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * Screen that displays available streaming sources for a content item. + * User can select a source, which will be used for playback. + * + * @param apiName The API/provider name to use for loading links + * @param dataUrl The data URL to load links for (movie URL or episode data) + * @param currentSourceUrl The currently selected source URL (for showing check mark) + * @param onSourceSelected Callback when a source is selected + */ +class SourceSelectionScreen( + carContext: CarContext, + private val apiName: String, + private val dataUrl: String, + private val currentSourceUrl: String? = null, + private val onSourceSelected: (ExtractorLink) -> Unit +) : Screen(carContext) { + + private val scope = CoroutineScope(Dispatchers.IO + Job()) + private var isLoading = true + private var sources: List = emptyList() + private var errorMessage: String? = null + + init { + loadSources() + } + + private fun loadSources() { + scope.launch { + try { + val api = getApiFromNameNull(apiName) + if (api == null) { + errorMessage = CarStrings.get(R.string.car_provider_not_found) + isLoading = false + invalidate() + return@launch + } + + val links = mutableListOf() + api.loadLinks(dataUrl, false, {}, { link -> + links.add(link) + }) + + withContext(Dispatchers.Main) { + if (links.isEmpty()) { + errorMessage = CarStrings.get(R.string.car_no_source_found) + } else { + // Sort by quality (highest first) + sources = links.sortedByDescending { it.quality } + } + isLoading = false + invalidate() + } + } catch (e: Exception) { + withContext(Dispatchers.Main) { + errorMessage = "${CarStrings.get(R.string.car_error)}: ${e.message}" + isLoading = false + invalidate() + } + } + } + } + + override fun onGetTemplate(): Template { + val templateBuilder = ListTemplate.Builder() + .setTitle(CarStrings.get(R.string.car_sources)) + .setHeaderAction(Action.BACK) + + if (isLoading) { + // When loading, just set loading state without any list + templateBuilder.setLoading(true) + } else { + // Not loading - build the list + val listBuilder = ItemList.Builder() + + if (errorMessage != null) { + listBuilder.setNoItemsMessage(errorMessage!!) + } else if (sources.isEmpty()) { + listBuilder.setNoItemsMessage(CarStrings.get(R.string.car_no_source_available)) + } else { + // Add each source as a row + for (source in sources) { + val qualityStr = Qualities.getStringByInt(source.quality) + val title = if (qualityStr.isNotEmpty()) { + "${source.name} - $qualityStr" + } else { + source.name + } + + val rowBuilder = Row.Builder() + .setTitle(title) + .addText(source.source) + .setOnClickListener { + onSourceSelected(source) + CarToast.makeText(carContext, "${CarStrings.get(R.string.car_source_selected)}: ${source.name}", CarToast.LENGTH_SHORT).show() + screenManager.pop() + } + + + listBuilder.addItem(rowBuilder.build()) + } + } + + templateBuilder.setSingleList(listBuilder.build()) + templateBuilder.setLoading(false) + } + + return templateBuilder.build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/car/TvSeriesDetailScreen.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/car/TvSeriesDetailScreen.kt new file mode 100644 index 00000000000..5c41951ccc4 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/car/TvSeriesDetailScreen.kt @@ -0,0 +1,195 @@ +package com.lagradost.cloudstream3.ui.car + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.CarColor +import androidx.car.app.model.CarIcon +import androidx.car.app.model.ForegroundCarColorSpan +import androidx.car.app.model.Pane +import androidx.car.app.model.PaneTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import androidx.core.graphics.drawable.toBitmap +import coil3.asDrawable +import coil3.request.ImageRequest +import coil3.SingletonImageLoader +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.LoadResponse +import com.lagradost.cloudstream3.SearchResponse +import com.lagradost.cloudstream3.TvSeriesLoadResponse +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.ui.APIRepository +import com.lagradost.cloudstream3.utils.DataStoreHelper +import com.lagradost.cloudstream3.utils.DataStoreHelper.FavoritesData +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import android.text.SpannableString +import android.text.Spanned + +class TvSeriesDetailScreen( + carContext: CarContext, + private val item: SearchResponse +) : Screen(carContext) { + + private val scope = CoroutineScope(Dispatchers.IO + Job()) + private var fullDetails: TvSeriesLoadResponse? = null + private var isLoading = true + private var errorMessage: String? = null + private var posterBitmap: android.graphics.Bitmap? = null + private var isFavorite: Boolean = false + + init { + loadDetails() + } + + private fun loadDetails() { + scope.launch { + // Load header image + if (!item.posterUrl.isNullOrEmpty()) { + try { + val request = ImageRequest.Builder(carContext) + .data(item.posterUrl) + .size(600, 900) + .build() + val result = SingletonImageLoader.get(carContext).execute(request) + posterBitmap = result.image?.asDrawable(carContext.resources)?.toBitmap() + } catch (e: Exception) { + e.printStackTrace() + } + } + + // Load full details + val api = getApiFromNameNull(item.apiName) + if (api != null) { + val repo = APIRepository(api) + when (val result = repo.load(item.url)) { + is Resource.Success -> { + val data = result.value + if (data is TvSeriesLoadResponse) { + fullDetails = data + // Check Favorite status + val id = data.url.replace(api.mainUrl, "").replace("/", "").hashCode() + isFavorite = DataStoreHelper.getFavoritesData(id) != null + } else { + errorMessage = CarStrings.get(R.string.car_not_tv_series) + } + isLoading = false + } + is Resource.Failure -> { + errorMessage = result.errorString ?: CarStrings.get(R.string.car_error_loading_details) + isLoading = false + } + is Resource.Loading -> {} + } + } else { + errorMessage = CarStrings.get(R.string.car_provider_not_found) + isLoading = false + } + invalidate() + } + } + + private fun toggleFavorite() { + CarHelper.toggleFavorite(carContext, fullDetails, isFavorite) { newStatus -> + isFavorite = newStatus + invalidate() + } + } + + override fun onGetTemplate(): Template { + val paneBuilder = Pane.Builder() + + if (isLoading) { + paneBuilder.setLoading(true) + } else { + val details = fullDetails + + // Header: Title + paneBuilder.addRow( + Row.Builder() + .setTitle(details?.name ?: item.name) + .build() + ) + + // Include Hero Image if available + posterBitmap?.let { + paneBuilder.setImage(CarIcon.Builder(IconCompat.createWithBitmap(it)).build()) + } ?: run { + paneBuilder.setImage(CarIcon.Builder(IconCompat.createWithResource(carContext, R.mipmap.ic_launcher)).build()) + } + + if (details != null) { + // Meta Row: Year • Score • Duration/Seasons + val metaStringBuilder = StringBuilder() + details.year?.let { metaStringBuilder.append("$it") } + + val score = details.score + if (score != null) { + if (metaStringBuilder.isNotEmpty()) metaStringBuilder.append(" • ") + metaStringBuilder.append(String.format("%.1f/10", score.toDouble(10))) + } + + // Show season count in meta + // details.seasonNames could be used, or just aggregating episodes + val seasonCount = details.episodes.mapNotNull { it.season }.distinct().count() + if (metaStringBuilder.isNotEmpty()) metaStringBuilder.append(" • ") + metaStringBuilder.append("$seasonCount ${CarStrings.get(R.string.car_seasons)}") + + if (metaStringBuilder.isNotEmpty()) { + paneBuilder.addRow( + Row.Builder() + .setTitle(metaStringBuilder.toString()) + .build() + ) + } + + // Favorite Action + val favoriteIconRes = if (isFavorite) R.drawable.ic_baseline_favorite_24 else R.drawable.ic_baseline_favorite_border_24 + val favoriteIcon = IconCompat.createWithResource(carContext, favoriteIconRes) + if (isFavorite) { + favoriteIcon.setTint(0xFFFF0000.toInt()) // Red + } else { + favoriteIcon.setTint(android.graphics.Color.WHITE) // White + } + + val favoriteAction = Action.Builder() + .setIcon(CarIcon.Builder(favoriteIcon).build()) + .setOnClickListener { + toggleFavorite() + } + .build() + + // Episodes Button Action + // "Episode List >" + paneBuilder.addAction( + Action.Builder() + .setTitle(CarStrings.get(R.string.car_episode_list)) + .setBackgroundColor(CarColor.PRIMARY) + .setOnClickListener { + screenManager.push(EpisodeListScreen(carContext, details)) + } + .build() + ) + + paneBuilder.addAction(favoriteAction) + + // Plot and Cast + CarHelper.addPlotAndCast(paneBuilder, details) + + } else if (errorMessage != null) { + paneBuilder.addRow(Row.Builder().setTitle("${CarStrings.get(R.string.car_error)}: $errorMessage").build()) + } + } + + return PaneTemplate.Builder(paneBuilder.build()) + .setTitle(item.name) + .setHeaderAction(Action.BACK) + .build() + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt index 49c6d0d7732..6fe20e4e648 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt @@ -847,6 +847,11 @@ class HomeFragment : BaseFragment( return@observeNullable } + // Fix: Prevent WindowLeaked crash if activity is not in a valid state (e.g. when using Android Auto) + if (activity?.isFinishing == true || activity?.isDestroyed == true || !lifecycle.currentState.isAtLeast(androidx.lifecycle.Lifecycle.State.RESUMED)) { + return@observeNullable + } + // don't recreate if (bottomSheetDialog != null) { return@observeNullable diff --git a/app/src/main/res-car/values-b+af/strings_car.xml b/app/src/main/res-car/values-b+af/strings_car.xml new file mode 100644 index 00000000000..f39d2aacfe2 --- /dev/null +++ b/app/src/main/res-car/values-b+af/strings_car.xml @@ -0,0 +1,51 @@ + + + Laai tans... + Fout + Fout met laai van inhoud + Gunstelinge + Geskiedenis + Aflaaie + Verskaffer + Huidige + Kieslys + Tuisinhoud + Geen inhoud van verskaffer + Verskaffer nie gevind nie + Bron + Bronne + Storielyn + Rolverdeling + Fout met laai van besonderhede + Episode lys + Seisoen + Seisoene + Episode + Geen episodes gevind nie + Nie \'n TV-reeks nie + By gunstelinge gevoeg + Van gunstelinge verwyder + Geen gunstelinge gevind nie + Begin terugspeel... + Speel tans + Geen skakel gevind nie + Geen speelbare inhoud gevind nie + Kan nie besonderhede laai nie + Fout met laai van skakels + Pas by skerm + Vul skerm + Geen bron gevind nie + Geen bron beskikbaar nie + Bron gekies + Soek + Geen resultate gevind nie + \'Gaan voort om te kyk\' nie gevind nie + Geen aflaaie gevind nie + Lêer nie gevind nie + Geen geldige episode gevind nie + Kies Verskaffer + Gekies + Biblioteek + Boekmerke + Hervat %1$s... + diff --git a/app/src/main/res-car/values-b+am/strings_car.xml b/app/src/main/res-car/values-b+am/strings_car.xml new file mode 100644 index 00000000000..73d1b93ae2e --- /dev/null +++ b/app/src/main/res-car/values-b+am/strings_car.xml @@ -0,0 +1,51 @@ + + + በመጫን ላይ... + ስህተት + ይዘት በመጫን ላይ ስህተት + ተወዳጆች + ታሪክ + ውርዶች + አቅራቢ + የአሁኑ + ምናሌ + የመነሻ ይዘት + ከአቅራቢው ምንም ይዘት የለም + አቅራቢ አልተገኘም + ምንጭ + ምንጮች + ሴራ + ተዋንያን + ዝርዝሮችን በመጫን ላይ ስህተት + የክፍሎች ዝርዝር + ወቅት + ወቅቶች + ክፍል + ምንም ክፍሎች አልተገኙም + የቲቪ ተከታታይ አይደለም + ወደ ተወዳጆች ታክሏል + ከተወዳጆች ተወግዷል + ምንም ተወዳጆች አልተገኙም + ማጫወት በመጀመር ላይ... + በማጫወት ላይ + ምንም አገናኝ አልተገኘም + ምንም የሚጫወት ይዘት አልተገኘም + ዝርዝሮችን መጫን አልተቻለም + አገናኞችን በመጫን ላይ ስህተት + ስክሪን ላይ ይግጠም + ስክሪን ይሙሉ + ምንም ምንጭ አልተገኘም + ምንም ምንጭ የለም + ምንጭ ተመርጧል + ፈልግ + ምንም ውጤቶች አልተገኙም + \'መመልከት ይቀጥሉ\' አልተገኘም + ምንም ውርዶች አልተገኙም + ፋይል አልተገኘም + ምንም ትክክለኛ ክፍል አልተገኘም + አቅራቢ ይምረጡ + ተመርጧል + ቤተ-መጽሐፍት + ዕልባቶች + %1$s በመቀጠል ላይ... + diff --git a/app/src/main/res-car/values-b+apc/strings_car.xml b/app/src/main/res-car/values-b+apc/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+apc/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+ar/strings_car.xml b/app/src/main/res-car/values-b+ar/strings_car.xml new file mode 100644 index 00000000000..2f75de73f8e --- /dev/null +++ b/app/src/main/res-car/values-b+ar/strings_car.xml @@ -0,0 +1,51 @@ + + + جارٍ التحميل... + خطأ + خطأ في تحميل المحتوى + المفضلة + السجل + التنزيلات + المزود + الحالي + القائمة + محتوى الصفحة الرئيسية + لا يوجد محتوى من المزود + المزود غير موجود + المصدر + المصادر + القصة + الممثلون + خطأ في تحميل التفاصيل + قائمة الحلقات + الموسم + المواسم + الحلقة + لم يتم العثور على حلقات + ليس مسلسلاً تلفزيونياً + تمت الإضافة إلى المفضلة + تمت الإزالة من المفضلة + لم يتم العثور على مفضلة + بدء التشغيل... + تشغيل + لم يتم العثور على رابط + لم يتم العثور على محتوى قابل للتشغيل + تعذر تحميل التفاصيل + خطأ في تحميل الروابط + ملاءمة للشاشة + ملء الشاشة + لم يتم العثور على مصدر + لا يوجد مصدر متاح + تم اختيار المصدر + بحث + لم يتم العثور على نتائج + لم يتم العثور على \'متابعة المشاهدة\' + لم يتم العثور على تنزيلات + الملف غير موجود + لا توجد حلقة صالحة + اختر المزود + محدد + المكتبة + الإشارات المرجعية + استئناف %1$s... + diff --git a/app/src/main/res-car/values-b+ars/strings_car.xml b/app/src/main/res-car/values-b+ars/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+ars/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+as/strings_car.xml b/app/src/main/res-car/values-b+as/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+as/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+az/strings_car.xml b/app/src/main/res-car/values-b+az/strings_car.xml new file mode 100644 index 00000000000..2d7a522db98 --- /dev/null +++ b/app/src/main/res-car/values-b+az/strings_car.xml @@ -0,0 +1,51 @@ + + + Yüklənir... + Xəta + Məzmun yüklənərkən xəta + Sevimlilər + Tarixçə + Yükləmələr + Provayder + Cari + Menyu + Ana səhifə məzmunu + Provayderdən məzmun yoxdur + Provayder tapılmadı + Mənbə + Mənbələr + Süjet + Rollarda + Təfərrüatları yükləyərkən xəta + Epizod siyahısı + Mövsüm + Mövsümlər + Epizod + Epizod tapılmadı + TV serialı deyil + Sevimlilərə əlavə edildi + Sevimlilərdən silindi + Sevimli tapılmadı + Oxutma başlayır... + Oxudulur + Link tapılmadı + Oxudula bilən məzmun tapılmadı + Təfərrüatları yükləmək mümkün olmadı + Linkləri yükləyərkən xəta + Ekranı uyğunlaşdır + Ekranı doldur + Mənbə tapılmadı + Mövcud mənbə yoxdur + Mənbə seçildi + Axtarış + Nəticə tapılmadı + \'İzləməyə davam et\' tapılmadı + Yükləmə tapılmadı + Fayl tapılmadı + Etibarlı epizod tapılmadı + Provayder seç + Seçildi + Kitabxana + Əlfəcinlər + %1$s davam etdirilir... + diff --git a/app/src/main/res-car/values-b+be/strings_car.xml b/app/src/main/res-car/values-b+be/strings_car.xml new file mode 100644 index 00000000000..4601e262724 --- /dev/null +++ b/app/src/main/res-car/values-b+be/strings_car.xml @@ -0,0 +1,51 @@ + + + Загрузка... + Памылка + Памылка загрузкі кантэнту + Выбранае + Гісторыя + Спампоўкі + Пастаўшчык + Бягучы + Меню + Галоўны кантэнт + Няма кантэнту ад пастаўшчыка + Пастаўшчык не знойдзены + Крыніца + Крыніцы + Сюжэт + Акцёры + Памылка загрузкі дэталяў + Спіс серый + Сезон + Сезоны + Серыя + Серый не знойдзена + Не серыял + Дададзена ў выбранае + Выдалена з выбранага + Няма выбранага + Пачатак прайгравання... + Прайграванне + Спасылка не знойдзена + Няма кантэнту для прайгравання + Не ўдалося загрузіць дэталі + Памылка загрузкі спасылак + Па памеры экрана + Запоўніць экран + Крыніца не знойдзена + Няма даступных крыніц + Крыніца выбрана + Пошук + Вынікаў не знойдзена + \'Працягнуць прагляд\' не знойдзена + Няма спамповак + Файл не знойдзены + Няма сапраўднай серыі + Выберыце пастаўшчыка + Выбрана + Бібліятэка + Закладкі + Аднаўленне %1$s... + diff --git a/app/src/main/res-car/values-b+bg/strings_car.xml b/app/src/main/res-car/values-b+bg/strings_car.xml new file mode 100644 index 00000000000..9c7ba83e426 --- /dev/null +++ b/app/src/main/res-car/values-b+bg/strings_car.xml @@ -0,0 +1,51 @@ + + + Зареждане... + Грешка + Грешка при зареждане на съдържание + Любими + История + Изтегляния + Доставчик + Текущ + Меню + Начално съдържание + Няма съдържание от доставчика + Доставчикът не е намерен + Източник + Източници + Сюжет + Актьорски състав + Грешка при зареждане на детайли + Списък с епизоди + Сезон + Сезони + Епизод + Няма намерени епизоди + Не е ТВ сериал + Добавено към любими + Премахнато от любими + Няма намерени любими + Стартиране на възпроизвеждане... + Възпроизвеждане + Няма намерена връзка + Няма намерено съдържание за възпроизвеждане + Не може да се заредят детайли + Грешка при зареждане на връзки + Побиране на екрана + Запълване на екрана + Няма намерен източник + Няма наличен източник + Избран източник + Търсене + Няма намерени резултати + Няма намерено \'Продължи гледането\' + Няма намерени изтегляния + Файлът не е намерен + Няма намерен валиден епизод + Избор на доставчик + Избрано + Библиотека + Отметки + Възобновяване %1$s... + diff --git a/app/src/main/res-car/values-b+bn/strings_car.xml b/app/src/main/res-car/values-b+bn/strings_car.xml new file mode 100644 index 00000000000..fb8281709e4 --- /dev/null +++ b/app/src/main/res-car/values-b+bn/strings_car.xml @@ -0,0 +1,51 @@ + + + লোড হচ্ছে... + ত্রুটি + কন্টেন্ট লোড করতে ত্রুটি + পছন্দ + ইতিহাস + ডাউনলোড + প্রদানকারী + বর্তমান + মেনু + হোম কন্টেন্ট + প্রদানকারী থেকে কোন কন্টেন্ট নেই + প্রদানকারী পাওয়া যায়নি + উৎস + উৎসসমূহ + কাহিনী + কুশীলব + বিস্তারিত লোড করতে ত্রুটি + পর্বের তালিকা + সিজন + সিজনসমূহ + পর্ব + কোন পর্ব পাওয়া যায়নি + টিভি সিরিজ নয় + পছন্দে যোগ করা হয়েছে + পছন্দ থেকে সরানো হয়েছে + কোন পছন্দ পাওয়া যায়নি + প্লেব্যাক শুরু হচ্ছে... + চলছে + কোন লিঙ্ক পাওয়া যায়নি + কোন চালানোর যোগ্য কন্টেন্ট পাওয়া যায়নি + বিস্তারিত লোড করা যায়নি + লিঙ্ক লোড করতে ত্রুটি + স্ক্রিনে মানানসই করুন + স্ক্রিন পূর্ণ করুন + কোন উৎস পাওয়া যায়নি + কোন উৎস উপলব্ধ নেই + উৎস নির্বাচিত + অনুসন্ধান + কোন ফলাফল পাওয়া যায়নি + \'দেখা চালিয়ে যান\' পাওয়া যায়নি + কোন ডাউনলোড পাওয়া যায়নি + ফাইল পাওয়া যায়নি + কোন বৈধ পর্ব পাওয়া যায়নি + প্রদানকারী নির্বাচন করুন + নির্বাচিত + লাইব্রেরি + বুকমার্ক + %1$s পুনরায় শুরু হচ্ছে... + diff --git a/app/src/main/res-car/values-b+bs/strings_car.xml b/app/src/main/res-car/values-b+bs/strings_car.xml new file mode 100644 index 00000000000..dfbc9fef949 --- /dev/null +++ b/app/src/main/res-car/values-b+bs/strings_car.xml @@ -0,0 +1,51 @@ + + + Učitavanje... + Greška + Greška pri učitavanju sadržaja + Omiljeni + Historija + Preuzimanja + Provajder + Trenutno + Meni + Početni sadržaj + Nema sadržaja od provajdera + Provajder nije pronađen + Izvor + Izvori + Radnja + Uloge + Greška pri učitavanju detalja + Lista epizoda + Sezona + Sezone + Epizoda + Nema pronađenih epizoda + Nije TV serija + Dodano u omiljene + Uklonjeno iz omiljenih + Nema omiljenih + Pokretanje reprodukcije... + Reprodukcija + Link nije pronađen + Sadržaj za reprodukciju nije pronađen + Nije moguće učitati detalje + Greška pri učitavanju linkova + Prilagodi ekranu + Popuni ekran + Izvor nije pronađen + Izvor nije dostupan + Izvor odabran + Pretraga + Nema rezultata + \'Nastavi gledanje\' nije pronađeno + Nema preuzimanja + Datoteka nije pronađena + Nema važeće epizode + Izaberi provajdera + Odabrano + Biblioteka + Obeleživači + Nastavljanje %1$s... + diff --git a/app/src/main/res-car/values-b+ca/strings_car.xml b/app/src/main/res-car/values-b+ca/strings_car.xml new file mode 100644 index 00000000000..6a7e285ec11 --- /dev/null +++ b/app/src/main/res-car/values-b+ca/strings_car.xml @@ -0,0 +1,51 @@ + + + Carregant... + Error + Error carregant contingut + Preferits + Historial + Descàrregues + Proveïdor + Actual + Menú + Contingut d\'inici + Sense contingut del proveïdor + Proveïdor no trobat + Font + Fonts + Argument + Repartiment + Error carregant detalls + Llista d\'episodis + Temporada + Temporades + Episodi + No s\'han trobat episodis + No és una sèrie de TV + Afegit a preferits + Eliminat de preferits + Cap preferit trobat + Iniciant reproducció... + Reproduint + Enllaç no trobat + Contingut reproduïble no trobat + No es poden carregar els detalls + Error carregant enllaços + Ajustar a la pantalla + Omplir la pantalla + Font no trobada + Cap font disponible + Font seleccionada + Cercar + Sense resultats + \'Continuar mirant\' no trobat + Sense descàrregues + Fitxer no trobat + Cap episodi vàlid + Seleccionar proveïdor + Seleccionat + Biblioteca + Marcadors + Reprenent %1$s... + diff --git a/app/src/main/res-car/values-b+ckb/strings_car.xml b/app/src/main/res-car/values-b+ckb/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+ckb/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+cs/strings_car.xml b/app/src/main/res-car/values-b+cs/strings_car.xml new file mode 100644 index 00000000000..d9011304d0a --- /dev/null +++ b/app/src/main/res-car/values-b+cs/strings_car.xml @@ -0,0 +1,51 @@ + + + Načítání... + Chyba + Chyba při načítání obsahu + Oblíbené + Historie + Stažené + Poskytovatel + Aktuální + Menu + Domovský obsah + Žádný obsah od poskytovatele + Poskytovatel nenalezen + Zdroj + Zdroje + Děj + Obsazení + Chyba při načítání podrobností + Seznam epizod + Série + Série + Epizoda + Nenalezeny žádné epizody + Není TV seriál + Přidáno do oblíbených + Odebráno z oblíbených + Nenalezeny žádné oblíbené + Spouštění přehrávání... + Přehrávání + Odkaz nenalezen + Nenalezen žádný přehrávatelný obsah + Nelze načíst podrobnosti + Chyba při načítání odkazů + Přizpůsobit obrazovce + Vyplnit obrazovku + Zdroj nenalezen + Žádný zdroj k dispozici + Zdroj vybrán + Hledat + Nenalezeny žádné výsledky + Nenalezeno \'Pokračovat ve sledování\' + Nenalezeny žádné stažené soubory + Soubor nenalezen + Nenalezena žádná platná epizoda + Vybrat poskytovatele + Vybráno + Knihovna + Záložky + Obnovování %1$s... + diff --git a/app/src/main/res-car/values-b+da/strings_car.xml b/app/src/main/res-car/values-b+da/strings_car.xml new file mode 100644 index 00000000000..afb929b5b50 --- /dev/null +++ b/app/src/main/res-car/values-b+da/strings_car.xml @@ -0,0 +1,51 @@ + + + Indlæser... + Fejl + Fejl ved indlæsning af indhold + Favoritter + Historik + Downloads + Udbydere + Nuværende + Menu + Hjemmeindhold + Intet indhold fra udbyder + Udbyder ikke fundet + Kilde + Kilder + Handling + Medvirkende + Fejl ved indlæsning af detaljer + Afsnitsliste + Sæson + Sæsoner + Afsnit + Ingen afsnit fundet + Ikke en TV-serie + Tilføjet til favoritter + Fjernet fra favoritter + Ingen favoritter fundet + Starter afspilning... + Afspiller + Intet link fundet + Intet afspilleligt indhold fundet + Kunne ikke indlæse detaljer + Fejl ved indlæsning af links + Tilpas til skærm + Fyld skærm + Ingen kilde fundet + Ingen kilde tilgængelig + Kilde valgt + Søg + Ingen resultater fundet + \'Fortsæt med at se\' ikke fundet + Ingen downloads fundet + Fil ikke fundet + Intet gyldigt afsnit fundet + Vælg udbyder + Valgt + Bibliotek + Bogmærker + Genoptager %1$s... + diff --git a/app/src/main/res-car/values-b+de/strings_car.xml b/app/src/main/res-car/values-b+de/strings_car.xml new file mode 100644 index 00000000000..2c88723f817 --- /dev/null +++ b/app/src/main/res-car/values-b+de/strings_car.xml @@ -0,0 +1,51 @@ + + + Laden... + Fehler + Fehler beim Laden des Inhalts + Favoriten + Verlauf + Downloads + Anbieter + Aktuell + Menü + Startseiteninhalt + Kein Inhalt vom Anbieter + Anbieter nicht gefunden + Quelle + Quellen + Handlung + Besetzung + Fehler beim Laden der Details + Episodenliste + Staffel + Staffeln + Episode + Keine Episoden gefunden + Keine TV-Serie + Zu Favoriten hinzugefügt + Aus Favoriten entfernt + Keine Favoriten gefunden + Wiedergabe wird gestartet... + Wiedergabe + Kein Link gefunden + Kein abspielbarer Inhalt gefunden + Details konnten nicht geladen werden + Fehler beim Laden der Links + An Bildschirm anpassen + Bildschirm füllen + Keine Quelle gefunden + Keine Quelle verfügbar + Quelle ausgewählt + Suchen + Keine Ergebnisse gefunden + Keine \'Weiterschauen\'-Elemente gefunden + Keine Downloads gefunden + Datei nicht gefunden + Keine gültige Episode gefunden + Anbieter auswählen + Ausgewählt + Bibliothek + Lesezeichen + Setze %1$s fort... + diff --git a/app/src/main/res-car/values-b+el/strings_car.xml b/app/src/main/res-car/values-b+el/strings_car.xml new file mode 100644 index 00000000000..fd08dfb2f56 --- /dev/null +++ b/app/src/main/res-car/values-b+el/strings_car.xml @@ -0,0 +1,51 @@ + + + Φόρτωση... + Σφάλμα + Σφάλμα φόρτωσης περιεχομένου + Αγαπημένα + Ιστορικό + Λήψεις + Πάροχος + Τρέχον + Μενού + Περιεχόμενο αρχικής σελίδας + Δεν υπάρχει περιεχόμενο από τον πάροχο + Ο πάροχος δεν βρέθηκε + Πηγή + Πηγές + Πλοκή + Ηθοποιοί + Σφάλμα φόρτωσης λεπτομερειών + Λίστα επεισοδίων + Σεζόν + Σεζόν + Επεισόδιο + Δεν βρέθηκαν επεισόδια + Δεν είναι τηλεοπτική σειρά + Προστέθηκε στα αγαπημένα + Αφαιρέθηκε από τα αγαπημένα + Δεν βρέθηκαν αγαπημένα + Έναρξη αναπαραγωγής... + Αναπαραγωγή + Δεν βρέθηκε σύνδεσμος + Δεν βρέθηκε περιεχόμενο για αναπαραγωγή + Αδυναμία φόρτωσης λεπτομερειών + Σφάλμα φόρτωσης συνδέσμων + Προσαρμογή στην οθόνη + Γέμισμα οθόνης + Δεν βρέθηκε πηγή + Καμία διαθέσιμη πηγή + Επιλέχθηκε πηγή + Αναζήτηση + Δεν βρέθηκαν αποτελέσματα + Δεν βρέθηκε \'Συνέχεια παρακολούθησης\' + Δεν βρέθηκαν λήψεις + Το αρχείο δεν βρέθηκε + Δεν βρέθηκε έγκυρο επεισόδιο + Επιλογή παρόχου + Επιλεγμένο + Βιβλιοθήκη + Σελιδοδείκτες + Συνέχιση %1$s... + diff --git a/app/src/main/res-car/values-b+eo/strings_car.xml b/app/src/main/res-car/values-b+eo/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+eo/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+es/strings_car.xml b/app/src/main/res-car/values-b+es/strings_car.xml new file mode 100644 index 00000000000..515293d8a82 --- /dev/null +++ b/app/src/main/res-car/values-b+es/strings_car.xml @@ -0,0 +1,51 @@ + + + Cargando... + Error + Error al cargar contenido + Favoritos + Historial + Descargas + Proveedor + Actual + Menú + Contenido de inicio + Sin contenido del proveedor + Proveedor no encontrado + Fuente + Fuentes + Trama + Reparto + Error al cargar detalles + Lista de episodios + Temporada + Temporadas + Episodio + No se encontraron episodios + No es una serie de TV + Añadido a favoritos + Eliminado de favoritos + No se encontraron favoritos + Iniciando reproducción... + Reproduciendo + No se encontró enlace + No se encontró contenido reproducible + No se pudieron cargar los detalles + Error al cargar enlaces + Ajustar a la pantalla + Llenar pantalla + No se encontró fuente + Ninguna fuente disponible + Fuente seleccionada + Buscar + No se encontraron resultados + No se encontró \'Continuar viendo\' + No se encontraron descargas + Archivo no encontrado + No se encontró episodio válido + Seleccionar proveedor + Seleccionado + Biblioteca + Marcadores + Reanudando %1$s... + diff --git a/app/src/main/res-car/values-b+et/strings_car.xml b/app/src/main/res-car/values-b+et/strings_car.xml new file mode 100644 index 00000000000..64067503545 --- /dev/null +++ b/app/src/main/res-car/values-b+et/strings_car.xml @@ -0,0 +1,51 @@ + + + Laadimine... + Viga + Sisu laadimise viga + Lemmikud + Ajalugu + Allalaadimised + Teenusepakkuja + Praegune + Menüü + Avalehe sisu + Teenusepakkujalt puudub sisu + Teenusepakkujat ei leitud + Allikas + Allikad + Sisu + Osades + Viga üksikasjade laadimisel + Episoodide loend + Hooaeg + Hooajad + Episood + Episoode ei leitud + Ei ole telesari + Lisatud lemmikutesse + Eemaldatud lemmikutest + Lemmikuid ei leitud + Taasesituse alustamine... + Esitamine + Link ei leitud + Mängitavat sisu ei leitud + Üksikasju ei saa laadida + Viga linkide laadimisel + Mahuta ekraanile + Täida ekraan + Allikat ei leitud + Ühtegi allikat pole saadaval + Allikas valitud + Otsi + Tulemusi ei leitud + \'Jätka vaatamist\' ei leitud + Allalaadimisi ei leitud + Faili ei leitud + Kehtivat episoodi ei leitud + Vali teenusepakkuja + Valitud + Raamatukogu + Järjehoidjad + Jätkamine %1$s... + diff --git a/app/src/main/res-car/values-b+eu/strings_car.xml b/app/src/main/res-car/values-b+eu/strings_car.xml new file mode 100644 index 00000000000..dd794473078 --- /dev/null +++ b/app/src/main/res-car/values-b+eu/strings_car.xml @@ -0,0 +1,51 @@ + + + Kargatzen... + Errorea + Errorea edukia kargatzean + Gogokoak + Historia + Deskargak + Hornitzailea + Unekoa + Menua + Hasierako edukia + Hornitzailearen edukirik ez + Hornitzailea ez da aurkitu + Iturburua + Iturburuak + Argumentua + Aktoreak + Errorea xehetasunak kargatzean + Atalen zerrenda + Denboraldia + Denboraldiak + Atala + Ez da atalik aurkitu + Ez da telebista saioa + Gogokoetan gehitu da + Gogokoetatik kendu da + Ez da gogokorik aurkitu + Erreprodukzioa hasten... + Erreproduzitzen + Ez da estekarik aurkitu + Ez da erreproduzitzeko edukirik aurkitu + Ezin dira xehetasunak kargatu + Errorea estekak kargatzean + Doitu pantailara + Bete pantaila + Ez da iturbururik aurkitu + Ez dago iturbururik eskuragarri + Iturburua hautatuta + Bilatu + Ez da emaitzarik aurkitu + Ez da \'Jarraitu ikusten\' aurkitu + Ez da deskargarik aurkitu + Ez da fitxategia aurkitu + Ez da baliozko atalik aurkitu + Hautatu hornitzailea + Hautatuta + Liburutegia + Laster-markak + %1$s jarraitzen... + diff --git a/app/src/main/res-car/values-b+fa/strings_car.xml b/app/src/main/res-car/values-b+fa/strings_car.xml new file mode 100644 index 00000000000..8c23b79e7fd --- /dev/null +++ b/app/src/main/res-car/values-b+fa/strings_car.xml @@ -0,0 +1,51 @@ + + + درحال بارگذاری... + خطا + خطا در بارگذاری محتوا + علاقه‌مندی‌ها + تاریخچه + دانلودها + ارائه‌دهنده + کنونی + منو + محتوای خانه + بدون محتوا از ارائه‌دهنده + ارائه‌دهنده یافت نشد + منبع + منابع + داستان + بازیگران + خطا در بارگذاری جزئیات + لیست قسمت‌ها + فصل + فصل‌ها + قسمت + قسمتی یافت نشد + سریال تلویزیونی نیست + به علاقه‌مندی‌ها اضافه شد + از علاقه‌مندی‌ها حذف شد + علاقه‌مندی یافت نشد + شروع پخش... + درحال پخش + لینکی یافت نشد + محتوای قابل پخش یافت نشد + ناتوان در بارگذاری جزئیات + خطا در بارگذاری لینک‌ها + فیت صفحه + پر کردن صفحه + منبع یافت نشد + منبعی در دسترس نیست + منبع انتخاب شد + جستجو + نتیجه‌ای یافت نشد + \'ادامه تماشا\' یافت نشد + دانلودی یافت نشد + فایل یافت نشد + قسمت معتبری یافت نشد + انتخاب ارائه‌دهنده + انتخاب شد + کتابخانه + نشانک‌ها + درحال ادامه %1$s... + diff --git a/app/src/main/res-car/values-b+fi/strings_car.xml b/app/src/main/res-car/values-b+fi/strings_car.xml new file mode 100644 index 00000000000..4c609c8cfcb --- /dev/null +++ b/app/src/main/res-car/values-b+fi/strings_car.xml @@ -0,0 +1,51 @@ + + + Ladataan... + Virhe + Virhe ladattaessa sisältöä + Suosikit + Historia + Lataukset + Palveluntarjoaja + Nykyinen + Valikko + Etusivun sisältö + Ei sisältöä palveluntarjoajalta + Palveluntarjoajaa ei löytynyt + Lähde + Lähteet + Juoni + Näyttelijät + Virhe ladattaessa tietoja + Jaksot + Kausi + Kaudet + Jakso + Jaksoja ei löytynyt + Ei TV-sarja + Lisätty suosikkeihin + Poistettu suosikeista + Ei suosikkeja löytynyt + Aloitetaan toistoa... + Toistetaan + Linkkiä ei löytynyt + Toistettavaa sisältöä ei löytynyt + Tietoja ei voitu ladata + Virhe ladattaessa linkkejä + Sovita näyttöön + Täytä näyttö + Lähdettä ei löytynyt + Ei lähdettä saatavilla + Lähde valittu + Haku + Tuloksia ei löytynyt + \'Jatka katselua\' ei löytynyt + Latauksia ei löytynyt + Tiedostoa ei löytynyt + Kelvollista jaksoa ei löytynyt + Valitse palveluntarjoaja + Valittu + Kirjasto + Kirjanmerkit + Jatketaan %1$s... + diff --git a/app/src/main/res-car/values-b+fil/strings_car.xml b/app/src/main/res-car/values-b+fil/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+fil/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+fr/strings_car.xml b/app/src/main/res-car/values-b+fr/strings_car.xml new file mode 100644 index 00000000000..86f178c5683 --- /dev/null +++ b/app/src/main/res-car/values-b+fr/strings_car.xml @@ -0,0 +1,51 @@ + + + Chargement... + Erreur + Erreur de chargement du contenu + Favoris + Historique + Téléchargements + Fournisseur + Actuel + Menu + Contenu d\'accueil + Aucun contenu du fournisseur + Fournisseur non trouvé + Source + Sources + Intrigue + Distribution + Erreur de chargement des détails + Liste des épisodes + Saison + Saisons + Épisode + Aucun épisode trouvé + Pas une série TV + Ajouté aux favoris + Retiré des favoris + Aucun favori trouvé + Démarrage de la lecture... + Lecture + Aucun lien trouvé + Aucun contenu lisible trouvé + Impossible de charger les détails + Erreur de chargement des liens + Adapter à l\'écran + Remplir l\'écran + Aucune source trouvée + Aucune source disponible + Source sélectionnée + Rechercher + Aucun résultat trouvé + Aucun élément \'Continuer à regarder\' trouvé + Aucun téléchargement trouvé + Fichier non trouvé + Aucun épisode valide trouvé + Sélectionner le fournisseur + Sélectionné + Bibliothèque + Marque-pages + Reprise %1$s... + diff --git a/app/src/main/res-car/values-b+gl/strings_car.xml b/app/src/main/res-car/values-b+gl/strings_car.xml new file mode 100644 index 00000000000..7ae2aa29f06 --- /dev/null +++ b/app/src/main/res-car/values-b+gl/strings_car.xml @@ -0,0 +1,51 @@ + + + Cargando... + Erro + Erro cargando contido + Favoritos + Historial + Descargas + Provedor + Actual + Menú + Contido de inicio + Sen contido do provedor + Provedor non atopado + Fonte + Fontes + Argumento + Reparto + Erro cargando detalles + Lista de episodios + Tempada + Tempadas + Episodio + Non se atoparon episodios + Non é unha serie de TV + Engadido a favoritos + Eliminado de favoritos + Non se atoparon favoritos + Iniciando reprodución... + Reproducindo + Ligazón non atopada + Contido reproducible non atopado + Non se poden cargar os detalles + Erro cargando ligazóns + Axustar á pantalla + Encher pantalla + Fonte non atopada + Non hai fonte dispoñible + Fonte seleccionada + Buscar + Sen resultados + \'Continuar vendo\' non atopado + Sen descargas + Ficheiro non atopado + Sen episodio válido + Seleccionar provedor + Seleccionado + Biblioteca + Marcadores + Retomando %1$s... + diff --git a/app/src/main/res-car/values-b+gu/strings_car.xml b/app/src/main/res-car/values-b+gu/strings_car.xml new file mode 100644 index 00000000000..458737dab3b --- /dev/null +++ b/app/src/main/res-car/values-b+gu/strings_car.xml @@ -0,0 +1,51 @@ + + + લોડ થઈ રહ્યું છે... + ભૂલ + સામગ્રી લોડ કરવામાં ભૂલ + મનપસંદ + ઇતિહાસ + ડાઉનલોડ્સ + પ્રદાતા + વર્તમાન + મેનુ + હોમ સામગ્રી + પ્રદાતા તરફથી કોઈ સામગ્રી નથી + પ્રદાતા મળ્યા નથી + સ્ત્રોત + સ્ત્રોતો + પ્લોટ + કલાકારો + વિગતો લોડ કરવામાં ભૂલ + એ એપિસોડ સૂચિ + સીઝન + સીઝન + એપિસોડ + કોઈ એપિસોડ મળ્યા નથી + ટીવી શ્રેણી નથી + મનપસંદમાં ઉમેર્યું + મનપસંદમાંથી દૂર કર્યું + કોઈ મનપસંદ મળ્યા નથી + પ્લેબેક શરૂ થઈ રહ્યું છે... + રમી રહ્યું છે + કોઈ લિંક મળી નથી + કોઈ રમી શકાય તેવી સામગ્રી મળી નથી + વિગતો લોડ કરવામાં અસમર્થ + લિંક્સ લોડ કરવામાં ભૂલ + સ્ક્રીન પર ફિટ કરો + સ્ક્રીન ભરો + કોઈ સ્ત્રોત મળ્યો નથી + કોઈ સ્ત્રોત ઉપલબ્ધ નથી + સ્ત્રોત પસંદ કર્યો + શોધો + કોઈ પરિણામ મળ્યા નથી + \'જોવાનું ચાલુ રાખો\' મળ્યું નથી + કોઈ ડાઉનલોડ્સ મળ્યા નથી + ફાઇલ મળી નથી + કોઈ માન્ય એપિસોડ મળ્યો નથી + પ્રદાતા પસંદ કરો + પસંદ કરેલ + લાઇબ્રેરી + બુકમાર્ક્સ + %1$s ફરી શરૂ કરી રહ્યું છે... + diff --git a/app/src/main/res-car/values-b+hi/strings_car.xml b/app/src/main/res-car/values-b+hi/strings_car.xml new file mode 100644 index 00000000000..f3418c0e4e3 --- /dev/null +++ b/app/src/main/res-car/values-b+hi/strings_car.xml @@ -0,0 +1,51 @@ + + + 로드 중... + गलती + सामग्री लोड हो रही है + पसंदीदा + इतिहास + डाउनलोड + प्रदाता + वर्तमान + मेन्यू + गृह सामग्री + प्रदाता से कोई सामग्री नहीं + प्रदाता नहीं मिला + स्रोत + सूत्रों + भूखंड + ढालना + विवरण लोड करने में त्रुटि + एपिसोड सूची + मौसम + मौसम + प्रसंग + कोई एपिसोड नहीं मिला + टीवी श्रृंखला नहीं + पसंदीदा में जोड़ा गया + पसंदीदा से हटाया गया + कोई पसंदीदा नहीं मिला + प्लेबैक प्रारंभ हो रहा है... + खेल + कोई लिंक नहीं मिला + कोई खेलने योग्य सामग्री नहीं मिली + विवरण लोड करने में असमर्थ + लिंक लोड करने में त्रुटि + स्क्रीन पर फिट करें + स्क्रीन भरें + कोई स्रोत नहीं मिला + कोई स्रोत उपलब्ध नहीं है + स्रोत चयनित + खोज + कोई परिणाम नहीं मिला + \'देखना जारी रखें\' नहीं मिला + कोई डाउनलोड नहीं मिला + फ़ाइल नहीं मिली + कोई मान्य एपिसोड नहीं मिला + प्रदाता का चयन करें + चयनित + पुस्तकालय + बुकमार्क + %1$s फिर से शुरू... + diff --git a/app/src/main/res-car/values-b+hr/strings_car.xml b/app/src/main/res-car/values-b+hr/strings_car.xml new file mode 100644 index 00000000000..8bf55c3fab5 --- /dev/null +++ b/app/src/main/res-car/values-b+hr/strings_car.xml @@ -0,0 +1,51 @@ + + + Učitavanje... + Greška + Greška pri učitavanju sadržaja + Favoriti + Povijest + Preuzimanja + Pružatelj + Trenutno + Izbornik + Početni sadržaj + Nema sadržaja od pružatelja + Pružatelj nije pronađen + Izvor + Izvori + Radnja + Glumci + Greška pri učitavanju detalja + Popis epizoda + Sezona + Sezone + Epizoda + Nema pronađenih epizoda + Nije TV serija + Dodano u favorite + Uklonjeno iz favorita + Nema favorita + Pokretanje reprodukcije... + Reprodukcija + Poveznica nije pronađena + Sadržaj za reprodukciju nije pronađen + Nije moguće učitati detalje + Greška pri učitavanju poveznica + Prilagodi ekranu + Ispuni ekran + Izvor nije pronađen + Izvor nije dostupan + Izvor odabran + Pretraži + Nema rezultata + \'Nastavi gledanje\' nije pronađeno + Nema preuzimanja + Datoteka nije pronađena + Nema važeće epizode + Odaberi pružatelja + Odabrano + Knjižnica + Oznake + Nastavljanje %1$s... + diff --git a/app/src/main/res-car/values-b+hu/strings_car.xml b/app/src/main/res-car/values-b+hu/strings_car.xml new file mode 100644 index 00000000000..3434ca4a290 --- /dev/null +++ b/app/src/main/res-car/values-b+hu/strings_car.xml @@ -0,0 +1,51 @@ + + + Betöltés... + Hiba + Tartalom betöltési hiba + Kedvencek + Előzmények + Letöltések + Szolgáltató + Jelenlegi + Menü + Kezdőlap tartalom + Nincs tartalom a szolgáltatótól + Szolgáltató nem található + Forrás + Források + Cselekmény + Szereplők + Részletek betöltési hiba + Epizódlista + Évad + Évadok + Epizód + Nem található epizód + Nem TV sorozat + Hozzáadva a kedvencekhez + Eltávolítva a kedvencekből + Nincs kedvenc + Lejátszás indítása... + Lejátszás + Link nem található + Nincs lejátszható tartalom + Nem sikerült betölteni a részleteket + Link betöltési hiba + Képernyőhöz igazítás + Kitöltés + Forrás nem található + Nincs elérhető forrás + Forrás kiválasztva + Keresés + Nincs találat + Nincs \'Nézés folytatása\' + Nincs letöltés + Fájl nem található + Nincs érvényes epizód + Válassz szolgáltatót + Kiválasztva + Könyvtár + Könyvjelzők + %1$s folytatása... + diff --git a/app/src/main/res-car/values-b+hy/strings_car.xml b/app/src/main/res-car/values-b+hy/strings_car.xml new file mode 100644 index 00000000000..414748b3d8b --- /dev/null +++ b/app/src/main/res-car/values-b+hy/strings_car.xml @@ -0,0 +1,51 @@ + + + Բեռնում... + Սխալ + Բովանդակության բեռնման սխալ + Ընտրյալներ + Պատմություն + Ներբեռնումներ + Մատակարար + Ընթացիկ + Մենյու + Գլխավոր էջի բովանդակություն + Մատակարարից բովանդակություն չկա + Մատակարարը չի գտնվել + Աղբյուր + Աղբյուրներ + Սյուժե + Դերասանական կազմ + Մանրամասների բեռնման սխալ + Սերիաների ցանկ + Եթերաշրջան + Եթերաշրջաններ + Սերիա + Սերիաներ չեն գտնվել + Հեռուստասերիալ չէ + Ավելացվել է ընտրյալներին + Հեռացվել է ընտրյալներից + Ընտրյալներ չեն գտնվել + Նվագարկման մեկնարկ... + Նվագարկվում է + Հղում չի գտնվել + Նվագարկվող բովանդակություն չի գտնվել + Հնարավոր չէ բեռնել մանրամասները + Հղումների բեռնման սխալ + Հարմարեցնել էկրանին + Լրացնել էկրանը + Աղբյուր չի գտնվել + Հասանելի աղբյուր չկա + Աղբյուրն ընտրված է + Որոնել + Արդյունքներ չեն գտնվել + \'Շարունակել դիտել\' չի գտնվել + Ներբեռնումներ չեն գտնվել + Ֆայլը չի գտնվել + Վավեր սերիա չի գտնվել + Ընտրեք մատակարար + Ընտրված է + Գրադարան + Էջանիշեր + Շարունակվում է %1$s... + diff --git a/app/src/main/res-car/values-b+in/strings_car.xml b/app/src/main/res-car/values-b+in/strings_car.xml new file mode 100644 index 00000000000..1caea08ba75 --- /dev/null +++ b/app/src/main/res-car/values-b+in/strings_car.xml @@ -0,0 +1,51 @@ + + + Memuat... + Kesalahan + Kesalahan memuat konten + Favorit + Riwayat + Unduhan + Penyedia + Saat Ini + Menu + Konten Beranda + Tidak ada konten dari penyedia + Penyedia tidak ditemukan + Sumber + Sumber + Plot + Pemeran + Kesalahan memuat detail + Daftar Episode + Musim + Musim + Episode + Tidak ada episode ditemukan + Bukan serial TV + Ditambahkan ke favorit + Dihapus dari favorit + Tidak ada favorit ditemukan + Memulai pemutaran... + Memutar + Tautan tidak ditemukan + Tidak ada konten yang dapat diputar + Tidak dapat memuat detail + Kesalahan memuat tautan + Pas ke Layar + Isi Layar + Sumber tidak ditemukan + Tidak ada sumber tersedia + Sumber dipilih + Cari + Tidak ada hasil ditemukan + \'Lanjutkan Menonton\' tidak ditemukan + Tidak ada unduhan ditemukan + Berkas tidak ditemukan + Tidak ada episode valid + Pilih Penyedia + Dipilih + Pustaka + Penanda + Melanjutkan %1$s... + diff --git a/app/src/main/res-car/values-b+is/strings_car.xml b/app/src/main/res-car/values-b+is/strings_car.xml new file mode 100644 index 00000000000..4bf48c74395 --- /dev/null +++ b/app/src/main/res-car/values-b+is/strings_car.xml @@ -0,0 +1,51 @@ + + + Hleður... + Villa + Villa við að hlaða efni + Eftirlæti + Saga + Niðurhal + Veita + Núverandi + Valmynd + Heimaefni + Ekkert efni frá veitu + Veita fannst ekki + Heimild + Heimildir + Söguþráður + Leikarar + Villa við að hlaða upplýsingum + Þáttalisti + Sería + Seríur + Þáttur + Engir þættir fundust + Ekki sjónvarpsþáttaröð + Bætt við eftirlæti + Fjarlægt úr eftirlæti + Engin eftirlæti fundust + Hefur spilun... + Spilar + Enginn tengill fannst + Ekkert spilanlegt efni fannst + Gat ekki hlaðið upplýsingum + Villa við að hlaða tenglum + Passa á skjá + Fylla skjá + Engin heimild fannst + Engin heimild tiltæk + Heimild valin + Leita + Engar niðurstöður fundust + \'Halda áfram að horfa\' fannst ekki + Ekkert niðurhal fannst + Skrá fannst ekki + Enginn gildur þáttur fannst + Veldu veitu + Valið + Bókasafn + Bókamerki + Heldur áfram %1$s... + diff --git a/app/src/main/res-car/values-b+iw/strings_car.xml b/app/src/main/res-car/values-b+iw/strings_car.xml new file mode 100644 index 00000000000..100c986137b --- /dev/null +++ b/app/src/main/res-car/values-b+iw/strings_car.xml @@ -0,0 +1,51 @@ + + + טוען... + שגיאה + שגיאה בטעינת תוכן + מועדפים + היסטוריה + הורדות + ספק + נוכחי + תפריט + תוכן דף הבית + אין תוכן מהספק + ספק לא נמצא + מקור + מקורות + עלילה + שחקנים + שגיאה בטעינת פרטים + רשימת פרקים + עונה + עונות + פרק + לא נמצאו פרקים + לא סדרת טלוויזיה + נוסף למועדפים + הוסר מהמועדפים + לא נמצאו מועדפים + מתחיל ניגון... + מנגן + לא נמצא קישור + לא נמצא תוכן לניגון + לא ניתן לטעון פרטים + שגיאה בטעינת קישורים + התאם למסך + מלא מסך + מקור לא נמצא + אין מקור זמין + מקור נבחר + חיפוש + לא נמצאו תוצאות + \'המשך צפייה\' לא נמצא + לא נמצאו הורדות + קובץ לא נמצא + לא נמצא פרק תקין + בחר ספק + נבחר + ספרייה + סימניות + ממשיך %1$s... + diff --git a/app/src/main/res-car/values-b+ja/strings_car.xml b/app/src/main/res-car/values-b+ja/strings_car.xml new file mode 100644 index 00000000000..940e87c68a5 --- /dev/null +++ b/app/src/main/res-car/values-b+ja/strings_car.xml @@ -0,0 +1,51 @@ + + + 読み込み中... + エラー + コンテンツの読み込みエラー + お気に入り + 履歴 + ダウンロード + プロバイダー + 現在 + メニュー + ホームコンテンツ + プロバイダーからのコンテンツなし + プロバイダーが見つかりません + ソース + ソース + あらすじ + キャスト + 詳細の読み込みエラー + エピソードリスト + シーズン + シーズン + エピソード + エピソードが見つかりません + TV番組ではありません + お気に入りに追加しました + お気に入りから削除しました + お気に入りが見つかりません + 再生を開始しています... + 再生中 + リンクが見つかりません + 再生可能なコンテンツが見つかりません + 詳細を読み込めません + リンクの読み込みエラー + 画面に合わせる + 画面を埋める + ソースが見つかりません + 利用可能なソースがありません + ソースを選択しました + 検索 + 結果が見つかりません + 続きを見るコンテンツがありません + ダウンロードが見つかりません + ファイルが見つかりません + 有効なエピソードが見つかりません + プロバイダーを選択 + 選択済み + ライブラリ + ブックマーク + %1$s を再開しています... + diff --git a/app/src/main/res-car/values-b+ka/strings_car.xml b/app/src/main/res-car/values-b+ka/strings_car.xml new file mode 100644 index 00000000000..d1b995dc81e --- /dev/null +++ b/app/src/main/res-car/values-b+ka/strings_car.xml @@ -0,0 +1,51 @@ + + + ჩატვირთვა... + შეცდომა + შინაარსის ჩატვირთვის შეცდომა + რჩეულები + ისტორია + ჩამოტვირთვები + მომწოდებელი + მიმდინარე + მენიუ + მთავარი შინაარსი + შინაარსი მომწოდებლისგან არ არის + მომწოდებელი ვერ მოიძებნა + წყარო + წყაროები + სიუჟეტი + მსახიობები + დეტალების ჩატვირთვის შეცდომა + ეპიზოდების სია + სეზონი + სეზონები + ეპიზოდი + ეპიზოდები ვერ მოიძებნა + არ არის სატელევიზიო სერიალი + დაემატა რჩეულებში + ამოღებულია რჩეულებიდან + რჩეულები ვერ მოიძებნა + დაკვრის დაწყება... + დაკვრა + ბმული ვერ მოიძებნა + დასაკრავი შინაარსი ვერ მოიძებნა + დეტალების ჩატვირთვა ვერ მოხერხდა + ბმულების ჩატვირთვის შეცდომა + ეკრანზე მორგება + ეკრანის შევსება + წყარო ვერ მოიძებნა + წყარო არ არის ხელმისაწვდომი + წყარო არჩეულია + ძიება + შედეგები ვერ მოიძებნა + \'ყურების გაგრძელება\' ვერ მოიძებნა + ჩამოტვირთვები ვერ მოიძებნა + ფაილი ვერ მოიძებნა + ვალიდური ეპიზოდი ვერ მოიძებნა + აირჩიეთ მომწოდებელი + არჩეულია + ბიბლიოთეკა + სანიშნეები + გრძელდება %1$s... + diff --git a/app/src/main/res-car/values-b+kk/strings_car.xml b/app/src/main/res-car/values-b+kk/strings_car.xml new file mode 100644 index 00000000000..e1cffdd409d --- /dev/null +++ b/app/src/main/res-car/values-b+kk/strings_car.xml @@ -0,0 +1,51 @@ + + + Жүктелуде... + Қате + Мазмұнды жүктеу қатесі + Таңдаулылар + Тарих + Жүктеулер + Провайдер + Ағымдағы + Мәзір + Басты бет мазмұны + Провайдерден мазмұн жоқ + Провайдер табылмады + Дереккөз + Дереккөздер + Сюжет + Актерлер + Мәліметтерді жүктеу қатесі + Эпизодтар тізімі + Маусым + Маусымдар + Эпизод + Эпизодтар табылмады + ТВ сериалы емес + Таңдаулыларға қосылды + Таңдаулылардан жойылды + Таңдаулылар табылмады + Ойнату басталуда... + Ойнатылуда + Сілтеме табылмады + Ойнатылатын мазмұн табылмады + Мәліметтерді жүктеу мүмкін емес + Сілтемелерді жүктеу қатесі + Экранға сыйғызу + Экранды толтыру + Дереккөз табылмады + Қолжетімді дереккөз жоқ + Дереккөз таңдалды + Іздеу + Нәтижелер табылмады + \'Көруді жалғастыру\' табылмады + Жүктеулер табылмады + Файл табылмады + Жарамды эпизод табылмады + Провайдерді таңдаңыз + Таңдалды + Кітапхана + Бетбелгілер + Жалғастырылуда %1$s... + diff --git a/app/src/main/res-car/values-b+km/strings_car.xml b/app/src/main/res-car/values-b+km/strings_car.xml new file mode 100644 index 00000000000..0a6743d3ba1 --- /dev/null +++ b/app/src/main/res-car/values-b+km/strings_car.xml @@ -0,0 +1,51 @@ + + + កំពុងផ្ទុក... + កំហុស + កំហុសក្នុងការផ្ទុកមាតិកា + ដែលចូលចិត្ត + ប្រវត្តិ + ការទាញយក + អ្នកផ្តល់សេវា + បច្ចុប្បន្ន + ម៉ឺនុយ + មាតិកាដើម + គ្មានមាតិកាពីអ្នកផ្តល់សេវា + រកមិនឃើញអ្នកផ្តល់សេវា + ប្រភព + ប្រភព + សាច់រឿង + តួសម្តែង + កំហុសក្នុងការផ្ទុកព័ត៌មានលម្អិត + បញ្ជីភាគ + រដូវកាល + រដូវកាល + ភាគ + រកមិនឃើញភាគ + មិនមែនជាស៊េរីទូរទស្សន៍ + បានបន្ថែមទៅការចូលចិត្ត + បានលុបចេញពីការចូលចិត្ត + រកមិនឃើញការចូលចិត្ត + កំពុងចាប់ផ្តើមការចាក់សារថ្មី... + កំពុងចាក់ + រកមិនឃើញតំណ + រកមិនឃើញមាតិកាដែលអាចចាក់បាន + មិនអាចផ្ទុកព័ត៌មានលម្អិត + កំហុសក្នុងការផ្ទុកតំណ + សមនឹងអេក្រង់ + ពេញអេក្រង់ + រកមិនឃើញប្រភព + គ្មានប្រភពដែលអាចប្រើបាន + បានជ្រើសរើសប្រភព + ស្វែងរក + រកមិនឃើញលទ្ធផល + រកមិនឃើញ \'បន្តមើល\' + រកមិនឃើញការទាញយក + រកមិនឃើញឯកសារ + រកមិនឃើញភាគដែលមានសុពលភាព + ជ្រើសរើសអ្នកផ្តល់សេវា + បានជ្រើសរើស + បណ្ណាល័យ + ចំណាំ + កំពុងបន្ត %1$s... + diff --git a/app/src/main/res-car/values-b+kn/strings_car.xml b/app/src/main/res-car/values-b+kn/strings_car.xml new file mode 100644 index 00000000000..7a20b0d2a20 --- /dev/null +++ b/app/src/main/res-car/values-b+kn/strings_car.xml @@ -0,0 +1,51 @@ + + + ಲೋಡ್ ಆಗುತ್ತಿದೆ... + ದೋಷ + ವಿಷಯವನ್ನು ಲೋಡ್ ಮಾಡುವಲ್ಲಿ ದೋಷ + ಮೆಚ್ಚಿನವುಗಳು + ಇತಿಹಾಸ + ಡೌನ್‌ಲೋಡ್‌ಗಳು + ಪೂರೈಕೆದಾರ + ಪ್ರಸ್ತುತ + ಮೆನು + ಮುಖಪುಟ ವಿಷಯ + ಪೂರೈಕೆದಾರರಿಂದ ಯಾವುದೇ ವಿಷಯವಿಲ್ಲ + ಪೂರೈಕೆದಾರ ಕಂಡುಬಂದಿಲ್ಲ + ಮೂಲ + ಮೂಲಗಳು + ಕಥಾವಸ್ತು + ಪಾತ್ರವರ್ಗ + ವಿವರಗಳನ್ನು ಲೋಡ್ ಮಾಡುವಲ್ಲಿ ದೋಷ + ಸಂಚಿಕೆ ಪಟ್ಟಿ + ಋತು + ಋತುಗಳು + ಸಂಚಿಕೆ + ಯಾವುದೇ ಸಂಚಿಕೆಗಳು ಕಂಡುಬಂದಿಲ್ಲ + ಟಿವಿ ಸರಣಿಯಲ್ಲ + ಮೆಚ್ಚಿನವುಗಳಿಗೆ ಸೇರಿಸಲಾಗಿದೆ + ಮೆಚ್ಚಿನವುಗಳಿಂದ ತೆಗೆದುಹಾಕಲಾಗಿದೆ + ಯಾವುದೇ ಮೆಚ್ಚಿನವುಗಳು ಕಂಡುಬಂದಿಲ್ಲ + ಪ್ಲೇಬ್ಯಾಕ್ ಪ್ರಾರಂಭವಾಗುತ್ತಿದೆ... + ಪ್ಲೇ ಆಗುತ್ತಿದೆ + ಯಾವುದೇ ಲಿಂಕ್ ಕಂಡುಬಂದಿಲ್ಲ + ಯಾವುದೇ ಪ್ಲೇ ಮಾಡಬಹುದಾದ ವಿಷಯ ಕಂಡುಬಂದಿಲ್ಲ + ವಿವರಗಳನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ + ಲಿಂಕ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡುವಲ್ಲಿ ದೋಷ + ಪರದೆಗೆ ಹೊಂದಿಸಿ + ಪರದೆ ತುಂಬಿಸಿ + ಯಾವುದೇ ಮೂಲ ಕಂಡುಬಂದಿಲ್ಲ + ಯಾವುದೇ ಮೂಲ ಲಭ್ಯವಿಲ್ಲ + ಮೂಲ ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ + ಹುಡುಕಿ + ಯಾವುದೇ ಫಲಿತಾಂಶಗಳು ಕಂಡುಬಂದಿಲ್ಲ + \'ವೀಕ್ಷಣೆ ಮುಂದುವರಿಸಿ\' ಕಂಡುಬಂದಿಲ್ಲ + ಯಾವುದೇ ಡೌನ್‌ಲೋಡ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ + ಫೈಲ್ ಕಂಡುಬಂದಿಲ್ಲ + ಯಾವುದೇ ಮಾನ್ಯ ಸಂಚಿಕೆ ಕಂಡುಬಂದಿಲ್ಲ + ಪೂರೈಕೆದಾರರನ್ನು ಆಯ್ಕೆಮಾಡಿ + ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ + ಗ್ರಂಥಾಲಯ + ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು + %1$s ಪುನರಾರಂಭವಾಗುತ್ತಿದೆ... + diff --git a/app/src/main/res-car/values-b+ko/strings_car.xml b/app/src/main/res-car/values-b+ko/strings_car.xml new file mode 100644 index 00000000000..0c6f7bf81fd --- /dev/null +++ b/app/src/main/res-car/values-b+ko/strings_car.xml @@ -0,0 +1,51 @@ + + + 로드 중... + 오류 + 콘텐츠 로드 오류 + 즐겨찾기 + 기록 + 다운로드 + 제공자 + 현재 + 메뉴 + 홈 콘텐츠 + 제공자의 콘텐츠 없음 + 제공자를 찾을 수 없음 + 소스 + 소스 + 줄거리 + 출연진 + 세부 정보 로드 오류 + 에피소드 목록 + 시즌 + 시즌 + 에피소드 + 에피소드 없음 + TV 시리즈 아님 + 즐겨찾기에 추가됨 + 즐겨찾기에서 제거됨 + 즐겨찾기 없음 + 재생 시작 중... + 재생 중 + 링크 없음 + 재생 가능한 콘텐츠 없음 + 세부 정보를 로드할 수 없음 + 링크 로드 오류 + 화면에 맞춤 + 화면 채우기 + 소스 없음 + 사용 가능한 소스 없음 + 소스 선택됨 + 검색 + 결과 없음 + 이어보기 없음 + 다운로드 없음 + 파일 없음 + 유효한 에피소드 없음 + 제공자 선택 + 선택됨 + 라이브러리 + 북마크 + %1$s 이어보는 중... + diff --git a/app/src/main/res-car/values-b+ky/strings_car.xml b/app/src/main/res-car/values-b+ky/strings_car.xml new file mode 100644 index 00000000000..4f5a4790a09 --- /dev/null +++ b/app/src/main/res-car/values-b+ky/strings_car.xml @@ -0,0 +1,51 @@ + + + Жүктөө... + Ката + Мазмунду жүктөө катасы + Сүйүктүүлөр + Тарых + Жүктөөлөр + Провайдер + Учурдагы + Меню + Башкы мазмун + Провайдерден мазмун жок + Провайдер табылган жок + Булак + Булактар + Сюжет + Актерлор + Маалыматтарды жүктөө катасы + Эпизоддор тизмеси + Сезон + Сезондор + Эпизод + Эпизоддор табылган жок + ТВ сериалы эмес + Сүйүктүүлөргө кошулду + Сүйүктүүлөрдөн алынды + Сүйүктүүлөр табылган жок + Ойнотуу башталууда... + Ойнотулууда + Шилтеме табылган жок + Ойнотула турган мазмун табылган жок + Маалыматтарды жүктөө мүмкүн эмес + Шилтемелерди жүктөө катасы + Экранга тууралоо + Экранды толтуруу + Булак табылган жок + Жеткиликтүү булак жок + Булак тандалды + Издөө + Жыйынтык табылган жок + \'Көрүүнү улантуу\' табылган жок + Жүктөөлөр табылган жок + Файл табылган жок + Жарактуу эпизод табылган жок + Провайдерди тандоо + Тандалды + Китепкана + Кыстармалар + Улантылууда %1$s... + diff --git a/app/src/main/res-car/values-b+lo/strings_car.xml b/app/src/main/res-car/values-b+lo/strings_car.xml new file mode 100644 index 00000000000..6241b14e84c --- /dev/null +++ b/app/src/main/res-car/values-b+lo/strings_car.xml @@ -0,0 +1,51 @@ + + + ກຳລັງໂຫຼດ... + ຂໍ້ຜິດພາດ + ເກີດຂໍ້ຜິດພາດໃນການໂຫຼດເນື້ອຫາ + ລາຍການທີ່ມັກ + ປະຫວັດການເຂົ້າຊົມ + ການດາວໂຫຼດ + ຜູ້ໃຫ້ບໍລິການ + ປັດຈຸບັນ + ເມນູ + ເນື້ອຫາໜ້າຫຼັກ + ບໍ່ມີເນື້ອຫາຈາກຜູ້ໃຫ້ບໍລິການ + ບໍ່ພົບຜູ້ໃຫ້ບໍລິການ + ແຫຼ່ງທີ່ມາ + ແຫຼ່ງທີ່ມາ + ເນື້ອເລື່ອງ + ນັກສະແດງ + ເກີດຂໍ້ຜິດພາດໃນການໂຫຼດລາຍລະອຽດ + ລາຍການຕອນ + ຊີຊັນ + ຊີຊັນ + ຕອນ + ບໍ່ພົບຕອນ + ບໍ່ແມ່ນຊີຣີໂທລະທັດ + ເພີ່ມເຂົ້າໃນລາຍການທີ່ມັກແລ້ວ + ລົບອອກຈາກລາຍການທີ່ມັກແລ້ວ + ບໍ່ພົບລາຍການທີ່ມັກ + ກຳລັງເລີ່ມການຫຼິ້ນ... + ກຳລັງຫຼິ້ນ + ບໍ່ພົບລິ້ງ + ບໍ່ພົບເນື້ອຫາທີ່ສາມາດຫຼິ້ນໄດ້ + ບໍ່ສາມາດໂຫຼດລາຍລະອຽດໄດ້ + ເກີດຂໍ້ຜິດພາດໃນການໂຫຼດລິ້ງ + ປັບໃຫ້ພໍດີກັບໜ້າຈໍ + ຂະຫຍາຍເຕັ້ນໜ້າຈໍ + ບໍ່ພົບແຫຼ່ງທີ່ມາ + ບໍ່ມີແຫຼ່ງທີ່ມາທີ່ໃຊ້ໄດ້ + ເລືອກແຫຼ່ງທີ່ມາແລ້ວ + ຄົ້ນຫາ + ບໍ່ພົບຜົນການຄົ້ນຫາ + ບໍ່ພົບ \'ເບິ່ງຕໍ່\' + ບໍ່ພົບການດາວໂຫຼດ + ບໍ່ພົບໄຟລ໌ + ບໍ່ພົບຕອນທີ່ຖືກຕ້ອງ + ເລືອກຜູ້ໃຫ້ບໍລິການ + ທີ່ເລືອກ + ຫ້ອງສະໝຸດ + ບຸກມາກ + ກຳລັງເບິ່ງຕໍ່ %1$s... + diff --git a/app/src/main/res-car/values-b+lt/strings_car.xml b/app/src/main/res-car/values-b+lt/strings_car.xml new file mode 100644 index 00000000000..2812345f660 --- /dev/null +++ b/app/src/main/res-car/values-b+lt/strings_car.xml @@ -0,0 +1,51 @@ + + + Įkeliama... + Klaida + Klaida įkeliant turinį + Mėgstamiausi + Istorija + Atsisiuntimai + Tiekėjas + Dabartinis + Meniu + Pradžios turinys + Nėra turinio iš tiekėjo + Tiekėjas nerastas + Šaltinis + Šaltiniai + Siužetas + Aktoriai + Klaida įkeliant informaciją + Epizodų sąrašas + Sezonas + Sezonai + Epizodas + Epizodų nerasta + Ne TV serialas + Pridėta prie mėgstamiausių + Pašalinta iš mėgstamiausių + Mėgstamiausių nerasta + Pradedamas atkūrimas... + Atkuriama + Nuoroda nerasta + Atkuriamo turinio nerasta + Nepavyko įkelti informacijos + Klaida įkeliant nuorodas + Pritaikyti ekranui + Užpildyti ekraną + Šaltinis nerastas + Nėra galimų šaltinių + Šaltinis pasirinktas + Paieška + Rezultatų nerasta + \'Tęsti žiūrėjimą\' nerasta + Atsisiuntimų nerasta + Failas nerastas + Nerastas tinkamas epizodas + Pasirinkite tiekėją + Pasirinkta + Biblioteka + Žymos + Tęsiama %1$s... + diff --git a/app/src/main/res-car/values-b+lv/strings_car.xml b/app/src/main/res-car/values-b+lv/strings_car.xml new file mode 100644 index 00000000000..386bf2b92fa --- /dev/null +++ b/app/src/main/res-car/values-b+lv/strings_car.xml @@ -0,0 +1,51 @@ + + + Ielādē... + Kļūda + Satura ielādes kļūda + Izlase + Vēsture + Lejupielādes + Piegādātājs + Pašreizējais + Izvēlne + Sākuma saturs + Nav satura no piegādātāja + Piegādātājs nav atrasts + Avots + Avoti + Sižets + Lomas + Kļūda ielādējot informāciju + Epizožu saraksts + Sezona + Sezonas + Epizode + Epizodes nav atrastas + Nav TV seriāls + Pievienots izlasei + Noņemts no izlases + Izlase nav atrasta + Sāk atskaņošanu... + Atskaņo + Saite nav atrasta + Nav atrasts atskaņojams saturs + Nevar ielādēt informāciju + Kļūda ielādējot saites + Pielāgot ekrānam + Aizpildīt ekrānu + Avots nav atrasts + Nav pieejamu avotu + Avots izvēlēts + Meklēt + Rezultāti nav atrasti + \'Turpināt skatīties\' nav atrasts + Lejupielādes nav atrastas + Fails nav atrasts + Nav atrasta derīga epizode + Izvēlēties piegādātāju + Izvēlēts + Bibliotēka + Grāmatzīmes + Atsāk %1$s... + diff --git a/app/src/main/res-car/values-b+mk/strings_car.xml b/app/src/main/res-car/values-b+mk/strings_car.xml new file mode 100644 index 00000000000..bdc47d33110 --- /dev/null +++ b/app/src/main/res-car/values-b+mk/strings_car.xml @@ -0,0 +1,51 @@ + + + Вчитување... + Грешка + Грешка при вчитување содржина + Омилени + Историја + Преземања + Добавувач + Тековно + Мени + Почетна содржина + Нема содржина од добавувачот + Добавувачот не е пронајден + Извор + Извори + Дејство + Улоги + Грешка при вчитување детали + Листа на епизоди + Сезона + Сезони + Епизода + Не се пронајдени епизоди + Не е ТВ серија + Додадено во омилени + Отстрането од омилени + Не се пронајдени омилени + Започнување репродукција... + Репродукција + Врската не е пронајдена + Не е пронајдена содржина за репродукција + Не може да се вчитаат детали + Грешка при вчитување врски + Вклопи во екран + Пополни екран + Изворот не е пронајден + Нема достапен извор + Изворот е избран + Пребарување + Не се пронајдени резултати + \'Продолжи со гледање\' не е пронајдено + Не се пронајдени преземања + Датотеката не е пронајдена + Не е пронајдена валидна епизода + Избери добавувач + Избрано + Библиотека + Обележувачи + Продолжување %1$s... + diff --git a/app/src/main/res-car/values-b+ml/strings_car.xml b/app/src/main/res-car/values-b+ml/strings_car.xml new file mode 100644 index 00000000000..d1af8f61ff2 --- /dev/null +++ b/app/src/main/res-car/values-b+ml/strings_car.xml @@ -0,0 +1,51 @@ + + + ലോഡ് ചെയ്യുന്നു... + പിശക് + ഉള്ളടക്കം ലോഡ് ചെയ്യുന്നതിൽ പിശക് + പ്രിയപ്പെട്ടവ + ചരിത്രം + ഡൗൺലോഡുകൾ + ദാതാവ് + നിലവിലുള്ള + മെനു + ഹോം ഉള്ളടക്കം + ദാതാവിൽ നിന്ന് ഉള്ളടക്കമില്ല + ദാതാവിനെ കണ്ടെത്തിയില്ല + ഉറവിടം + ഉറവിടങ്ങൾ + ഇതിവൃത്തം + അഭിനേതാക്കൾ + വിശദാംശങ്ങൾ ലോഡ് ചെയ്യുന്നതിൽ പിശക് + എപ്പിസോഡ് ലിസ്റ്റ് + സീസൺ + സീസണുകൾ + എപ്പിസോഡ് + എപ്പിസോഡുകളൊന്നും കണ്ടെത്തിയില്ല + ടിവി സീരീസ് അല്ല + പ്രിയപ്പെട്ടവയിലേക്ക് ചേർത്തു + പ്രിയപ്പെട്ടവയിൽ നിന്ന് നീക്കം ചെയ്തു + പ്രിയപ്പെട്ടവയൊന്നും കണ്ടെത്തിയില്ല + പ്ലേബാക്ക് ആരംഭിക്കുന്നു... + പ്ലേ ചെയ്യുന്നു + ലിങ്ക് കണ്ടെത്തിയില്ല + പ്ലേ ചെയ്യാവുന്ന ഉള്ളടക്കമൊന്നും കണ്ടെത്തിയില്ല + വിശദാംശങ്ങൾ ലോഡ് ചെയ്യാനായില്ല + ലിങ്കുകൾ ലോഡ് ചെയ്യുന്നതിൽ പിശക് + സ്‌ക്രീനിലേക്ക് യോജിപ്പിക്കുക + സ്‌ക്രീൻ നിറയ്ക്കുക + ഉറവിടം കണ്ടെത്തിയില്ല + ഉറവിടമൊന്നും ലഭ്യമല്ല + ഉറവിടം തിരഞ്ഞെടുത്തു + തിരയുക + ഫലങ്ങളൊന്നും കണ്ടെത്തിയില്ല + \'കാണുന്നത് തുടരുക\' കണ്ടെത്തിയില്ല + ഡൗൺലോഡുകളൊന്നും കണ്ടെത്തിയില്ല + ഫയൽ കണ്ടെത്തിയില്ല + സാധുവായ എപ്പിസോഡ് കണ്ടെത്തിയില്ല + ദാതാവിനെ തിരഞ്ഞെടുക്കുക + തിരഞ്ഞെടുത്തു + ലൈബ്രറി + ബുക്ക്മാർക്കുകൾ + %1$s പുനരാരംഭിക്കുന്നു... + diff --git a/app/src/main/res-car/values-b+mn/strings_car.xml b/app/src/main/res-car/values-b+mn/strings_car.xml new file mode 100644 index 00000000000..69bb275def9 --- /dev/null +++ b/app/src/main/res-car/values-b+mn/strings_car.xml @@ -0,0 +1,51 @@ + + + Ачаалж байна... + Алдаа + Контент ачаалахад алдаа гарлаа + Таалагдсан + Түүх + Татаж авсан + Нийлүүлэгч + Одоогийн + Цэс + Нүүр хуудасны контент + Нийлүүлэгчээс контент алга + Нийлүүлэгч олдсонгүй + Эх сурвалж + Эх сурвалжууд + Үйл явдал + Дүрүүд + Дэлгэрэнгүйг ачаалахад алдаа гарлаа + Ангийн жагсаалт + Бүлэг + Бүлгүүд + Анги + Анги олдсонгүй + ТВ цуврал биш + Таалагдсанд нэмлээ + Таалагдсанаас хаслаа + Таалагдсан контент олдсонгүй + Тоглуулж эхэлж байна... + Тоглуулж байна + Холбоос олдсонгүй + Тоглуулах контент олдсонгүй + Дэлгэрэнгүйг ачаалах боломжгүй + Холбоос ачаалахад алдаа гарлаа + Дэлгэцэнд тааруулах + Дэлгэц дүүргэх + Эх сурвалж олдсонгүй + Боломжит эх сурвалж алга + Эх сурвалж сонгогдсон + Хайх + Үр дүн олдсонгүй + \'Үргэлжлүүлж үзэх\' олдсонгүй + Таталт олдсонгүй + Файл олдсонгүй + Хүчинтэй анги олдсонгүй + Нийлүүлэгч сонгох + Сонгогдсон + Сан + Хавчуурга + %1$s үргэлжлүүлж байна... + diff --git a/app/src/main/res-car/values-b+mr/strings_car.xml b/app/src/main/res-car/values-b+mr/strings_car.xml new file mode 100644 index 00000000000..656591ef267 --- /dev/null +++ b/app/src/main/res-car/values-b+mr/strings_car.xml @@ -0,0 +1,51 @@ + + + लोड होत आहे... + त्रुटी + सामग्री लोड करताना त्रुटी + आवडते + इतिहास + डाउनलोड + पुरवठादार + वर्तमान + मेनू + होम सामग्री + पुरवठादाराकडून कोणतीही सामग्री नाही + पुरवठादार सापडला नाही + स्त्रोत + स्त्रोत + कथानक + कलाकार + तपशील लोड करताना त्रुटी + एपिसोड यादी + सीझन + सीझन + एपिसोड + कोणतेही एपिसोड सापडले नाहीत + टीव्ही मालिका नाही + आवडत्यांमध्ये जोडले + आवडत्यांमधून काढले + कोणतेही आवडते सापडले नाहीत + प्लेबॅक सुरू होत आहे... + प्ले होत आहे + कोणतीही लिंक सापडली नाही + कोणतीही प्ले करण्यायोग्य सामग्री सापडली नाही + तपशील लोड करण्यास अक्षम + लिंक लोड करताना त्रुटी + स्क्रीनवर बसवा + स्क्रीन भरा + कोणताही स्त्रोत सापडला नाही + कोणताही स्त्रोत उपलब्ध नाही + स्त्रोत निवडला + शोधा + कोणतेही परिणाम सापडले नाहीत + \'पाहणे सुरू ठेवा\' सापडले नाही + कोणतेही डाउनलोड सापडले नाहीत + फाइल सापडली नाही + कोणताही वैध एपिसोड सापडला नाही + पुरवठादार निवडा + निवडलेले + ग्रंथालय + बुकमार्क + %1$s पुन्हा सुरू करत आहे... + diff --git a/app/src/main/res-car/values-b+ms/strings_car.xml b/app/src/main/res-car/values-b+ms/strings_car.xml new file mode 100644 index 00000000000..3735de6abcc --- /dev/null +++ b/app/src/main/res-car/values-b+ms/strings_car.xml @@ -0,0 +1,51 @@ + + + Memuatkan... + Ralat + Ralat memuatkan kandungan + Kegemaran + Sejarah + Muat Turun + Penyedia + Semasa + Menu + Kandungan Laman Utama + Tiada kandungan dari penyedia + Penyedia tidak ditemui + Sumber + Sumber + Plot + Pelakon + Ralat memuatkan butiran + Senarai Episod + Musim + Musim + Episod + Tiada episod ditemui + Bukan siri TV + Ditambah ke kegemaran + Dibuang dari kegemaran + Tiada kegemaran ditemui + Memulakan main balik... + Memainkan + Pautan tidak ditemui + Tiada kandungan boleh dimainkan ditemui + Tidak dapat memuatkan butiran + Ralat memuatkan pautan + Muat ke Skrin + Penuhi Skrin + Tiada sumber ditemui + Tiada sumber tersedia + Sumber dipilih + Cari + Tiada hasil ditemui + \'Teruskan Menonton\' tidak ditemui + Tiada muat turun ditemui + Fail tidak ditemui + Tiada episod sah ditemui + Pilih Penyedia + Dipilih + Perpustakaan + Penanda Buku + Menyambung semula %1$s... + diff --git a/app/src/main/res-car/values-b+mt/strings_car.xml b/app/src/main/res-car/values-b+mt/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+mt/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+my/strings_car.xml b/app/src/main/res-car/values-b+my/strings_car.xml new file mode 100644 index 00000000000..67f29ecd327 --- /dev/null +++ b/app/src/main/res-car/values-b+my/strings_car.xml @@ -0,0 +1,51 @@ + + + Loading... + အမှား + အကြောင်းအရာကို ဆွဲယူရာတွင် အမှားဖြစ်နေသည် + အကြိုက်ဆုံးများ + မှတ်တမ်း + ဒေါင်းလုဒ်များ + ပံ့ပိုးသူ + လက်ရှိ + မီနူး + ပင်မစာမျက်နှာ + ပံ့ပိုးသူထံမှ အကြောင်းအရာ မရှိပါ + ပံ့ပိုးသူကို မတွေ့ပါ + အရင်းအမြစ် + အရင်းအမြစ်များ + ဇာတ်လမ်းအကျဉ်း + သရုပ်ဆောင်များ + အသေးစိတ်အချက်အလက်များကို ဆွဲယူရာတွင် အမှားဖြစ်နေသည် + အပိုင်းများ + ရာသီ + ရာသီများ + အပိုင်း + အပိုင်းများ မတွေ့ပါ + တီဗီစီးရီး မဟုတ်ပါ + အကြိုက်ဆုံးများသို့ ထည့်ပြီးပါပြီ + အကြိုက်ဆုံးများမှ ဖယ်ရှားလိုက်ပါပြီ + အကြိုက်ဆုံးများ မတွေ့ပါ + ဖွင့်နေသည်... + ဖွင့်နေသည် + လင့်ခ်မတွေ့ပါ + ဖွင့်နိုင်သော အကြောင်းအရာ မတွေ့ပါ + အသေးစိတ်အချက်အလက်များကို မဆွဲယူနိုင်ပါ + လင့်ခ်များကို ဆွဲယူရာတွင် အမှားဖြစ်နေသည် + မျက်နှာပြင်နှင့် အံကိုက် + မျက်နှာပြင်အပြည့် + အရင်းအမြစ် မတွေ့ပါ + ရရှိနိုင်သော အရင်းအမြစ် မရှိပါ + အရင်းအမြစ်ကို ရွေးချယ်လိုက်သည် + ရှာဖွေရန် + ရလဒ်မတွေ့ပါ + \'ဆက်လက်ကြည့်ရှုရန်\' မတွေ့ပါ + ဒေါင်းလုဒ်များ မတွေ့ပါ + ဖိုင်မတွေ့ပါ + မှန်ကန်သော အပိုင်း မတွေ့ပါ + ပံ့ပိုးသူကို ရွေးချယ်ပါ + ရွေးချယ်ပြီး + စာကြည့်တိုက် + မှတ်သားမှုများ + %1$s ကို ဆက်လက်ကြည့်ရှုနေသည်... + diff --git a/app/src/main/res-car/values-b+ne/strings_car.xml b/app/src/main/res-car/values-b+ne/strings_car.xml new file mode 100644 index 00000000000..ec6ce51b767 --- /dev/null +++ b/app/src/main/res-car/values-b+ne/strings_car.xml @@ -0,0 +1,51 @@ + + + लोड हुँदैछ... + त्रुटि + सामग्री लोड गर्दा त्रुटि + मनपर्नेहरू + इतिहास + डाउनलोडहरू + प्रदायक + हालको + मेनु + गृह सामग्री + प्रदायकबाट कुनै सामग्री छैन + प्रदायक फेला परेन + स्रोत + स्रोतहरू + कथा + कलाकारहरू + विवरण लोड गर्दा त्रुटि + एपिसोड सूची + सिजन + सिजनहरू + एपिसोड + कुनै एपिसोड फेला परेन + टिभी शृङ्खला होइन + मनपर्नेमा थपियो + मनपर्नेबाट हटाइयो + कुनै मनपर्ने फेला परेन + प्लेब्याक सुरु हुँदैछ... + बजाउँदै + कुनै लिङ्क फेला परेन + कुनै बजाउन योग्य सामग्री फेला परेन + विवरण लोड गर्न असक्षम + लिङ्कहरू लोड गर्दा त्रुटि + स्क्रिनमा मिलाउनुहोस् + स्क्रिन भर्नुहोस् + कुनै स्रोत फेला परेन + कुनै स्रोत उपलब्ध छैन + स्रोत चयन गरियो + खोज्नुहोस् + कुनै नतिजा फेला परेन + \'हेर्न जारी राख्नुहोस्\' फेला परेन + कुनै डाउनलोड फेला परेन + फाइल फेला परेन + कुनै मान्य एपिसोड फेला परेन + प्रदायक चयन गर्नुहोस् + चयन गरिएको + पुस्तकालय + बुकमार्कहरू + %1$s सुचारु हुँदैछ... + diff --git a/app/src/main/res-car/values-b+nl/strings_car.xml b/app/src/main/res-car/values-b+nl/strings_car.xml new file mode 100644 index 00000000000..891c01a4b40 --- /dev/null +++ b/app/src/main/res-car/values-b+nl/strings_car.xml @@ -0,0 +1,51 @@ + + + Laden... + Fout + Fout bij laden inhoud + Favorieten + Geschiedenis + Downloads + Aanbieder + Huidig + Menu + De inhoud van het huis + Geen inhoud van aanbieder + Aanbieder niet gevonden + Bron + Bronnen + Verhaal + Cast + Fout bij laden details + Afleveringenlijst + Seizoen + Seizoenen + Aflevering + Geen afleveringen gevonden + Geen TV-serie + Toegevoegd aan favorieten + Verwijderd uit favorieten + Geen favorieten gevonden + Afspelen starten... + Afspelen + Geen link gevonden + Geen afspeelbare inhoud gevonden + Kan details niet laden + Fout bij laden links + Passend maken + Scherm vullen + Geen bron gevonden + Geen bron beschikbaar + Bron geselecteerd + Zoeken + Geen resultaten gevonden + Geen \'Verder kijken\' gevonden + Geen downloads gevonden + Bestand niet gevonden + Geen geldige aflevering gevonden + Selecteer aanbieder + Geselecteerd + Bibliotheek + Bladwijzers + Hervatten %1$s... + diff --git a/app/src/main/res-car/values-b+nn/strings_car.xml b/app/src/main/res-car/values-b+nn/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+nn/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+no/strings_car.xml b/app/src/main/res-car/values-b+no/strings_car.xml new file mode 100644 index 00000000000..1b884c6e828 --- /dev/null +++ b/app/src/main/res-car/values-b+no/strings_car.xml @@ -0,0 +1,51 @@ + + + Laster inn... + Feil + Feil ved lasting av innhold + Favoritter + Historikk + Nedlastinger + Leverandør + Nåværende + Meny + Hjem-innhold + Ingen innhold fra leverandør + Leverandør ikke funnet + Kilde + Kilder + Handling + Skuespillere + Feil ved lasting av detaljer + Episodeliste + Sesong + Sesonger + Episode + Ingen episoder funnet + Ikke en TV-serie + Lagt til i favoritter + Fjernet fra favoritter + Ingen favoritter funnet + Starter avspilling... + Spiller av + Ingen lenke funnet + Ingen spillbart innhold funnet + Kan ikke laste detaljer + Feil ved lasting av lenker + Tilpass til skjerm + Fyll skjerm + Ingen kilde funnet + Ingen kilde tilgjengelig + Kilde valgt + Søk + Ingen resultater funnet + \'Fortsett å se\' ikke funnet + Ingen nedlastinger funnet + Fil ikke funnet + Ingen gyldig episode funnet + Velg leverandør + Valgt + Bibliotek + Bokmerker + Gjenopptar %1$s... + diff --git a/app/src/main/res-car/values-b+or/strings_car.xml b/app/src/main/res-car/values-b+or/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+or/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+pa/strings_car.xml b/app/src/main/res-car/values-b+pa/strings_car.xml new file mode 100644 index 00000000000..6b1e7ca0dc0 --- /dev/null +++ b/app/src/main/res-car/values-b+pa/strings_car.xml @@ -0,0 +1,51 @@ + + + ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... + ਗਲਤੀ + ਸਮੱਗਰੀ ਲੋਡ ਕਰਨ ਵਿੱਚ ਗਲਤੀ + ਮਨਪਸੰਦ + ਇਤਿਹਾਸ + ਡਾਊਨਲੋਡ + ਪ੍ਰਦਾਤਾ + ਮੌਜੂਦਾ + ਮੀਨੂ + ਘਰੇਲੂ ਸਮੱਗਰੀ + ਪ੍ਰਦਾਤਾ ਤੋਂ ਕੋਈ ਸਮੱਗਰੀ ਨਹੀਂ + ਪ੍ਰਦਾਤਾ ਨਹੀਂ ਮਿਲਿਆ + ਸਰੋਤ + ਸਰੋਤ + ਕਹਾਣੀ + ਕਲਾਕਾਰ + ਵੇਰਵੇ ਲੋਡ ਕਰਨ ਵਿੱਚ ਗਲਤੀ + ਐਪੀਸੋਡ ਸੂਚੀ + ਸੀਜ਼ਨ + ਸੀਜ਼ਨ + ਐਪੀਸੋਡ + ਕੋਈ ਐਪੀਸੋਡ ਨਹੀਂ ਮਿਲਿਆ + ਟੀਵੀ ਲੜੀਵਾਰ ਨਹੀਂ + ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ + ਮਨਪਸੰਦ ਤੋਂ ਹਟਾਇਆ ਗਿਆ + ਕੋਈ ਮਨਪਸੰਦ ਨਹੀਂ ਮਿਲਿਆ + ਪਲੇਬੈਕ ਸ਼ੁਰੂ ਹੋ ਰਿਹਾ ਹੈ... + ਖੇਡ ਰਿਹਾ ਹੈ + ਕੋਈ ਲਿੰਕ ਨਹੀਂ ਮਿਲਿਆ + ਕੋਈ ਖੇਡਣ ਯੋਗ ਸਮੱਗਰੀ ਨਹੀਂ ਮਿਲੀ + ਵੇਰਵੇ ਲੋਡ ਕਰਨ ਵਿੱਚ ਅਸਮਰੱਥ + ਲਿੰਕ ਲੋਡ ਕਰਨ ਵਿੱਚ ਗਲਤੀ + ਸਕ੍ਰੀਨ \'ਤੇ ਫਿੱਟ ਕਰੋ + ਸਕ੍ਰੀਨ ਭਰੋ + ਕੋਈ ਸਰੋਤ ਨਹੀਂ ਮਿਲਿਆ + ਕੋਈ ਸਰੋਤ ਉਪਲਬਧ ਨਹੀਂ + ਸਰੋਤ ਚੁਣਿਆ ਗਿਆ + ਖੋਜ + ਕੋਈ ਨਤੀਜਾ ਨਹੀਂ ਮਿਲਿਆ + \'ਦੇਖਣਾ ਜਾਰੀ ਰੱਖੋ\' ਨਹੀਂ ਮਿਲਿਆ + ਕੋਈ ਡਾਊਨਲੋਡ ਨਹੀਂ ਮਿਲਿਆ + ਫਾਈਲ ਨਹੀਂ ਮਿਲੀ + ਕੋਈ ਵੈਧ ਐਪੀਸੋਡ ਨਹੀਂ ਮਿਲਿਆ + ਪ੍ਰਦਾਤਾ ਚੁਣੋ + ਚੁਣਿਆ ਗਿਆ + ਲਾਇਬ੍ਰੇਰੀ + ਬੁੱਕਮਾਰਕ + %1$s ਮੁੜ ਸ਼ੁਰੂ ਹੋ ਰਿਹਾ ਹੈ... + diff --git a/app/src/main/res-car/values-b+pl/strings_car.xml b/app/src/main/res-car/values-b+pl/strings_car.xml new file mode 100644 index 00000000000..99f3d4095b1 --- /dev/null +++ b/app/src/main/res-car/values-b+pl/strings_car.xml @@ -0,0 +1,51 @@ + + + Ładowanie... + Błąd + Błąd ładowania treści + Ulubione + Historia + Pobrane + Dostawca + Obecny + Menu + Treść główna + Brak treści od dostawcy + Nie znaleziono dostawcy + Źródło + Źródła + Fabuła + Obsada + Błąd ładowania szczegółów + Lista odcinków + Sezon + Sezony + Odcinek + Nie znaleziono odcinków + To nie jest serial TV + Dodano do ulubionych + Usunięto z ulubionych + Nie znaleziono ulubionych + Rozpoczynanie odtwarzania... + Odtwarzanie + Nie znaleziono łącza + Nie znaleziono treści do odtworzenia + Nie można załadować szczegółów + Błąd ładowania łączy + Dopasuj do ekranu + Wypełnij ekran + Nie znaleziono źródła + Brak dostępnych źródeł + Wybrano źródło + Szukaj + Brak wyników + Nie znaleziono „Oglądaj dalej” + Brak pobranych plików + Plik nie znaleziony + Brak poprawnego odcinka + Wybierz dostawcę + Wybrano + Biblioteka + Zakładki + Wznawianie %1$s... + diff --git a/app/src/main/res-car/values-b+pt+BR/strings_car.xml b/app/src/main/res-car/values-b+pt+BR/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+pt+BR/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+pt/strings_car.xml b/app/src/main/res-car/values-b+pt/strings_car.xml new file mode 100644 index 00000000000..0195a196e51 --- /dev/null +++ b/app/src/main/res-car/values-b+pt/strings_car.xml @@ -0,0 +1,51 @@ + + + Carregando... + Erro + Erro ao carregar conteúdo + Favoritos + Histórico + Downloads + Provedor + Atual + Menu + Conteúdo da página inicial + Nenhum conteúdo do provedor + Provedor não encontrado + Fonte + Fontes + Enredo + Elenco + Erro ao carregar detalhes + Lista de episódios + Temporada + Temporadas + Episódio + Nenhum episódio encontrado + Não é uma série de TV + Adicionado aos favoritos + Removido dos favoritos + Nenhum favorito encontrado + Iniciando reprodução... + Reproduzindo + Nenhum link encontrado + Nenhum conteúdo reproduzível encontrado + Não foi possível carregar os detalhes + Erro ao carregar links + Ajustar à tela + Preencher tela + Nenhuma fonte encontrada + Nenhuma fonte disponível + Fonte selecionada + Buscar + Nenhum resultado encontrado + Nenhum item \'Continuar assistindo\' encontrado + Nenhum download encontrado + Arquivo não encontrado + Nenhum episódio válido encontrado + Selecionar provedor + Selecionado + Biblioteca + Marcadores + Retomando %1$s... + diff --git a/app/src/main/res-car/values-b+qt/strings_car.xml b/app/src/main/res-car/values-b+qt/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+qt/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+ro/strings_car.xml b/app/src/main/res-car/values-b+ro/strings_car.xml new file mode 100644 index 00000000000..fb7f4316bbe --- /dev/null +++ b/app/src/main/res-car/values-b+ro/strings_car.xml @@ -0,0 +1,51 @@ + + + Se încarcă... + Eroare + Eroare la încărcarea conținutului + Favorite + Istoric + Descărcări + Furnizor + Curent + Meniu + Conținut acasă + Niciun conținut de la furnizor + Furnizorul nu a fost găsit + Sursă + Surse + Intrigă + Distribuție + Eroare la încărcarea detaliilor + Listă episoade + Sezon + Sezoane + Episod + Nu s-au găsit episoade + Nu este serial TV + Adăugat la favorite + Eliminat din favorite + Nu s-au găsit favorite + Se începe redarea... + Se redă + Nu s-a găsit link + Nu s-a găsit conținut care poate fi redat + Nu se pot încărca detaliile + Eroare la încărcarea linkurilor + Potrivire la ecran + Umplere ecran + Nu s-a găsit sursă + Nicio sursă disponibilă + Sursă selectată + Căutare + Niciun rezultat găsit + Nu s-a găsit \'Continuare vizionare\' + Nu s-au găsit descărcări + Fișierul nu a fost găsit + Nu s-a găsit episod valid + Selectează furnizor + Selectat + Bibliotecă + Marcaje + Se reia %1$s... + diff --git a/app/src/main/res-car/values-b+ru/strings_car.xml b/app/src/main/res-car/values-b+ru/strings_car.xml new file mode 100644 index 00000000000..5d9ba1db8ac --- /dev/null +++ b/app/src/main/res-car/values-b+ru/strings_car.xml @@ -0,0 +1,51 @@ + + + Загрузка... + Ошибка + Ошибка загрузки контента + Избранное + История + Загрузки + Провайдер + Текущий + Меню + Контент главной + Нет контента от провайдера + Провайдер не найден + Источник + Источники + Сюжет + Актеры + Ошибка загрузки деталей + Список эпизодов + Сезон + Сезоны + Эпизод + Эпизоды не найдены + Не сериал + Добавлено в избранное + Удалено из избранного + Избранное не найдено + Запуск воспроизведения... + Воспроизведение + Ссылка не найдена + Нет воспроизводимого контента + Не удалось загрузить детали + Ошибка загрузки ссылок + По размеру экрана + Заполнить экран + Источник не найден + Нет доступных источников + Источник выбран + Поиск + Результаты не найдены + Нет "Продолжить просмотр" + Загрузки не найдены + Файл не найден + Нет валидного эпизода + Выбрать провайдера + Выбрано + Библиотека + Закладки + Возобновление %1$s... + diff --git a/app/src/main/res-car/values-b+si/strings_car.xml b/app/src/main/res-car/values-b+si/strings_car.xml new file mode 100644 index 00000000000..62482b2491c --- /dev/null +++ b/app/src/main/res-car/values-b+si/strings_car.xml @@ -0,0 +1,51 @@ + + + පූරණය වෙමින්... + දෝෂය + අන්තර්ගතය පූරණය කිරීමේ දෝෂය + ප්‍රියතමයන් + ඉතිහාසය + බාගැනීම් + සැපයුම්කරු + වත්මන් + මෙනුව + මුල් පිටුව අන්තර්ගතය + සැපයුම්කරුගෙන් අන්තර්ගතයක් නැත + සැපයුම්කරු හමු නොවිණි + මූලාශ්‍රය + මූලාශ්‍ර + කතාව + නළු නිළියන් + විස්තර පූරණය කිරීමේ දෝෂය + කොටස් ලැයිස්තුව + වාරය + වාර + කොටස + කොටස් හමු නොවිණි + රූපවාහිනී කතා මාලාවක් නොවේ + ප්‍රියතමයන් වෙත එක් කරන ලදී + ප්‍රියතමයන්ගෙන් ඉවත් කරන ලදී + ප්‍රියතමයන් හමු නොවිණි + ප්‍රතිණිර්මාණය ආරම්භ කරමින්... + වාදනය වෙමින් + සබැඳියක් හමු නොවිණි + වාදනය කළ හැකි අන්තර්ගතයක් හමු නොවිණි + විස්තර පූරණය කළ නොහැක + සබැඳි පූරණය කිරීමේ දෝෂය + තිරයට ගැලපේ + තිරය පුරවන්න + මූලාශ්‍රයක් හමු නොවිණි + මූලාශ්‍රයක් නොමැත + මූලාශ්‍රය තෝරා ගන්නා ලදී + සොයන්න + ප්‍රතිඵල හමු නොවිණි + \'නැරඹීම අඛණ්ඩව\' හමු නොවිණි + බාගැනීම් හමු නොවිණි + ගොනුව හමු නොවිණි + වලංගු කොටසක් හමු නොවිණි + සැපයුම්කරු තෝරන්න + තෝරා ගන්නා ලදී + පුස්තකාලය + පොත් යොමු + %1$s නැවත ආරම්භ කරමින්... + diff --git a/app/src/main/res-car/values-b+sk/strings_car.xml b/app/src/main/res-car/values-b+sk/strings_car.xml new file mode 100644 index 00000000000..250aa89c43a --- /dev/null +++ b/app/src/main/res-car/values-b+sk/strings_car.xml @@ -0,0 +1,51 @@ + + + Načítavanie... + Chyba + Chyba pri načítavaní obsahu + Obľúbené + História + Sťahovania + Poskytovateľ + Aktuálne + Menu + Domovský obsah + Žiadny obsah od poskytovateľa + Poskytovateľ nenájdený + Zdroj + Zdroje + Dej + Obsadenie + Chyba pri načítavaní podrobností + Zoznam epizód + Séria + Série + Epizóda + Nenašli sa žiadne epizódy + Nie je to TV seriál + Pridané do obľúbených + Odstránené z obľúbených + Žiadne obľúbené položky + Spúšťanie prehrávania... + Prehrávanie + Odkaz sa nenašiel + Žiadny prehrávateľný obsah + Nedá sa načítať podrobnosti + Chyba pri načítavaní odkazov + Prispôsobiť na obrazovku + Vyplniť obrazovku + Zdroj sa nenašiel + Žiadny zdroj k dispozícii + Zdroj vybraný + Hľadať + Žiadne výsledky sa nenašli + \'Pokračovať v sledovaní\' sa nenašlo + Žiadne sťahovania + Súbor nenájdený + Žiadna platná epizóda + Vybrať poskytovateľa + Vybrané + Knižnica + Záložky + Obnovovanie %1$s... + diff --git a/app/src/main/res-car/values-b+sl/strings_car.xml b/app/src/main/res-car/values-b+sl/strings_car.xml new file mode 100644 index 00000000000..5a97685aaff --- /dev/null +++ b/app/src/main/res-car/values-b+sl/strings_car.xml @@ -0,0 +1,51 @@ + + + Nalaganje... + Napaka + Napaka pri nalaganju vsebine + Priljubljene + Zgodovina + Prenosi + Ponudnik + Trenutno + Meni + Domača vsebina + Ni vsebine od ponudnika + Ponudnik ni najden + Vir + Viri + Zgodba + Igralska zasedba + Napaka pri nalaganju podrobnosti + Seznam epizod + Sezona + Sezone + Epizoda + Ni najdenih epizod + Ni TV serija + Dodano med priljubljene + Odstranjeno iz priljubljenih + Ni priljubljenih + Začenjam predvajanje... + Predvajam + Povezava ni najdena + Ni vsebine za predvajanje + Ni bilo mogoče naložiti podrobnosti + Napaka pri nalaganju povezav + Prilagodi zaslonu + Napolni zaslon + Vir ni najden + Ni razpoložljivih virov + Vir izbran + Iskanje + Ni rezultatov + \'Nadaljuj z ogledom\' ni najdeno + Ni prenosov + Datoteka ni najdena + Ni veljavne epizode + Izberi ponudnika + Izbrano + Knjižnica + Zaznamki + Nadaljujem %1$s... + diff --git a/app/src/main/res-car/values-b+so/strings_car.xml b/app/src/main/res-car/values-b+so/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+so/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+sq/strings_car.xml b/app/src/main/res-car/values-b+sq/strings_car.xml new file mode 100644 index 00000000000..dcb8bc43bfd --- /dev/null +++ b/app/src/main/res-car/values-b+sq/strings_car.xml @@ -0,0 +1,51 @@ + + + Duke ngarkuar... + Gabim + Gabim në ngarkimin e përmbajtjes + Të preferuarat + Historia + Shkarkimet + Ofruesi + Aktual + Menu + Përmbajtja e kreut + Nuk ka përmbajtje nga ofruesi + Ofruesi nuk u gjet + Burimi + Burimet + Përmbajtja + Aktorët + Gabim në ngarkimin e detajeve + Lista e episodeve + Sezoni + Sezonet + Episodi + Nuk u gjetën episode + Nuk është serial TV + U shtua te të preferuarat + U hoq nga të preferuarat + Nuk u gjetën të preferuara + Duke filluar luajtjen... + Duke luajtur + Nuk u gjet lidhje + Nuk u gjet përmbajtje për t\'u luajtur + Nuk mund të ngarkohen detajet + Gabim në ngarkimin e lidhjeve + Përshtat në ekran + Mbush ekranin + Nuk u gjet burim + Asnjë burim i disponueshëm + Burimi u zgjodh + Kërko + Nuk u gjetën rezultate + \'Vazhdo shikimin\' nuk u gjet + Nuk u gjetën shkarkime + Skedari nuk u gjet + Nuk u gjet episod i vlefshëm + Zgjidh ofruesin + E zgjedhur + Biblioteka + Faqerojtësit + Duke vazhduar %1$s... + diff --git a/app/src/main/res-car/values-b+sr/strings_car.xml b/app/src/main/res-car/values-b+sr/strings_car.xml new file mode 100644 index 00000000000..6b81d44509b --- /dev/null +++ b/app/src/main/res-car/values-b+sr/strings_car.xml @@ -0,0 +1,51 @@ + + + Učitavanje... + Greška + Greška pri učitavanju sadržaja + Favoriti + Istorija + Preuzimanja + Provajder + Trenutno + Meni + Početni sadržaj + Nema sadržaja od provajdera + Provajder nije pronađen + Izvor + Izvori + Radnja + Uloge + Greška pri učitavanju detalja + Lista epizoda + Sezona + Sezone + Epizoda + Nema pronađenih epizoda + Nije TV serija + Dodato u favorite + Uklonjeno iz favorita + Nema favorita + Pokretanje reprodukcije... + Reprodukcija + Link nije pronađen + Sadržaj za reprodukciju nije pronađen + Nije moguće učitati detalje + Greška pri učitavanju linkova + Prilagodi ekranu + Popuni ekran + Izvor nije pronađen + Izvor nije dostupan + Izvor izabran + Pretraga + Nema rezultata + \'Nastavi gledanje\' nije pronađeno + Nema preuzimanja + Datoteka nije pronađena + Nema važeće epizode + Izaberi provajdera + Izabrano + Biblioteka + Obeleživači + Nastavljanje %1$s... + diff --git a/app/src/main/res-car/values-b+sv/strings_car.xml b/app/src/main/res-car/values-b+sv/strings_car.xml new file mode 100644 index 00000000000..fcbf7528bc8 --- /dev/null +++ b/app/src/main/res-car/values-b+sv/strings_car.xml @@ -0,0 +1,51 @@ + + + Laddar... + Fel + Fel vid laddning av innehåll + Favoriter + Historik + Nedladdningar + Leverantör + Nuvarande + Meny + Heminnehåll + Inget innehåll från leverantör + Leverantör hittades inte + Källa + Källor + Handling + Skådespelare + Fel vid laddning av detaljer + Avsnittslista + Säsong + Säsonger + Avsnitt + Inga avsnitt hittades + Inte en TV-serie + Tillagd i favoriter + Borttagen från favoriter + Inga favoriter hittades + Startar uppspelning... + Spelar + Ingen länk hittades + Inget spelbart innehåll hittades + Kunde inte ladda detaljer + Fel vid laddning av länkar + Anpassa till skärm + Fyll skärm + Ingen källa hittades + Ingen källa tillgänglig + Källa vald + Sök + Inga resultat hittades + Inget \'Fortsätt titta\' hittades + Inga nedladdningar hittades + Filen hittades inte + Inget giltigt avsnitt hittades + Välj leverantör + Vald + Bibliotek + Bokmärken + Återupptar %1$s... + diff --git a/app/src/main/res-car/values-b+sw/strings_car.xml b/app/src/main/res-car/values-b+sw/strings_car.xml new file mode 100644 index 00000000000..97997a98256 --- /dev/null +++ b/app/src/main/res-car/values-b+sw/strings_car.xml @@ -0,0 +1,51 @@ + + + Inapakia... + Hitilafu + Hitilafu katika kupakia maudhui + Vipendwa + Historia + Vipakuliwa + Mtoaji + Sasa + Menyu + Maudhui ya Nyumbani + Hakuna maudhui kutoka kwa mtoaji + Mtoaji hajapatikana + Chanzo + Vyanzo + Hadithi + Waigizaji + Hitilafu katika kupakia maelezo + Orodha ya Vipindi + Msimu + Misimu + Kipindi + Hakuna vipindi vilivyopatikana + Si mfululizo wa TV + Imeongezwa kwenye vipendwa + Imeondolewa kwenye vipendwa + Hakuna vipendwa vilivyopatikana + Inaanza kucheza... + Inacheza + Hakuna kiungo kilichopatikana + Hakuna maudhui ya kucheza yaliyopatikana + Imeshindwa kupakia maelezo + Hitilafu katika kupakia viungo + Toshea kwenye Skrini + Jaza Skrini + Hakuna chanzo kilichopatikana + Hakuna chanzo kinachopatikana + Chanzo kimechaguliwa + Tafuta + Hakuna matokeo yaliyopatikana + \'Endelea Kutazama\' haijapatikana + Hakuna vipakuliwa vilivyopatikana + Faili haijapatikana + Hakuna kipindi halali kilichopatikana + Chagua Mtoaji + Imechaguliwa + Maktaba + Alamisho + Inaendelea %1$s... + diff --git a/app/src/main/res-car/values-b+ta/strings_car.xml b/app/src/main/res-car/values-b+ta/strings_car.xml new file mode 100644 index 00000000000..b7960e0b796 --- /dev/null +++ b/app/src/main/res-car/values-b+ta/strings_car.xml @@ -0,0 +1,51 @@ + + + ஏற்றுகிறது... + பிழை + உள்ளடக்கத்தை ஏற்றுவதில் பிழை + விருப்பங்கள் + வரலாறு + பதிவிறக்கங்கள் + வழங்குநர் + தற்போதைய + மெனு + முகப்பு உள்ளடக்கம் + வழங்குநரிடமிருந்து உள்ளடக்கம் இல்லை + வழங்குநரைக் காணவில்லை + மூலம் + மூலங்கள் + கதைக்களம் + நடிப்பு + விவரங்களை ஏற்றுவதில் பிழை + அத்தியாயப் பட்டியல் + பருவம் + பருவங்கள் + அத்தியாயம் + அத்தியாயங்கள் எதுவும் காணப்படவில்லை + தொலைக்காட்சித் தொடர் அல்ல + விருப்பங்களில் சேர்க்கப்பட்டது + விருப்பங்களிலிருந்து நீக்கப்பட்டது + விருப்பங்கள் எதுவும் இல்லை + இயக்கத்தைத் தொடங்குகிறது... + இயங்குகிறது + இணைப்பு எதுவும் காணப்படவில்லை + இயக்கக்கூடிய உள்ளடக்கம் எதுவும் இல்லை + விவரங்களை ஏற்ற முடியவில்லை + இணைப்புகளை ஏற்றுவதில் பிழை + திரைக்குப் பொருத்து + திரையை நிரப்பு + மூலம் எதுவும் காணப்படவில்லை + மூலம் எதுவும் கிடைக்கவில்லை + மூலம் தேர்ந்தெடுக்கப்பட்டது + தேடு + முடிவுகள் எதுவும் இல்லை + \'தொடர்ந்து பார்க்க\' எதுவும் இல்லை + பதிவிறக்கங்கள் எதுவும் இல்லை + கோப்பைக் காணவில்லை + செல்லுபடியாகும் அத்தியாயம் எதுவும் இல்லை + வழங்குநரைத் தேர்ந்தெடு + தேர்ந்தெடுக்கப்பட்டது + நூலகம் + புத்தகக்குறிகள் + %1$s தொடர்கிறது... + diff --git a/app/src/main/res-car/values-b+te/strings_car.xml b/app/src/main/res-car/values-b+te/strings_car.xml new file mode 100644 index 00000000000..d2d9ace81ac --- /dev/null +++ b/app/src/main/res-car/values-b+te/strings_car.xml @@ -0,0 +1,51 @@ + + + లోడ్ అవుతోంది... + లోపం + కంటెంట్ లోడ్ చేయడంలో లోపం + ఇష్టమైనవి + చరిత్ర + డౌన్‌లోడ్‌లు + ప్రొవైడర్ + ప్రస్తుత + మెనూ + హోమ్ కంటెంట్ + ప్రొవైడర్ నుండి కంటెంట్ లేదు + ప్రొవైడర్ కనుగొనబడలేదు + మూలం + మూలాలు + కథాంశం + నటీనటులు + వివరాలు లోడ్ చేయడంలో లోపం + ఎపిసోడ్ జాబితా + సీజన్ + సీజన్లు + ఎపిసోడ్ + ఎపిసోడ్‌లు కనుగొనబడలేదు + టీవీ సిరీస్ కాదు + ఇష్టమైన వాటికి జోడించబడింది + ఇష్టమైన వాటి నుండి తీసివేయబడింది + ఇష్టమైనవి కనుగొనబడలేదు + ప్లేబ్యాక్ ప్రారంభమవుతోంది... + ప్లే అవుతోంది + లింక్ కనుగొనబడలేదు + ప్లే చేయగల కంటెంట్ కనుగొనబడలేదు + వివరాలు లోడ్ చేయడం సాధ్యం కాలేదు + లింక్‌లు లోడ్ చేయడంలో లోపం + స్క్రీన్‌కు సరిపోల్చండి + స్క్రీన్‌ను నింపండి + మూలం కనుగొనబడలేదు + మూలం అందుబాటులో లేదు + మూలం ఎంపిక చేయబడింది + శోధించు + ఫలితాలు కనుగొనబడలేదు + \'చూడటం కొనసాగించు\' కనుగొనబడలేదు + డౌన్‌లోడ్‌లు కనుగొనబడలేదు + ఫైల్ కనుగొనబడలేదు + చెల్లుబాటు అయ్యే ఎపిసోడ్ కనుగొనబడలేదు + ప్రొవైడర్‌ను ఎంచుకోండి + ఎంపిక చేయబడింది + లైబ్రరీ + బుక్‌మార్క్‌లు + %1$s పునఃప్రారంభించబడుతోంది... + diff --git a/app/src/main/res-car/values-b+tg/strings_car.xml b/app/src/main/res-car/values-b+tg/strings_car.xml new file mode 100644 index 00000000000..f29105798bb --- /dev/null +++ b/app/src/main/res-car/values-b+tg/strings_car.xml @@ -0,0 +1,51 @@ + + + Боргирӣ... + Хатогӣ + Хатогӣ дар боргирии муҳтаво + Дӯстдоштаҳо + Таърих + Боргириҳо + Провайдер + Ҷорӣ + Меню + Муҳтавои хона + Ҳеҷ муҳтаво аз провайдер нест + Провайдер ёфт нашуд + Манбаъ + Манбаъҳо + Сюжет + Ҳунармандон + Хатогӣ дар боргирии тафсилот + Рӯйхати қисмҳо + Мавсим + Мавсимҳо + Қисм + Ҳеҷ қисм ёфт нашуд + Силсилафилм нест + Ба дӯстдоштаҳо илова шуд + Аз дӯстдоштаҳо хориҷ шуд + Ҳеҷ дӯстдошта ёфт нашуд + Оғози пахш... + Дар ҳоли пахш + Ҳеҷ пайванд ёфт нашуд + Ҳеҷ муҳтавои қобили пахш ёфт нашуд + Тафсилот боргирӣ нашуд + Хатогӣ дар боргирии пайвандҳо + Ба экран мувофиқ кардан + Пур кардани экран + Ҳеҷ манбаъ ёфт нашуд + Ҳеҷ манбаъ дастрас нест + Манбаъ интихоб шуд + Ҷустуҷӯ + Ҳеҷ натиҷа ёфт нашуд + \'Идомаи тамошо\' ёфт нашуд + Ҳеҷ боргирӣ ёфт нашуд + Файл ёфт нашуд + Ҳеҷ қисми дуруст ёфт нашуд + Провайдерро интихоб кунед + Интихобшуда + Китобхона + Хабовҳо + Идомаи %1$s... + diff --git a/app/src/main/res-car/values-b+th/strings_car.xml b/app/src/main/res-car/values-b+th/strings_car.xml new file mode 100644 index 00000000000..374658cc309 --- /dev/null +++ b/app/src/main/res-car/values-b+th/strings_car.xml @@ -0,0 +1,51 @@ + + + กำลังโหลด... + ข้อผิดพลาด + ข้อผิดพลาดในการโหลดเนื้อหา + รายการโปรด + ประวัติ + ดาวน์โหลด + ผู้ให้บริการ + ปัจจุบัน + เมนู + เนื้อหาหน้าแรก + ไม่มีเนื้อหาจากผู้ให้บริการ + ไม่พบผู้ให้บริการ + แหล่งที่มา + แหล่งที่มา + เนื้อเรื่อง + นักแสดง + ข้อผิดพลาดในการโหลดรายละเอียด + รายการตอน + ซีซั่น + ซีซั่น + ตอน + ไม่พบตอน + ไม่ใช่ทีวีซีรีส์ + เพิ่มในรายการโปรดแล้ว + ลบออกจากรายการโปรดแล้ว + ไม่พบรายการโปรด + กำลังเริ่มเล่น... + กำลังเล่น + ไม่พบลิงก์ + ไม่พบเนื้อหาที่เล่นได้ + ไม่สามารถโหลดรายละเอียดได้ + ข้อผิดพลาดในการโหลดลิงก์ + พอดีหน้าจอ + เต็มหน้าจอ + ไม่พบแหล่งที่มา + ไม่มีแหล่งที่มาที่ใช้ได้ + เลือกแหล่งที่มาแล้ว + ค้นหา + ไม่พบผลลัพธ์ + ไม่พบ \'ดูต่อ\' + ไม่พบการดาวน์โหลด + ไม่พบไฟล์ + ไม่พบตอนที่ถูกต้อง + เลือกผู้ให้บริการ + ที่เลือก + ห้องสมุด + บุ๊กมาร์ก + กำลังดูต่อ %1$s... + diff --git a/app/src/main/res-car/values-b+ti/strings_car.xml b/app/src/main/res-car/values-b+ti/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+ti/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+tl/strings_car.xml b/app/src/main/res-car/values-b+tl/strings_car.xml new file mode 100644 index 00000000000..a99f6e086a9 --- /dev/null +++ b/app/src/main/res-car/values-b+tl/strings_car.xml @@ -0,0 +1,51 @@ + + + Naglo-load... + Error + Error sa pag-load ng nilalaman + Mga Paborito + Kasaysayan + Mga Download + Tagapagbigay + Kasalukuyan + Menu + Nilalaman ng tahanan + Walang nilalaman mula sa tagapagbigay + Hindi natagpuan ang tagapagbigay + Pinagmulan + Mga Pinagmulan + Kuwento + Tauhan + Error sa pag-load ng mga detalye + Listahan ng Episodyo + Season + Mga Season + Episodyo + Walang natagpuang episodyo + Hindi serye sa TV + Idinagdag sa mga paborito + Inalis sa mga paborito + Walang natagpuang paborito + Sinisimulan ang pag-playback... + Gumagana + Walang natagpuang link + Walang natagpuang puwedeng i-play na nilalaman + Hindi ma-load ang mga detalye + Error sa pag-load ng mga link + Pagkasyahin sa Screen + Punuin ang Screen + Walang napiling pinagmulan + Walang magagamit na pinagmulan + Napiling pinagmulan + Maghanap + Walang natagpuang resulta + Hindi natagpuan ang \'Ituloy ang Panonood\' + Walang natagpuang download + Hindi natagpuan ang file + Walang wastong episodyo na natagpuan + Piliin ang Tagapagbigay + Napili + Aklatan + Mga Bookmark + Ipinagpapatuloy ang %1$s... + diff --git a/app/src/main/res-car/values-b+tr/strings_car.xml b/app/src/main/res-car/values-b+tr/strings_car.xml new file mode 100644 index 00000000000..17b162f542f --- /dev/null +++ b/app/src/main/res-car/values-b+tr/strings_car.xml @@ -0,0 +1,51 @@ + + + Yükleniyor... + Hata + İçerik yüklenirken hata + Favoriler + Geçmiş + İndirilenler + Sağlayıcı + Mevcut + Menü + Ana Sayfa İçeriği + Sağlayıcıdan içerik yok + Sağlayıcı bulunamadı + Kaynak + Kaynaklar + Konu + Oyuncular + Detaylar yüklenirken hata + Bölüm Listesi + Sezon + Sezonlar + Bölüm + Bölüm bulunamadı + TV dizisi değil + Favorilere eklendi + Favorilerden çıkarıldı + Favori bulunamadı + Oynatma başlatılıyor... + Oynatılıyor + Bağlantı bulunamadı + Oynatılabilir içerik bulunamadı + Detaylar yüklenemedi + Bağlantılar yüklenirken hata + Ekrana Sığdır + Ekranı Doldur + Kaynak bulunamadı + Mevcut kaynak yok + Kaynak seçildi + Ara + Sonuç bulunamadı + \'İzlemeye Devam Et\' bulunamadı + İndirme bulunamadı + Dosya bulunamadı + Geçerli bölüm bulunamadı + Sağlayıcı Seç + Seçildi + Kütüphane + Yer İmleri + %1$s devam ettiriliyor... + diff --git a/app/src/main/res-car/values-b+uk/strings_car.xml b/app/src/main/res-car/values-b+uk/strings_car.xml new file mode 100644 index 00000000000..5cd25097ff6 --- /dev/null +++ b/app/src/main/res-car/values-b+uk/strings_car.xml @@ -0,0 +1,51 @@ + + + Завантаження... + Помилка + Помилка завантаження вмісту + Обране + Історія + Завантаження + Провайдер + Поточний + Меню + Домашній вміст + Немає вмісту від провайдера + Провайдера не знайдено + Джерело + Джерела + Сюжет + Актори + Помилка завантаження деталей + Список епізодів + Сезон + Сезони + Епізод + Епізодів не знайдено + Не серіал + Додано до обраного + Видалено з обраного + Немає обраного + Початок відтворення... + Відтворення + Посилання не знайдено + Вміст для відтворення не знайдено + Не вдалося завантажити деталі + Помилка завантаження посилань + Припасувати до екрану + Заповнити екран + Джерело не знайдено + Джерела недоступні + Джерело вибрано + Пошук + Результатів не знайдено + \'Продовжити перегляд\' не знайдено + Завантажень не знайдено + Файл не знайдено + Дійсний епізод не знайдено + Вибрати провайдера + Вибрано + Бібліотека + Закладки + Відновлення %1$s... + diff --git a/app/src/main/res-car/values-b+ur/strings_car.xml b/app/src/main/res-car/values-b+ur/strings_car.xml new file mode 100644 index 00000000000..43b74a6a62e --- /dev/null +++ b/app/src/main/res-car/values-b+ur/strings_car.xml @@ -0,0 +1,51 @@ + + + لوڈ ہو رہا ہے... + خرابی + مواد لوڈ کرنے میں خرابی + پسندیدہ + تاریخچہ + ڈاؤن لوڈز + فراہم کنندہ + موجودہ + مینو + ہوم مواد + فراہم کنندہ سے کوئی مواد نہیں + فراہم کنندہ نہیں ملا + ماخذ + ماخذات + پلاٹ + کاسٹ + تفصیلات لوڈ کرنے میں خرابی + اقساط کی فہرست + سیزن + سیزنز + قسط + کوئی قسط نہیں ملی + ٹی وی سیریز نہیں + پسندیدہ میں شامل کر دیا گیا + پسندیدہ سے ہٹا دیا گیا + کوئی پسندیدہ نہیں ملا + پلے بیک شروع ہو رہا ہے... + پلے ہو رہا ہے + کوئی لنک نہیں ملا + کوئی قابل پلے مواد نہیں ملا + تفصیلات لوڈ نہیں ہو سکیں + لنکس لوڈ کرنے میں خرابی + اسکرین پر فٹ کریں + اسکرین بھریں + کوئی ماخذ نہیں ملا + کوئی ماخذ دستیاب نہیں + ماخذ منتخب ہو گیا + تلاش + کوئی نتیجہ نہیں ملا + \'دیکھنا جاری رکھیں\' نہیں ملا + کوئی ڈاؤن لوڈ نہیں ملا + فائل نہیں ملی + کوئی درست قسط نہیں ملی + فراہم کنندہ منتخب کریں + منتخب شدہ + لائبریری + بک مارکس + %1$s دوبارہ شروع ہو رہا ہے... + diff --git a/app/src/main/res-car/values-b+uz/strings_car.xml b/app/src/main/res-car/values-b+uz/strings_car.xml new file mode 100644 index 00000000000..30f36208f3f --- /dev/null +++ b/app/src/main/res-car/values-b+uz/strings_car.xml @@ -0,0 +1,51 @@ + + + Yuklanmoqda... + Xato + Kontentni yuklashda xato + Sevimlilar + Tarix + Yuklanmalar + Provayder + Joriy + Menyu + Bosh sahifa kontenti + Provayderdan kontent yo\'q + Provayder topilmadi + Manba + Manbalar + Syujet + Rollarda + Tafsilotlarni yuklashda xato + Qismlar ro\'yxati + Mavsum + Mavsumlar + Qism + Qismlar topilmadi + TV serial emas + Sevimlilarga qo\'shildi + Sevimlilardan olib tashlandi + Sevimlilar topilmadi + Ijro boshlanmoqda... + Ijro etilmoqda + Havola topilmadi + Ijro etib bo\'ladigan kontent topilmadi + Tafsilotlarni yuklab bo\'lmadi + Havolalarni yuklashda xato + Ekranga moslash + Ekranni to\'ldirish + Manba topilmadi + Mavjud manba yo\'q + Manba tanlandi + Qidirish + Natijalar topilmadi + \'Ko\'rishni davom ettirish\' topilmadi + Yuklanmalar topilmadi + Fayl topilmadi + Yaroqli qism topilmadi + Provayderni tanlash + Tanlandi + Kutubxona + Xatcho\'plar + %1$s davom ettirilmoqda... + diff --git a/app/src/main/res-car/values-b+vi/strings_car.xml b/app/src/main/res-car/values-b+vi/strings_car.xml new file mode 100644 index 00000000000..68c2393b14b --- /dev/null +++ b/app/src/main/res-car/values-b+vi/strings_car.xml @@ -0,0 +1,51 @@ + + + Đang tải... + Lỗi + Lỗi tải nội dung + Yêu thích + Lịch sử + Tải xuống + Nguồn phát + Hiện tại + Menu + Nội dung trang chủ + Không có nội dung từ nguồn + Không tìm thấy nguồn + Nguồn + Nguồn + Cốt truyện + Diễn viên + Lỗi tải chi tiết + Danh sách tập + Mùa + Mùa + Tập + Không tìm thấy tập nào + Không phải phim bộ + Đã thêm vào yêu thích + Đã xóa khỏi yêu thích + Không có yêu thích + Đang bắt đầu phát... + Đang phát + Không tìm thấy liên kết + Không có nội dung phát được + Không thể tải chi tiết + Lỗi tải liên kết + Vừa màn hình + Lấp đầy màn hình + Không tìm thấy nguồn + Không có nguồn khả dụng + Đã chọn nguồn + Tìm kiếm + Không tìm thấy kết quả + Không tìm thấy \'Tiếp tục xem\' + Không tìm thấy bản tải xuống + Không tìm thấy tệp + Không có tập hợp lệ + Chọn nguồn + Đã chọn + Thư viện + Dấu trang + Đang tiếp tục %1$s... + diff --git a/app/src/main/res-car/values-b+zh+TW/strings_car.xml b/app/src/main/res-car/values-b+zh+TW/strings_car.xml new file mode 100644 index 00000000000..ac0a25531bb --- /dev/null +++ b/app/src/main/res-car/values-b+zh+TW/strings_car.xml @@ -0,0 +1,74 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res-car/values-b+zh/strings_car.xml b/app/src/main/res-car/values-b+zh/strings_car.xml new file mode 100644 index 00000000000..8f950f7828b --- /dev/null +++ b/app/src/main/res-car/values-b+zh/strings_car.xml @@ -0,0 +1,51 @@ + + + 加载中... + 错误 + 加载内容错误 + 收藏 + 历史 + 下载 + 提供商 + 当前 + 菜单 + 首页内容 + 无提供商内容 + 未找到提供商 + 来源 + 来源 + 剧情 + 演员 + 加载详情错误 + 剧集列表 + + + + 未找到剧集 + 非电视剧 + 已添加到收藏 + 已从收藏移除 + 无收藏 + 开始播放... + 播放中 + 无链接 + 无由播放内容 + 无法加载详情 + 加载链接错误 + 适应屏幕 + 充满屏幕 + 未找到来源 + 无可用来源 + 已选来源 + 搜索 + 无结果 + 无继续观看 + 无下载 + 文件未找到 + 无有效剧集 + 选择提供商 + 已选 + + 书签 + 恢复播放 %1$s... + diff --git a/app/src/main/res-car/values-b+zu/strings_car.xml b/app/src/main/res-car/values-b+zu/strings_car.xml new file mode 100644 index 00000000000..28edfa24bb2 --- /dev/null +++ b/app/src/main/res-car/values-b+zu/strings_car.xml @@ -0,0 +1,51 @@ + + + Iyalayisha... + Iphutha + Iphutha ekulayisheni okuqukethwe + Izintandokazi + Umlando + Okulandiwe + Umhlinzeki + Okwamanje + Imenyu + Okuqukethwe Kwasekhaya + Akukho okuqukethwe okuvela kumhlinzeki + Umhlinzeki akatholakalanga + Umthombo + Imithombo + Icebo + Abalingisi + Iphutha ekulayisheni imininingwane + Uhlu Lweziqephu + Isizini + Izinkathi + Isiqephu + Azikho iziqephu ezitholiwe + Akulona uchungechunge lwe-TV + Kungezwe kuzintandokazi + Kususiwe kuzintandokazi + Azikho izintandokazi ezitholiwe + Iqala ukudlala... + Iyadlala + Asikho isixhumanisi esitholiwe + Akukho okuqukethwe okudlalekayo okutholiwe + Ayikwazi ukulayisha imininingwane + Iphutha ekulayisheni izixhumanisi + Lingana nesikrini + Gcwalisa Isikrini + Awukho umthombo otholiwe + Awukho umthombo otholakalayo + Umthombo ukhethiwe + Sesha + Ayikho imiphumela etholiwe + \'Qhubeka nokubuka\' ayitholakali + Akukho okulandiwe okutholiwe + Ifayela alitholakalanga + Asikho isiqephu esivumelekile esitholiwe + Khetha Umhlinzeki + Kukhethiwe + Umtapo wolwazi + Amabhukhimakhi + Iyaqhubeka %1$s... + diff --git a/app/src/main/res-car/values-it/strings_car.xml b/app/src/main/res-car/values-it/strings_car.xml new file mode 100644 index 00000000000..cb20b104b35 --- /dev/null +++ b/app/src/main/res-car/values-it/strings_car.xml @@ -0,0 +1,75 @@ + + + + Caricamento... + Errore + Errore caricamento contenuti + + + Preferiti + Cronologia + Download + Provider + Attuale + Menu + Contenuti Home + Nessun contenuto dal provider + Provider non trovato + Info su di me + + + Sorgente + Sorgenti + Trama + Cast + Errore caricamento dettagli + + + Lista Episodi + Stagione + Stagioni + Episodio + Nessun episodio trovato + Non è una serie TV + + + Aggiunto ai preferiti + Rimosso dai preferiti + Nessun preferito trovato + + + Avvio riproduzione... + In riproduzione + Nessun link trovato + Nessun contenuto riproducibile trovato + Impossibile caricare i dettagli + Errore caricamento link + Adatta allo schermo + Riempi schermo + + + Nessuna sorgente trovata + Nessuna sorgente disponibile + Sorgente selezionata + + + Cerca + Nessun risultato trovato + + + Nessun elemento \'Continua a guardare\' trovato + + + Nessun download completato trovato + File non trovato + Nessun episodio valido trovato + + + Seleziona Provider + Selezionato + + + Libreria + Segnalibri + Riprendo %1$s... + diff --git a/app/src/main/res-car/values/strings_car.xml b/app/src/main/res-car/values/strings_car.xml new file mode 100644 index 00000000000..607af3ff28a --- /dev/null +++ b/app/src/main/res-car/values/strings_car.xml @@ -0,0 +1,75 @@ + + + + Loading... + Error + Error loading content + + + Favorites + History + Downloads + Provider + Current + Menu + Home Content + No content from provider + Provider not found + About me + + + Source + Sources + Plot + Cast + Error loading details + + + Episode List + Season + Seasons + Episode + No episodes found + Not a TV series + + + Added to favorites + Removed from favorites + No favorites found + + + Starting playback... + Playing + No link found + No playable content found + Unable to load details + Error loading links + Fit to screen + Fill screen + + + No source found + No source available + Source selected + + + Search + No results found + + + No \'Continue watching\' items found + + + No completed downloads found + File not found + No valid episode found + + + Select Provider + Selected + + + Library + Bookmarks + Resuming %1$s... + diff --git a/app/src/main/res/drawable/go_back_30.xml b/app/src/main/res/drawable/go_back_30.xml index 14999011662..8202d3ce42c 100644 --- a/app/src/main/res/drawable/go_back_30.xml +++ b/app/src/main/res/drawable/go_back_30.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/drawable/ic_baseline_aspect_ratio_24.xml b/app/src/main/res/drawable/ic_baseline_aspect_ratio_24.xml index d93d1b64b91..c7b8b5f55fb 100644 --- a/app/src/main/res/drawable/ic_baseline_aspect_ratio_24.xml +++ b/app/src/main/res/drawable/ic_baseline_aspect_ratio_24.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml b/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml index f880379f0bb..0870be8f615 100644 --- a/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml +++ b/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_baseline_source_24.xml b/app/src/main/res/drawable/ic_baseline_source_24.xml new file mode 100644 index 00000000000..0d7eb86d55f --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_source_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_tune_24.xml b/app/src/main/res/drawable/ic_baseline_tune_24.xml index d0c63a3d17d..0342fb06ea8 100644 --- a/app/src/main/res/drawable/ic_baseline_tune_24.xml +++ b/app/src/main/res/drawable/ic_baseline_tune_24.xml @@ -2,7 +2,7 @@ android:height="24dp" android:viewportWidth="48" android:viewportHeight="48" - android:tint="?attr/white" + android:tint="#FFFFFF" xmlns:android="http://schemas.android.com/apk/res/android"> diff --git a/app/src/main/res/raw/aboutme.mp4 b/app/src/main/res/raw/aboutme.mp4 new file mode 100644 index 00000000000..7a107a59ff8 Binary files /dev/null and b/app/src/main/res/raw/aboutme.mp4 differ diff --git a/app/src/main/res/values-b+es/array.xml b/app/src/main/res/values-es/array.xml similarity index 100% rename from app/src/main/res/values-b+es/array.xml rename to app/src/main/res/values-es/array.xml diff --git a/app/src/main/res/values-b+es/strings.xml b/app/src/main/res/values-es/strings.xml similarity index 100% rename from app/src/main/res/values-b+es/strings.xml rename to app/src/main/res/values-es/strings.xml diff --git a/app/src/main/res/values-b+it/strings.xml b/app/src/main/res/values-it/strings.xml similarity index 100% rename from app/src/main/res/values-b+it/strings.xml rename to app/src/main/res/values-it/strings.xml diff --git a/app/src/main/res/xml/automotive_app_desc.xml b/app/src/main/res/xml/automotive_app_desc.xml new file mode 100644 index 00000000000..c601d28ff79 --- /dev/null +++ b/app/src/main/res/xml/automotive_app_desc.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f0119613ca6..3c2f71a04c8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,6 +6,7 @@ androidGradlePlugin = "8.13.2" appcompat = "1.7.1" biometric = "1.4.0-alpha04" buildkonfigGradlePlugin = "0.17.1" +carApp = "1.8.0-alpha03" coil = "3.3.0" colorpicker = "6b46b49bd5" conscryptAndroid = { strictly = "2.5.2" } # 2.5.3 crashes everything @@ -50,7 +51,7 @@ gpuv = "3a107f995b" jvmTarget = "1.8" jdkToolchain = "17" -minSdk = "21" +minSdk = "23" compileSdk = "36" targetSdk = "36" @@ -58,6 +59,7 @@ targetSdk = "36" activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" } appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } biometric = { module = "androidx.biometric:biometric", version.ref = "biometric" } +car-app = { module = "androidx.car.app:app", version.ref = "carApp" } coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } colorpicker = { module = "com.github.recloudstream:color-picker-android", version.ref = "colorpicker" }