mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-08-19 22:07:14 +00:00
merge: PR #1029 feat(i18n) extract last deep-cut hardcoded strings
Resolved conflicts in values/strings.xml and values-fr/strings.xml by concatenating both blocks (no duplicate keys).
This commit is contained in:
commit
fd71323cb5
9 changed files with 84 additions and 14 deletions
|
|
@ -8,6 +8,10 @@ import androidx.media3.datasource.DataSource
|
|||
import androidx.media3.datasource.DataSpec
|
||||
import androidx.media3.datasource.DefaultHttpDataSource
|
||||
import androidx.media3.datasource.TransferListener
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.player_error_unable_to_play_stream
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
/**
|
||||
* A DataSource.Factory that wraps DefaultHttpDataSource and appends YouTube's
|
||||
|
|
@ -75,7 +79,9 @@ class YoutubeChunkedDataSourceFactory(
|
|||
}
|
||||
|
||||
private fun openNextChunk(): Long {
|
||||
val spec = originalDataSpec ?: throw IllegalStateException("No DataSpec")
|
||||
val spec = originalDataSpec ?: throw IllegalStateException(
|
||||
runBlocking { getString(Res.string.player_error_unable_to_play_stream) },
|
||||
)
|
||||
val end = if (totalContentLength != C.LENGTH_UNSET.toLong()) {
|
||||
minOf(currentChunkStart + chunkSize - 1, currentChunkStart + totalContentLength - 1)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1527,4 +1527,17 @@
|
|||
<string name="downloads_error_open_partial_file_failed">Impossible d’ouvrir le fichier de téléchargement partiel</string>
|
||||
<string name="downloads_error_partial_file_not_open">Le fichier de téléchargement partiel n’est pas ouvert</string>
|
||||
<string name="downloads_error_write_partial_file_failed">Impossible d’écrire dans le fichier de téléchargement partiel</string>
|
||||
<string name="details_runtime_hours_minutes">%1$d h %2$d min</string>
|
||||
<string name="details_runtime_hours_only">%1$d h</string>
|
||||
<string name="details_runtime_minutes_only">%1$d min</string>
|
||||
<string name="search_error_no_results_for_catalog">Aucun résultat de recherche pour %1$s.</string>
|
||||
<string name="plugins_repository_already_installed">Ce dépôt de plugin est déjà installé.</string>
|
||||
<string name="plugins_repository_install_failed">Impossible d’installer le dépôt de plugin</string>
|
||||
<string name="plugins_repository_refresh_failed">Impossible d’actualiser le dépôt</string>
|
||||
<string name="plugins_manifest_name_missing">Le nom du manifeste est manquant.</string>
|
||||
<string name="plugins_manifest_version_missing">La version du manifeste est manquante.</string>
|
||||
<string name="plugins_manifest_no_providers">Le manifeste ne contient aucun fournisseur.</string>
|
||||
<string name="addons_manifest_missing_field">Champ « %1$s » manquant dans le manifeste</string>
|
||||
<string name="player_error_mpv_unavailable">Moteur de lecture MPV indisponible. Reconstruis l’app.</string>
|
||||
<string name="player_error_unable_to_play_stream">Impossible de lire ce flux.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1584,4 +1584,17 @@
|
|||
<string name="downloads_error_open_partial_file_failed">Failed to open partial download file</string>
|
||||
<string name="downloads_error_partial_file_not_open">Partial download file is not open</string>
|
||||
<string name="downloads_error_write_partial_file_failed">Failed to write partial download file</string>
|
||||
<string name="details_runtime_hours_minutes">%1$dh %2$dm</string>
|
||||
<string name="details_runtime_hours_only">%1$dh</string>
|
||||
<string name="details_runtime_minutes_only">%1$dm</string>
|
||||
<string name="search_error_no_results_for_catalog">No search results returned for %1$s.</string>
|
||||
<string name="plugins_repository_already_installed">That plugin repository is already installed.</string>
|
||||
<string name="plugins_repository_install_failed">Unable to install plugin repository</string>
|
||||
<string name="plugins_repository_refresh_failed">Unable to refresh repository</string>
|
||||
<string name="plugins_manifest_name_missing">Manifest name is missing.</string>
|
||||
<string name="plugins_manifest_version_missing">Manifest version is missing.</string>
|
||||
<string name="plugins_manifest_no_providers">Manifest has no providers.</string>
|
||||
<string name="addons_manifest_missing_field">Manifest missing \"%1$s\"</string>
|
||||
<string name="player_error_mpv_unavailable">MPV player engine not available. Please rebuild the app.</string>
|
||||
<string name="player_error_unable_to_play_stream">Unable to play this stream.</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.nuvio.app.features.addons
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
|
|
@ -8,6 +9,9 @@ import kotlinx.serialization.json.booleanOrNull
|
|||
import kotlinx.serialization.json.contentOrNull
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.addons_manifest_missing_field
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
internal object AddonManifestParser {
|
||||
private val json = Json {
|
||||
|
|
@ -92,7 +96,9 @@ internal object AddonManifestParser {
|
|||
|
||||
private fun JsonObject.requiredString(name: String): String =
|
||||
optionalString(name)?.takeIf { it.isNotBlank() }
|
||||
?: throw IllegalArgumentException("Manifest missing \"$name\"")
|
||||
?: throw IllegalArgumentException(
|
||||
runBlocking { getString(Res.string.addons_manifest_missing_field, name) },
|
||||
)
|
||||
|
||||
private fun JsonObject.optionalString(name: String): String? =
|
||||
this[name]?.jsonPrimitive?.contentOrNull
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
package com.nuvio.app.features.details
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.details_runtime_hours_minutes
|
||||
import nuvio.composeapp.generated.resources.details_runtime_hours_only
|
||||
import nuvio.composeapp.generated.resources.details_runtime_minutes_only
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
private val hourTokenRegex = Regex("""(?i)(\d+)\s*h(?:ours?)?""")
|
||||
private val minuteTokenRegex = Regex("""(?i)(\d+)\s*m(?:in(?:ute)?s?)?""")
|
||||
private val hourMinuteColonRegex = Regex("""^\s*(\d+)\s*:\s*(\d{1,2})\s*$""")
|
||||
|
|
@ -16,10 +23,12 @@ internal fun formatRuntimeFromMinutes(totalMinutes: Int): String {
|
|||
val hours = totalMinutes / 60
|
||||
val minutes = totalMinutes % 60
|
||||
|
||||
return when {
|
||||
hours > 0 && minutes > 0 -> "${hours}h ${minutes}m"
|
||||
hours > 0 -> "${hours}h"
|
||||
else -> "${minutes}m"
|
||||
return runBlocking {
|
||||
when {
|
||||
hours > 0 && minutes > 0 -> getString(Res.string.details_runtime_hours_minutes, hours, minutes)
|
||||
hours > 0 -> getString(Res.string.details_runtime_hours_only, hours)
|
||||
else -> getString(Res.string.details_runtime_minutes_only, minutes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -369,7 +369,9 @@ object SearchRepository {
|
|||
search = query,
|
||||
).withUnreleasedFilter()
|
||||
val items = page.items
|
||||
require(items.isNotEmpty()) { "No search results returned for $catalogName." }
|
||||
require(items.isNotEmpty()) {
|
||||
getString(Res.string.search_error_no_results_for_catalog, catalogName)
|
||||
}
|
||||
|
||||
return HomeCatalogSection(
|
||||
key = "${manifest.id}:search:$type:$catalogId:${query.lowercase()}",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
package com.nuvio.app.features.plugins
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.json.Json
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.plugins_manifest_name_missing
|
||||
import nuvio.composeapp.generated.resources.plugins_manifest_no_providers
|
||||
import nuvio.composeapp.generated.resources.plugins_manifest_version_missing
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
internal object PluginManifestParser {
|
||||
private val json = Json {
|
||||
|
|
@ -9,9 +15,15 @@ internal object PluginManifestParser {
|
|||
|
||||
fun parse(payload: String): PluginManifest {
|
||||
val manifest = json.decodeFromString<PluginManifest>(payload)
|
||||
require(manifest.name.isNotBlank()) { "Manifest name is missing." }
|
||||
require(manifest.version.isNotBlank()) { "Manifest version is missing." }
|
||||
require(manifest.scrapers.isNotEmpty()) { "Manifest has no providers." }
|
||||
require(manifest.name.isNotBlank()) {
|
||||
runBlocking { getString(Res.string.plugins_manifest_name_missing) }
|
||||
}
|
||||
require(manifest.version.isNotBlank()) {
|
||||
runBlocking { getString(Res.string.plugins_manifest_version_missing) }
|
||||
}
|
||||
require(manifest.scrapers.isNotEmpty()) {
|
||||
runBlocking { getString(Res.string.plugins_manifest_no_providers) }
|
||||
}
|
||||
return manifest
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
|
@ -25,6 +26,11 @@ import kotlinx.serialization.json.Json
|
|||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.encodeToJsonElement
|
||||
import kotlinx.serialization.json.put
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.plugins_repository_already_installed
|
||||
import nuvio.composeapp.generated.resources.plugins_repository_install_failed
|
||||
import nuvio.composeapp.generated.resources.plugins_repository_refresh_failed
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
@Serializable
|
||||
private data class PluginRow(
|
||||
|
|
@ -149,7 +155,7 @@ actual object PluginRepository {
|
|||
}
|
||||
|
||||
if (_uiState.value.repositories.any { it.manifestUrl == manifestUrl }) {
|
||||
return AddPluginRepositoryResult.Error("That plugin repository is already installed.")
|
||||
return AddPluginRepositoryResult.Error(getString(Res.string.plugins_repository_already_installed))
|
||||
}
|
||||
|
||||
return try {
|
||||
|
|
@ -168,7 +174,7 @@ actual object PluginRepository {
|
|||
pushToServer()
|
||||
AddPluginRepositoryResult.Success(repo)
|
||||
} catch (error: Throwable) {
|
||||
AddPluginRepositoryResult.Error(error.message ?: "Unable to install plugin repository")
|
||||
AddPluginRepositoryResult.Error(error.message ?: getString(Res.string.plugins_repository_install_failed))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +238,7 @@ actual object PluginRepository {
|
|||
if (existing.manifestUrl == manifestUrl) {
|
||||
existing.copy(
|
||||
isRefreshing = false,
|
||||
errorMessage = error.message ?: "Unable to refresh repository",
|
||||
errorMessage = error.message ?: runBlocking { getString(Res.string.plugins_repository_refresh_failed) },
|
||||
)
|
||||
} else {
|
||||
existing
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ import kotlinx.coroutines.delay
|
|||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.player_error_mpv_unavailable
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
private const val TAG = "NuvioiOSPlayer"
|
||||
|
||||
|
|
@ -49,7 +52,7 @@ actual fun PlatformPlayerSurface(
|
|||
|
||||
if (bridge == null) {
|
||||
LaunchedEffect(Unit) {
|
||||
latestOnError.value("MPV player engine not available. Please rebuild the app.")
|
||||
latestOnError.value(getString(Res.string.player_error_mpv_unavailable))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue