mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-07-26 22:42:17 +00:00
Merge branch 'cmp-rewrite' of https://github.com/NuvioMedia/NuvioMobile into cmp-rewrite
This commit is contained in:
commit
c3da1cf36f
16 changed files with 624 additions and 32 deletions
|
|
@ -29,7 +29,7 @@ actual object ThemeSettingsStorage {
|
|||
|
||||
fun initialize(context: Context) {
|
||||
preferences = context.getSharedPreferences(preferencesName, Context.MODE_PRIVATE)
|
||||
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.ENGLISH.code)
|
||||
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.DEVICE.code)
|
||||
}
|
||||
|
||||
actual fun loadSelectedTheme(): String? =
|
||||
|
|
@ -84,9 +84,13 @@ actual object ThemeSettingsStorage {
|
|||
}
|
||||
|
||||
actual fun applySelectedAppLanguage(languageCode: String) {
|
||||
AppCompatDelegate.setApplicationLocales(
|
||||
LocaleListCompat.forLanguageTags(languageCode),
|
||||
)
|
||||
if (languageCode.equals("device", ignoreCase = true)) {
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList())
|
||||
} else {
|
||||
AppCompatDelegate.setApplicationLocales(
|
||||
LocaleListCompat.forLanguageTags(languageCode),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
actual fun exportToSyncPayload(): JsonObject = buildJsonObject {
|
||||
|
|
@ -103,6 +107,6 @@ actual object ThemeSettingsStorage {
|
|||
payload.decodeSyncString(selectedThemeKey)?.let(::saveSelectedTheme)
|
||||
payload.decodeSyncBoolean(amoledEnabledKey)?.let(::saveAmoledEnabled)
|
||||
payload.decodeSyncBoolean(liquidGlassNativeTabBarEnabledKey)?.let(::saveLiquidGlassNativeTabBarEnabled)
|
||||
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.ENGLISH.code)
|
||||
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.DEVICE.code)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1459,4 +1459,415 @@
|
|||
<string name="settings_stream_addon_logo_title">Logo dodatku</string>
|
||||
<string name="settings_stream_addon_logo_description">Pokazuj logo i nazwę dodatku obok źródeł.</string>
|
||||
<string name="settings_stream_display_section">Wyświetlanie</string>
|
||||
<string name="settings_playback_option_original">Język oryginalny</string>
|
||||
<string name="settings_playback_option_original_hint">Wymaga włączonego wzbogacania TMDB</string>
|
||||
<string name="settings_appearance_app_language_device">Język urządzenia</string>
|
||||
<string name="addons_manifest_missing_field">W manifeście brakuje \"%1$s\"</string>
|
||||
<string name="cloud_library_playback_disabled">Biblioteka w chmurze jest wyłączona.</string>
|
||||
<string name="cloud_library_provider_unavailable">Biblioteka w chmurze nie jest dostępna dla %1$s.</string>
|
||||
<string name="collections_editor_media_movies_suffix">Filmy</string>
|
||||
<string name="collections_editor_media_series_suffix">Seriale</string>
|
||||
<string name="collections_editor_resolved_trakt_list">Rozpoznana lista Trakt</string>
|
||||
<string name="collections_editor_tmdb_collection_title_format">Kolekcja TMDB %1$s</string>
|
||||
<string name="collections_editor_tmdb_country_au">Australia</string>
|
||||
<string name="collections_editor_tmdb_country_ca">Kanada</string>
|
||||
<string name="collections_editor_tmdb_country_de">Niemcy</string>
|
||||
<string name="collections_editor_tmdb_country_placeholder">US, KR, JP, IN</string>
|
||||
<string name="collections_editor_tmdb_date_from_placeholder">2020-01-01</string>
|
||||
<string name="collections_editor_tmdb_date_to_placeholder">2024-12-31</string>
|
||||
<string name="collections_editor_tmdb_director_title_format">Reżyser TMDB %1$s</string>
|
||||
<string name="collections_editor_tmdb_discover">TMDB Odkrywaj</string>
|
||||
<string name="collections_editor_tmdb_discover_title">TMDB Odkrywaj</string>
|
||||
<string name="collections_editor_tmdb_genres_movie_placeholder">28,12</string>
|
||||
<string name="collections_editor_tmdb_genres_series_placeholder">18,35</string>
|
||||
<string name="collections_editor_tmdb_invalid_id_error">Wprowadź prawidłowy ID lub URL TMDB.</string>
|
||||
<string name="collections_editor_tmdb_invalid_id_or_url">Wprowadź prawidłowy ID lub URL TMDB.</string>
|
||||
<string name="collections_editor_tmdb_language_placeholder">en, ko, ja, hi</string>
|
||||
<string name="collections_editor_tmdb_list_title_format">Lista TMDB %1$s</string>
|
||||
<string name="collections_editor_tmdb_load_error">Nie udało się załadować źródła TMDB</string>
|
||||
<string name="collections_editor_tmdb_network_title_format">Sieć TMDB %1$s</string>
|
||||
<string name="collections_editor_tmdb_person_title_format">Osoba TMDB %1$s</string>
|
||||
<string name="collections_editor_tmdb_production_title_format">Produkcja TMDB %1$s</string>
|
||||
<string name="collections_editor_tmdb_rating_max_placeholder">10</string>
|
||||
<string name="collections_editor_tmdb_rating_min_placeholder">7.0</string>
|
||||
<string name="collections_editor_tmdb_source_load_failed">Nie udało się załadować źródła TMDB</string>
|
||||
<string name="collections_editor_tmdb_votes_min_placeholder">100</string>
|
||||
<string name="collections_editor_tmdb_year_placeholder">2024</string>
|
||||
<string name="collections_editor_trakt_enter_id_or_url">Wprowadź ID lub URL listy Trakt</string>
|
||||
<string name="collections_editor_trakt_enter_name_url_or_id">Wprowadź nazwę, URL lub ID listy Trakt</string>
|
||||
<string name="collections_editor_trakt_fallback_title">Lista Trakt %1$d</string>
|
||||
<string name="collections_editor_trakt_id_url_required">Wprowadź ID lub URL listy Trakt</string>
|
||||
<string name="collections_editor_trakt_input_required">Wprowadź nazwę, URL lub ID listy Trakt</string>
|
||||
<string name="collections_editor_trakt_list_id_format">ID %1$s</string>
|
||||
<string name="collections_editor_trakt_list_title_format">Lista Trakt %1$s</string>
|
||||
<string name="collections_editor_trakt_load_error">Nie udało się załadować listy Trakt</string>
|
||||
<string name="collections_editor_trakt_load_failed">Nie udało się załadować listy Trakt</string>
|
||||
<string name="collections_editor_trakt_no_lists_found">Nie znaleziono list Trakt</string>
|
||||
<string name="collections_editor_trakt_resolved_subtitle">Rozpoznana lista Trakt</string>
|
||||
<string name="collections_editor_watch_region_placeholder">US, KR, JP, IN</string>
|
||||
<string name="collections_folder_trakt_movie_list">Lista filmów Trakt</string>
|
||||
<string name="collections_folder_trakt_series_list">Lista seriali Trakt</string>
|
||||
<string name="collections_tmdb_api_key_required">Dodaj klucz API TMDB w Ustawieniach, aby korzystać ze źródeł TMDB.</string>
|
||||
<string name="collections_tmdb_collection_not_found">Nie znaleziono kolekcji TMDB</string>
|
||||
<string name="collections_tmdb_company_not_found">Nie znaleziono firmy TMDB</string>
|
||||
<string name="collections_tmdb_discover_no_data">TMDB Odkrywaj nie zwrócił danych</string>
|
||||
<string name="collections_tmdb_list_not_found">Nie znaleziono listy TMDB</string>
|
||||
<string name="collections_tmdb_missing_collection_id">Brak ID kolekcji TMDB</string>
|
||||
<string name="collections_tmdb_missing_list_id">Brak ID listy TMDB</string>
|
||||
<string name="collections_tmdb_missing_person_id">Brak ID osoby TMDB</string>
|
||||
<string name="collections_tmdb_network_not_found">Nie znaleziono sieci TMDB</string>
|
||||
<string name="collections_tmdb_person_credits_not_found">Nie znaleziono filmografii osoby TMDB</string>
|
||||
<string name="collections_tmdb_person_not_found">Nie znaleziono osoby TMDB</string>
|
||||
<string name="collections_trakt_credentials_missing">Brak danych uwierzytelniających Trakt.</string>
|
||||
<string name="collections_trakt_error_with_code">%1$s (%2$d)</string>
|
||||
<string name="collections_trakt_invalid_list_id_or_url">Wprowadź prawidłowy ID lub URL listy Trakt</string>
|
||||
<string name="collections_trakt_list_items_count">%1$d elementów</string>
|
||||
<string name="collections_trakt_list_likes_count">%1$d polubień</string>
|
||||
<string name="collections_trakt_list_not_found_or_private">Lista Trakt nie znaleziona lub niepubliczna</string>
|
||||
<string name="collections_trakt_missing_list_id">Brak ID listy Trakt</string>
|
||||
<string name="collections_trakt_missing_numeric_id">Lista Trakt nie zawiera numerycznego ID</string>
|
||||
<string name="collections_trakt_public_list">Publiczna lista Trakt</string>
|
||||
<string name="collections_trakt_rate_limit_reached">Osiągnięto limit zapytań Trakt</string>
|
||||
<string name="collections_trakt_request_failed">Zapytanie Trakt nie powiodło się</string>
|
||||
<string name="compose_player_no_subtitle_lines_found">Nie znaleziono linii napisów</string>
|
||||
<string name="compose_player_subtitle_lines_load_error">Nie udało się załadować linii napisów</string>
|
||||
<string name="compose_settings_page_advanced">Zaawansowane</string>
|
||||
<string name="compose_settings_page_streams">Źródła</string>
|
||||
<string name="compose_settings_root_advanced_description">Uruchamianie i zachowanie profilu.</string>
|
||||
<string name="compose_settings_root_advanced_section">ZAAWANSOWANE</string>
|
||||
<string name="compose_settings_root_streams_description">Wyświetlanie wyników źródeł i reguły badge URL.</string>
|
||||
<string name="detail_more_like_this_powered_by_tmdb">Napędzane przez TMDB</string>
|
||||
<string name="detail_more_like_this_powered_by_trakt">Napędzane przez Trakt</string>
|
||||
<string name="details_actions_menu_label">Więcej akcji</string>
|
||||
<string name="details_comments_trakt_load_failed_with_code">Nie udało się załadować komentarzy Trakt (%1$d)</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="downloads_error_finalize_failed">Nie udało się sfinalizować pobieranego pliku</string>
|
||||
<string name="downloads_error_finalize_file_failed">Nie udało się sfinalizować pobieranego pliku</string>
|
||||
<string name="downloads_error_open_partial_failed">Nie udało się otworzyć częściowego pliku</string>
|
||||
<string name="downloads_error_open_partial_file_failed">Nie udało się otworzyć częściowego pliku</string>
|
||||
<string name="downloads_error_partial_file_not_open">Częściowy plik nie jest otwarty</string>
|
||||
<string name="downloads_error_partial_not_open">Częściowy plik nie jest otwarty</string>
|
||||
<string name="downloads_error_write_partial_failed">Nie udało się zapisać częściowego pliku</string>
|
||||
<string name="downloads_error_write_partial_file_failed">Nie udało się zapisać częściowego pliku</string>
|
||||
<string name="external_player_android_system">Systemowy odtwarzacz Android</string>
|
||||
<string name="home_continue_watching_hours_minutes_left">Pozostało %1$dh %2$dm</string>
|
||||
<string name="home_continue_watching_minutes_left">Pozostało %1$dm</string>
|
||||
<string name="library_local_tab_title">Biblioteka Nuvio</string>
|
||||
<string name="network_connection_issue">Problem z połączeniem</string>
|
||||
<string name="network_empty_response_body">Pusta treść odpowiedzi</string>
|
||||
<string name="network_error_empty_response_body">Pusta treść odpowiedzi</string>
|
||||
<string name="network_error_request_failed_http">Zapytanie nie powiodło się z kodem HTTP %1$d</string>
|
||||
<string name="network_please_check_connection">Sprawdź połączenie i spróbuj ponownie.</string>
|
||||
<string name="network_request_failed_http">Zapytanie nie powiodło się z kodem HTTP %1$d</string>
|
||||
<string name="p2p_consent_body">Ten strumień wykorzystuje technologię peer-to-peer (P2P). Włączając P2P, przyjmujesz do wiadomości i zgadzasz się, że:\n\n• Twój adres IP będzie widoczny dla innych użytkowników w sieci\n• Ponosisz wyłączną odpowiedzialność za treści, do których uzyskujesz dostęp\n• Potwierdzasz, że masz prawo do strumieniowania tych treści w swojej jurysdykcji\n• Nuvio nie hostuje, nie dystrybuuje ani nie kontroluje żadnych treści P2P\n• Nuvio nie ponosi odpowiedzialności za jakiekolwiek konsekwencje prawne wynikające z korzystania ze strumieniowania P2P\n\nKorzystasz z tej funkcji wyłącznie na własne ryzyko. P2P można wyłączyć w dowolnym momencie w Ustawieniach.</string>
|
||||
<string name="p2p_consent_cancel">Anuluj</string>
|
||||
<string name="p2p_consent_enable">Włącz P2P</string>
|
||||
<string name="p2p_consent_title">Strumieniowanie P2P</string>
|
||||
<string name="p2p_error_unknown">Nieznany błąd torrenta</string>
|
||||
<string name="player_action_submit_intro">Zgłoś intro</string>
|
||||
<string name="player_action_video_settings">Ustawienia wideo</string>
|
||||
<string name="player_addon_subtitle_display_format">%1$s (%2$s)</string>
|
||||
<string name="player_engine_unavailable_rebuild">Silnik odtwarzacza MPV niedostępny. Przebuduj aplikację.</string>
|
||||
<string name="player_error_failed_start_torrent">Nie udało się uruchomić torrenta: %1$s</string>
|
||||
<string name="player_error_mpv_unavailable">Silnik odtwarzacza MPV niedostępny. Przebuduj aplikację.</string>
|
||||
<string name="player_error_torrent">Błąd torrenta: %1$s</string>
|
||||
<string name="player_error_unable_to_play_stream">Nie można odtworzyć tego strumienia.</string>
|
||||
<string name="player_ios_hardware_decoder_off">Wyłączony</string>
|
||||
<string name="player_ios_preset_compatibility_desc">Najbliżej starszego zachowania MPV na iOS.</string>
|
||||
<string name="player_ios_preset_compatibility_label">Kompatybilność</string>
|
||||
<string name="player_ios_preset_custom_desc">Użyj własnych zaawansowanych wartości poniżej.</string>
|
||||
<string name="player_ios_preset_custom_label">Własne</string>
|
||||
<string name="player_ios_preset_native_edr_desc">Najlepsze dla iPhone\'ów i iPadów z obsługą HDR.</string>
|
||||
<string name="player_ios_preset_native_edr_label">Natywne EDR</string>
|
||||
<string name="player_ios_preset_sdr_tone_mapped_desc">Bardziej przewidywalne biele i czernie na wyjściu SDR.</string>
|
||||
<string name="player_ios_preset_sdr_tone_mapped_label">Mapowanie tonalne SDR</string>
|
||||
<string name="player_torrent_buffered_status">%1$s buforowane · %2$s · %3$s</string>
|
||||
<string name="player_torrent_connecting_peers">Łączenie z peerami…</string>
|
||||
<string name="player_torrent_peer_info">%1$d seedów · %2$d peerów</string>
|
||||
<string name="player_torrent_starting_engine">Uruchamianie silnika P2P…</string>
|
||||
<string name="player_torrent_stats">%1$d peerów · %2$d seedów · %3$d%%</string>
|
||||
<string name="player_torrent_status">%1$s · %2$s</string>
|
||||
<string name="player_video_settings_brightness">Jasność</string>
|
||||
<string name="player_video_settings_contrast">Kontrast</string>
|
||||
<string name="player_video_settings_deband">Deband</string>
|
||||
<string name="player_video_settings_deband_desc">Zmniejsz pasmowanie kolorów kosztem wydajności.</string>
|
||||
<string name="player_video_settings_gamma">Gamma</string>
|
||||
<string name="player_video_settings_hdr_peak_detection">Wykrywanie szczytów HDR</string>
|
||||
<string name="player_video_settings_hdr_peak_detection_desc">Szacuj szczytową jasność HDR gdy metadane są błędne lub brakujące.</string>
|
||||
<string name="player_video_settings_interpolation">Interpolacja klatek</string>
|
||||
<string name="player_video_settings_interpolation_desc">Płynny ruch gdy mpv może czysto zsynchronizować z wyświetlaczem.</string>
|
||||
<string name="player_video_settings_output_preset">Preset wyjściowy</string>
|
||||
<string name="player_video_settings_reset_tuning">Resetuj strojenie</string>
|
||||
<string name="player_video_settings_saturation">Nasycenie</string>
|
||||
<string name="player_video_settings_title">Wideo</string>
|
||||
<string name="player_video_settings_tone_mapping">Mapowanie tonalne</string>
|
||||
<string name="plugins_badge_disabled">Wtyczki wyłączone</string>
|
||||
<string name="plugins_badge_enabled">Wtyczki włączone</string>
|
||||
<string name="plugins_badge_providers">%1$d dostawców</string>
|
||||
<string name="plugins_badge_refreshing">Odświeżanie</string>
|
||||
<string name="plugins_badge_repos">%1$d repozytoriów</string>
|
||||
<string name="plugins_badge_tmdb_key_missing">Brak klucza API TMDB</string>
|
||||
<string name="plugins_badge_tmdb_key_set">Klucz API TMDB ustawiony</string>
|
||||
<string name="plugins_button_installing">Instalowanie…</string>
|
||||
<string name="plugins_button_install_repo">Zainstaluj repozytorium wtyczek</string>
|
||||
<string name="plugins_button_testing">Testowanie…</string>
|
||||
<string name="plugins_button_test_provider">Testuj dostawcę</string>
|
||||
<string name="plugins_cd_delete_repo">Usuń repozytorium wtyczek</string>
|
||||
<string name="plugins_cd_refresh_repo">Odśwież repozytorium wtyczek</string>
|
||||
<string name="plugins_empty_providers">Brak dostępnych dostawców.</string>
|
||||
<string name="plugins_empty_repos_subtitle">Dodaj URL repozytorium, aby zainstalować wtyczki do odkrywania źródeł.</string>
|
||||
<string name="plugins_empty_repos_title">Nie zainstalowano jeszcze repozytoriów wtyczek.</string>
|
||||
<string name="plugins_enable_globally_desc">Używaj dostawców wtyczek podczas wyszukiwania źródeł.</string>
|
||||
<string name="plugins_enable_globally_title">Włącz dostawców wtyczek globalnie</string>
|
||||
<string name="plugins_error_already_installed">To repozytorium wtyczek jest już zainstalowane.</string>
|
||||
<string name="plugins_error_enter_repo_url">Wprowadź URL repozytorium wtyczek.</string>
|
||||
<string name="plugins_error_enter_valid_url">Wprowadź prawidłowy URL wtyczki.</string>
|
||||
<string name="plugins_error_install_failed">Nie udało się zainstalować repozytorium wtyczek</string>
|
||||
<string name="plugins_error_provider_not_found">Nie znaleziono dostawcy</string>
|
||||
<string name="plugins_error_refresh_failed">Nie udało się odświeżyć repozytorium</string>
|
||||
<string name="plugins_error_unavailable_build">Wtyczki nie są dostępne w tej wersji.</string>
|
||||
<string name="plugins_group_by_repo_desc">W Źródłach pokazuj jednego dostawcę na repozytorium zamiast na źródło.</string>
|
||||
<string name="plugins_group_by_repo_title">Grupuj dostawców wtyczek wg repozytorium</string>
|
||||
<string name="plugins_input_manifest_placeholder">URL manifestu wtyczki</string>
|
||||
<string name="plugins_manifest_error_name_missing">Brak nazwy w manifeście.</string>
|
||||
<string name="plugins_manifest_error_no_providers">Manifest nie ma dostawców.</string>
|
||||
<string name="plugins_manifest_error_version_missing">Brak wersji w manifeście.</string>
|
||||
<string name="plugins_manifest_name_missing">Brak nazwy w manifeście.</string>
|
||||
<string name="plugins_manifest_no_providers">Manifest nie ma dostawców.</string>
|
||||
<string name="plugins_manifest_version_missing">Brak wersji w manifeście.</string>
|
||||
<string name="plugins_message_installed">Zainstalowano %1$s.</string>
|
||||
<string name="plugins_provider_disabled_by_repo">Wyłączony przez repozytorium</string>
|
||||
<string name="plugins_provider_no_description">Brak opisu</string>
|
||||
<string name="plugins_provider_version">v%1$s</string>
|
||||
<string name="plugins_repo_fallback_label">Repozytorium wtyczek</string>
|
||||
<string name="plugins_repository_already_installed">To repozytorium wtyczek jest już zainstalowane.</string>
|
||||
<string name="plugins_repository_install_failed">Nie udało się zainstalować repozytorium wtyczek</string>
|
||||
<string name="plugins_repository_refresh_failed">Nie udało się odświeżyć repozytorium</string>
|
||||
<string name="plugins_repo_version">Wersja %1$s</string>
|
||||
<string name="plugins_section_add_repo">DODAJ REPOZYTORIUM</string>
|
||||
<string name="plugins_section_installed_repos">ZAINSTALOWANE REPOZYTORIA</string>
|
||||
<string name="plugins_section_overview">PRZEGLĄD</string>
|
||||
<string name="plugins_section_providers">DOSTAWCY</string>
|
||||
<string name="plugins_test_error_title">Błąd</string>
|
||||
<string name="plugins_test_failed">Test dostawcy nie powiódł się</string>
|
||||
<string name="plugins_test_results_count">Wyniki testu (%1$d)</string>
|
||||
<string name="plugins_tmdb_required_message">Dostawcy wtyczek wymagają klucza API TMDB. Ustaw go na ekranie TMDB, w przeciwnym razie dostawcy nie będą działać poprawnie.</string>
|
||||
<string name="search_error_no_results_for_catalog">Brak wyników wyszukiwania dla %1$s.</string>
|
||||
<string name="settings_account_sync_backend">Backend synchronizacji</string>
|
||||
<string name="settings_advanced_clear_cw_cache">Wyczyść pamięć Kontynuuj oglądanie</string>
|
||||
<string name="settings_advanced_clear_cw_cache_done">Pamięć wyczyszczona</string>
|
||||
<string name="settings_advanced_clear_cw_cache_subtitle">Usuń dane Kontynuuj oglądanie i odśwież postęp</string>
|
||||
<string name="settings_advanced_remember_last_profile">Zapamiętaj ostatni profil</string>
|
||||
<string name="settings_advanced_remember_last_profile_description">Zapamiętaj ostatnio wybrany profil przy uruchomieniu</string>
|
||||
<string name="settings_advanced_section_cache">PAMIĘĆ PODRĘCZNA</string>
|
||||
<string name="settings_advanced_section_startup">URUCHAMIANIE</string>
|
||||
<string name="settings_continue_watching_style_card">Karta</string>
|
||||
<string name="settings_continue_watching_style_card_description">Karta pozioma w stylu TV</string>
|
||||
<string name="settings_debrid_learn_more">Dowiedz się więcej</string>
|
||||
<string name="settings_debrid_max_results">Maks. wyników</string>
|
||||
<string name="settings_debrid_max_results_desc">Ogranicz liczbę wyświetlanych wyników.</string>
|
||||
<string name="settings_debrid_per_quality_limit">Limit na jakość</string>
|
||||
<string name="settings_debrid_per_quality_limit_desc">Ogranicz powtarzające się wyniki BluRay, WEB-DL, REMUX po sortowaniu.</string>
|
||||
<string name="settings_debrid_per_resolution_limit">Limit na rozdzielczość</string>
|
||||
<string name="settings_debrid_per_resolution_limit_desc">Ogranicz powtarzające się wyniki 2160p, 1080p, 720p po sortowaniu.</string>
|
||||
<string name="settings_debrid_release_groups_hint">Wprowadź jedną grupę na linię.</string>
|
||||
<string name="settings_debrid_results_all">Wszystkie wyniki</string>
|
||||
<string name="settings_debrid_results_count">%1$d wyników</string>
|
||||
<string name="settings_debrid_rule_excluded_audio_tags">Wykluczone tagi audio</string>
|
||||
<string name="settings_debrid_rule_excluded_audio_tags_desc">Ukryj wybrane tagi audio.</string>
|
||||
<string name="settings_debrid_rule_excluded_channels">Wykluczone kanały</string>
|
||||
<string name="settings_debrid_rule_excluded_channels_desc">Ukryj wybrane układy kanałów.</string>
|
||||
<string name="settings_debrid_rule_excluded_encodes">Wykluczone kodowania</string>
|
||||
<string name="settings_debrid_rule_excluded_encodes_desc">Ukryj wybrane kodowania.</string>
|
||||
<string name="settings_debrid_rule_excluded_languages">Wykluczone języki</string>
|
||||
<string name="settings_debrid_rule_excluded_languages_desc">Ukryj wyniki gdzie każdy język jest wykluczony.</string>
|
||||
<string name="settings_debrid_rule_excluded_qualities">Wykluczone jakości</string>
|
||||
<string name="settings_debrid_rule_excluded_qualities_desc">Ukryj wybrane jakości.</string>
|
||||
<string name="settings_debrid_rule_excluded_release_groups">Wykluczone grupy release</string>
|
||||
<string name="settings_debrid_rule_excluded_release_groups_desc">Ukryj wybrane grupy release.</string>
|
||||
<string name="settings_debrid_rule_excluded_resolutions">Wykluczone rozdzielczości</string>
|
||||
<string name="settings_debrid_rule_excluded_resolutions_desc">Ukryj wybrane rozdzielczości.</string>
|
||||
<string name="settings_debrid_rule_excluded_visual_tags">Wykluczone tagi wizualne</string>
|
||||
<string name="settings_debrid_rule_excluded_visual_tags_desc">Ukryj DV, HDR, 10bit, 3D i podobne tagi.</string>
|
||||
<string name="settings_debrid_rule_preferred_audio_tags">Preferowane tagi audio</string>
|
||||
<string name="settings_debrid_rule_preferred_audio_tags_desc">Sortuj Atmos, TrueHD, DTS, AAC i podobne tagi.</string>
|
||||
<string name="settings_debrid_rule_preferred_channels">Preferowane kanały</string>
|
||||
<string name="settings_debrid_rule_preferred_channels_desc">Sortuj preferowane układy kanałów jako pierwsze.</string>
|
||||
<string name="settings_debrid_rule_preferred_encodes">Preferowane kodowania</string>
|
||||
<string name="settings_debrid_rule_preferred_encodes_desc">Sortuj AV1, HEVC, AVC i podobne kodowania.</string>
|
||||
<string name="settings_debrid_rule_preferred_languages">Preferowane języki</string>
|
||||
<string name="settings_debrid_rule_preferred_languages_desc">Sortuj preferowane języki audio jako pierwsze.</string>
|
||||
<string name="settings_debrid_rule_preferred_qualities">Preferowane jakości</string>
|
||||
<string name="settings_debrid_rule_preferred_qualities_desc">Sortuj wybrane jakości jako pierwsze, w domyślnej kolejności.</string>
|
||||
<string name="settings_debrid_rule_preferred_resolutions">Preferowane rozdzielczości</string>
|
||||
<string name="settings_debrid_rule_preferred_resolutions_desc">Sortuj wybrane rozdzielczości jako pierwsze, w domyślnej kolejności.</string>
|
||||
<string name="settings_debrid_rule_preferred_visual_tags">Preferowane tagi wizualne</string>
|
||||
<string name="settings_debrid_rule_preferred_visual_tags_desc">Sortuj DV, HDR, 10bit, IMAX i podobne tagi.</string>
|
||||
<string name="settings_debrid_rule_required_audio_tags">Wymagane tagi audio</string>
|
||||
<string name="settings_debrid_rule_required_audio_tags_desc">Wymagaj Atmos, TrueHD, DTS, AAC i podobnych tagów.</string>
|
||||
<string name="settings_debrid_rule_required_channels">Wymagane kanały</string>
|
||||
<string name="settings_debrid_rule_required_channels_desc">Pokazuj tylko wybrane układy kanałów.</string>
|
||||
<string name="settings_debrid_rule_required_encodes">Wymagane kodowania</string>
|
||||
<string name="settings_debrid_rule_required_encodes_desc">Wymagaj AV1, HEVC, AVC i podobnych kodowań.</string>
|
||||
<string name="settings_debrid_rule_required_languages">Wymagane języki</string>
|
||||
<string name="settings_debrid_rule_required_languages_desc">Pokazuj tylko wyniki z wybranymi językami.</string>
|
||||
<string name="settings_debrid_rule_required_qualities">Wymagane jakości</string>
|
||||
<string name="settings_debrid_rule_required_qualities_desc">Pokazuj tylko wybrane jakości.</string>
|
||||
<string name="settings_debrid_rule_required_release_groups">Wymagane grupy release</string>
|
||||
<string name="settings_debrid_rule_required_release_groups_desc">Pokazuj tylko wybrane grupy release.</string>
|
||||
<string name="settings_debrid_rule_required_resolutions">Wymagane rozdzielczości</string>
|
||||
<string name="settings_debrid_rule_required_resolutions_desc">Pokazuj tylko wybrane rozdzielczości.</string>
|
||||
<string name="settings_debrid_rule_required_visual_tags">Wymagane tagi wizualne</string>
|
||||
<string name="settings_debrid_rule_required_visual_tags_desc">Wymagaj DV, HDR, 10bit, IMAX, SDR i podobnych tagów.</string>
|
||||
<string name="settings_debrid_section_result_management">Zarządzanie wynikami</string>
|
||||
<string name="settings_debrid_selection_any">Dowolne</string>
|
||||
<string name="settings_debrid_selection_count">%1$d wybranych</string>
|
||||
<string name="settings_debrid_size_min">%1$dGB+</string>
|
||||
<string name="settings_debrid_size_range">Zakres rozmiaru</string>
|
||||
<string name="settings_debrid_size_range_desc">Filtruj wyniki wg rozmiaru pliku.</string>
|
||||
<string name="settings_debrid_size_range_value">%1$d-%2$dGB</string>
|
||||
<string name="settings_debrid_size_up_to">Do %1$dGB</string>
|
||||
<string name="settings_debrid_sort_best_audio">Najlepszy dźwięk najpierw</string>
|
||||
<string name="settings_debrid_sort_best_quality">Najlepsza jakość najpierw</string>
|
||||
<string name="settings_debrid_sort_language">Język najpierw</string>
|
||||
<string name="settings_debrid_sort_largest">Największe najpierw</string>
|
||||
<string name="settings_debrid_sort_original">Oryginalna kolejność</string>
|
||||
<string name="settings_debrid_sort_results">Sortuj wyniki</string>
|
||||
<string name="settings_debrid_sort_results_desc">Wybierz kolejność wyników.</string>
|
||||
<string name="settings_debrid_sort_smallest">Najmniejsze najpierw</string>
|
||||
<string name="settings_debrid_template_default_format">Format domyślny</string>
|
||||
<string name="settings_debrid_template_original_format">Format oryginalny</string>
|
||||
<string name="settings_fusion_badge_group_title">Grupa %1$d</string>
|
||||
<string name="settings_fusion_badge_other_group_title">Inne badge Fusion</string>
|
||||
<string name="settings_fusion_badge_preview_action">Podgląd</string>
|
||||
<string name="settings_fusion_badge_preview_count">%1$d badge Fusion z tego URL</string>
|
||||
<string name="settings_fusion_badge_preview_empty">Brak badge Fusion w tym URL.</string>
|
||||
<string name="settings_fusion_badge_preview_title">Podgląd badge Fusion</string>
|
||||
<string name="settings_fusion_badges_empty">Brak zaimportowanych URL badge Fusion.</string>
|
||||
<string name="settings_fusion_badges_summary">%1$d/%2$d URL, %3$d aktywnych badge Fusion</string>
|
||||
<string name="settings_fusion_badge_url_active">Aktywny</string>
|
||||
<string name="settings_fusion_badge_url_inactive">Nieaktywny</string>
|
||||
<string name="settings_fusion_badge_url_label">URL JSON badge Fusion</string>
|
||||
<string name="settings_fusion_badge_urls_imported">%1$d/%2$d URL Fusion zaimportowanych</string>
|
||||
<string name="settings_fusion_badge_url_status_summary">%1$s, %2$d włączonych badge, %3$d grup</string>
|
||||
<string name="settings_meta_hero_trailer_playback">Odtwarzanie zwiastuna w tle</string>
|
||||
<string name="settings_meta_hero_trailer_playback_description">Odtwarzaj podgląd zwiastuna w tle szczegółów gdy dostępny.</string>
|
||||
<string name="settings_p2p_hide_stats_subtitle">Ukryj bufor, seedy, peery i prędkość pobierania podczas ładowania i odtwarzania</string>
|
||||
<string name="settings_p2p_hide_stats_title">Ukryj statystyki torrenta</string>
|
||||
<string name="settings_p2p_subtitle">Zezwalaj na strumienie peer-to-peer (torrent)</string>
|
||||
<string name="settings_p2p_title">Strumieniowanie P2P</string>
|
||||
<string name="settings_playback_introdb_invalid_api_key">Nieprawidłowy klucz API lub błąd połączenia</string>
|
||||
<string name="settings_playback_introdb_invalid_key">Nieprawidłowy klucz API lub błąd połączenia</string>
|
||||
<string name="settings_playback_ios_audio_output">Wyjście audio</string>
|
||||
<string name="settings_playback_ios_audio_output_audiounit_desc">Użyj starszego wyjścia AudioUnit.</string>
|
||||
<string name="settings_playback_ios_audio_output_auto_desc">Najpierw AVFoundation, potem AudioUnit jako zapasowe.</string>
|
||||
<string name="settings_playback_ios_audio_output_avfoundation_desc">Eksperymentalna obsługa Spatial Audio i wielokanałowego wyjścia.</string>
|
||||
<string name="settings_playback_ios_audio_output_dialog">Wyjście audio</string>
|
||||
<string name="settings_playback_ios_audio_output_section">Wyjście audio iOS</string>
|
||||
<string name="settings_playback_ios_display_color_hint">Wskazówka koloru wyświetlacza</string>
|
||||
<string name="settings_playback_ios_display_color_hint_desc">Pozwól mpv celować w aktywną przestrzeń kolorów wyświetlacza.</string>
|
||||
<string name="settings_playback_ios_extended_dynamic_range">Rozszerzony zakres dynamiczny</string>
|
||||
<string name="settings_playback_ios_extended_dynamic_range_desc">Domyślny tryb wyjścia Metal dla nowych sesji odtwarzania.</string>
|
||||
<string name="settings_playback_ios_hardware_decoder">Dekoder sprzętowy</string>
|
||||
<string name="settings_playback_ios_hw_decoder_dialog">Dekoder sprzętowy</string>
|
||||
<string name="settings_playback_ios_target_primaries">Docelowe kolory podstawowe</string>
|
||||
<string name="settings_playback_ios_target_primaries_dialog">Docelowe kolory podstawowe</string>
|
||||
<string name="settings_playback_ios_target_transfer">Docelowy transfer</string>
|
||||
<string name="settings_playback_ios_target_transfer_dialog">Docelowy transfer</string>
|
||||
<string name="settings_playback_ios_video_output">Wyjście wideo iOS</string>
|
||||
<string name="settings_playback_touch_gestures">Gesty dotykowe</string>
|
||||
<string name="settings_playback_touch_gestures_description">Pozwól na przesunięcia i podwójne dotknięcia na powierzchni odtwarzacza do przewijania, regulacji jasności lub głośności.</string>
|
||||
<string name="settings_stream_badge_enter_url">Wprowadź URL JSON badge.</string>
|
||||
<string name="settings_stream_badge_import_failed">Import badge nie powiódł się.</string>
|
||||
<string name="settings_stream_badge_import_limit">Możesz zaimportować do %1$d URL badge.</string>
|
||||
<string name="settings_stream_badge_position_bottom">Na dole</string>
|
||||
<string name="settings_stream_badge_position_description">Wybierz czy badge Fusion i rozmiaru pojawiają się nad czy pod kartami źródeł.</string>
|
||||
<string name="settings_stream_badge_position_dialog_description">Wybierz gdzie badge źródeł pojawiają się na kartach.</string>
|
||||
<string name="settings_stream_badge_position_dialog_title">Pozycja badge</string>
|
||||
<string name="settings_stream_badge_position_title">Pozycja badge</string>
|
||||
<string name="settings_stream_badge_position_top">Na górze</string>
|
||||
<string name="settings_stream_badges_section">Styl Fusion</string>
|
||||
<string name="settings_stream_badge_url_scheme_invalid">URL badge musi zaczynać się od http:// lub https://.</string>
|
||||
<string name="settings_stream_badge_urls_description">Importuj do %1$d URL JSON badge Fusion. Każdy URL można aktualizować lub usuwać osobno.</string>
|
||||
<string name="settings_stream_badge_urls_search_description">Zarządzaj zaimportowanymi URL JSON badge Fusion.</string>
|
||||
<string name="settings_stream_badge_urls_title">URL badge Fusion</string>
|
||||
<string name="settings_stream_size_badges_description">Pokazuj badge rozmiaru pliku w wynikach źródeł i panelu źródeł odtwarzacza.</string>
|
||||
<string name="settings_stream_size_badges_title">Badge rozmiaru</string>
|
||||
<string name="streams_plugin_repository_fallback">Repozytorium wtyczek</string>
|
||||
<string name="submit_intro_action">Zgłoś intro</string>
|
||||
<string name="submit_intro_button_submit">Wyślij</string>
|
||||
<string name="submit_intro_capture">Przechwyć</string>
|
||||
<string name="submit_intro_capture_button">Przechwyć</string>
|
||||
<string name="submit_intro_end_time">CZAS KOŃCA (MM:SS)</string>
|
||||
<string name="submit_intro_end_time_label">CZAS KOŃCA (MM:SS)</string>
|
||||
<string name="submit_intro_segment_intro">Intro</string>
|
||||
<string name="submit_intro_segment_outro">Outro</string>
|
||||
<string name="submit_intro_segment_recap">Podsumowanie</string>
|
||||
<string name="submit_intro_segment_type">TYP SEGMENTU</string>
|
||||
<string name="submit_intro_segment_type_label">TYP SEGMENTU</string>
|
||||
<string name="submit_intro_start_time">CZAS STARTU (MM:SS)</string>
|
||||
<string name="submit_intro_start_time_label">CZAS STARTU (MM:SS)</string>
|
||||
<string name="submit_intro_submit">Wyślij</string>
|
||||
<string name="submit_intro_title">Zgłoś znaczniki czasu</string>
|
||||
<string name="tmdb_sources_api_key_required">Dodaj klucz API TMDB w Ustawieniach, aby korzystać ze źródeł TMDB.</string>
|
||||
<string name="tmdb_sources_collection_fallback_title">Kolekcja TMDB %1$d</string>
|
||||
<string name="tmdb_sources_collection_not_found">Nie znaleziono kolekcji TMDB</string>
|
||||
<string name="tmdb_sources_company_fallback_title">Produkcja TMDB %1$d</string>
|
||||
<string name="tmdb_sources_company_not_found">Nie znaleziono firmy TMDB</string>
|
||||
<string name="tmdb_sources_director_fallback_title">Reżyser TMDB %1$d</string>
|
||||
<string name="tmdb_sources_discover_no_data">TMDB Odkrywaj nie zwrócił danych</string>
|
||||
<string name="tmdb_sources_discover_title">TMDB Odkrywaj</string>
|
||||
<string name="tmdb_sources_invalid_id_or_url">Wprowadź prawidłowy ID lub URL TMDB.</string>
|
||||
<string name="tmdb_sources_list_fallback_title">Lista TMDB %1$d</string>
|
||||
<string name="tmdb_sources_list_not_found">Nie znaleziono listy TMDB</string>
|
||||
<string name="tmdb_sources_load_failed">Nie udało się załadować źródła TMDB</string>
|
||||
<string name="tmdb_sources_missing_collection_id">Brak ID kolekcji TMDB</string>
|
||||
<string name="tmdb_sources_missing_list_id">Brak ID listy TMDB</string>
|
||||
<string name="tmdb_sources_missing_person_id">Brak ID osoby TMDB</string>
|
||||
<string name="tmdb_sources_network_fallback_title">Sieć TMDB %1$d</string>
|
||||
<string name="tmdb_sources_network_not_found">Nie znaleziono sieci TMDB</string>
|
||||
<string name="tmdb_sources_person_credits_not_found">Nie znaleziono filmografii osoby TMDB</string>
|
||||
<string name="tmdb_sources_person_fallback_title">Osoba TMDB %1$d</string>
|
||||
<string name="tmdb_sources_person_not_found">Nie znaleziono osoby TMDB</string>
|
||||
<string name="trakt_connected">Połączono z Trakt</string>
|
||||
<string name="trakt_connected_status">Połączono z Trakt</string>
|
||||
<string name="trakt_disconnected">Rozłączono z Trakt</string>
|
||||
<string name="trakt_disconnected_status">Rozłączono z Trakt</string>
|
||||
<string name="trakt_error_add_list_failed">Nie udało się dodać do listy Trakt</string>
|
||||
<string name="trakt_error_add_watchlist_failed">Nie udało się dodać do listy obserwowanych Trakt</string>
|
||||
<string name="trakt_error_authorization_expired">Autoryzacja Trakt wygasła</string>
|
||||
<string name="trakt_error_empty_response">Pusta treść odpowiedzi</string>
|
||||
<string name="trakt_error_list_limit_reached">Osiągnięto limit list Trakt</string>
|
||||
<string name="trakt_error_list_not_found">Nie znaleziono listy Trakt</string>
|
||||
<string name="trakt_error_missing_ids">Brak kompatybilnych ID Trakt</string>
|
||||
<string name="trakt_error_rate_limit_reached">Osiągnięto limit zapytań Trakt</string>
|
||||
<string name="trakt_error_request_failed">Zapytanie Trakt nie powiodło się</string>
|
||||
<string name="trakt_more_like_this_source_dialog_subtitle">Wybierz źródło rekomendacji na stronach szczegółów.</string>
|
||||
<string name="trakt_more_like_this_source_dialog_title">Źródło Podobnych</string>
|
||||
<string name="trakt_more_like_this_source_subtitle">Wybierz skąd pochodzą rekomendacje na stronach szczegółów</string>
|
||||
<string name="trakt_more_like_this_source_title">Źródło Podobnych</string>
|
||||
<string name="trakt_more_like_this_source_tmdb">TMDB</string>
|
||||
<string name="trakt_more_like_this_source_trakt">Trakt</string>
|
||||
<string name="trakt_public_list">Publiczna lista Trakt</string>
|
||||
<string name="trakt_public_list_enter_valid_id_or_url">Wprowadź prawidłowy ID lub URL listy Trakt</string>
|
||||
<string name="trakt_public_list_items_count">%1$d elementów</string>
|
||||
<string name="trakt_public_list_likes_count">%1$d polubień</string>
|
||||
<string name="trakt_public_list_missing_credentials">Brak danych uwierzytelniających Trakt w local.properties (TRAKT_CLIENT_ID).</string>
|
||||
<string name="trakt_public_list_missing_id">Brak ID listy Trakt</string>
|
||||
<string name="trakt_public_list_missing_numeric_id">Lista Trakt nie zawiera numerycznego ID</string>
|
||||
<string name="trakt_public_list_not_found_or_not_public">Lista Trakt nie znaleziona lub niepubliczna</string>
|
||||
<string name="trakt_public_list_rate_limit_reached">Osiągnięto limit zapytań Trakt</string>
|
||||
<string name="trakt_public_list_request_failed">Zapytanie Trakt nie powiodło się</string>
|
||||
<string name="unit_bytes_tb">TB</string>
|
||||
<string name="updates_apk_asset_missing">Brak pliku APK w wydaniu</string>
|
||||
<string name="updates_downloaded_file_missing">Pobrany plik aktualizacji nie istnieje.</string>
|
||||
<string name="updates_download_empty_body">Pusta treść pobierania</string>
|
||||
<string name="updates_download_failed_http">Pobieranie nie powiodło się z kodem HTTP %1$d</string>
|
||||
<string name="updates_download_file_missing">Pobrany plik aktualizacji nie istnieje.</string>
|
||||
<string name="updates_empty_download_body">Pusta treść pobierania</string>
|
||||
<string name="updates_github_api_error">Błąd API GitHub releases: %1$d</string>
|
||||
<string name="updates_no_channel_release">Nie opublikowano jeszcze żadnej aktualizacji.</string>
|
||||
<string name="updates_release_missing_title">Wydanie nie ma tagu ani nazwy</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -536,6 +536,7 @@
|
|||
<string name="settings_appearance_amoled_black">AMOLED Black</string>
|
||||
<string name="settings_appearance_amoled_description">Use pure black backgrounds for OLED screens.</string>
|
||||
<string name="settings_appearance_app_language">App Language</string>
|
||||
<string name="settings_appearance_app_language_device">Device language</string>
|
||||
<string name="settings_appearance_app_language_sheet_title">Choose Language</string>
|
||||
<string name="settings_appearance_continue_watching_description">Settings for the Continue Watching section.</string>
|
||||
<string name="settings_appearance_liquid_glass">Liquid Glass</string>
|
||||
|
|
@ -864,6 +865,8 @@
|
|||
<string name="settings_playback_not_set">Not set</string>
|
||||
<string name="settings_playback_option_default">Default (media file)</string>
|
||||
<string name="settings_playback_option_device_language">Device language</string>
|
||||
<string name="settings_playback_option_original">Original language</string>
|
||||
<string name="settings_playback_option_original_hint">Requires TMDB enrichment to be enabled</string>
|
||||
<string name="settings_playback_option_forced">Forced</string>
|
||||
<string name="settings_playback_option_none">None</string>
|
||||
<string name="settings_playback_addon_subtitle_startup_all">All subtitles</string>
|
||||
|
|
|
|||
|
|
@ -2004,6 +2004,7 @@ private fun MainAppContent(
|
|||
parentMetaType = launch.parentMetaType ?: launch.type,
|
||||
initialPositionMs = launch.resumePositionMs ?: 0L,
|
||||
initialProgressFraction = launch.resumeProgressFraction,
|
||||
contentLanguage = cached.contentLanguage,
|
||||
)
|
||||
if (playerSettings.externalPlayerEnabled) {
|
||||
openExternalPlayback(playerLaunch)
|
||||
|
|
@ -2430,6 +2431,7 @@ private fun MainAppContent(
|
|||
torrentTrackers = launch.torrentTrackers,
|
||||
initialPositionMs = launch.initialPositionMs,
|
||||
initialProgressFraction = launch.initialProgressFraction,
|
||||
contentLanguage = launch.contentLanguage,
|
||||
onBack = {
|
||||
ResumePromptRepository.markPlayerExitedNormally()
|
||||
PlayerLaunchStore.remove(route.launchId)
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ import nuvio.composeapp.generated.resources.settings_playback_option_default
|
|||
import nuvio.composeapp.generated.resources.settings_playback_option_device_language
|
||||
import nuvio.composeapp.generated.resources.settings_playback_option_forced
|
||||
import nuvio.composeapp.generated.resources.settings_playback_option_none
|
||||
import nuvio.composeapp.generated.resources.settings_playback_option_original
|
||||
import nuvio.composeapp.generated.resources.subtitle_language_unknown
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
|
@ -97,6 +98,7 @@ data class LanguagePreferenceOption(
|
|||
object AudioLanguageOption {
|
||||
const val DEFAULT = "default"
|
||||
const val DEVICE = "device"
|
||||
const val ORIGINAL = "original"
|
||||
}
|
||||
|
||||
object SubtitleLanguageOption {
|
||||
|
|
@ -463,6 +465,8 @@ fun languageLabelForCode(code: String?): String = when {
|
|||
code.equals(AudioLanguageOption.DEVICE, ignoreCase = true) ||
|
||||
code.equals(SubtitleLanguageOption.DEVICE, ignoreCase = true) ->
|
||||
stringResource(Res.string.settings_playback_option_device_language)
|
||||
code.equals(AudioLanguageOption.ORIGINAL, ignoreCase = true) ->
|
||||
stringResource(Res.string.settings_playback_option_original)
|
||||
else -> languageLabelResForCode(code)?.let { stringResource(it) }
|
||||
?: stringResource(Res.string.subtitle_language_unknown)
|
||||
}
|
||||
|
|
@ -477,6 +481,8 @@ suspend fun getLanguageLabelForCode(code: String?): String = when {
|
|||
code.equals(AudioLanguageOption.DEVICE, ignoreCase = true) ||
|
||||
code.equals(SubtitleLanguageOption.DEVICE, ignoreCase = true) ->
|
||||
getString(Res.string.settings_playback_option_device_language)
|
||||
code.equals(AudioLanguageOption.ORIGINAL, ignoreCase = true) ->
|
||||
getString(Res.string.settings_playback_option_original)
|
||||
else -> languageLabelResForCode(code)?.let { getString(it) }
|
||||
?: getString(Res.string.subtitle_language_unknown)
|
||||
}
|
||||
|
|
@ -485,6 +491,7 @@ fun resolvePreferredAudioLanguageTargets(
|
|||
preferredAudioLanguage: String,
|
||||
secondaryPreferredAudioLanguage: String?,
|
||||
deviceLanguages: List<String>,
|
||||
contentOriginalLanguage: String? = null,
|
||||
): List<String> {
|
||||
fun normalize(language: String?): String? {
|
||||
val normalized = normalizeLanguageCode(language)
|
||||
|
|
@ -495,6 +502,7 @@ fun resolvePreferredAudioLanguageTargets(
|
|||
SubtitleLanguageOption.NONE,
|
||||
SubtitleLanguageOption.FORCED,
|
||||
-> null
|
||||
AudioLanguageOption.ORIGINAL -> contentOriginalLanguage?.trim()?.lowercase()?.takeIf { it.isNotBlank() }
|
||||
else -> normalized
|
||||
}
|
||||
}
|
||||
|
|
@ -511,6 +519,21 @@ fun resolvePreferredAudioLanguageTargets(
|
|||
+ listOfNotNull(normalize(secondaryPreferredAudioLanguage))
|
||||
).distinct()
|
||||
|
||||
AudioLanguageOption.ORIGINAL -> {
|
||||
val originalLang = contentOriginalLanguage?.trim()?.lowercase()?.takeIf { it.isNotBlank() }
|
||||
if (originalLang != null) {
|
||||
listOfNotNull(
|
||||
originalLang,
|
||||
normalize(secondaryPreferredAudioLanguage),
|
||||
).distinct()
|
||||
} else {
|
||||
// Fallback to device languages when original language is unknown
|
||||
(deviceLanguages.mapNotNull(::normalize)
|
||||
+ listOfNotNull(normalize(secondaryPreferredAudioLanguage))
|
||||
).distinct()
|
||||
}
|
||||
}
|
||||
|
||||
else -> listOfNotNull(
|
||||
normalize(preferredAudioLanguage),
|
||||
normalize(secondaryPreferredAudioLanguage),
|
||||
|
|
@ -575,3 +598,51 @@ fun inferForcedSubtitleTrack(
|
|||
if ("forced" in text) return true
|
||||
return text.contains("songs") && text.contains("sign")
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort mapping from country name/code to ISO 639-1 primary language.
|
||||
* Used as a fallback when [resolveContentLanguage] has no explicit language field.
|
||||
*/
|
||||
fun countryToLanguageCode(country: String?): String? {
|
||||
val normalized = country?.trim()?.lowercase()?.takeIf { it.isNotBlank() } ?: return null
|
||||
return COUNTRY_TO_LANGUAGE_MAP[normalized]
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the original content language as an ISO 639-1 code.
|
||||
* Falls back to country-based inference when the explicit language field is absent.
|
||||
*/
|
||||
fun resolveContentLanguage(language: String?, country: String?): String? {
|
||||
normalizeLanguageCode(language)?.let { return it }
|
||||
countryToLanguageCode(country)?.let { return it }
|
||||
return null
|
||||
}
|
||||
|
||||
private val COUNTRY_TO_LANGUAGE_MAP = mapOf(
|
||||
// ISO 3166-1 alpha-2
|
||||
"jp" to "ja", "kr" to "ko", "cn" to "zh", "tw" to "zh",
|
||||
"fr" to "fr", "de" to "de", "it" to "it", "es" to "es",
|
||||
"pt" to "pt", "br" to "pt", "ru" to "ru", "in" to "hi",
|
||||
"tr" to "tr", "pl" to "pl", "nl" to "nl", "se" to "sv",
|
||||
"no" to "no", "dk" to "da", "fi" to "fi", "th" to "th",
|
||||
"il" to "he", "cz" to "cs", "ro" to "ro", "hu" to "hu",
|
||||
"ua" to "uk", "gr" to "el",
|
||||
// ISO 3166-1 alpha-3
|
||||
"jpn" to "ja", "kor" to "ko", "chn" to "zh", "twn" to "zh",
|
||||
"fra" to "fr", "deu" to "de", "ita" to "it", "esp" to "es",
|
||||
"prt" to "pt", "bra" to "pt", "rus" to "ru", "ind" to "hi",
|
||||
"tur" to "tr", "pol" to "pl", "nld" to "nl", "swe" to "sv",
|
||||
"nor" to "no", "dnk" to "da", "fin" to "fi", "tha" to "th",
|
||||
"isr" to "he", "cze" to "cs", "rou" to "ro", "hun" to "hu",
|
||||
"ukr" to "uk", "grc" to "el",
|
||||
// Common full names
|
||||
"japan" to "ja", "south korea" to "ko", "korea" to "ko",
|
||||
"china" to "zh", "taiwan" to "zh", "france" to "fr",
|
||||
"germany" to "de", "italy" to "it", "spain" to "es",
|
||||
"portugal" to "pt", "brazil" to "pt", "russia" to "ru",
|
||||
"india" to "hi", "turkey" to "tr", "poland" to "pl",
|
||||
"netherlands" to "nl", "sweden" to "sv", "norway" to "no",
|
||||
"denmark" to "da", "finland" to "fi", "thailand" to "th",
|
||||
"israel" to "he", "romania" to "ro", "hungary" to "hu",
|
||||
"ukraine" to "uk", "greece" to "el",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ data class PlayerLaunch(
|
|||
val torrentTrackers: List<String> = emptyList(),
|
||||
val initialPositionMs: Long = 0L,
|
||||
val initialProgressFraction: Float? = null,
|
||||
val contentLanguage: String? = null,
|
||||
)
|
||||
|
||||
object PlayerLaunchStore {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ fun PlayerScreen(
|
|||
torrentTrackers: List<String> = emptyList(),
|
||||
initialPositionMs: Long = 0L,
|
||||
initialProgressFraction: Float? = null,
|
||||
contentLanguage: String? = null,
|
||||
) {
|
||||
PlayerScreenContent(
|
||||
PlayerScreenArgs(
|
||||
|
|
@ -74,6 +75,7 @@ fun PlayerScreen(
|
|||
torrentTrackers = torrentTrackers,
|
||||
initialPositionMs = initialPositionMs,
|
||||
initialProgressFraction = initialProgressFraction,
|
||||
contentLanguage = contentLanguage,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,4 +36,5 @@ internal data class PlayerScreenArgs(
|
|||
val torrentTrackers: List<String>,
|
||||
val initialPositionMs: Long,
|
||||
val initialProgressFraction: Float?,
|
||||
val contentLanguage: String? = null,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -482,5 +482,9 @@ private fun PlayerScreenRuntime.saveDirectStreamForReuse(
|
|||
videoSize = stream.behaviorHints.videoSize,
|
||||
bingeGroup = stream.behaviorHints.bingeGroup,
|
||||
streamType = stream.streamType,
|
||||
contentLanguage = resolveContentLanguage(
|
||||
language = metaUiState.meta?.language,
|
||||
country = metaUiState.meta?.country,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,10 @@ internal fun PlayerScreenRuntime.refreshTracks() {
|
|||
preferredAudioLanguage = playerSettingsUiState.preferredAudioLanguage,
|
||||
secondaryPreferredAudioLanguage = playerSettingsUiState.secondaryPreferredAudioLanguage,
|
||||
deviceLanguages = DeviceLanguagePreferences.preferredLanguageCodes(),
|
||||
contentOriginalLanguage = resolveContentLanguage(
|
||||
language = metaUiState.meta?.language,
|
||||
country = metaUiState.meta?.country,
|
||||
) ?: args.contentLanguage,
|
||||
)
|
||||
if (preferredAudioTargets.isEmpty()) {
|
||||
preferredAudioSelectionApplied = true
|
||||
|
|
|
|||
|
|
@ -13,12 +13,14 @@ import nuvio.composeapp.generated.resources.lang_portuguese_portugal
|
|||
import nuvio.composeapp.generated.resources.lang_spanish
|
||||
import nuvio.composeapp.generated.resources.lang_turkish
|
||||
import nuvio.composeapp.generated.resources.lang_norwegian
|
||||
import nuvio.composeapp.generated.resources.settings_appearance_app_language_device
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
|
||||
enum class AppLanguage(
|
||||
val code: String,
|
||||
val labelRes: StringResource,
|
||||
) {
|
||||
DEVICE("device", Res.string.settings_appearance_app_language_device),
|
||||
CZECH("cs", Res.string.lang_czech),
|
||||
ENGLISH("en", Res.string.lang_english),
|
||||
FRENCH("fr", Res.string.lang_french),
|
||||
|
|
@ -35,6 +37,6 @@ enum class AppLanguage(
|
|||
|
||||
companion object {
|
||||
fun fromCode(code: String?): AppLanguage =
|
||||
entries.firstOrNull { it.code.equals(code, ignoreCase = true) } ?: ENGLISH
|
||||
entries.firstOrNull { it.code.equals(code, ignoreCase = true) } ?: DEVICE
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ private fun PlaybackSettingsSection(
|
|||
description = when (preferredAudioLanguage) {
|
||||
AudioLanguageOption.DEFAULT -> stringResource(Res.string.settings_playback_option_default)
|
||||
AudioLanguageOption.DEVICE -> stringResource(Res.string.settings_playback_option_device_language)
|
||||
AudioLanguageOption.ORIGINAL -> stringResource(Res.string.settings_playback_option_original)
|
||||
else -> languageLabelForCode(preferredAudioLanguage)
|
||||
},
|
||||
enabled = audioLanguageEnabled,
|
||||
|
|
@ -1090,11 +1091,13 @@ private fun PlaybackSettingsSection(
|
|||
}
|
||||
|
||||
if (showPreferredAudioDialog) {
|
||||
val originalHint = stringResource(Res.string.settings_playback_option_original_hint)
|
||||
LanguageSelectionDialog(
|
||||
title = stringResource(Res.string.settings_playback_preferred_audio_language),
|
||||
options = listOf(
|
||||
LanguageSelectionOption(AudioLanguageOption.DEFAULT, stringResource(Res.string.settings_playback_option_default)),
|
||||
LanguageSelectionOption(AudioLanguageOption.DEVICE, stringResource(Res.string.settings_playback_option_device_language)),
|
||||
LanguageSelectionOption(AudioLanguageOption.ORIGINAL, stringResource(Res.string.settings_playback_option_original), description = originalHint),
|
||||
) + AvailableLanguageOptions.map { option ->
|
||||
LanguageSelectionOption(option.code, stringResource(option.labelRes))
|
||||
},
|
||||
|
|
@ -1108,10 +1111,12 @@ private fun PlaybackSettingsSection(
|
|||
}
|
||||
|
||||
if (showSecondaryAudioDialog) {
|
||||
val originalHint = stringResource(Res.string.settings_playback_option_original_hint)
|
||||
LanguageSelectionDialog(
|
||||
title = stringResource(Res.string.settings_playback_secondary_audio_language),
|
||||
options = listOf(
|
||||
LanguageSelectionOption(null, stringResource(Res.string.settings_playback_option_none)),
|
||||
LanguageSelectionOption(AudioLanguageOption.ORIGINAL, stringResource(Res.string.settings_playback_option_original), description = originalHint),
|
||||
) + AvailableLanguageOptions.map { option ->
|
||||
LanguageSelectionOption(option.code, stringResource(option.labelRes))
|
||||
},
|
||||
|
|
@ -1441,6 +1446,7 @@ private fun formatReuseCacheDuration(hours: Int): String = when {
|
|||
private data class LanguageSelectionOption(
|
||||
val value: String?,
|
||||
val label: String,
|
||||
val description: String? = null,
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
@ -1720,12 +1726,20 @@ private fun LanguageSelectionDialog(
|
|||
.padding(horizontal = 14.dp, vertical = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = option.label,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = option.label,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
if (!option.description.isNullOrBlank()) {
|
||||
Text(
|
||||
text = option.description,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier.size(24.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ object ThemeSettingsRepository {
|
|||
private val _liquidGlassNativeTabBarEnabled = MutableStateFlow(false)
|
||||
val liquidGlassNativeTabBarEnabled: StateFlow<Boolean> = _liquidGlassNativeTabBarEnabled.asStateFlow()
|
||||
|
||||
private val _selectedAppLanguage = MutableStateFlow(AppLanguage.ENGLISH)
|
||||
private val _selectedAppLanguage = MutableStateFlow(AppLanguage.DEVICE)
|
||||
val selectedAppLanguage: StateFlow<AppLanguage> = _selectedAppLanguage.asStateFlow()
|
||||
|
||||
private var hasLoaded = false
|
||||
|
|
@ -38,7 +38,7 @@ object ThemeSettingsRepository {
|
|||
_liquidGlassNativeTabBarEnabled.value = false
|
||||
NativeTabBridge.publishAccentColor(AppTheme.WHITE.nativeTabAccentHex())
|
||||
NativeTabBridge.publishLiquidGlassEnabled(false)
|
||||
_selectedAppLanguage.value = AppLanguage.ENGLISH
|
||||
_selectedAppLanguage.value = AppLanguage.DEVICE
|
||||
}
|
||||
|
||||
private fun loadFromDisk() {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ data class CachedStreamLink(
|
|||
val sources: List<String> = emptyList(),
|
||||
val bingeGroup: String? = null,
|
||||
val streamType: String? = null,
|
||||
val contentLanguage: String? = null,
|
||||
)
|
||||
|
||||
internal expect fun epochMs(): Long
|
||||
|
|
@ -56,6 +57,7 @@ object StreamLinkCacheRepository {
|
|||
sources: List<String> = emptyList(),
|
||||
bingeGroup: String? = null,
|
||||
streamType: String? = null,
|
||||
contentLanguage: String? = null,
|
||||
) {
|
||||
if (url.isNotBlank() && url.hasLikelyExpiringPlaybackCredentials()) {
|
||||
remove(contentKey)
|
||||
|
|
@ -77,6 +79,7 @@ object StreamLinkCacheRepository {
|
|||
sources = sources,
|
||||
bingeGroup = bingeGroup,
|
||||
streamType = streamType,
|
||||
contentLanguage = contentLanguage,
|
||||
)
|
||||
val payload = json.encodeToString(CachedStreamLink.serializer(), entry)
|
||||
StreamLinkCacheStorage.saveEntry(hashedKey(contentKey), payload)
|
||||
|
|
|
|||
|
|
@ -85,6 +85,9 @@ import androidx.compose.material3.rememberModalBottomSheetState
|
|||
import coil3.compose.AsyncImage
|
||||
import com.nuvio.app.core.ui.nuvioSafeBottomPadding
|
||||
import com.nuvio.app.features.debrid.DebridSettingsRepository
|
||||
import com.nuvio.app.features.debrid.DirectDebridPlayableResult
|
||||
import com.nuvio.app.features.debrid.DirectDebridPlaybackResolver
|
||||
import com.nuvio.app.features.debrid.toastMessage
|
||||
import com.nuvio.app.features.player.PlayerSettingsRepository
|
||||
import com.nuvio.app.features.watchprogress.WatchProgressRepository
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -145,6 +148,7 @@ fun StreamsScreen(
|
|||
val streamLinkCopiedText = stringResource(Res.string.streams_link_copied)
|
||||
val noDirectStreamLinkText = stringResource(Res.string.streams_no_direct_link)
|
||||
var streamActionsTarget by remember(videoId) { mutableStateOf<StreamItem?>(null) }
|
||||
val downloadScope = rememberCoroutineScope()
|
||||
var preferredFilterApplied by remember(videoId) { mutableStateOf(false) }
|
||||
var autoPlayOverlayLogoLoadError by remember(logo) { mutableStateOf(false) }
|
||||
val autoPlayOverlayLogoUrl = logo?.takeIf { it.isNotBlank() }
|
||||
|
|
@ -356,27 +360,88 @@ fun StreamsScreen(
|
|||
if (!directUrl.isNullOrBlank()) {
|
||||
clipboardManager.setText(AnnotatedString(directUrl))
|
||||
NuvioToastController.show(streamLinkCopiedText)
|
||||
} else if (DirectDebridPlaybackResolver.shouldResolveToPlayableStream(stream)) {
|
||||
downloadScope.launch {
|
||||
val resolved = DirectDebridPlaybackResolver.resolveToPlayableStream(
|
||||
stream = stream,
|
||||
season = seasonNumber,
|
||||
episode = episodeNumber,
|
||||
)
|
||||
when (resolved) {
|
||||
is DirectDebridPlayableResult.Success -> {
|
||||
val resolvedUrl = resolved.stream.playableDirectUrl
|
||||
if (!resolvedUrl.isNullOrBlank()) {
|
||||
clipboardManager.setText(AnnotatedString(resolvedUrl))
|
||||
NuvioToastController.show(streamLinkCopiedText)
|
||||
} else {
|
||||
NuvioToastController.show(noDirectStreamLinkText)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
val message = resolved.toastMessage()
|
||||
if (message != null) {
|
||||
NuvioToastController.show(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NuvioToastController.show(noDirectStreamLinkText)
|
||||
}
|
||||
},
|
||||
onDownload = { stream ->
|
||||
val result = DownloadsRepository.enqueueFromStream(
|
||||
contentType = type,
|
||||
videoId = videoId,
|
||||
parentMetaId = parentMetaId,
|
||||
parentMetaType = parentMetaType,
|
||||
title = title,
|
||||
logo = logo,
|
||||
poster = poster,
|
||||
background = background,
|
||||
seasonNumber = seasonNumber,
|
||||
episodeNumber = episodeNumber,
|
||||
episodeTitle = episodeTitle,
|
||||
episodeThumbnail = episodeThumbnail,
|
||||
stream = stream,
|
||||
)
|
||||
NuvioToastController.show(result.toastMessage())
|
||||
if (DirectDebridPlaybackResolver.shouldResolveToPlayableStream(stream)) {
|
||||
downloadScope.launch {
|
||||
val resolved = DirectDebridPlaybackResolver.resolveToPlayableStream(
|
||||
stream = stream,
|
||||
season = seasonNumber,
|
||||
episode = episodeNumber,
|
||||
)
|
||||
when (resolved) {
|
||||
is DirectDebridPlayableResult.Success -> {
|
||||
val result = DownloadsRepository.enqueueFromStream(
|
||||
contentType = type,
|
||||
videoId = videoId,
|
||||
parentMetaId = parentMetaId,
|
||||
parentMetaType = parentMetaType,
|
||||
title = title,
|
||||
logo = logo,
|
||||
poster = poster,
|
||||
background = background,
|
||||
seasonNumber = seasonNumber,
|
||||
episodeNumber = episodeNumber,
|
||||
episodeTitle = episodeTitle,
|
||||
episodeThumbnail = episodeThumbnail,
|
||||
stream = resolved.stream,
|
||||
)
|
||||
NuvioToastController.show(result.toastMessage())
|
||||
}
|
||||
else -> {
|
||||
val message = resolved.toastMessage()
|
||||
if (message != null) {
|
||||
NuvioToastController.show(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val result = DownloadsRepository.enqueueFromStream(
|
||||
contentType = type,
|
||||
videoId = videoId,
|
||||
parentMetaId = parentMetaId,
|
||||
parentMetaType = parentMetaType,
|
||||
title = title,
|
||||
logo = logo,
|
||||
poster = poster,
|
||||
background = background,
|
||||
seasonNumber = seasonNumber,
|
||||
episodeNumber = episodeNumber,
|
||||
episodeTitle = episodeTitle,
|
||||
episodeThumbnail = episodeThumbnail,
|
||||
stream = stream,
|
||||
)
|
||||
NuvioToastController.show(result.toastMessage())
|
||||
}
|
||||
},
|
||||
onOpen = { stream, openExternally ->
|
||||
onStreamActionOpen(
|
||||
|
|
@ -922,7 +987,7 @@ private fun LazyListScope.streamSection(
|
|||
}
|
||||
},
|
||||
onLongClick = {
|
||||
if (stream.playableDirectUrl != null) {
|
||||
if (stream.playableDirectUrl != null || stream.isAddonDebridCandidate) {
|
||||
onStreamLongPress(stream)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -72,6 +72,11 @@ actual object ThemeSettingsStorage {
|
|||
}
|
||||
|
||||
actual fun applySelectedAppLanguage(languageCode: String) {
|
||||
if (languageCode.equals("device", ignoreCase = true)) {
|
||||
NSUserDefaults.standardUserDefaults.removeObjectForKey("AppleLanguages")
|
||||
NSUserDefaults.standardUserDefaults.synchronize()
|
||||
return
|
||||
}
|
||||
val normalizedCode = languageCode
|
||||
.trim()
|
||||
.takeIf { it.isNotBlank() }
|
||||
|
|
@ -97,6 +102,6 @@ actual object ThemeSettingsStorage {
|
|||
payload.decodeSyncString(selectedThemeKey)?.let(::saveSelectedTheme)
|
||||
payload.decodeSyncBoolean(amoledEnabledKey)?.let(::saveAmoledEnabled)
|
||||
payload.decodeSyncBoolean(liquidGlassNativeTabBarEnabledKey)?.let(::saveLiquidGlassNativeTabBarEnabled)
|
||||
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.ENGLISH.code)
|
||||
applySelectedAppLanguage(loadSelectedAppLanguage() ?: AppLanguage.DEVICE.code)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue