diff --git a/lib/i18n/da.i18n.json b/lib/i18n/da.i18n.json index 1dccaff0..53f61f51 100644 --- a/lib/i18n/da.i18n.json +++ b/lib/i18n/da.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Spring automatisk intromarkører over efter få sekunder", "autoSkipCredits": "Auto-spring rulletekster", "autoSkipCreditsDescription": "Spring automatisk rulletekster over og afspil næste episode", + "forceSkipMarkerFallback": "Tving reservemarkører", + "forceSkipMarkerFallbackDescription": "Brug kapitel-titelmønstre til springmarkører, selv når Plex leverer indbyggede markører", "autoSkipDelay": "Auto-spring forsinkelse", "autoSkipDelayDescription": "Vent ${seconds} sekunder før automatisk spring", "introPattern": "Intromarkørmønster", diff --git a/lib/i18n/de.i18n.json b/lib/i18n/de.i18n.json index f7c18c90..7faec3e3 100644 --- a/lib/i18n/de.i18n.json +++ b/lib/i18n/de.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Intro-Marker nach wenigen Sekunden automatisch überspringen", "autoSkipCredits": "Abspann automatisch überspringen", "autoSkipCreditsDescription": "Abspann automatisch überspringen und nächste Episode abspielen", + "forceSkipMarkerFallback": "Fallback-Markierungen erzwingen", + "forceSkipMarkerFallbackDescription": "Kapitel-Titelmuster für Überspring-Markierungen verwenden, auch wenn Plex native Markierungen bereitstellt", "autoSkipDelay": "Verzögerung für automatisches Überspringen", "autoSkipDelayDescription": "${seconds} Sekunden vor dem automatischen Überspringen warten", "introPattern": "Intro-Markierungsmuster", diff --git a/lib/i18n/en.i18n.json b/lib/i18n/en.i18n.json index 500c7602..f6bb47a0 100644 --- a/lib/i18n/en.i18n.json +++ b/lib/i18n/en.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Automatically skip intro markers after a few seconds", "autoSkipCredits": "Auto Skip Credits", "autoSkipCreditsDescription": "Automatically skip credits and play next episode", + "forceSkipMarkerFallback": "Force Fallback Markers", + "forceSkipMarkerFallbackDescription": "Use chapter title patterns for skip markers even when Plex provides native markers", "autoSkipDelay": "Auto Skip Delay", "autoSkipDelayDescription": "Wait ${seconds} seconds before auto-skipping", "introPattern": "Intro Marker Pattern", diff --git a/lib/i18n/es.i18n.json b/lib/i18n/es.i18n.json index 26fda581..178d6573 100644 --- a/lib/i18n/es.i18n.json +++ b/lib/i18n/es.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Saltar automáticamente los marcadores de intro después de unos segundos", "autoSkipCredits": "Saltar Créditos automáticamente", "autoSkipCreditsDescription": "Saltar automáticamente los créditos y reproducir el siguiente episodio", + "forceSkipMarkerFallback": "Forzar marcadores alternativos", + "forceSkipMarkerFallbackDescription": "Usar patrones de títulos de capítulos para marcadores de salto incluso cuando Plex proporciona marcadores nativos", "autoSkipDelay": "Retraso de Salto automático", "autoSkipDelayDescription": "Esperar ${seconds} segundos antes de saltar automáticamente", "introPattern": "Patrón de marcador de intro", diff --git a/lib/i18n/fr.i18n.json b/lib/i18n/fr.i18n.json index 8df2b39d..8e157d1e 100644 --- a/lib/i18n/fr.i18n.json +++ b/lib/i18n/fr.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Skipper automatiquement l'introduction après quelques secondes", "autoSkipCredits": "Skip automatique des crédits", "autoSkipCreditsDescription": "Passer les crédits et passer à l'épisode suivant automatiquement", + "forceSkipMarkerFallback": "Forcer les marqueurs de repli", + "forceSkipMarkerFallbackDescription": "Utiliser les motifs de titres de chapitres pour les marqueurs de saut même si Plex fournit des marqueurs natifs", "autoSkipDelay": "Délai avant skip automatique", "autoSkipDelayDescription": "Attendre ${seconds} secondes avant l'auto-skip", "introPattern": "Modèle de marqueur d'intro", diff --git a/lib/i18n/it.i18n.json b/lib/i18n/it.i18n.json index 4b65b6e3..981d3684 100644 --- a/lib/i18n/it.i18n.json +++ b/lib/i18n/it.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Salta automaticamente i marcatori dell'intro dopo alcuni secondi", "autoSkipCredits": "Salta Crediti Automaticamente", "autoSkipCreditsDescription": "Salta automaticamente i crediti e riproduci l'episodio successivo", + "forceSkipMarkerFallback": "Forza marcatori fallback", + "forceSkipMarkerFallbackDescription": "Usa i pattern dei titoli dei capitoli per i marcatori di salto anche quando Plex fornisce marcatori nativi", "autoSkipDelay": "Ritardo Salto Automatico", "autoSkipDelayDescription": "Aspetta ${seconds} secondi prima del salto automatico", "introPattern": "Pattern marcatore intro", diff --git a/lib/i18n/ja.i18n.json b/lib/i18n/ja.i18n.json index 50e401fd..46b3d48f 100644 --- a/lib/i18n/ja.i18n.json +++ b/lib/i18n/ja.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "数秒後にイントロマーカーを自動的にスキップ", "autoSkipCredits": "クレジットを自動スキップ", "autoSkipCreditsDescription": "クレジットを自動的にスキップして次のエピソードを再生", + "forceSkipMarkerFallback": "フォールバックマーカーを強制", + "forceSkipMarkerFallbackDescription": "Plex がネイティブマーカーを提供している場合でも、スキップマーカーにはチャプタータイトルのパターンを使用する", "autoSkipDelay": "自動スキップの遅延", "autoSkipDelayDescription": "自動スキップまで${seconds}秒待機", "introPattern": "イントロマーカーパターン", diff --git a/lib/i18n/ko.i18n.json b/lib/i18n/ko.i18n.json index 39a8d610..3975fb97 100644 --- a/lib/i18n/ko.i18n.json +++ b/lib/i18n/ko.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "몇 초 후 오프닝을 자동으로 건너뛰기", "autoSkipCredits": "자동으로 엔딩 건너뛰기", "autoSkipCreditsDescription": "엔딩 크레딧 자동 건너뛰기 후 다음 에피소드 재생", + "forceSkipMarkerFallback": "대체 마커 강제 사용", + "forceSkipMarkerFallbackDescription": "Plex가 기본 마커를 제공하더라도 건너뛰기 마커에 챕터 제목 패턴 사용", "autoSkipDelay": "자동 건너뛰기 지연", "autoSkipDelayDescription": "자동 건너뛰기 전 ${seconds} 초 대기", "introPattern": "인트로 마커 패턴", diff --git a/lib/i18n/nb.i18n.json b/lib/i18n/nb.i18n.json index 27fc9683..d8228baa 100644 --- a/lib/i18n/nb.i18n.json +++ b/lib/i18n/nb.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Hopp automatisk over intromarkører etter noen sekunder", "autoSkipCredits": "Hopp over rulletekst automatisk", "autoSkipCreditsDescription": "Hopp automatisk over rulletekst og spill neste episode", + "forceSkipMarkerFallback": "Tving reservemarkører", + "forceSkipMarkerFallbackDescription": "Bruk kapitteltittel-mønstre for hoppmarkører selv når Plex leverer innebygde markører", "autoSkipDelay": "Forsinkelse for automatisk hopp", "autoSkipDelayDescription": "Vent ${seconds} sekunder før automatisk hopping", "introPattern": "Intromarkørmønster", diff --git a/lib/i18n/nl.i18n.json b/lib/i18n/nl.i18n.json index 5189b240..42475996 100644 --- a/lib/i18n/nl.i18n.json +++ b/lib/i18n/nl.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Intro-markeringen na enkele seconden automatisch overslaan", "autoSkipCredits": "Credits Automatisch Overslaan", "autoSkipCreditsDescription": "Credits automatisch overslaan en volgende aflevering afspelen", + "forceSkipMarkerFallback": "Fallbackmarkeringen afdwingen", + "forceSkipMarkerFallbackDescription": "Gebruik hoofdstuktitelpatronen voor overslaanmarkeringen, zelfs wanneer Plex native markeringen biedt", "autoSkipDelay": "Vertraging Automatisch Overslaan", "autoSkipDelayDescription": "${seconds} seconden wachten voor automatisch overslaan", "introPattern": "Intromarkeringspatroon", diff --git a/lib/i18n/pl.i18n.json b/lib/i18n/pl.i18n.json index 4d075786..2ec4674f 100644 --- a/lib/i18n/pl.i18n.json +++ b/lib/i18n/pl.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Automatycznie pomijaj znaczniki intro po kilku sekundach", "autoSkipCredits": "Automatyczne pomijanie napisów końcowych", "autoSkipCreditsDescription": "Automatycznie pomijaj napisy końcowe i odtwórz następny odcinek", + "forceSkipMarkerFallback": "Wymuś znaczniki awaryjne", + "forceSkipMarkerFallbackDescription": "Używaj wzorców tytułów rozdziałów dla znaczników pomijania, nawet gdy Plex udostępnia natywne znaczniki", "autoSkipDelay": "Opóźnienie automatycznego pomijania", "autoSkipDelayDescription": "Czekaj ${seconds} sekund przed automatycznym pominięciem", "introPattern": "Wzorzec znacznika intro", diff --git a/lib/i18n/pt.i18n.json b/lib/i18n/pt.i18n.json index e4c0dce2..32ece3af 100644 --- a/lib/i18n/pt.i18n.json +++ b/lib/i18n/pt.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Pular marcadores de intro automaticamente após alguns segundos", "autoSkipCredits": "Pular Créditos Automaticamente", "autoSkipCreditsDescription": "Pular créditos automaticamente e reproduzir próximo episódio", + "forceSkipMarkerFallback": "Forçar marcadores alternativos", + "forceSkipMarkerFallbackDescription": "Usar padrões de títulos de capítulos para marcadores de pulo mesmo quando o Plex fornece marcadores nativos", "autoSkipDelay": "Atraso do Pulo Automático", "autoSkipDelayDescription": "Aguardar ${seconds} segundos antes de pular automaticamente", "introPattern": "Padrão de marcador de intro", diff --git a/lib/i18n/ru.i18n.json b/lib/i18n/ru.i18n.json index 4ff46a7e..fd07f251 100644 --- a/lib/i18n/ru.i18n.json +++ b/lib/i18n/ru.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Автоматически пропускать маркеры вступления через несколько секунд", "autoSkipCredits": "Автопропуск титров", "autoSkipCreditsDescription": "Автоматически пропускать титры и воспроизводить следующий эпизод", + "forceSkipMarkerFallback": "Принудительные резервные маркеры", + "forceSkipMarkerFallbackDescription": "Использовать шаблоны заголовков глав для маркеров пропуска, даже если Plex предоставляет встроенные маркеры", "autoSkipDelay": "Задержка автопропуска", "autoSkipDelayDescription": "Подождать ${seconds} секунд перед автопропуском", "introPattern": "Шаблон маркера вступления", diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 4bf134f7..9a22dd45 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 15 -/// Strings: 16365 (1091 per locale) +/// Strings: 16395 (1093 per locale) /// -/// Built on 2026-05-01 at 02:07 UTC +/// Built on 2026-05-01 at 02:25 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/lib/i18n/strings_da.g.dart b/lib/i18n/strings_da.g.dart index c681d2fd..65aeb814 100644 --- a/lib/i18n/strings_da.g.dart +++ b/lib/i18n/strings_da.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsDa extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Spring automatisk intromarkører over efter få sekunder'; @override String get autoSkipCredits => 'Auto-spring rulletekster'; @override String get autoSkipCreditsDescription => 'Spring automatisk rulletekster over og afspil næste episode'; + @override String get forceSkipMarkerFallback => 'Tving reservemarkører'; + @override String get forceSkipMarkerFallbackDescription => 'Brug kapitel-titelmønstre til springmarkører, selv når Plex leverer indbyggede markører'; @override String get autoSkipDelay => 'Auto-spring forsinkelse'; @override String autoSkipDelayDescription({required Object seconds}) => 'Vent ${seconds} sekunder før automatisk spring'; @override String get introPattern => 'Intromarkørmønster'; @@ -1901,6 +1903,8 @@ extension on TranslationsDa { 'settings.autoSkipIntroDescription' => 'Spring automatisk intromarkører over efter få sekunder', 'settings.autoSkipCredits' => 'Auto-spring rulletekster', 'settings.autoSkipCreditsDescription' => 'Spring automatisk rulletekster over og afspil næste episode', + 'settings.forceSkipMarkerFallback' => 'Tving reservemarkører', + 'settings.forceSkipMarkerFallbackDescription' => 'Brug kapitel-titelmønstre til springmarkører, selv når Plex leverer indbyggede markører', 'settings.autoSkipDelay' => 'Auto-spring forsinkelse', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Vent ${seconds} sekunder før automatisk spring', 'settings.introPattern' => 'Intromarkørmønster', @@ -2220,10 +2224,10 @@ extension on TranslationsDa { 'profiles.setPin' => 'Angiv PIN', 'profiles.connectionsLabel' => 'Forbindelser', 'profiles.add' => 'Tilføj', - 'profiles.deleteProfileButton' => 'Slet profil', - 'profiles.noConnectionsHint' => 'Ingen forbindelser — tilføj en for at bruge denne profil.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Slet profil', + 'profiles.noConnectionsHint' => 'Ingen forbindelser — tilføj en for at bruge denne profil.', 'profiles.plexHomeAccount' => 'Plex Home-konto', 'profiles.connectionDefault' => 'Standard', 'profiles.makeDefault' => 'Gør til standard', @@ -2734,10 +2738,10 @@ extension on TranslationsDa { 'trakt.connectedAs' => ({required Object username}) => 'Forbundet som @${username}', 'trakt.disconnectConfirm' => 'Frakobl Trakt-konto?', 'trakt.disconnectConfirmBody' => 'Plezy stopper med at sende afspilningsbegivenheder til Trakt. Du kan genoprette forbindelse når som helst.', - 'trakt.scrobble' => 'Realtids-scrobbling', - 'trakt.scrobbleDescription' => 'Send afspil-, pause- og stop-begivenheder til Trakt under afspilning.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Realtids-scrobbling', + 'trakt.scrobbleDescription' => 'Send afspil-, pause- og stop-begivenheder til Trakt under afspilning.', 'trakt.watchedSync' => 'Synkroniser sét-status', 'trakt.watchedSyncDescription' => 'Når du markerer ting som sét i Plezy, markeres de også på Trakt.', 'trackers.title' => 'Trackere', diff --git a/lib/i18n/strings_de.g.dart b/lib/i18n/strings_de.g.dart index 3f0d4c0b..dc3ffd52 100644 --- a/lib/i18n/strings_de.g.dart +++ b/lib/i18n/strings_de.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsDe extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Intro-Marker nach wenigen Sekunden automatisch überspringen'; @override String get autoSkipCredits => 'Abspann automatisch überspringen'; @override String get autoSkipCreditsDescription => 'Abspann automatisch überspringen und nächste Episode abspielen'; + @override String get forceSkipMarkerFallback => 'Fallback-Markierungen erzwingen'; + @override String get forceSkipMarkerFallbackDescription => 'Kapitel-Titelmuster für Überspring-Markierungen verwenden, auch wenn Plex native Markierungen bereitstellt'; @override String get autoSkipDelay => 'Verzögerung für automatisches Überspringen'; @override String autoSkipDelayDescription({required Object seconds}) => '${seconds} Sekunden vor dem automatischen Überspringen warten'; @override String get introPattern => 'Intro-Markierungsmuster'; @@ -1901,6 +1903,8 @@ extension on TranslationsDe { 'settings.autoSkipIntroDescription' => 'Intro-Marker nach wenigen Sekunden automatisch überspringen', 'settings.autoSkipCredits' => 'Abspann automatisch überspringen', 'settings.autoSkipCreditsDescription' => 'Abspann automatisch überspringen und nächste Episode abspielen', + 'settings.forceSkipMarkerFallback' => 'Fallback-Markierungen erzwingen', + 'settings.forceSkipMarkerFallbackDescription' => 'Kapitel-Titelmuster für Überspring-Markierungen verwenden, auch wenn Plex native Markierungen bereitstellt', 'settings.autoSkipDelay' => 'Verzögerung für automatisches Überspringen', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => '${seconds} Sekunden vor dem automatischen Überspringen warten', 'settings.introPattern' => 'Intro-Markierungsmuster', @@ -2220,10 +2224,10 @@ extension on TranslationsDe { 'profiles.setPin' => 'PIN festlegen', 'profiles.connectionsLabel' => 'Verbindungen', 'profiles.add' => 'Hinzufügen', - 'profiles.deleteProfileButton' => 'Profil löschen', - 'profiles.noConnectionsHint' => 'Keine Verbindungen — füge eine hinzu, um dieses Profil zu nutzen.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Profil löschen', + 'profiles.noConnectionsHint' => 'Keine Verbindungen — füge eine hinzu, um dieses Profil zu nutzen.', 'profiles.plexHomeAccount' => 'Plex Home-Konto', 'profiles.connectionDefault' => 'Standard', 'profiles.makeDefault' => 'Als Standard', @@ -2734,10 +2738,10 @@ extension on TranslationsDe { 'trakt.connectedAs' => ({required Object username}) => 'Verbunden als @${username}', 'trakt.disconnectConfirm' => 'Trakt-Konto trennen?', 'trakt.disconnectConfirmBody' => 'Plezy sendet keine Wiedergabe-Ereignisse mehr an Trakt. Du kannst dich jederzeit erneut verbinden.', - 'trakt.scrobble' => 'Echtzeit-Scrobbling', - 'trakt.scrobbleDescription' => 'Sende Play-, Pause- und Stopp-Ereignisse während der Wiedergabe an Trakt.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Echtzeit-Scrobbling', + 'trakt.scrobbleDescription' => 'Sende Play-, Pause- und Stopp-Ereignisse während der Wiedergabe an Trakt.', 'trakt.watchedSync' => 'Gesehen-Status synchronisieren', 'trakt.watchedSyncDescription' => 'Wenn du Inhalte in Plezy als gesehen markierst, werden sie auch auf Trakt markiert.', 'trackers.title' => 'Tracker', diff --git a/lib/i18n/strings_en.g.dart b/lib/i18n/strings_en.g.dart index f661dc10..a7a29a99 100644 --- a/lib/i18n/strings_en.g.dart +++ b/lib/i18n/strings_en.g.dart @@ -712,6 +712,12 @@ class TranslationsSettingsEn { /// en: 'Automatically skip credits and play next episode' String get autoSkipCreditsDescription => 'Automatically skip credits and play next episode'; + /// en: 'Force Fallback Markers' + String get forceSkipMarkerFallback => 'Force Fallback Markers'; + + /// en: 'Use chapter title patterns for skip markers even when Plex provides native markers' + String get forceSkipMarkerFallbackDescription => 'Use chapter title patterns for skip markers even when Plex provides native markers'; + /// en: 'Auto Skip Delay' String get autoSkipDelay => 'Auto Skip Delay'; @@ -4089,6 +4095,8 @@ extension on Translations { 'settings.autoSkipIntroDescription' => 'Automatically skip intro markers after a few seconds', 'settings.autoSkipCredits' => 'Auto Skip Credits', 'settings.autoSkipCreditsDescription' => 'Automatically skip credits and play next episode', + 'settings.forceSkipMarkerFallback' => 'Force Fallback Markers', + 'settings.forceSkipMarkerFallbackDescription' => 'Use chapter title patterns for skip markers even when Plex provides native markers', 'settings.autoSkipDelay' => 'Auto Skip Delay', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Wait ${seconds} seconds before auto-skipping', 'settings.introPattern' => 'Intro Marker Pattern', @@ -4408,10 +4416,10 @@ extension on Translations { 'profiles.setPin' => 'Set PIN', 'profiles.connectionsLabel' => 'Connections', 'profiles.add' => 'Add', - 'profiles.deleteProfileButton' => 'Delete profile', - 'profiles.noConnectionsHint' => 'No connections — add one to use this profile.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Delete profile', + 'profiles.noConnectionsHint' => 'No connections — add one to use this profile.', 'profiles.plexHomeAccount' => 'Plex Home account', 'profiles.connectionDefault' => 'Default', 'profiles.makeDefault' => 'Make default', @@ -4922,10 +4930,10 @@ extension on Translations { 'trakt.connectedAs' => ({required Object username}) => 'Connected as @${username}', 'trakt.disconnectConfirm' => 'Disconnect Trakt account?', 'trakt.disconnectConfirmBody' => 'Plezy will stop sending playback events to Trakt. You can reconnect at any time.', - 'trakt.scrobble' => 'Real-time scrobbling', - 'trakt.scrobbleDescription' => 'Send play, pause, and stop events to Trakt during playback.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Real-time scrobbling', + 'trakt.scrobbleDescription' => 'Send play, pause, and stop events to Trakt during playback.', 'trakt.watchedSync' => 'Sync watched status', 'trakt.watchedSyncDescription' => 'When you mark items watched in Plezy, mark them on Trakt.', 'trackers.title' => 'Trackers', diff --git a/lib/i18n/strings_es.g.dart b/lib/i18n/strings_es.g.dart index dc981514..8f0c00ef 100644 --- a/lib/i18n/strings_es.g.dart +++ b/lib/i18n/strings_es.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsEs extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Saltar automáticamente los marcadores de intro después de unos segundos'; @override String get autoSkipCredits => 'Saltar Créditos automáticamente'; @override String get autoSkipCreditsDescription => 'Saltar automáticamente los créditos y reproducir el siguiente episodio'; + @override String get forceSkipMarkerFallback => 'Forzar marcadores alternativos'; + @override String get forceSkipMarkerFallbackDescription => 'Usar patrones de títulos de capítulos para marcadores de salto incluso cuando Plex proporciona marcadores nativos'; @override String get autoSkipDelay => 'Retraso de Salto automático'; @override String autoSkipDelayDescription({required Object seconds}) => 'Esperar ${seconds} segundos antes de saltar automáticamente'; @override String get introPattern => 'Patrón de marcador de intro'; @@ -1901,6 +1903,8 @@ extension on TranslationsEs { 'settings.autoSkipIntroDescription' => 'Saltar automáticamente los marcadores de intro después de unos segundos', 'settings.autoSkipCredits' => 'Saltar Créditos automáticamente', 'settings.autoSkipCreditsDescription' => 'Saltar automáticamente los créditos y reproducir el siguiente episodio', + 'settings.forceSkipMarkerFallback' => 'Forzar marcadores alternativos', + 'settings.forceSkipMarkerFallbackDescription' => 'Usar patrones de títulos de capítulos para marcadores de salto incluso cuando Plex proporciona marcadores nativos', 'settings.autoSkipDelay' => 'Retraso de Salto automático', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Esperar ${seconds} segundos antes de saltar automáticamente', 'settings.introPattern' => 'Patrón de marcador de intro', @@ -2220,10 +2224,10 @@ extension on TranslationsEs { 'profiles.setPin' => 'Establecer PIN', 'profiles.connectionsLabel' => 'Conexiones', 'profiles.add' => 'Añadir', - 'profiles.deleteProfileButton' => 'Eliminar perfil', - 'profiles.noConnectionsHint' => 'Sin conexiones — añade una para usar este perfil.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Eliminar perfil', + 'profiles.noConnectionsHint' => 'Sin conexiones — añade una para usar este perfil.', 'profiles.plexHomeAccount' => 'Cuenta Plex Home', 'profiles.connectionDefault' => 'Predeterminada', 'profiles.makeDefault' => 'Establecer como predeterminada', @@ -2734,10 +2738,10 @@ extension on TranslationsEs { 'trakt.connectedAs' => ({required Object username}) => 'Conectado como @${username}', 'trakt.disconnectConfirm' => '¿Desconectar cuenta de Trakt?', 'trakt.disconnectConfirmBody' => 'Plezy dejará de enviar eventos de reproducción a Trakt. Puedes volver a conectar cuando quieras.', - 'trakt.scrobble' => 'Scrobbling en tiempo real', - 'trakt.scrobbleDescription' => 'Enviar eventos de reproducción, pausa y parada a Trakt durante la reproducción.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Scrobbling en tiempo real', + 'trakt.scrobbleDescription' => 'Enviar eventos de reproducción, pausa y parada a Trakt durante la reproducción.', 'trakt.watchedSync' => 'Sincronizar estado de visto', 'trakt.watchedSyncDescription' => 'Cuando marques elementos como vistos en Plezy, también se marcarán en Trakt.', 'trackers.title' => 'Rastreadores', diff --git a/lib/i18n/strings_fr.g.dart b/lib/i18n/strings_fr.g.dart index 73a62bb7..3823ae60 100644 --- a/lib/i18n/strings_fr.g.dart +++ b/lib/i18n/strings_fr.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsFr extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Skipper automatiquement l\'introduction après quelques secondes'; @override String get autoSkipCredits => 'Skip automatique des crédits'; @override String get autoSkipCreditsDescription => 'Passer les crédits et passer à l\'épisode suivant automatiquement'; + @override String get forceSkipMarkerFallback => 'Forcer les marqueurs de repli'; + @override String get forceSkipMarkerFallbackDescription => 'Utiliser les motifs de titres de chapitres pour les marqueurs de saut même si Plex fournit des marqueurs natifs'; @override String get autoSkipDelay => 'Délai avant skip automatique'; @override String autoSkipDelayDescription({required Object seconds}) => 'Attendre ${seconds} secondes avant l\'auto-skip'; @override String get introPattern => 'Modèle de marqueur d\'intro'; @@ -1901,6 +1903,8 @@ extension on TranslationsFr { 'settings.autoSkipIntroDescription' => 'Skipper automatiquement l\'introduction après quelques secondes', 'settings.autoSkipCredits' => 'Skip automatique des crédits', 'settings.autoSkipCreditsDescription' => 'Passer les crédits et passer à l\'épisode suivant automatiquement', + 'settings.forceSkipMarkerFallback' => 'Forcer les marqueurs de repli', + 'settings.forceSkipMarkerFallbackDescription' => 'Utiliser les motifs de titres de chapitres pour les marqueurs de saut même si Plex fournit des marqueurs natifs', 'settings.autoSkipDelay' => 'Délai avant skip automatique', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Attendre ${seconds} secondes avant l\'auto-skip', 'settings.introPattern' => 'Modèle de marqueur d\'intro', @@ -2220,10 +2224,10 @@ extension on TranslationsFr { 'profiles.setPin' => 'Définir un PIN', 'profiles.connectionsLabel' => 'Connexions', 'profiles.add' => 'Ajouter', - 'profiles.deleteProfileButton' => 'Supprimer le profil', - 'profiles.noConnectionsHint' => 'Aucune connexion — ajoutez-en une pour utiliser ce profil.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Supprimer le profil', + 'profiles.noConnectionsHint' => 'Aucune connexion — ajoutez-en une pour utiliser ce profil.', 'profiles.plexHomeAccount' => 'Compte Plex Home', 'profiles.connectionDefault' => 'Par défaut', 'profiles.makeDefault' => 'Définir par défaut', @@ -2734,10 +2738,10 @@ extension on TranslationsFr { 'trakt.connectedAs' => ({required Object username}) => 'Connecté en tant que @${username}', 'trakt.disconnectConfirm' => 'Déconnecter le compte Trakt ?', 'trakt.disconnectConfirmBody' => 'Plezy n\'enverra plus d\'événements de lecture à Trakt. Vous pouvez vous reconnecter à tout moment.', - 'trakt.scrobble' => 'Scrobbling en temps réel', - 'trakt.scrobbleDescription' => 'Envoyer les événements de lecture, pause et arrêt à Trakt pendant la lecture.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Scrobbling en temps réel', + 'trakt.scrobbleDescription' => 'Envoyer les événements de lecture, pause et arrêt à Trakt pendant la lecture.', 'trakt.watchedSync' => 'Synchroniser le statut « vu »', 'trakt.watchedSyncDescription' => 'Lorsque vous marquez un élément comme vu dans Plezy, il l\'est aussi sur Trakt.', 'trackers.title' => 'Trackers', diff --git a/lib/i18n/strings_it.g.dart b/lib/i18n/strings_it.g.dart index 6fcd6900..49783911 100644 --- a/lib/i18n/strings_it.g.dart +++ b/lib/i18n/strings_it.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsIt extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Salta automaticamente i marcatori dell\'intro dopo alcuni secondi'; @override String get autoSkipCredits => 'Salta Crediti Automaticamente'; @override String get autoSkipCreditsDescription => 'Salta automaticamente i crediti e riproduci l\'episodio successivo'; + @override String get forceSkipMarkerFallback => 'Forza marcatori fallback'; + @override String get forceSkipMarkerFallbackDescription => 'Usa i pattern dei titoli dei capitoli per i marcatori di salto anche quando Plex fornisce marcatori nativi'; @override String get autoSkipDelay => 'Ritardo Salto Automatico'; @override String autoSkipDelayDescription({required Object seconds}) => 'Aspetta ${seconds} secondi prima del salto automatico'; @override String get introPattern => 'Pattern marcatore intro'; @@ -1901,6 +1903,8 @@ extension on TranslationsIt { 'settings.autoSkipIntroDescription' => 'Salta automaticamente i marcatori dell\'intro dopo alcuni secondi', 'settings.autoSkipCredits' => 'Salta Crediti Automaticamente', 'settings.autoSkipCreditsDescription' => 'Salta automaticamente i crediti e riproduci l\'episodio successivo', + 'settings.forceSkipMarkerFallback' => 'Forza marcatori fallback', + 'settings.forceSkipMarkerFallbackDescription' => 'Usa i pattern dei titoli dei capitoli per i marcatori di salto anche quando Plex fornisce marcatori nativi', 'settings.autoSkipDelay' => 'Ritardo Salto Automatico', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Aspetta ${seconds} secondi prima del salto automatico', 'settings.introPattern' => 'Pattern marcatore intro', @@ -2220,10 +2224,10 @@ extension on TranslationsIt { 'profiles.setPin' => 'Imposta PIN', 'profiles.connectionsLabel' => 'Connessioni', 'profiles.add' => 'Aggiungi', - 'profiles.deleteProfileButton' => 'Elimina profilo', - 'profiles.noConnectionsHint' => 'Nessuna connessione — aggiungine una per usare questo profilo.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Elimina profilo', + 'profiles.noConnectionsHint' => 'Nessuna connessione — aggiungine una per usare questo profilo.', 'profiles.plexHomeAccount' => 'Account Plex Home', 'profiles.connectionDefault' => 'Predefinita', 'profiles.makeDefault' => 'Imposta come predefinita', @@ -2734,10 +2738,10 @@ extension on TranslationsIt { 'trakt.connectedAs' => ({required Object username}) => 'Connesso come @${username}', 'trakt.disconnectConfirm' => 'Disconnettere l\'account Trakt?', 'trakt.disconnectConfirmBody' => 'Plezy smetterà di inviare eventi di riproduzione a Trakt. Puoi riconnetterti in qualsiasi momento.', - 'trakt.scrobble' => 'Scrobbling in tempo reale', - 'trakt.scrobbleDescription' => 'Invia eventi di riproduzione, pausa e arresto a Trakt durante la riproduzione.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Scrobbling in tempo reale', + 'trakt.scrobbleDescription' => 'Invia eventi di riproduzione, pausa e arresto a Trakt durante la riproduzione.', 'trakt.watchedSync' => 'Sincronizza stato visualizzato', 'trakt.watchedSyncDescription' => 'Quando segni elementi come visti in Plezy, vengono segnati anche su Trakt.', 'trackers.title' => 'Tracker', diff --git a/lib/i18n/strings_ja.g.dart b/lib/i18n/strings_ja.g.dart index 90d9e292..dc5f6523 100644 --- a/lib/i18n/strings_ja.g.dart +++ b/lib/i18n/strings_ja.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsJa extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => '数秒後にイントロマーカーを自動的にスキップ'; @override String get autoSkipCredits => 'クレジットを自動スキップ'; @override String get autoSkipCreditsDescription => 'クレジットを自動的にスキップして次のエピソードを再生'; + @override String get forceSkipMarkerFallback => 'フォールバックマーカーを強制'; + @override String get forceSkipMarkerFallbackDescription => 'Plex がネイティブマーカーを提供している場合でも、スキップマーカーにはチャプタータイトルのパターンを使用する'; @override String get autoSkipDelay => '自動スキップの遅延'; @override String autoSkipDelayDescription({required Object seconds}) => '自動スキップまで${seconds}秒待機'; @override String get introPattern => 'イントロマーカーパターン'; @@ -1901,6 +1903,8 @@ extension on TranslationsJa { 'settings.autoSkipIntroDescription' => '数秒後にイントロマーカーを自動的にスキップ', 'settings.autoSkipCredits' => 'クレジットを自動スキップ', 'settings.autoSkipCreditsDescription' => 'クレジットを自動的にスキップして次のエピソードを再生', + 'settings.forceSkipMarkerFallback' => 'フォールバックマーカーを強制', + 'settings.forceSkipMarkerFallbackDescription' => 'Plex がネイティブマーカーを提供している場合でも、スキップマーカーにはチャプタータイトルのパターンを使用する', 'settings.autoSkipDelay' => '自動スキップの遅延', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => '自動スキップまで${seconds}秒待機', 'settings.introPattern' => 'イントロマーカーパターン', @@ -2220,10 +2224,10 @@ extension on TranslationsJa { 'profiles.setPin' => 'PINを設定', 'profiles.connectionsLabel' => '接続', 'profiles.add' => '追加', - 'profiles.deleteProfileButton' => 'プロファイルを削除', - 'profiles.noConnectionsHint' => '接続がありません — このプロファイルを使うには1つ追加してください。', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'プロファイルを削除', + 'profiles.noConnectionsHint' => '接続がありません — このプロファイルを使うには1つ追加してください。', 'profiles.plexHomeAccount' => 'Plex Homeアカウント', 'profiles.connectionDefault' => 'デフォルト', 'profiles.makeDefault' => 'デフォルトに設定', @@ -2734,10 +2738,10 @@ extension on TranslationsJa { 'trakt.connectedAs' => ({required Object username}) => '@${username} として接続済み', 'trakt.disconnectConfirm' => 'Trakt アカウントを切断しますか?', 'trakt.disconnectConfirmBody' => 'Plezy から Trakt への再生イベント送信が停止します。いつでも再接続できます。', - 'trakt.scrobble' => 'リアルタイムのスクロブル', - 'trakt.scrobbleDescription' => '再生中に再生・一時停止・停止イベントを Trakt に送信します。', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'リアルタイムのスクロブル', + 'trakt.scrobbleDescription' => '再生中に再生・一時停止・停止イベントを Trakt に送信します。', 'trakt.watchedSync' => '視聴済みステータスを同期', 'trakt.watchedSyncDescription' => 'Plezy で項目を視聴済みにすると、Trakt でも視聴済みになります。', 'trackers.title' => 'トラッカー', diff --git a/lib/i18n/strings_ko.g.dart b/lib/i18n/strings_ko.g.dart index 22bff67b..ce0ab18f 100644 --- a/lib/i18n/strings_ko.g.dart +++ b/lib/i18n/strings_ko.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsKo extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => '몇 초 후 오프닝을 자동으로 건너뛰기'; @override String get autoSkipCredits => '자동으로 엔딩 건너뛰기'; @override String get autoSkipCreditsDescription => '엔딩 크레딧 자동 건너뛰기 후 다음 에피소드 재생'; + @override String get forceSkipMarkerFallback => '대체 마커 강제 사용'; + @override String get forceSkipMarkerFallbackDescription => 'Plex가 기본 마커를 제공하더라도 건너뛰기 마커에 챕터 제목 패턴 사용'; @override String get autoSkipDelay => '자동 건너뛰기 지연'; @override String autoSkipDelayDescription({required Object seconds}) => '자동 건너뛰기 전 ${seconds} 초 대기'; @override String get introPattern => '인트로 마커 패턴'; @@ -1901,6 +1903,8 @@ extension on TranslationsKo { 'settings.autoSkipIntroDescription' => '몇 초 후 오프닝을 자동으로 건너뛰기', 'settings.autoSkipCredits' => '자동으로 엔딩 건너뛰기', 'settings.autoSkipCreditsDescription' => '엔딩 크레딧 자동 건너뛰기 후 다음 에피소드 재생', + 'settings.forceSkipMarkerFallback' => '대체 마커 강제 사용', + 'settings.forceSkipMarkerFallbackDescription' => 'Plex가 기본 마커를 제공하더라도 건너뛰기 마커에 챕터 제목 패턴 사용', 'settings.autoSkipDelay' => '자동 건너뛰기 지연', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => '자동 건너뛰기 전 ${seconds} 초 대기', 'settings.introPattern' => '인트로 마커 패턴', @@ -2220,10 +2224,10 @@ extension on TranslationsKo { 'profiles.setPin' => 'PIN 설정', 'profiles.connectionsLabel' => '연결', 'profiles.add' => '추가', - 'profiles.deleteProfileButton' => '프로필 삭제', - 'profiles.noConnectionsHint' => '연결이 없습니다 — 이 프로필을 사용하려면 하나 추가하세요.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => '프로필 삭제', + 'profiles.noConnectionsHint' => '연결이 없습니다 — 이 프로필을 사용하려면 하나 추가하세요.', 'profiles.plexHomeAccount' => 'Plex Home 계정', 'profiles.connectionDefault' => '기본값', 'profiles.makeDefault' => '기본값으로 설정', @@ -2734,10 +2738,10 @@ extension on TranslationsKo { 'trakt.connectedAs' => ({required Object username}) => '@${username}(으)로 연결됨', 'trakt.disconnectConfirm' => 'Trakt 계정 연결을 끊으시겠습니까?', 'trakt.disconnectConfirmBody' => 'Plezy가 Trakt로 재생 이벤트를 보내지 않습니다. 언제든지 다시 연결할 수 있습니다.', - 'trakt.scrobble' => '실시간 스크로블', - 'trakt.scrobbleDescription' => '재생 중 재생, 일시정지, 정지 이벤트를 Trakt로 전송합니다.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => '실시간 스크로블', + 'trakt.scrobbleDescription' => '재생 중 재생, 일시정지, 정지 이벤트를 Trakt로 전송합니다.', 'trakt.watchedSync' => '시청 상태 동기화', 'trakt.watchedSyncDescription' => 'Plezy에서 시청 완료로 표시한 항목이 Trakt에도 시청 완료로 표시됩니다.', 'trackers.title' => '트래커', diff --git a/lib/i18n/strings_nb.g.dart b/lib/i18n/strings_nb.g.dart index 2768f2b9..b77d655c 100644 --- a/lib/i18n/strings_nb.g.dart +++ b/lib/i18n/strings_nb.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsNb extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Hopp automatisk over intromarkører etter noen sekunder'; @override String get autoSkipCredits => 'Hopp over rulletekst automatisk'; @override String get autoSkipCreditsDescription => 'Hopp automatisk over rulletekst og spill neste episode'; + @override String get forceSkipMarkerFallback => 'Tving reservemarkører'; + @override String get forceSkipMarkerFallbackDescription => 'Bruk kapitteltittel-mønstre for hoppmarkører selv når Plex leverer innebygde markører'; @override String get autoSkipDelay => 'Forsinkelse for automatisk hopp'; @override String autoSkipDelayDescription({required Object seconds}) => 'Vent ${seconds} sekunder før automatisk hopping'; @override String get introPattern => 'Intromarkørmønster'; @@ -1901,6 +1903,8 @@ extension on TranslationsNb { 'settings.autoSkipIntroDescription' => 'Hopp automatisk over intromarkører etter noen sekunder', 'settings.autoSkipCredits' => 'Hopp over rulletekst automatisk', 'settings.autoSkipCreditsDescription' => 'Hopp automatisk over rulletekst og spill neste episode', + 'settings.forceSkipMarkerFallback' => 'Tving reservemarkører', + 'settings.forceSkipMarkerFallbackDescription' => 'Bruk kapitteltittel-mønstre for hoppmarkører selv når Plex leverer innebygde markører', 'settings.autoSkipDelay' => 'Forsinkelse for automatisk hopp', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Vent ${seconds} sekunder før automatisk hopping', 'settings.introPattern' => 'Intromarkørmønster', @@ -2220,10 +2224,10 @@ extension on TranslationsNb { 'profiles.setPin' => 'Sett PIN', 'profiles.connectionsLabel' => 'Tilkoblinger', 'profiles.add' => 'Legg til', - 'profiles.deleteProfileButton' => 'Slett profil', - 'profiles.noConnectionsHint' => 'Ingen tilkoblinger — legg til én for å bruke denne profilen.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Slett profil', + 'profiles.noConnectionsHint' => 'Ingen tilkoblinger — legg til én for å bruke denne profilen.', 'profiles.plexHomeAccount' => 'Plex Home-konto', 'profiles.connectionDefault' => 'Standard', 'profiles.makeDefault' => 'Gjør til standard', @@ -2734,10 +2738,10 @@ extension on TranslationsNb { 'trakt.connectedAs' => ({required Object username}) => 'Tilkoblet som @${username}', 'trakt.disconnectConfirm' => 'Koble fra Trakt-konto?', 'trakt.disconnectConfirmBody' => 'Plezy slutter å sende avspillingshendelser til Trakt. Du kan koble til igjen når som helst.', - 'trakt.scrobble' => 'Sanntids-scrobbling', - 'trakt.scrobbleDescription' => 'Send avspillings-, pause- og stopphendelser til Trakt under avspilling.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Sanntids-scrobbling', + 'trakt.scrobbleDescription' => 'Send avspillings-, pause- og stopphendelser til Trakt under avspilling.', 'trakt.watchedSync' => 'Synkroniser sett-status', 'trakt.watchedSyncDescription' => 'Når du markerer noe som sett i Plezy, markeres det også på Trakt.', 'trackers.title' => 'Trackere', diff --git a/lib/i18n/strings_nl.g.dart b/lib/i18n/strings_nl.g.dart index aacf68e3..9a95a942 100644 --- a/lib/i18n/strings_nl.g.dart +++ b/lib/i18n/strings_nl.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsNl extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Intro-markeringen na enkele seconden automatisch overslaan'; @override String get autoSkipCredits => 'Credits Automatisch Overslaan'; @override String get autoSkipCreditsDescription => 'Credits automatisch overslaan en volgende aflevering afspelen'; + @override String get forceSkipMarkerFallback => 'Fallbackmarkeringen afdwingen'; + @override String get forceSkipMarkerFallbackDescription => 'Gebruik hoofdstuktitelpatronen voor overslaanmarkeringen, zelfs wanneer Plex native markeringen biedt'; @override String get autoSkipDelay => 'Vertraging Automatisch Overslaan'; @override String autoSkipDelayDescription({required Object seconds}) => '${seconds} seconden wachten voor automatisch overslaan'; @override String get introPattern => 'Intromarkeringspatroon'; @@ -1901,6 +1903,8 @@ extension on TranslationsNl { 'settings.autoSkipIntroDescription' => 'Intro-markeringen na enkele seconden automatisch overslaan', 'settings.autoSkipCredits' => 'Credits Automatisch Overslaan', 'settings.autoSkipCreditsDescription' => 'Credits automatisch overslaan en volgende aflevering afspelen', + 'settings.forceSkipMarkerFallback' => 'Fallbackmarkeringen afdwingen', + 'settings.forceSkipMarkerFallbackDescription' => 'Gebruik hoofdstuktitelpatronen voor overslaanmarkeringen, zelfs wanneer Plex native markeringen biedt', 'settings.autoSkipDelay' => 'Vertraging Automatisch Overslaan', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => '${seconds} seconden wachten voor automatisch overslaan', 'settings.introPattern' => 'Intromarkeringspatroon', @@ -2220,10 +2224,10 @@ extension on TranslationsNl { 'profiles.setPin' => 'PIN instellen', 'profiles.connectionsLabel' => 'Verbindingen', 'profiles.add' => 'Toevoegen', - 'profiles.deleteProfileButton' => 'Profiel verwijderen', - 'profiles.noConnectionsHint' => 'Geen verbindingen — voeg er één toe om dit profiel te gebruiken.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Profiel verwijderen', + 'profiles.noConnectionsHint' => 'Geen verbindingen — voeg er één toe om dit profiel te gebruiken.', 'profiles.plexHomeAccount' => 'Plex Home-account', 'profiles.connectionDefault' => 'Standaard', 'profiles.makeDefault' => 'Als standaard instellen', @@ -2734,10 +2738,10 @@ extension on TranslationsNl { 'trakt.connectedAs' => ({required Object username}) => 'Verbonden als @${username}', 'trakt.disconnectConfirm' => 'Trakt-account loskoppelen?', 'trakt.disconnectConfirmBody' => 'Plezy stopt met het versturen van afspeelgebeurtenissen naar Trakt. Je kunt op elk moment opnieuw verbinden.', - 'trakt.scrobble' => 'Realtime scrobbling', - 'trakt.scrobbleDescription' => 'Verstuur play-, pauze- en stopgebeurtenissen tijdens afspelen naar Trakt.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Realtime scrobbling', + 'trakt.scrobbleDescription' => 'Verstuur play-, pauze- en stopgebeurtenissen tijdens afspelen naar Trakt.', 'trakt.watchedSync' => 'Bekeken-status synchroniseren', 'trakt.watchedSyncDescription' => 'Wanneer je items als bekeken markeert in Plezy, worden ze ook op Trakt gemarkeerd.', 'trackers.title' => 'Trackers', diff --git a/lib/i18n/strings_pl.g.dart b/lib/i18n/strings_pl.g.dart index 782d055c..d0ae00be 100644 --- a/lib/i18n/strings_pl.g.dart +++ b/lib/i18n/strings_pl.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsPl extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Automatycznie pomijaj znaczniki intro po kilku sekundach'; @override String get autoSkipCredits => 'Automatyczne pomijanie napisów końcowych'; @override String get autoSkipCreditsDescription => 'Automatycznie pomijaj napisy końcowe i odtwórz następny odcinek'; + @override String get forceSkipMarkerFallback => 'Wymuś znaczniki awaryjne'; + @override String get forceSkipMarkerFallbackDescription => 'Używaj wzorców tytułów rozdziałów dla znaczników pomijania, nawet gdy Plex udostępnia natywne znaczniki'; @override String get autoSkipDelay => 'Opóźnienie automatycznego pomijania'; @override String autoSkipDelayDescription({required Object seconds}) => 'Czekaj ${seconds} sekund przed automatycznym pominięciem'; @override String get introPattern => 'Wzorzec znacznika intro'; @@ -1901,6 +1903,8 @@ extension on TranslationsPl { 'settings.autoSkipIntroDescription' => 'Automatycznie pomijaj znaczniki intro po kilku sekundach', 'settings.autoSkipCredits' => 'Automatyczne pomijanie napisów końcowych', 'settings.autoSkipCreditsDescription' => 'Automatycznie pomijaj napisy końcowe i odtwórz następny odcinek', + 'settings.forceSkipMarkerFallback' => 'Wymuś znaczniki awaryjne', + 'settings.forceSkipMarkerFallbackDescription' => 'Używaj wzorców tytułów rozdziałów dla znaczników pomijania, nawet gdy Plex udostępnia natywne znaczniki', 'settings.autoSkipDelay' => 'Opóźnienie automatycznego pomijania', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Czekaj ${seconds} sekund przed automatycznym pominięciem', 'settings.introPattern' => 'Wzorzec znacznika intro', @@ -2220,10 +2224,10 @@ extension on TranslationsPl { 'profiles.setPin' => 'Ustaw PIN', 'profiles.connectionsLabel' => 'Połączenia', 'profiles.add' => 'Dodaj', - 'profiles.deleteProfileButton' => 'Usuń profil', - 'profiles.noConnectionsHint' => 'Brak połączeń — dodaj jedno, aby używać tego profilu.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Usuń profil', + 'profiles.noConnectionsHint' => 'Brak połączeń — dodaj jedno, aby używać tego profilu.', 'profiles.plexHomeAccount' => 'Konto Plex Home', 'profiles.connectionDefault' => 'Domyślne', 'profiles.makeDefault' => 'Ustaw jako domyślne', @@ -2734,10 +2738,10 @@ extension on TranslationsPl { 'trakt.connectedAs' => ({required Object username}) => 'Połączono jako @${username}', 'trakt.disconnectConfirm' => 'Rozłączyć konto Trakt?', 'trakt.disconnectConfirmBody' => 'Plezy przestanie wysyłać zdarzenia odtwarzania do Trakt. Możesz połączyć się ponownie w dowolnej chwili.', - 'trakt.scrobble' => 'Scrobbling w czasie rzeczywistym', - 'trakt.scrobbleDescription' => 'Wysyłaj zdarzenia odtwarzania, pauzy i zatrzymania do Trakt podczas odtwarzania.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Scrobbling w czasie rzeczywistym', + 'trakt.scrobbleDescription' => 'Wysyłaj zdarzenia odtwarzania, pauzy i zatrzymania do Trakt podczas odtwarzania.', 'trakt.watchedSync' => 'Synchronizuj status obejrzane', 'trakt.watchedSyncDescription' => 'Gdy oznaczysz pozycje jako obejrzane w Plezy, zostaną też oznaczone w Trakt.', 'trackers.title' => 'Trackery', diff --git a/lib/i18n/strings_pt.g.dart b/lib/i18n/strings_pt.g.dart index af3cd36a..7ff074ca 100644 --- a/lib/i18n/strings_pt.g.dart +++ b/lib/i18n/strings_pt.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsPt extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Pular marcadores de intro automaticamente após alguns segundos'; @override String get autoSkipCredits => 'Pular Créditos Automaticamente'; @override String get autoSkipCreditsDescription => 'Pular créditos automaticamente e reproduzir próximo episódio'; + @override String get forceSkipMarkerFallback => 'Forçar marcadores alternativos'; + @override String get forceSkipMarkerFallbackDescription => 'Usar padrões de títulos de capítulos para marcadores de pulo mesmo quando o Plex fornece marcadores nativos'; @override String get autoSkipDelay => 'Atraso do Pulo Automático'; @override String autoSkipDelayDescription({required Object seconds}) => 'Aguardar ${seconds} segundos antes de pular automaticamente'; @override String get introPattern => 'Padrão de marcador de intro'; @@ -1901,6 +1903,8 @@ extension on TranslationsPt { 'settings.autoSkipIntroDescription' => 'Pular marcadores de intro automaticamente após alguns segundos', 'settings.autoSkipCredits' => 'Pular Créditos Automaticamente', 'settings.autoSkipCreditsDescription' => 'Pular créditos automaticamente e reproduzir próximo episódio', + 'settings.forceSkipMarkerFallback' => 'Forçar marcadores alternativos', + 'settings.forceSkipMarkerFallbackDescription' => 'Usar padrões de títulos de capítulos para marcadores de pulo mesmo quando o Plex fornece marcadores nativos', 'settings.autoSkipDelay' => 'Atraso do Pulo Automático', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Aguardar ${seconds} segundos antes de pular automaticamente', 'settings.introPattern' => 'Padrão de marcador de intro', @@ -2220,10 +2224,10 @@ extension on TranslationsPt { 'profiles.setPin' => 'Definir PIN', 'profiles.connectionsLabel' => 'Conexões', 'profiles.add' => 'Adicionar', - 'profiles.deleteProfileButton' => 'Excluir perfil', - 'profiles.noConnectionsHint' => 'Sem conexões — adicione uma para usar este perfil.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Excluir perfil', + 'profiles.noConnectionsHint' => 'Sem conexões — adicione uma para usar este perfil.', 'profiles.plexHomeAccount' => 'Conta Plex Home', 'profiles.connectionDefault' => 'Padrão', 'profiles.makeDefault' => 'Definir como padrão', @@ -2734,10 +2738,10 @@ extension on TranslationsPt { 'trakt.connectedAs' => ({required Object username}) => 'Conectado como @${username}', 'trakt.disconnectConfirm' => 'Desconectar conta do Trakt?', 'trakt.disconnectConfirmBody' => 'O Plezy deixará de enviar eventos de reprodução ao Trakt. Você pode reconectar a qualquer momento.', - 'trakt.scrobble' => 'Scrobbling em tempo real', - 'trakt.scrobbleDescription' => 'Envia eventos de reprodução, pausa e parada ao Trakt durante a exibição.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Scrobbling em tempo real', + 'trakt.scrobbleDescription' => 'Envia eventos de reprodução, pausa e parada ao Trakt durante a exibição.', 'trakt.watchedSync' => 'Sincronizar status de assistido', 'trakt.watchedSyncDescription' => 'Ao marcar itens como assistidos no Plezy, eles também serão marcados no Trakt.', 'trackers.title' => 'Rastreadores', diff --git a/lib/i18n/strings_ru.g.dart b/lib/i18n/strings_ru.g.dart index 45445c05..d18180e9 100644 --- a/lib/i18n/strings_ru.g.dart +++ b/lib/i18n/strings_ru.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsRu extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Автоматически пропускать маркеры вступления через несколько секунд'; @override String get autoSkipCredits => 'Автопропуск титров'; @override String get autoSkipCreditsDescription => 'Автоматически пропускать титры и воспроизводить следующий эпизод'; + @override String get forceSkipMarkerFallback => 'Принудительные резервные маркеры'; + @override String get forceSkipMarkerFallbackDescription => 'Использовать шаблоны заголовков глав для маркеров пропуска, даже если Plex предоставляет встроенные маркеры'; @override String get autoSkipDelay => 'Задержка автопропуска'; @override String autoSkipDelayDescription({required Object seconds}) => 'Подождать ${seconds} секунд перед автопропуском'; @override String get introPattern => 'Шаблон маркера вступления'; @@ -1901,6 +1903,8 @@ extension on TranslationsRu { 'settings.autoSkipIntroDescription' => 'Автоматически пропускать маркеры вступления через несколько секунд', 'settings.autoSkipCredits' => 'Автопропуск титров', 'settings.autoSkipCreditsDescription' => 'Автоматически пропускать титры и воспроизводить следующий эпизод', + 'settings.forceSkipMarkerFallback' => 'Принудительные резервные маркеры', + 'settings.forceSkipMarkerFallbackDescription' => 'Использовать шаблоны заголовков глав для маркеров пропуска, даже если Plex предоставляет встроенные маркеры', 'settings.autoSkipDelay' => 'Задержка автопропуска', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Подождать ${seconds} секунд перед автопропуском', 'settings.introPattern' => 'Шаблон маркера вступления', @@ -2220,10 +2224,10 @@ extension on TranslationsRu { 'profiles.setPin' => 'Установить PIN', 'profiles.connectionsLabel' => 'Соединения', 'profiles.add' => 'Добавить', - 'profiles.deleteProfileButton' => 'Удалить профиль', - 'profiles.noConnectionsHint' => 'Нет соединений — добавьте одно, чтобы использовать этот профиль.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Удалить профиль', + 'profiles.noConnectionsHint' => 'Нет соединений — добавьте одно, чтобы использовать этот профиль.', 'profiles.plexHomeAccount' => 'Аккаунт Plex Home', 'profiles.connectionDefault' => 'По умолчанию', 'profiles.makeDefault' => 'Сделать по умолчанию', @@ -2734,10 +2738,10 @@ extension on TranslationsRu { 'trakt.connectedAs' => ({required Object username}) => 'Подключено как @${username}', 'trakt.disconnectConfirm' => 'Отключить аккаунт Trakt?', 'trakt.disconnectConfirmBody' => 'Plezy перестанет отправлять события воспроизведения в Trakt. Вы можете подключиться снова в любое время.', - 'trakt.scrobble' => 'Скробблинг в реальном времени', - 'trakt.scrobbleDescription' => 'Отправлять события воспроизведения, паузы и остановки в Trakt во время просмотра.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Скробблинг в реальном времени', + 'trakt.scrobbleDescription' => 'Отправлять события воспроизведения, паузы и остановки в Trakt во время просмотра.', 'trakt.watchedSync' => 'Синхронизация статуса просмотра', 'trakt.watchedSyncDescription' => 'Когда вы отмечаете элементы как просмотренные в Plezy, они отмечаются и в Trakt.', 'trackers.title' => 'Трекеры', diff --git a/lib/i18n/strings_sv.g.dart b/lib/i18n/strings_sv.g.dart index a9a62b2c..f616d9f6 100644 --- a/lib/i18n/strings_sv.g.dart +++ b/lib/i18n/strings_sv.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsSv extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => 'Hoppa automatiskt över intro-markörer efter några sekunder'; @override String get autoSkipCredits => 'Hoppa Över Credits Automatiskt'; @override String get autoSkipCreditsDescription => 'Hoppa automatiskt över credits och spela nästa avsnitt'; + @override String get forceSkipMarkerFallback => 'Tvinga reservmarkörer'; + @override String get forceSkipMarkerFallbackDescription => 'Använd kapiteltitelmönster för hoppmarkörer även när Plex tillhandahåller inbyggda markörer'; @override String get autoSkipDelay => 'Fördröjning Auto Hoppa Över'; @override String autoSkipDelayDescription({required Object seconds}) => 'Vänta ${seconds} sekunder innan automatisk överhoppning'; @override String get introPattern => 'Intromarkörsmönster'; @@ -1901,6 +1903,8 @@ extension on TranslationsSv { 'settings.autoSkipIntroDescription' => 'Hoppa automatiskt över intro-markörer efter några sekunder', 'settings.autoSkipCredits' => 'Hoppa Över Credits Automatiskt', 'settings.autoSkipCreditsDescription' => 'Hoppa automatiskt över credits och spela nästa avsnitt', + 'settings.forceSkipMarkerFallback' => 'Tvinga reservmarkörer', + 'settings.forceSkipMarkerFallbackDescription' => 'Använd kapiteltitelmönster för hoppmarkörer även när Plex tillhandahåller inbyggda markörer', 'settings.autoSkipDelay' => 'Fördröjning Auto Hoppa Över', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => 'Vänta ${seconds} sekunder innan automatisk överhoppning', 'settings.introPattern' => 'Intromarkörsmönster', @@ -2220,10 +2224,10 @@ extension on TranslationsSv { 'profiles.setPin' => 'Ange PIN', 'profiles.connectionsLabel' => 'Anslutningar', 'profiles.add' => 'Lägg till', - 'profiles.deleteProfileButton' => 'Ta bort profil', - 'profiles.noConnectionsHint' => 'Inga anslutningar — lägg till en för att använda den här profilen.', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => 'Ta bort profil', + 'profiles.noConnectionsHint' => 'Inga anslutningar — lägg till en för att använda den här profilen.', 'profiles.plexHomeAccount' => 'Plex Home-konto', 'profiles.connectionDefault' => 'Standard', 'profiles.makeDefault' => 'Gör till standard', @@ -2734,10 +2738,10 @@ extension on TranslationsSv { 'trakt.connectedAs' => ({required Object username}) => 'Ansluten som @${username}', 'trakt.disconnectConfirm' => 'Koppla från Trakt-konto?', 'trakt.disconnectConfirmBody' => 'Plezy slutar skicka uppspelningshändelser till Trakt. Du kan ansluta igen när som helst.', - 'trakt.scrobble' => 'Realtids-scrobbling', - 'trakt.scrobbleDescription' => 'Skicka uppspelnings-, paus- och stopphändelser till Trakt under uppspelning.', _ => null, } ?? switch (path) { + 'trakt.scrobble' => 'Realtids-scrobbling', + 'trakt.scrobbleDescription' => 'Skicka uppspelnings-, paus- och stopphändelser till Trakt under uppspelning.', 'trakt.watchedSync' => 'Synkronisera tittad-status', 'trakt.watchedSyncDescription' => 'När du markerar något som tittat i Plezy markeras det också på Trakt.', 'trackers.title' => 'Spårare', diff --git a/lib/i18n/strings_zh.g.dart b/lib/i18n/strings_zh.g.dart index 5b701c57..947c2f09 100644 --- a/lib/i18n/strings_zh.g.dart +++ b/lib/i18n/strings_zh.g.dart @@ -328,6 +328,8 @@ class _TranslationsSettingsZh extends TranslationsSettingsEn { @override String get autoSkipIntroDescription => '几秒钟后自动跳过片头标记'; @override String get autoSkipCredits => '自动跳过片尾'; @override String get autoSkipCreditsDescription => '自动跳过片尾并播放下一集'; + @override String get forceSkipMarkerFallback => '强制使用备用标记'; + @override String get forceSkipMarkerFallbackDescription => '即使 Plex 提供原生标记,也使用章节标题模式作为跳过标记'; @override String get autoSkipDelay => '自动跳过延迟'; @override String autoSkipDelayDescription({required Object seconds}) => '自动跳过前等待 ${seconds} 秒'; @override String get introPattern => '片头标记模式'; @@ -1901,6 +1903,8 @@ extension on TranslationsZh { 'settings.autoSkipIntroDescription' => '几秒钟后自动跳过片头标记', 'settings.autoSkipCredits' => '自动跳过片尾', 'settings.autoSkipCreditsDescription' => '自动跳过片尾并播放下一集', + 'settings.forceSkipMarkerFallback' => '强制使用备用标记', + 'settings.forceSkipMarkerFallbackDescription' => '即使 Plex 提供原生标记,也使用章节标题模式作为跳过标记', 'settings.autoSkipDelay' => '自动跳过延迟', 'settings.autoSkipDelayDescription' => ({required Object seconds}) => '自动跳过前等待 ${seconds} 秒', 'settings.introPattern' => '片头标记模式', @@ -2220,10 +2224,10 @@ extension on TranslationsZh { 'profiles.setPin' => '设置 PIN', 'profiles.connectionsLabel' => '连接', 'profiles.add' => '添加', - 'profiles.deleteProfileButton' => '删除配置文件', - 'profiles.noConnectionsHint' => '没有连接 — 添加一个以使用此配置文件。', _ => null, } ?? switch (path) { + 'profiles.deleteProfileButton' => '删除配置文件', + 'profiles.noConnectionsHint' => '没有连接 — 添加一个以使用此配置文件。', 'profiles.plexHomeAccount' => 'Plex Home 账户', 'profiles.connectionDefault' => '默认', 'profiles.makeDefault' => '设为默认', @@ -2734,10 +2738,10 @@ extension on TranslationsZh { 'trakt.connectedAs' => ({required Object username}) => '已以 @${username} 身份连接', 'trakt.disconnectConfirm' => '断开 Trakt 账户?', 'trakt.disconnectConfirmBody' => 'Plezy 将停止向 Trakt 发送播放事件。您随时可以重新连接。', - 'trakt.scrobble' => '实时 Scrobble', - 'trakt.scrobbleDescription' => '在播放时向 Trakt 发送播放、暂停和停止事件。', _ => null, } ?? switch (path) { + 'trakt.scrobble' => '实时 Scrobble', + 'trakt.scrobbleDescription' => '在播放时向 Trakt 发送播放、暂停和停止事件。', 'trakt.watchedSync' => '同步已观看状态', 'trakt.watchedSyncDescription' => '在 Plezy 中将内容标记为已观看时,也会在 Trakt 上标记为已观看。', 'trackers.title' => '追踪器', diff --git a/lib/i18n/sv.i18n.json b/lib/i18n/sv.i18n.json index 9a2a8ce8..fc3441ec 100644 --- a/lib/i18n/sv.i18n.json +++ b/lib/i18n/sv.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "Hoppa automatiskt över intro-markörer efter några sekunder", "autoSkipCredits": "Hoppa Över Credits Automatiskt", "autoSkipCreditsDescription": "Hoppa automatiskt över credits och spela nästa avsnitt", + "forceSkipMarkerFallback": "Tvinga reservmarkörer", + "forceSkipMarkerFallbackDescription": "Använd kapiteltitelmönster för hoppmarkörer även när Plex tillhandahåller inbyggda markörer", "autoSkipDelay": "Fördröjning Auto Hoppa Över", "autoSkipDelayDescription": "Vänta ${seconds} sekunder innan automatisk överhoppning", "introPattern": "Intromarkörsmönster", diff --git a/lib/i18n/zh.i18n.json b/lib/i18n/zh.i18n.json index 959955ca..ef3f0b70 100644 --- a/lib/i18n/zh.i18n.json +++ b/lib/i18n/zh.i18n.json @@ -201,6 +201,8 @@ "autoSkipIntroDescription": "几秒钟后自动跳过片头标记", "autoSkipCredits": "自动跳过片尾", "autoSkipCreditsDescription": "自动跳过片尾并播放下一集", + "forceSkipMarkerFallback": "强制使用备用标记", + "forceSkipMarkerFallbackDescription": "即使 Plex 提供原生标记,也使用章节标题模式作为跳过标记", "autoSkipDelay": "自动跳过延迟", "autoSkipDelayDescription": "自动跳过前等待 ${seconds} 秒", "introPattern": "片头标记模式", diff --git a/lib/media/media_server_client.dart b/lib/media/media_server_client.dart index 49922ad2..0507625d 100644 --- a/lib/media/media_server_client.dart +++ b/lib/media/media_server_client.dart @@ -368,6 +368,7 @@ abstract class MediaServerClient { String itemId, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, bool forceRefresh = false, }); @@ -380,6 +381,7 @@ abstract class MediaServerClient { String itemId, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, }); /// Cache-only [MediaSourceInfo] read for [itemId]. Used by the offline diff --git a/lib/media/media_source_info.dart b/lib/media/media_source_info.dart index a68a78be..44916e53 100644 --- a/lib/media/media_source_info.dart +++ b/lib/media/media_source_info.dart @@ -244,15 +244,17 @@ class PlaybackExtras { return null; } - /// Returns [PlaybackExtras] using real markers when available, otherwise - /// synthesises markers from chapter titles matching intro/credits patterns. - /// When real markers exist, reclassifies markers with unknown types against - /// the patterns so non-standard type strings (e.g. "OP-Song") get recognized. + /// Returns [PlaybackExtras] using real markers when available, filling any + /// missing marker types from chapter titles matching intro/credits patterns. + /// [forceChapterFallback] prefers chapter-derived markers for any type they + /// provide. When real markers exist, reclassifies markers with unknown types + /// against the patterns so non-standard type strings get recognized. factory PlaybackExtras.withChapterFallback({ required List chapters, required List markers, String? introPatternStr, String? creditsPatternStr, + bool forceChapterFallback = false, }) { final introPattern = RegExp( introPatternStr ?? r'(?:^|\b)(?:intro(?:duction)?|opening)(?:\b|$)|^op(?:\s?\d+)?$', @@ -263,24 +265,6 @@ class PlaybackExtras { caseSensitive: false, ); - if (markers.isNotEmpty) { - // Reclassify markers with non-standard types against the patterns - final reclassified = markers.map((m) { - if (m.type == 'intro' || m.type == 'credits') return m; - final newType = _classifyChapterTitle(m.type, introPattern, creditsPattern); - if (newType != null) { - return MediaMarker( - id: m.id, - type: newType, - startTimeOffset: m.startTimeOffset, - endTimeOffset: m.endTimeOffset, - ); - } - return m; - }).toList(); - return PlaybackExtras(chapters: chapters, markers: reclassified); - } - final synthetic = []; for (var i = 0; i < chapters.length; i++) { final ch = chapters[i]; @@ -299,6 +283,33 @@ class PlaybackExtras { synthetic.add(MediaMarker(id: ch.id, type: type, startTimeOffset: start, endTimeOffset: end)); } + if (markers.isNotEmpty) { + // Reclassify markers with non-standard types against the patterns. + final reclassified = markers.map((m) { + if (m.type == 'intro' || m.type == 'credits') return m; + final newType = _classifyChapterTitle(m.type, introPattern, creditsPattern); + if (newType != null) { + return MediaMarker( + id: m.id, + type: newType, + startTimeOffset: m.startTimeOffset, + endTimeOffset: m.endTimeOffset, + ); + } + return m; + }).toList(); + + if (synthetic.isEmpty) return PlaybackExtras(chapters: chapters, markers: reclassified); + + final syntheticTypes = synthetic.map((m) => m.type).toSet(); + final nativeTypes = reclassified.map((m) => m.type).toSet(); + final merged = forceChapterFallback + ? [...reclassified.where((m) => !syntheticTypes.contains(m.type)), ...synthetic] + : [...reclassified, ...synthetic.where((m) => !nativeTypes.contains(m.type))]; + merged.sort((a, b) => a.startTimeOffset.compareTo(b.startTimeOffset)); + return PlaybackExtras(chapters: chapters, markers: merged); + } + return PlaybackExtras(chapters: chapters, markers: synthetic); } } diff --git a/lib/screens/settings/playback_settings_screen.dart b/lib/screens/settings/playback_settings_screen.dart index 4a0d6d1f..fbb4bbec 100644 --- a/lib/screens/settings/playback_settings_screen.dart +++ b/lib/screens/settings/playback_settings_screen.dart @@ -42,6 +42,7 @@ class _PlaybackSettingsScreenState extends State { bool _clickVideoTogglesPlayback = false; bool _autoSkipIntro = false; bool _autoSkipCredits = false; + bool _forceSkipMarkerFallback = false; int _autoSkipDelay = 5; String _introPattern = settings.SettingsService.defaultIntroPattern; String _creditsPattern = settings.SettingsService.defaultCreditsPattern; @@ -83,6 +84,7 @@ class _PlaybackSettingsScreenState extends State { _clickVideoTogglesPlayback = _settingsService.read(settings.SettingsService.clickVideoTogglesPlayback); _autoSkipIntro = _settingsService.read(settings.SettingsService.autoSkipIntro); _autoSkipCredits = _settingsService.read(settings.SettingsService.autoSkipCredits); + _forceSkipMarkerFallback = _settingsService.read(settings.SettingsService.forceSkipMarkerFallback); _autoSkipDelay = _settingsService.read(settings.SettingsService.autoSkipDelay); _introPattern = _settingsService.read(settings.SettingsService.introPattern); _creditsPattern = _settingsService.read(settings.SettingsService.creditsPattern); @@ -161,6 +163,7 @@ class _PlaybackSettingsScreenState extends State { SettingsSectionHeader(t.settings.autoSkip), _buildAutoSkipIntro(), _buildAutoSkipCredits(), + _buildForceSkipMarkerFallback(), _buildAutoSkipDelay(), _buildIntroPattern(), _buildCreditsPattern(), @@ -595,6 +598,19 @@ class _PlaybackSettingsScreenState extends State { ); } + Widget _buildForceSkipMarkerFallback() { + return SwitchListTile( + secondary: const AppIcon(Symbols.tune_rounded, fill: 1), + title: Text(t.settings.forceSkipMarkerFallback), + subtitle: Text(t.settings.forceSkipMarkerFallbackDescription), + value: _forceSkipMarkerFallback, + onChanged: (value) async { + setState(() => _forceSkipMarkerFallback = value); + await _settingsService.write(settings.SettingsService.forceSkipMarkerFallback, value); + }, + ); + } + Widget _buildAutoSkipDelay() { return ListTile( leading: const AppIcon(Symbols.timer_rounded, fill: 1), diff --git a/lib/services/cached_playback_metadata_service.dart b/lib/services/cached_playback_metadata_service.dart index 29d758d2..d18abddc 100644 --- a/lib/services/cached_playback_metadata_service.dart +++ b/lib/services/cached_playback_metadata_service.dart @@ -36,6 +36,7 @@ class CachedPlaybackMetadataService { required String itemId, String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, }) async { try { return switch (backend) { @@ -44,6 +45,7 @@ class CachedPlaybackMetadataService { itemId, introPattern: introPattern, creditsPattern: creditsPattern, + forceChapterFallback: forceChapterFallback, ), MediaBackend.jellyfin => _fetchJellyfinPlaybackExtras(cacheServerId, itemId), }; @@ -67,10 +69,16 @@ class CachedPlaybackMetadataService { String itemId, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, }) async { final metadata = await _plexMetadata(serverId, itemId); if (metadata == null) return null; - return plexPlaybackExtrasFromCacheJson(metadata, introPattern: introPattern, creditsPattern: creditsPattern); + return plexPlaybackExtrasFromCacheJson( + metadata, + introPattern: introPattern, + creditsPattern: creditsPattern, + forceChapterFallback: forceChapterFallback, + ); } static Future?> _plexMetadata(String serverId, String itemId) async { diff --git a/lib/services/jellyfin_client.dart b/lib/services/jellyfin_client.dart index 659fef21..1f8c6eec 100644 --- a/lib/services/jellyfin_client.dart +++ b/lib/services/jellyfin_client.dart @@ -476,6 +476,7 @@ class JellyfinClient with MediaServerCacheMixin implements MediaServerClient, Sc String itemId, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, bool forceRefresh = false, }) async { final item = await fetchItem(itemId); @@ -487,6 +488,7 @@ class JellyfinClient with MediaServerCacheMixin implements MediaServerClient, Sc String itemId, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, }) async { final item = await cache.getMetadata(cacheServerId, itemId); if (item == null) return null; diff --git a/lib/services/plex_client.dart b/lib/services/plex_client.dart index 6cc6bc89..d36fe19f 100644 --- a/lib/services/plex_client.dart +++ b/lib/services/plex_client.dart @@ -1205,6 +1205,7 @@ class PlexClient with MediaServerCacheMixin implements MediaServerClient { String ratingKey, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, bool forceRefresh = false, }) async { try { @@ -1221,6 +1222,7 @@ class PlexClient with MediaServerCacheMixin implements MediaServerClient { metadataJson, introPattern: introPattern, creditsPattern: creditsPattern, + forceChapterFallback: forceChapterFallback, ); } catch (e) { appLogger.w('Failed to get playback extras', error: e); @@ -1233,7 +1235,13 @@ class PlexClient with MediaServerCacheMixin implements MediaServerClient { Map? metadataJson, { String? introPattern, String? creditsPattern, - }) => plexPlaybackExtrasFromCacheJson(metadataJson, introPattern: introPattern, creditsPattern: creditsPattern); + bool forceChapterFallback = false, + }) => plexPlaybackExtrasFromCacheJson( + metadataJson, + introPattern: introPattern, + creditsPattern: creditsPattern, + forceChapterFallback: forceChapterFallback, + ); /// Parse video playback data from raw metadata JSON (no network call). /// Used by [getVideoPlaybackData] to avoid redundant fetches when the @@ -3661,15 +3669,22 @@ class PlexClient with MediaServerCacheMixin implements MediaServerClient { String itemId, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, bool forceRefresh = false, - }) => - getPlaybackExtras(itemId, introPattern: introPattern, creditsPattern: creditsPattern, forceRefresh: forceRefresh); + }) => getPlaybackExtras( + itemId, + introPattern: introPattern, + creditsPattern: creditsPattern, + forceChapterFallback: forceChapterFallback, + forceRefresh: forceRefresh, + ); @override Future fetchPlaybackExtrasFromCacheOnly( String itemId, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, }) async { final cached = await cache.get(serverId, '/library/metadata/$itemId'); if (cached == null) return null; @@ -3679,6 +3694,7 @@ class PlexClient with MediaServerCacheMixin implements MediaServerClient { metadataJson, introPattern: introPattern, creditsPattern: creditsPattern, + forceChapterFallback: forceChapterFallback, ); } diff --git a/lib/services/plex_mappers.dart b/lib/services/plex_mappers.dart index 105f0d76..66967c44 100644 --- a/lib/services/plex_mappers.dart +++ b/lib/services/plex_mappers.dart @@ -1075,12 +1075,14 @@ PlaybackExtras plexPlaybackExtrasFromCacheJson( Map? metadataJson, { String? introPattern, String? creditsPattern, + bool forceChapterFallback = false, }) { return PlaybackExtras.withChapterFallback( chapters: plexChaptersFromCacheJson(metadataJson), markers: plexMarkersFromCacheJson(metadataJson), introPatternStr: introPattern, creditsPatternStr: creditsPattern, + forceChapterFallback: forceChapterFallback, ); } diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart index 46706206..137c97ff 100644 --- a/lib/services/settings_service.dart +++ b/lib/services/settings_service.dart @@ -289,6 +289,7 @@ class SettingsService extends BaseSharedPreferencesService { static const clickVideoTogglesPlayback = BoolPref('click_video_toggles_playback'); static const autoSkipIntro = BoolPref('auto_skip_intro'); static const autoSkipCredits = BoolPref('auto_skip_credits'); + static const forceSkipMarkerFallback = BoolPref('force_skip_marker_fallback'); static const autoSkipDelay = IntPref('auto_skip_delay', defaultValue: 5); static const introPattern = StringPref('intro_pattern', defaultValue: defaultIntroPattern); static const creditsPattern = StringPref('credits_pattern', defaultValue: defaultCreditsPattern); diff --git a/lib/widgets/video_controls/video_controls.dart b/lib/widgets/video_controls/video_controls.dart index 5db4a8c2..65db3b6e 100644 --- a/lib/widgets/video_controls/video_controls.dart +++ b/lib/widgets/video_controls/video_controls.dart @@ -1135,12 +1135,14 @@ class _PlexVideoControlsState extends State with WindowListen final settings = await SettingsService.getInstance(); final introPattern = settings.read(SettingsService.introPattern); final creditsPattern = settings.read(SettingsService.creditsPattern); + final forceChapterFallback = settings.read(SettingsService.forceSkipMarkerFallback); // Backend-aware: Plex hits /library/metadata?includeChapters=1; Jellyfin // pulls Chapters from /Users/{userId}/Items/{id}. final extras = await client.fetchPlaybackExtras( widget.metadata.id, introPattern: introPattern, creditsPattern: creditsPattern, + forceChapterFallback: forceChapterFallback, forceRefresh: forceRefresh, ); appLogger.d('_loadPlaybackExtras: got ${extras.chapters.length} chapters'); @@ -1156,6 +1158,7 @@ class _PlexVideoControlsState extends State with WindowListen widget.metadata.id, introPattern: settings.read(SettingsService.introPattern), creditsPattern: settings.read(SettingsService.creditsPattern), + forceChapterFallback: settings.read(SettingsService.forceSkipMarkerFallback), ); if (extras != null) { appLogger.d('_loadPlaybackExtras: loaded ${extras.chapters.length} chapters from cache'); @@ -1184,6 +1187,7 @@ class _PlexVideoControlsState extends State with WindowListen itemId: widget.metadata.id, introPattern: settings.read(SettingsService.introPattern), creditsPattern: settings.read(SettingsService.creditsPattern), + forceChapterFallback: settings.read(SettingsService.forceSkipMarkerFallback), ); if (extras != null) _applyPlaybackExtras(extras); } catch (e) { diff --git a/test/services/playback_initialization_offline_cache_test.dart b/test/services/playback_initialization_offline_cache_test.dart index 9c1790f1..72383a4a 100644 --- a/test/services/playback_initialization_offline_cache_test.dart +++ b/test/services/playback_initialization_offline_cache_test.dart @@ -18,6 +18,7 @@ import 'package:plezy/services/jellyfin_api_cache.dart'; import 'package:plezy/services/jellyfin_media_info_mapper.dart'; import 'package:plezy/services/playback_initialization_service.dart'; import 'package:plezy/services/plex_api_cache.dart'; +import 'package:plezy/services/plex_mappers.dart'; import 'package:plezy/services/settings_service.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -180,7 +181,7 @@ void main() { expect(result.externalSubtitles.single.uri, Uri.file(subtitlePath).toString()); }); - test('cache-only playback extras parses Plex chapters and markers', () async { + test('cache-only playback extras fills missing Plex marker types from chapters', () async { await PlexApiCache.instance.put('srv-1', '/library/metadata/movie-1', _plexMetadataEnvelope()); final extras = await CachedPlaybackMetadataService.fetchPlaybackExtras( @@ -190,7 +191,7 @@ void main() { ); expect(extras?.chapters.single.title, 'Intro'); - expect(extras?.markers.single.type, 'credits'); + expect(extras?.markers.map((m) => m.type), ['intro', 'credits']); }); test('Plex extras parser skips malformed entries and keeps valid ones', () async { @@ -203,7 +204,28 @@ void main() { ); expect(extras?.chapters.map((c) => c.title), ['Intro']); - expect(extras?.markers.map((m) => m.type), ['credits']); + expect(extras?.markers.map((m) => m.type), ['intro', 'credits']); + }); + + test('Plex extras parser can force chapter fallback over native marker timings', () { + final extras = plexPlaybackExtrasFromCacheJson({ + 'Chapter': [ + {'id': 1, 'index': 0, 'startTimeOffset': 5000, 'endTimeOffset': 45000, 'tag': 'Intro'}, + {'id': 2, 'index': 1, 'startTimeOffset': 90000, 'endTimeOffset': 100000, 'tag': 'Credits'}, + ], + 'Marker': [ + {'id': 10, 'type': 'intro', 'startTimeOffset': 12000, 'endTimeOffset': 30000}, + {'id': 11, 'type': 'credits', 'startTimeOffset': 93000, 'endTimeOffset': 98000}, + ], + }, forceChapterFallback: true); + + final intro = extras.markers.firstWhere((m) => m.type == 'intro'); + final credits = extras.markers.firstWhere((m) => m.type == 'credits'); + expect(intro.startTimeOffset, 5000); + expect(intro.endTimeOffset, 45000); + expect(credits.startTimeOffset, 90000); + expect(credits.endTimeOffset, 100000); + expect(extras.markers.any((m) => m.id == 10 || m.id == 11), isFalse); }); test('Jellyfin extras parser tolerates non-string chapter names', () {