fix: support forced skip marker fallback

close #956
This commit is contained in:
edde746
2026-05-01 04:35:30 +02:00
parent a351ca70ba
commit c602936d2a
41 changed files with 269 additions and 91 deletions
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -201,6 +201,8 @@
"autoSkipIntroDescription": "数秒後にイントロマーカーを自動的にスキップ",
"autoSkipCredits": "クレジットを自動スキップ",
"autoSkipCreditsDescription": "クレジットを自動的にスキップして次のエピソードを再生",
"forceSkipMarkerFallback": "フォールバックマーカーを強制",
"forceSkipMarkerFallbackDescription": "Plex がネイティブマーカーを提供している場合でも、スキップマーカーにはチャプタータイトルのパターンを使用する",
"autoSkipDelay": "自動スキップの遅延",
"autoSkipDelayDescription": "自動スキップまで${seconds}秒待機",
"introPattern": "イントロマーカーパターン",
+2
View File
@@ -201,6 +201,8 @@
"autoSkipIntroDescription": "몇 초 후 오프닝을 자동으로 건너뛰기",
"autoSkipCredits": "자동으로 엔딩 건너뛰기",
"autoSkipCreditsDescription": "엔딩 크레딧 자동 건너뛰기 후 다음 에피소드 재생",
"forceSkipMarkerFallback": "대체 마커 강제 사용",
"forceSkipMarkerFallbackDescription": "Plex가 기본 마커를 제공하더라도 건너뛰기 마커에 챕터 제목 패턴 사용",
"autoSkipDelay": "자동 건너뛰기 지연",
"autoSkipDelayDescription": "자동 건너뛰기 전 ${seconds} 초 대기",
"introPattern": "인트로 마커 패턴",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -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",
+2
View File
@@ -201,6 +201,8 @@
"autoSkipIntroDescription": "Автоматически пропускать маркеры вступления через несколько секунд",
"autoSkipCredits": "Автопропуск титров",
"autoSkipCreditsDescription": "Автоматически пропускать титры и воспроизводить следующий эпизод",
"forceSkipMarkerFallback": "Принудительные резервные маркеры",
"forceSkipMarkerFallbackDescription": "Использовать шаблоны заголовков глав для маркеров пропуска, даже если Plex предоставляет встроенные маркеры",
"autoSkipDelay": "Задержка автопропуска",
"autoSkipDelayDescription": "Подождать ${seconds} секунд перед автопропуском",
"introPattern": "Шаблон маркера вступления",
+2 -2
View File
@@ -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
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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',
+12 -4
View File
@@ -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',
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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' => 'トラッカー',
+8 -4
View File
@@ -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' => '트래커',
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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' => 'Трекеры',
+8 -4
View File
@@ -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',
+8 -4
View File
@@ -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' => '追踪器',
+2
View File
@@ -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",
+2
View File
@@ -201,6 +201,8 @@
"autoSkipIntroDescription": "几秒钟后自动跳过片头标记",
"autoSkipCredits": "自动跳过片尾",
"autoSkipCreditsDescription": "自动跳过片尾并播放下一集",
"forceSkipMarkerFallback": "强制使用备用标记",
"forceSkipMarkerFallbackDescription": "即使 Plex 提供原生标记,也使用章节标题模式作为跳过标记",
"autoSkipDelay": "自动跳过延迟",
"autoSkipDelayDescription": "自动跳过前等待 ${seconds} 秒",
"introPattern": "片头标记模式",
+2
View File
@@ -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
+33 -22
View File
@@ -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<MediaChapter> chapters,
required List<MediaMarker> 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 = <MediaMarker>[];
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
? <MediaMarker>[...reclassified.where((m) => !syntheticTypes.contains(m.type)), ...synthetic]
: <MediaMarker>[...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);
}
}
@@ -42,6 +42,7 @@ class _PlaybackSettingsScreenState extends State<PlaybackSettingsScreen> {
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<PlaybackSettingsScreen> {
_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<PlaybackSettingsScreen> {
SettingsSectionHeader(t.settings.autoSkip),
_buildAutoSkipIntro(),
_buildAutoSkipCredits(),
_buildForceSkipMarkerFallback(),
_buildAutoSkipDelay(),
_buildIntroPattern(),
_buildCreditsPattern(),
@@ -595,6 +598,19 @@ class _PlaybackSettingsScreenState extends State<PlaybackSettingsScreen> {
);
}
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),
@@ -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<Map<String, dynamic>?> _plexMetadata(String serverId, String itemId) async {
+2
View File
@@ -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;
+19 -3
View File
@@ -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<String, dynamic>? 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<PlaybackExtras?> 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,
);
}
+2
View File
@@ -1075,12 +1075,14 @@ PlaybackExtras plexPlaybackExtrasFromCacheJson(
Map<String, dynamic>? metadataJson, {
String? introPattern,
String? creditsPattern,
bool forceChapterFallback = false,
}) {
return PlaybackExtras.withChapterFallback(
chapters: plexChaptersFromCacheJson(metadataJson),
markers: plexMarkersFromCacheJson(metadataJson),
introPatternStr: introPattern,
creditsPatternStr: creditsPattern,
forceChapterFallback: forceChapterFallback,
);
}
+1
View File
@@ -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);
@@ -1135,12 +1135,14 @@ class _PlexVideoControlsState extends State<PlexVideoControls> 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<PlexVideoControls> 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<PlexVideoControls> 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) {
@@ -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', () {