diff --git a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngine.android.kt b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngine.android.kt index 7497c0607..93aecad7c 100644 --- a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngine.android.kt +++ b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/p2p/P2pStreamingEngine.android.kt @@ -2,6 +2,7 @@ package com.nuvio.app.features.p2p import android.content.Context import android.util.Log +import com.nuvio.app.core.i18n.localizedP2pUnknownTorrentError import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -93,7 +94,7 @@ actual object P2pStreamingEngine { throw e } catch (e: Exception) { if (isCurrentGeneration(generation)) { - _state.value = P2pStreamingState.Error(e.message ?: "Unknown torrent error") + _state.value = P2pStreamingState.Error(e.message ?: localizedP2pUnknownTorrentError()) } throw e } diff --git a/composeApp/src/commonMain/composeResources/values-fr/strings.xml b/composeApp/src/commonMain/composeResources/values-fr/strings.xml index a09f31754..f4a6a3dd6 100644 --- a/composeApp/src/commonMain/composeResources/values-fr/strings.xml +++ b/composeApp/src/commonMain/composeResources/values-fr/strings.xml @@ -320,8 +320,11 @@ Rechercher Pistes audio Audio + Synchro auto + Gras Intégré Décalage inférieur + Capturer Fermer le lecteur Couleur En cours de lecture @@ -332,11 +335,15 @@ Taille de police %1$dsp Verrouiller les contrôles du lecteur + Chargement des lignes de sous-titres… + Aucune ligne de sous-titres trouvée + Impossible de charger les lignes de sous-titres Aucune piste audio disponible Aucun épisode disponible Aucun stream trouvé Aucun Contour + Couleur du contour Épisodes Sources Streams @@ -344,6 +351,8 @@ Lecture en cours Appuie pour chercher des sous-titres Retour + Recharger + Réinitialiser Rétablir les valeurs par défaut Remplir Ajuster @@ -356,8 +365,11 @@ Avancer de 10 secondes Sources Style + Sélectionne d’abord un sous-titre d’addon Sous-titres + Délai des sous-titres Sous-titres + Opacité du texte Luminosité %1$s Volume %1$s Muet @@ -386,6 +398,7 @@ Général Compte Addons + Avancé Apparence Contenu et découverte Continuer à regarder @@ -400,12 +413,15 @@ Plugins Personnalisation des affiches Paramètres + Streams Supporters et contributeurs Enrichissement TMDB Trakt À PROPOS Gère ton compte, déconnecte-toi ou supprime-le. COMPTE + Comportement au démarrage et des profils. + AVANCÉ Ajuste la présentation de l’accueil et les préférences visuelles. Rechercher de nouvelles versions de l’application. Vérifier les mises à jour @@ -415,12 +431,20 @@ GÉNÉRAL Connecte les services TMDB et MDBList. Gère les alertes de sortie d’épisodes et envoie une notification de test. + Affichage des résultats de streams et règles d’URL de badges. Basculer vers un profil différent. Changer de profil Connecte Trakt, synchronise des listes et enregistre des titres directement dans Trakt. Aucun paramètre trouvé. Rechercher dans les paramètres… RÉSULTATS + DÉMARRAGE + CACHE + Mémoriser le dernier profil + Mémorise le dernier profil sélectionné au démarrage + Vider le cache de Continuer à regarder + Supprime les miniatures, titres et données d’enrichissement en cache pour Continuer à regarder + Cache vidé LICENCE DE L’APP DONNÉES ET SERVICES LICENCE DE LECTURE @@ -584,6 +608,8 @@ VISIBILITÉ Afficher le bandeau Continuer à regarder sur l’écran d’accueil. Afficher Continuer à regarder + Carte + Carte paysage façon TV Affiche Carte d’affiche centrée sur la couverture Large @@ -646,6 +672,38 @@ Contrôle les métadonnées affichées sous chaque résultat. Réinitialiser la mise en forme Restaurer la mise en forme par défaut des résultats. + Style Fusion + Badges de taille + Affiche les badges de taille de fichier dans les résultats de flux et les panneaux de source du lecteur. + Logo de l’addon + Affiche le logo et le nom de l’addon à côté des sources de streams. + Affichage + Position des badges + Choisis si les badges Fusion et de taille apparaissent au-dessus ou en dessous des cartes de flux. + Position des badges + Choisis où les badges de flux apparaissent sur les cartes de flux. + En haut + En bas + URL de badges Fusion + Importe jusqu’à %1$d URL JSON de badges de flux de style Fusion. Chaque URL peut être mise à jour ou supprimée séparément. + Gère les URL JSON de badges de flux de style Fusion importées. + Échec de l’import du badge. + Saisis une URL JSON de badge. + L’URL du badge doit commencer par http:// ou https://. + Tu peux importer jusqu’à %1$d URL de badges. + %1$d/%2$d URL, %3$d badges Fusion actifs + Aucune URL de badge Fusion importée. + URL JSON du badge Fusion + %1$d/%2$d URL Fusion importées + Active + Inactive + %1$s · %2$d badges activés · %3$d groupes + Aperçu + Aperçu du badge Fusion + %1$d badges de style Fusion depuis cette URL + Aucune image de badge de style Fusion dans cette URL. + Groupe %1$d + Autres badges Fusion Clé API validée. Impossible de valider cette clé API. Ajoute ta clé API MDBList ci-dessous avant d’activer les notes. @@ -669,6 +727,8 @@ Section de commentaires Trakt. Détails Durée, statut, date de sortie, langue et informations associées. + Lecture des bandes-annonces dans le Hero + Lit un aperçu de la bande-annonce dans le Hero des métadonnées quand une bande-annonce est disponible. Cartes d’épisodes Choisis comment les épisodes sont affichés sur l’écran de métadonnées. Horizontal @@ -768,10 +828,18 @@ App de lecteur externe Ouvre les nouvelles lectures avec l’app vidéo par défaut d’Android ou le sélecteur système. Ouvre les nouvelles lectures avec le lecteur installé sélectionné. + Transmettre les sous-titres au lecteur externe + Récupère les sous-titres d’addons dans ta langue préférée et les transmet au lecteur externe. Aucun lecteur externe compatible n’est installé + Lecteur + Interne + Externe + Choisis quel lecteur gère les nouvelles lectures. Vitesse au maintien Maintenir pour accélérer Garde le doigt appuyé n’importe où sur le lecteur pour accélérer temporairement. + Gestes tactiles + Autorise les balayages et les doubles appuis sur le lecteur pour avancer ou reculer, ajuster la luminosité ou le volume. Modèle regex invalide Durée du cache du dernier lien Mapper DV7 vers HEVC @@ -785,6 +853,13 @@ Langue de l’appareil Forcé Aucun + Tous les sous-titres + Récupère et affiche tous les sous-titres d’addons pour la vidéo. + Démarrage rapide + Ignore la récupération automatique des sous-titres d’addons jusqu’à ce que tu la demandes dans le lecteur. + Sous-titres d’addons au démarrage + Préférés uniquement + Récupère les sous-titres d’addons, mais n’affiche que ceux dans tes langues préférées. Préférer le groupe binge Lors de la lecture automatique, préférer un stream du même groupe binge que le stream actuel. Réutiliser le groupe de binge @@ -829,6 +904,20 @@ %1$d sélectionné(s) Afficher la superposition de chargement Afficher la superposition de chargement initiale pendant le démarrage d’un stream. + Couleur d’arrière-plan + Gras + Utilise une graisse de police plus épaisse pour les sous-titres. + Transparent + Contour + Couleur du contour + Dessine une bordure autour du texte des sous-titres. + Afficher uniquement les langues préférées + N’affiche que les sous-titres correspondant à tes langues de sous-titres préférées. + Taille des sous-titres + Couleur du texte + Utiliser les sous-titres forcés + Privilégie les sous-titres forcés selon tes préférences de langue de sous-titres. + Décalage vertical Passer l’intro/outro/récap Afficher un bouton de saut lors des segments d’intro, d’outro et de récapitulatif détectés. Périmètre des sources @@ -928,6 +1017,12 @@ Nuvio Sync Source de progression réglée sur Trakt Source de progression réglée sur Nuvio Sync + Source de la section Similaires + Choisis la provenance des recommandations sur les pages de détails + Source de la section Similaires + Sélectionne la source des recommandations affichées sur les pages de détails. + Trakt + TMDB Fenêtre de Continuer à regarder Historique Trakt pris en compte pour Continuer à regarder Fenêtre de Continuer à regarder @@ -1049,10 +1144,13 @@ Quitter l’application Ce catalogue n’a renvoyé aucun élément. Aucun titre trouvé + Plus d’actions Vérifie ta connexion Wi‑Fi ou données mobiles et réessaie. Réalisateur Échec du chargement À voir aussi + Données fournies par TMDB + Données fournies par Trakt Saisons Cet addon a renvoyé des vidéos pour la série, mais aucune n’incluait de numéros de saison ou d’épisode. Cet addon n’a fourni aucune métadonnée d’épisode pour cette série. @@ -1084,6 +1182,8 @@ Marquer comme vu À suivre %1$s vu + %1$d h %2$d min restantes + %1$d min restantes Installe et valide au moins un addon avant de charger des lignes de catalogue à l’accueil. Les addons installés n’exposent actuellement aucun catalogue compatible avec le tableau sans extras requis. Aucune ligne d’accueil disponible @@ -1179,6 +1279,7 @@ S%1$dE%2$d - %3$s Récupération… Recherche de la source… + Chargement des sous-titres depuis les addons… Recherche des streams… Lien du stream copié Aucun lien direct du stream disponible @@ -1283,6 +1384,16 @@ Impossible de terminer la connexion Trakt Utilisateur Trakt Liste de suivi + + Autorisation Trakt expirée + Liste Trakt introuvable + Limite de listes Trakt atteinte + Limite de requêtes Trakt atteinte + Échec de la requête Trakt + Échec de l’ajout à ta liste de suivi Trakt + Échec de l’ajout à la liste Trakt + Identifiants Trakt compatibles manquants + Réponse vide du serveur Ajoute une clé API TMDB dans les paramètres pour utiliser les sources TMDB. Collection TMDB %1$d Collection TMDB introuvable @@ -1483,6 +1594,11 @@ Permettre à mpv de cibler par défaut l’espace colorimétrique de l’écran actif. Primaires cibles Transfert cible + Sortie audio iOS + Sortie audio + Essaie d’abord AVFoundation, puis bascule sur AudioUnit. + Prise en charge expérimentale de l’audio spatial et de la sortie multicanal. + Utilise l’ancienne sortie AudioUnit. Gestion des résultats Nombre max de résultats @@ -1498,6 +1614,7 @@ En savoir plus Format par défaut + Format d’origine Saisis un groupe par ligne. Ordre original @@ -1582,6 +1699,7 @@ Capturer Décodeur matériel + Sortie audio Primaires cibles Transfert cible @@ -1760,4 +1878,21 @@ Liste Trakt %1$s Lecteur système Android + Streaming P2P + Ce flux utilise la technologie pair-à-pair (P2P). En activant le P2P, tu reconnais et acceptes que :\n\n• Ton adresse IP sera visible par les autres pairs du réseau\n• Tu es seul responsable du contenu auquel tu accèdes\n• Tu confirmes avoir le droit légal de visionner ce contenu dans ta juridiction\n• Nuvio n’héberge, ne distribue ni ne contrôle aucun contenu P2P\n• Nuvio ne peut être tenu responsable des conséquences légales liées à ton utilisation du streaming P2P\n\nTu utilises cette fonctionnalité entièrement à tes propres risques. Le P2P peut être désactivé à tout moment dans les paramètres. + Activer le P2P + Annuler + Erreur torrent inconnue + Streaming P2P + Autoriser les flux pair-à-pair (torrent) + Masquer les statistiques torrent + Masquer la mémoire tampon, les seeders, les pairs et la vitesse de téléchargement pendant le chargement et la lecture + %1$d sources · %2$d pairs + %1$s en mémoire tampon · %2$s · %3$s + %1$s · %2$s + %1$d pairs · %2$d sources · %3$d %% + Connexion aux pairs… + Démarrage du moteur P2P… + Impossible de démarrer le torrent : %1$s + Erreur de torrent : %1$s diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index b05145984..313d53338 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -344,6 +344,8 @@ %1$dsp Lock player controls Loading subtitle lines... + No subtitle lines found + Unable to load subtitle lines No audio tracks available No episodes available No streams found @@ -693,6 +695,10 @@ Fusion badge URLs Import up to %1$d Fusion-style stream badge JSON URLs. Each URL can be updated or deleted separately. Manage imported Fusion-style stream badge JSON URLs. + Badge import failed. + Enter a badge JSON URL. + Badge URL must start with http:// or https://. + You can import up to %1$d badge URLs. %1$d/%2$d URLs, %3$d active Fusion badges No Fusion badge URLs imported. Fusion badge JSON URL @@ -1146,6 +1152,7 @@ Exit app This catalog did not return any items. No titles found + More actions Check your Wi-Fi or mobile data connection and try again. Director Failed to load @@ -1389,6 +1396,16 @@ Failed to complete Trakt sign in Trakt user Watchlist + + Trakt authorization expired + Trakt list not found + Trakt list limit reached + Trakt rate limit reached + Trakt request failed + Failed to add to Trakt watchlist + Failed to add to Trakt list + Missing compatible Trakt IDs + Empty response body Add a TMDB API key in Settings to use TMDB sources. TMDB Collection %1$d TMDB collection not found @@ -1862,6 +1879,7 @@ This stream uses peer-to-peer (P2P) technology. By enabling P2P, you acknowledge and agree that:\n\n• Your IP address will be visible to other peers in the network\n• You are solely responsible for the content you access\n• You confirm you have the legal right to stream this content in your jurisdiction\n• Nuvio does not host, distribute, or control any P2P content\n• Nuvio bears no liability for any legal consequences arising from your use of P2P streaming\n\nYou use this feature entirely at your own risk. P2P can be disabled anytime in Settings. Enable P2P Cancel + Unknown torrent error P2P Streaming Allow peer-to-peer (torrent) streams Hide torrent stats diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/i18n/LocalizedUiText.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/i18n/LocalizedUiText.kt index ca955abb2..3c96e28c7 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/core/i18n/LocalizedUiText.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/core/i18n/LocalizedUiText.kt @@ -8,6 +8,8 @@ import nuvio.composeapp.generated.resources.action_resume import nuvio.composeapp.generated.resources.action_resume_episode import nuvio.composeapp.generated.resources.compose_player_episode_code_episode_only import nuvio.composeapp.generated.resources.compose_player_episode_code_full +import nuvio.composeapp.generated.resources.compose_player_no_subtitle_lines_found +import nuvio.composeapp.generated.resources.compose_player_subtitle_lines_load_error import nuvio.composeapp.generated.resources.continue_watching_up_next import nuvio.composeapp.generated.resources.continue_watching_up_next_episode import nuvio.composeapp.generated.resources.date_month_april @@ -40,6 +42,11 @@ import nuvio.composeapp.generated.resources.media_movie import nuvio.composeapp.generated.resources.media_movies import nuvio.composeapp.generated.resources.media_series import nuvio.composeapp.generated.resources.media_tv +import nuvio.composeapp.generated.resources.p2p_error_unknown +import nuvio.composeapp.generated.resources.settings_stream_badge_enter_url +import nuvio.composeapp.generated.resources.settings_stream_badge_import_failed +import nuvio.composeapp.generated.resources.settings_stream_badge_import_limit +import nuvio.composeapp.generated.resources.settings_stream_badge_url_scheme_invalid import nuvio.composeapp.generated.resources.unit_bytes_b import nuvio.composeapp.generated.resources.unit_bytes_gb import nuvio.composeapp.generated.resources.unit_bytes_kb @@ -134,6 +141,27 @@ fun localizedShortMonthName(month: Int): String = else -> month.toString() } +fun localizedNoSubtitleLinesFound(): String = + resourceString("No subtitle lines found") { getString(Res.string.compose_player_no_subtitle_lines_found) } + +fun localizedSubtitleLinesLoadError(): String = + resourceString("Unable to load subtitle lines") { getString(Res.string.compose_player_subtitle_lines_load_error) } + +fun localizedBadgeImportFailed(): String = + resourceString("Badge import failed.") { getString(Res.string.settings_stream_badge_import_failed) } + +fun localizedBadgeEnterUrl(): String = + resourceString("Enter a badge JSON URL.") { getString(Res.string.settings_stream_badge_enter_url) } + +fun localizedBadgeUrlSchemeInvalid(): String = + resourceString("Badge URL must start with http:// or https://.") { getString(Res.string.settings_stream_badge_url_scheme_invalid) } + +fun localizedBadgeImportLimit(limit: Int): String = + resourceString("You can import up to $limit badge URLs.") { getString(Res.string.settings_stream_badge_import_limit, limit) } + +fun localizedP2pUnknownTorrentError(): String = + resourceString("Unknown torrent error") { getString(Res.string.p2p_error_unknown) } + fun localizedByteUnit(unit: String): String = when (unit) { "GB" -> resourceString("GB") { getString(Res.string.unit_bytes_gb) } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/components/DetailActionButtons.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/components/DetailActionButtons.kt index 7c3324ba8..ae11644dc 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/components/DetailActionButtons.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/components/DetailActionButtons.kt @@ -58,7 +58,7 @@ fun DetailActionButtons( modifier: Modifier = Modifier, playLabel: String = stringResource(Res.string.action_play), secondaryActions: List = emptyList(), - actionsMenuLabel: String = "More actions", + actionsMenuLabel: String = stringResource(Res.string.details_actions_menu_label), isTablet: Boolean = false, onPlayClick: () -> Unit = {}, onPlayLongClick: (() -> Unit)? = null, diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreenRuntimeSubtitleActions.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreenRuntimeSubtitleActions.kt index fa9c8afcb..0823f8207 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreenRuntimeSubtitleActions.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreenRuntimeSubtitleActions.kt @@ -1,5 +1,7 @@ package com.nuvio.app.features.player +import com.nuvio.app.core.i18n.localizedNoSubtitleLinesFound +import com.nuvio.app.core.i18n.localizedSubtitleLinesLoadError import com.nuvio.app.features.addons.httpGetTextWithHeaders import kotlinx.coroutines.launch @@ -33,13 +35,13 @@ internal fun PlayerScreenRuntime.loadSubtitleAutoSyncCues(force: Boolean = false subtitleAutoSyncState = subtitleAutoSyncState.copy( cues = cues, isLoading = false, - errorMessage = if (cues.isEmpty()) "No subtitle lines found" else null, + errorMessage = if (cues.isEmpty()) localizedNoSubtitleLinesFound() else null, ) }, onFailure = { error -> subtitleAutoSyncState = subtitleAutoSyncState.copy( isLoading = false, - errorMessage = error.message ?: "Unable to load subtitle lines", + errorMessage = error.message ?: localizedSubtitleLinesLoadError(), ) }, ) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/StreamBadgeSettingsRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/StreamBadgeSettingsRepository.kt index 397d26adf..febd2b9b5 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/StreamBadgeSettingsRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/StreamBadgeSettingsRepository.kt @@ -1,5 +1,9 @@ package com.nuvio.app.features.streams +import com.nuvio.app.core.i18n.localizedBadgeEnterUrl +import com.nuvio.app.core.i18n.localizedBadgeImportFailed +import com.nuvio.app.core.i18n.localizedBadgeImportLimit +import com.nuvio.app.core.i18n.localizedBadgeUrlSchemeInvalid import com.nuvio.app.features.addons.httpGetText import kotlinx.coroutines.CancellationException import kotlinx.coroutines.flow.MutableStateFlow @@ -77,12 +81,12 @@ object StreamBadgeSettingsRepository { ensureLoaded() val normalizedUrl = url.trim() if (normalizedUrl.isBlank()) { - return StreamBadgeImportResult.Error("Enter a badge JSON URL.") + return StreamBadgeImportResult.Error(localizedBadgeEnterUrl()) } if (!normalizedUrl.startsWith("https://", ignoreCase = true) && !normalizedUrl.startsWith("http://", ignoreCase = true) ) { - return StreamBadgeImportResult.Error("Badge URL must start with http:// or https://.") + return StreamBadgeImportResult.Error(localizedBadgeUrlSchemeInvalid()) } return try { @@ -91,7 +95,7 @@ object StreamBadgeSettingsRepository { import.sourceUrl.equals(normalizedUrl, ignoreCase = true) } if (!isExistingImport && currentRules.imports.size >= STREAM_BADGE_IMPORT_LIMIT) { - return StreamBadgeImportResult.Error("You can import up to $STREAM_BADGE_IMPORT_LIMIT badge URLs.") + return StreamBadgeImportResult.Error(localizedBadgeImportLimit(STREAM_BADGE_IMPORT_LIMIT)) } val payload = httpGetText(normalizedUrl) val parsedImport = StreamBadgeRulesParser.parse( @@ -104,7 +108,7 @@ object StreamBadgeSettingsRepository { StreamBadgeImportResult.Success(streamBadgeRules) } catch (error: Exception) { if (error is CancellationException) throw error - StreamBadgeImportResult.Error(error.message ?: "Badge import failed.") + StreamBadgeImportResult.Error(error.message ?: localizedBadgeImportFailed()) } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/trakt/TraktLibraryRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/trakt/TraktLibraryRepository.kt index c8d365abf..39f82e9c2 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/trakt/TraktLibraryRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/trakt/TraktLibraryRepository.kt @@ -14,10 +14,12 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withLock import nuvio.composeapp.generated.resources.* +import org.jetbrains.compose.resources.StringResource import org.jetbrains.compose.resources.getString import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.selects.select @@ -612,10 +614,10 @@ object TraktLibraryRepository { followRedirects = true, ) if (response.status !in 200..299) { - throw IllegalStateException(errorMessageForStatus(response.status, "Trakt request failed")) + throw IllegalStateException(errorMessageForStatus(response.status, localizedString(Res.string.trakt_error_request_failed))) } if (response.body.isBlank()) { - throw IllegalStateException("Empty response body") + throw IllegalStateException(localizedString(Res.string.trakt_error_empty_response)) } return response } @@ -636,7 +638,7 @@ object TraktLibraryRepository { followRedirects = true, ) if (response.status !in 200..299) { - throw IllegalStateException(errorMessageForStatus(response.status, "Trakt request failed")) + throw IllegalStateException(errorMessageForStatus(response.status, localizedString(Res.string.trakt_error_request_failed))) } return response } @@ -661,7 +663,7 @@ object TraktLibraryRepository { headers = headers, ) if (!isSuccessfulAddResponse(response.body)) { - throw IllegalStateException(errorMessageForStatus(response.status, "Failed to add to Trakt watchlist")) + throw IllegalStateException(errorMessageForStatus(response.status, localizedString(Res.string.trakt_error_add_watchlist_failed))) } } @@ -682,7 +684,7 @@ object TraktLibraryRepository { headers = headers, ) if (!isSuccessfulAddResponse(response.body)) { - throw IllegalStateException(errorMessageForStatus(response.status, "Failed to add to Trakt list")) + throw IllegalStateException(errorMessageForStatus(response.status, localizedString(Res.string.trakt_error_add_list_failed))) } } @@ -699,7 +701,7 @@ object TraktLibraryRepository { val type = normalizeType(item.type) val ids = resolveIds(item) if (!ids.hasAnyId()) { - throw IllegalStateException("Missing compatible Trakt IDs") + throw IllegalStateException(localizedString(Res.string.trakt_error_missing_ids)) } val request = if (type == "movie") { @@ -819,12 +821,14 @@ object TraktLibraryRepository { return addCount > 0 || existingCount > 0 } + private fun localizedString(resource: StringResource): String = runBlocking { getString(resource) } + private fun errorMessageForStatus(status: Int, defaultMessage: String): String = when (status) { - 401, 403 -> "Trakt authorization expired" - 404 -> "Trakt list not found" - 420 -> "Trakt list limit reached" - 429 -> "Trakt rate limit reached" + 401, 403 -> localizedString(Res.string.trakt_error_authorization_expired) + 404 -> localizedString(Res.string.trakt_error_list_not_found) + 420 -> localizedString(Res.string.trakt_error_list_limit_reached) + 429 -> localizedString(Res.string.trakt_error_rate_limit_reached) else -> "$defaultMessage ($status)" }