From 03907db6c47c997bb765a5b8ce17b93e81084a99 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:59:22 +0100 Subject: [PATCH] feat: external player support close #388 --- assets/player_icons/celluloid.svg | 82 ++++++ assets/player_icons/iina.png | Bin 0 -> 43793 bytes assets/player_icons/infuse.png | Bin 0 -> 44755 bytes assets/player_icons/just_player.png | Bin 0 -> 16505 bytes assets/player_icons/mpv.svg | 46 +++ assets/player_icons/mx_player.svg | 21 ++ assets/player_icons/potplayer.png | Bin 0 -> 6629 bytes assets/player_icons/vlc.svg | 74 +++++ lib/i18n/de.i18n.json | 17 ++ lib/i18n/en.i18n.json | 17 ++ lib/i18n/es.i18n.json | 17 ++ lib/i18n/fr.i18n.json | 17 ++ lib/i18n/it.i18n.json | 17 ++ lib/i18n/ko.i18n.json | 17 ++ lib/i18n/nl.i18n.json | 17 ++ lib/i18n/strings.g.dart | 4 +- lib/i18n/strings_de.g.dart | 40 +++ lib/i18n/strings_en.g.dart | 70 +++++ lib/i18n/strings_es.g.dart | 40 +++ lib/i18n/strings_fr.g.dart | 40 +++ lib/i18n/strings_it.g.dart | 40 +++ lib/i18n/strings_ko.g.dart | 40 +++ lib/i18n/strings_nl.g.dart | 40 +++ lib/i18n/strings_sv.g.dart | 40 +++ lib/i18n/strings_zh.g.dart | 40 +++ lib/i18n/sv.i18n.json | 17 ++ lib/i18n/zh.i18n.json | 17 ++ lib/models/external_player_models.dart | 238 ++++++++++++++++ .../settings/external_player_screen.dart | 265 ++++++++++++++++++ lib/screens/settings/settings_screen.dart | 22 ++ lib/services/external_player_service.dart | 50 ++++ lib/services/settings_service.dart | 62 ++++ lib/utils/video_player_navigation.dart | 22 ++ lib/widgets/media_context_menu.dart | 28 ++ pubspec.lock | 8 + pubspec.yaml | 2 + 36 files changed, 1465 insertions(+), 2 deletions(-) create mode 100644 assets/player_icons/celluloid.svg create mode 100644 assets/player_icons/iina.png create mode 100644 assets/player_icons/infuse.png create mode 100644 assets/player_icons/just_player.png create mode 100644 assets/player_icons/mpv.svg create mode 100644 assets/player_icons/mx_player.svg create mode 100644 assets/player_icons/potplayer.png create mode 100644 assets/player_icons/vlc.svg create mode 100644 lib/models/external_player_models.dart create mode 100644 lib/screens/settings/external_player_screen.dart create mode 100644 lib/services/external_player_service.dart diff --git a/assets/player_icons/celluloid.svg b/assets/player_icons/celluloid.svg new file mode 100644 index 00000000..075431d7 --- /dev/null +++ b/assets/player_icons/celluloid.svg @@ -0,0 +1,82 @@ + + Adwaita Icon Template + + + + + + + + + + + + + + + + image/svg+xml + + + + GNOME Design Team + + + + + Adwaita Icon Template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/player_icons/iina.png b/assets/player_icons/iina.png new file mode 100644 index 0000000000000000000000000000000000000000..02fa0f79594cd199d1b33c1391aa6dd685875f06 GIT binary patch literal 43793 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 DK~Bbr literal 0 HcmV?d00001 diff --git a/assets/player_icons/infuse.png b/assets/player_icons/infuse.png new file mode 100644 index 0000000000000000000000000000000000000000..53e353c4d283e590c4e5f0d9233aec5dd163f5d7 GIT binary patch literal 44755 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%0AciivmGuC${46 zPNI+(gRptWYcXqEMnzeuo{4(MCAn%>?V1kCi}l989tA46F8UJRRo~e+xbI$=(xe?- zUX@B<^__|F;=5N@*O_FyAP%Qkuj;|=Ku{U{GeYU2o?5P1>h%q|uTk};Ftx(UY+bw7pm42h7q^zp}%0`~~8Dkd9p9rRx4xQ7Djr^Q$fo zC>50U8CNzun5za6(<6WV5x_=Vt!tI7^s5F82b2=;Ot?xiwq59Wh|$TMxT}IDR{8V1 z{@ynVr-)SnI0Ewc3RDRc7ZOkUO4S$t>VU^*yz#%>e*}@KoC46h~FdsE6_V!&d5@TQ<&@UL_aD z!Y)nQ4+iG9!$!Kie}KzCP@wvFVz3aGJ7P8`4OIfLFS_yPA;4Kvp6ZM8*y9W30j3_b zes|3g6i7j=0yOkCnQ>7kvlB!z#D*se!F>gpThi&{%J%L71-V2RtfMYZs3kG^%^dz( zRwpRK@_Jn9KI`X|rp<*>Tnk^v65(G)C=LK_HCSppr8liG2dvYSW`It5FbOy%mLlXZ_k#Zx=W-h>Yh6hU?(Jp8`?rwxf1W zeQOc!+zbYoOSk^L5`%h$V1*qHqS>&Fa5)>Jm!ovTwEL z=vXV{Q$6=907OLr&+cY7b!MwX+Mu7W6?OBWiRa;TV41ts#I3-jSFYR2{?sciLIZa3>+9jXCUhSO|64;vv zT(6k7bmXV{yq+qSt@JCgZr`{}pZ-T(;UmOeIwToT5DhN=2D}MI8kick{?_)s_UE>w zqDfeC^1aQ4!_5UB+_~l7Jtih)w;L|;cW=S>9Rn#kci}%dc_X}>`v6UwcJ;CaDOiX~ z+wZpt2#S+@NWb5Tt!qhotYhz&AhsZId8$nkvv39Zu?+B_$TVivh+qgsu6h|8xT|>M zk6y9CI{VlX(;JFsAjO|0*0N?i(Adi`< zi>@Wn<#z_?kX&B8tq+^_NhwLb7ZU%Eph?bCN8q_t5*SGs1wP16Z=70FpTN+NSK{IG zYoh$oJ8I{word%%+l8#glMb6Xz#7O>0M*#3+BgaJrT+ewM>|-+R6dvK=GgND<8$B` z=H=;t2eNqE`yYG)?2qrTMF=d-doc{r|GZQ(0jP>}vb4@HZ#)^zB>8b$L zC6D$4jRBW(oD7zxk!RX{PSVIu{!e0|P9;c&)eHUkgk?a==-ntQGv-ZwCp%^(Ec}Vn zR8deK;L=1GQbURx?2jkq5%Oan>_PdEd8Or_ zgH&LmmjPCs=)iyBm3zum`yZG;{`aqud%erjA9*z z=6w#u^2S|xpgg0iA;^o!MbGSWNXHI&RKocP8DP`~f?kBZ4~W;j!KLSL(2|w%nLxnn zZH6&7@WMnbEm92QTPg}`sTnV&-^_HtUq@RW;sek`E+A!i12Z#WRp+FA8*?!UjqIN L(PpS>BsTJYB6@>q literal 0 HcmV?d00001 diff --git a/assets/player_icons/just_player.png b/assets/player_icons/just_player.png new file mode 100644 index 0000000000000000000000000000000000000000..f1b49535af010ac981ba02e11f340d90a07af0bc GIT binary patch literal 16505 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/player_icons/mx_player.svg b/assets/player_icons/mx_player.svg new file mode 100644 index 00000000..91938cec --- /dev/null +++ b/assets/player_icons/mx_player.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/player_icons/potplayer.png b/assets/player_icons/potplayer.png new file mode 100644 index 0000000000000000000000000000000000000000..e59b04fe147651e2b4c9fbccc209396d45458187 GIT binary patch literal 6629 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/i18n/de.i18n.json b/lib/i18n/de.i18n.json index bafb0bec..4d50a016 100644 --- a/lib/i18n/de.i18n.json +++ b/lib/i18n/de.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "Audioausgabe", "performanceOverlay": "Leistungsanzeige" + }, + "externalPlayer": { + "title": "Externer Player", + "useExternalPlayer": "Externen Player verwenden", + "useExternalPlayerDescription": "Videos in einer externen App statt im integrierten Player öffnen", + "selectPlayer": "Player auswählen", + "systemDefault": "Systemstandard", + "addCustomPlayer": "Benutzerdefinierten Player hinzufügen", + "playerName": "Playername", + "playerCommand": "Befehl", + "playerPackage": "Paketname", + "playerUrlScheme": "URL-Schema", + "customPlayer": "Benutzerdefinierter Player", + "off": "Aus", + "launchFailed": "Externer Player konnte nicht geöffnet werden", + "appNotInstalled": "${name} ist nicht installiert", + "playInExternalPlayer": "In externem Player abspielen" } } diff --git a/lib/i18n/en.i18n.json b/lib/i18n/en.i18n.json index a3a2baef..76269b14 100644 --- a/lib/i18n/en.i18n.json +++ b/lib/i18n/en.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "Audio Output", "performanceOverlay": "Performance Overlay" + }, + "externalPlayer": { + "title": "External Player", + "useExternalPlayer": "Use External Player", + "useExternalPlayerDescription": "Open videos in an external app instead of the built-in player", + "selectPlayer": "Select Player", + "systemDefault": "System Default", + "addCustomPlayer": "Add Custom Player", + "playerName": "Player Name", + "playerCommand": "Command", + "playerPackage": "Package Name", + "playerUrlScheme": "URL Scheme", + "customPlayer": "Custom Player", + "off": "Off", + "launchFailed": "Failed to open external player", + "appNotInstalled": "${name} is not installed", + "playInExternalPlayer": "Play in External Player" } } diff --git a/lib/i18n/es.i18n.json b/lib/i18n/es.i18n.json index fc0eeb68..25a77486 100644 --- a/lib/i18n/es.i18n.json +++ b/lib/i18n/es.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "Salida de audio", "performanceOverlay": "Indicador de rendimiento" + }, + "externalPlayer": { + "title": "Reproductor externo", + "useExternalPlayer": "Usar reproductor externo", + "useExternalPlayerDescription": "Abrir vídeos en una app externa en lugar del reproductor integrado", + "selectPlayer": "Seleccionar reproductor", + "systemDefault": "Predeterminado del sistema", + "addCustomPlayer": "Añadir reproductor personalizado", + "playerName": "Nombre del reproductor", + "playerCommand": "Comando", + "playerPackage": "Nombre del paquete", + "playerUrlScheme": "Esquema URL", + "customPlayer": "Reproductor personalizado", + "off": "Desactivado", + "launchFailed": "No se pudo abrir el reproductor externo", + "appNotInstalled": "${name} no está instalado", + "playInExternalPlayer": "Reproducir en reproductor externo" } } diff --git a/lib/i18n/fr.i18n.json b/lib/i18n/fr.i18n.json index 2c394f26..d3a603c0 100644 --- a/lib/i18n/fr.i18n.json +++ b/lib/i18n/fr.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "Sortie audio", "performanceOverlay": "Superposition de performance" + }, + "externalPlayer": { + "title": "Lecteur externe", + "useExternalPlayer": "Utiliser un lecteur externe", + "useExternalPlayerDescription": "Ouvrir les vidéos dans une application externe au lieu du lecteur intégré", + "selectPlayer": "Sélectionner le lecteur", + "systemDefault": "Par défaut du système", + "addCustomPlayer": "Ajouter un lecteur personnalisé", + "playerName": "Nom du lecteur", + "playerCommand": "Commande", + "playerPackage": "Nom du paquet", + "playerUrlScheme": "Schéma URL", + "customPlayer": "Lecteur personnalisé", + "off": "Désactivé", + "launchFailed": "Impossible d'ouvrir le lecteur externe", + "appNotInstalled": "${name} n'est pas installé", + "playInExternalPlayer": "Lire dans un lecteur externe" } } diff --git a/lib/i18n/it.i18n.json b/lib/i18n/it.i18n.json index 6c19d6e1..6741c342 100644 --- a/lib/i18n/it.i18n.json +++ b/lib/i18n/it.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "Uscita audio", "performanceOverlay": "Overlay prestazioni" + }, + "externalPlayer": { + "title": "Lettore esterno", + "useExternalPlayer": "Usa lettore esterno", + "useExternalPlayerDescription": "Apri i video in un'app esterna invece del lettore integrato", + "selectPlayer": "Seleziona lettore", + "systemDefault": "Predefinito di sistema", + "addCustomPlayer": "Aggiungi lettore personalizzato", + "playerName": "Nome lettore", + "playerCommand": "Comando", + "playerPackage": "Nome pacchetto", + "playerUrlScheme": "Schema URL", + "customPlayer": "Lettore personalizzato", + "off": "Disattivato", + "launchFailed": "Impossibile aprire il lettore esterno", + "appNotInstalled": "${name} non è installato", + "playInExternalPlayer": "Riproduci in lettore esterno" } } diff --git a/lib/i18n/ko.i18n.json b/lib/i18n/ko.i18n.json index 5c90a72e..e6f73655 100644 --- a/lib/i18n/ko.i18n.json +++ b/lib/i18n/ko.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "오디오 출력", "performanceOverlay": "성능 오버레이" + }, + "externalPlayer": { + "title": "외부 플레이어", + "useExternalPlayer": "외부 플레이어 사용", + "useExternalPlayerDescription": "내장 플레이어 대신 외부 앱에서 동영상 열기", + "selectPlayer": "플레이어 선택", + "systemDefault": "시스템 기본값", + "addCustomPlayer": "사용자 정의 플레이어 추가", + "playerName": "플레이어 이름", + "playerCommand": "명령어", + "playerPackage": "패키지 이름", + "playerUrlScheme": "URL 스킴", + "customPlayer": "사용자 정의 플레이어", + "off": "꺼짐", + "launchFailed": "외부 플레이어를 열 수 없습니다", + "appNotInstalled": "${name}이(가) 설치되어 있지 않습니다", + "playInExternalPlayer": "외부 플레이어에서 재생" } } diff --git a/lib/i18n/nl.i18n.json b/lib/i18n/nl.i18n.json index 5a133175..f4a651fb 100644 --- a/lib/i18n/nl.i18n.json +++ b/lib/i18n/nl.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "Audio-uitvoer", "performanceOverlay": "Prestatie-overlay" + }, + "externalPlayer": { + "title": "Externe speler", + "useExternalPlayer": "Externe speler gebruiken", + "useExternalPlayerDescription": "Open video's in een externe app in plaats van de ingebouwde speler", + "selectPlayer": "Speler selecteren", + "systemDefault": "Systeemstandaard", + "addCustomPlayer": "Aangepaste speler toevoegen", + "playerName": "Spelernaam", + "playerCommand": "Commando", + "playerPackage": "Pakketnaam", + "playerUrlScheme": "URL-schema", + "customPlayer": "Aangepaste speler", + "off": "Uit", + "launchFailed": "Kan externe speler niet openen", + "appNotInstalled": "${name} is niet geïnstalleerd", + "playInExternalPlayer": "Afspelen in externe speler" } } diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index ee76c869..9aedac5f 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 9 -/// Strings: 6084 (676 per locale) +/// Strings: 6219 (691 per locale) /// -/// Built on 2026-02-10 at 21:45 UTC +/// Built on 2026-02-11 at 13:27 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/lib/i18n/strings_de.g.dart b/lib/i18n/strings_de.g.dart index fb942653..5cbbf0fe 100644 --- a/lib/i18n/strings_de.g.dart +++ b/lib/i18n/strings_de.g.dart @@ -72,6 +72,7 @@ class TranslationsDe with BaseTranslations implements T @override late final _TranslationsShadersDe shaders = _TranslationsShadersDe._(_root); @override late final _TranslationsCompanionRemoteDe companionRemote = _TranslationsCompanionRemoteDe._(_root); @override late final _TranslationsVideoSettingsDe videoSettings = _TranslationsVideoSettingsDe._(_root); + @override late final _TranslationsExternalPlayerDe externalPlayer = _TranslationsExternalPlayerDe._(_root); } // Path: app @@ -961,6 +962,30 @@ class _TranslationsVideoSettingsDe implements TranslationsVideoSettingsEn { @override String get performanceOverlay => 'Leistungsanzeige'; } +// Path: externalPlayer +class _TranslationsExternalPlayerDe implements TranslationsExternalPlayerEn { + _TranslationsExternalPlayerDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get title => 'Externer Player'; + @override String get useExternalPlayer => 'Externen Player verwenden'; + @override String get useExternalPlayerDescription => 'Videos in einer externen App statt im integrierten Player öffnen'; + @override String get selectPlayer => 'Player auswählen'; + @override String get systemDefault => 'Systemstandard'; + @override String get addCustomPlayer => 'Benutzerdefinierten Player hinzufügen'; + @override String get playerName => 'Playername'; + @override String get playerCommand => 'Befehl'; + @override String get playerPackage => 'Paketname'; + @override String get playerUrlScheme => 'URL-Schema'; + @override String get customPlayer => 'Benutzerdefinierter Player'; + @override String get off => 'Aus'; + @override String get launchFailed => 'Externer Player konnte nicht geöffnet werden'; + @override String appNotInstalled({required Object name}) => '${name} ist nicht installiert'; + @override String get playInExternalPlayer => 'In externem Player abspielen'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsDe implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsDe._(this._root); @@ -1821,6 +1846,21 @@ extension on TranslationsDe { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Audioausgabe', 'videoSettings.performanceOverlay' => 'Leistungsanzeige', + 'externalPlayer.title' => 'Externer Player', + 'externalPlayer.useExternalPlayer' => 'Externen Player verwenden', + 'externalPlayer.useExternalPlayerDescription' => 'Videos in einer externen App statt im integrierten Player öffnen', + 'externalPlayer.selectPlayer' => 'Player auswählen', + 'externalPlayer.systemDefault' => 'Systemstandard', + 'externalPlayer.addCustomPlayer' => 'Benutzerdefinierten Player hinzufügen', + 'externalPlayer.playerName' => 'Playername', + 'externalPlayer.playerCommand' => 'Befehl', + 'externalPlayer.playerPackage' => 'Paketname', + 'externalPlayer.playerUrlScheme' => 'URL-Schema', + 'externalPlayer.customPlayer' => 'Benutzerdefinierter Player', + 'externalPlayer.off' => 'Aus', + 'externalPlayer.launchFailed' => 'Externer Player konnte nicht geöffnet werden', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} ist nicht installiert', + 'externalPlayer.playInExternalPlayer' => 'In externem Player abspielen', _ => null, }; } diff --git a/lib/i18n/strings_en.g.dart b/lib/i18n/strings_en.g.dart index 2d1f8050..51b135e5 100644 --- a/lib/i18n/strings_en.g.dart +++ b/lib/i18n/strings_en.g.dart @@ -75,6 +75,7 @@ class Translations with BaseTranslations { late final TranslationsShadersEn shaders = TranslationsShadersEn._(_root); late final TranslationsCompanionRemoteEn companionRemote = TranslationsCompanionRemoteEn._(_root); late final TranslationsVideoSettingsEn videoSettings = TranslationsVideoSettingsEn._(_root); + late final TranslationsExternalPlayerEn externalPlayer = TranslationsExternalPlayerEn._(_root); } // Path: app @@ -2098,6 +2099,60 @@ class TranslationsVideoSettingsEn { String get performanceOverlay => 'Performance Overlay'; } +// Path: externalPlayer +class TranslationsExternalPlayerEn { + TranslationsExternalPlayerEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'External Player' + String get title => 'External Player'; + + /// en: 'Use External Player' + String get useExternalPlayer => 'Use External Player'; + + /// en: 'Open videos in an external app instead of the built-in player' + String get useExternalPlayerDescription => 'Open videos in an external app instead of the built-in player'; + + /// en: 'Select Player' + String get selectPlayer => 'Select Player'; + + /// en: 'System Default' + String get systemDefault => 'System Default'; + + /// en: 'Add Custom Player' + String get addCustomPlayer => 'Add Custom Player'; + + /// en: 'Player Name' + String get playerName => 'Player Name'; + + /// en: 'Command' + String get playerCommand => 'Command'; + + /// en: 'Package Name' + String get playerPackage => 'Package Name'; + + /// en: 'URL Scheme' + String get playerUrlScheme => 'URL Scheme'; + + /// en: 'Custom Player' + String get customPlayer => 'Custom Player'; + + /// en: 'Off' + String get off => 'Off'; + + /// en: 'Failed to open external player' + String get launchFailed => 'Failed to open external player'; + + /// en: '${name} is not installed' + String appNotInstalled({required Object name}) => '${name} is not installed'; + + /// en: 'Play in External Player' + String get playInExternalPlayer => 'Play in External Player'; +} + // Path: hotkeys.actions class TranslationsHotkeysActionsEn { TranslationsHotkeysActionsEn._(this._root); @@ -3180,6 +3235,21 @@ extension on Translations { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Audio Output', 'videoSettings.performanceOverlay' => 'Performance Overlay', + 'externalPlayer.title' => 'External Player', + 'externalPlayer.useExternalPlayer' => 'Use External Player', + 'externalPlayer.useExternalPlayerDescription' => 'Open videos in an external app instead of the built-in player', + 'externalPlayer.selectPlayer' => 'Select Player', + 'externalPlayer.systemDefault' => 'System Default', + 'externalPlayer.addCustomPlayer' => 'Add Custom Player', + 'externalPlayer.playerName' => 'Player Name', + 'externalPlayer.playerCommand' => 'Command', + 'externalPlayer.playerPackage' => 'Package Name', + 'externalPlayer.playerUrlScheme' => 'URL Scheme', + 'externalPlayer.customPlayer' => 'Custom Player', + 'externalPlayer.off' => 'Off', + 'externalPlayer.launchFailed' => 'Failed to open external player', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} is not installed', + 'externalPlayer.playInExternalPlayer' => 'Play in External Player', _ => null, }; } diff --git a/lib/i18n/strings_es.g.dart b/lib/i18n/strings_es.g.dart index 8df5148c..ef065fea 100644 --- a/lib/i18n/strings_es.g.dart +++ b/lib/i18n/strings_es.g.dart @@ -72,6 +72,7 @@ class TranslationsEs with BaseTranslations implements T @override late final _TranslationsShadersEs shaders = _TranslationsShadersEs._(_root); @override late final _TranslationsCompanionRemoteEs companionRemote = _TranslationsCompanionRemoteEs._(_root); @override late final _TranslationsVideoSettingsEs videoSettings = _TranslationsVideoSettingsEs._(_root); + @override late final _TranslationsExternalPlayerEs externalPlayer = _TranslationsExternalPlayerEs._(_root); } // Path: app @@ -961,6 +962,30 @@ class _TranslationsVideoSettingsEs implements TranslationsVideoSettingsEn { @override String get performanceOverlay => 'Indicador de rendimiento'; } +// Path: externalPlayer +class _TranslationsExternalPlayerEs implements TranslationsExternalPlayerEn { + _TranslationsExternalPlayerEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get title => 'Reproductor externo'; + @override String get useExternalPlayer => 'Usar reproductor externo'; + @override String get useExternalPlayerDescription => 'Abrir vídeos en una app externa en lugar del reproductor integrado'; + @override String get selectPlayer => 'Seleccionar reproductor'; + @override String get systemDefault => 'Predeterminado del sistema'; + @override String get addCustomPlayer => 'Añadir reproductor personalizado'; + @override String get playerName => 'Nombre del reproductor'; + @override String get playerCommand => 'Comando'; + @override String get playerPackage => 'Nombre del paquete'; + @override String get playerUrlScheme => 'Esquema URL'; + @override String get customPlayer => 'Reproductor personalizado'; + @override String get off => 'Desactivado'; + @override String get launchFailed => 'No se pudo abrir el reproductor externo'; + @override String appNotInstalled({required Object name}) => '${name} no está instalado'; + @override String get playInExternalPlayer => 'Reproducir en reproductor externo'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsEs implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsEs._(this._root); @@ -1821,6 +1846,21 @@ extension on TranslationsEs { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Salida de audio', 'videoSettings.performanceOverlay' => 'Indicador de rendimiento', + 'externalPlayer.title' => 'Reproductor externo', + 'externalPlayer.useExternalPlayer' => 'Usar reproductor externo', + 'externalPlayer.useExternalPlayerDescription' => 'Abrir vídeos en una app externa en lugar del reproductor integrado', + 'externalPlayer.selectPlayer' => 'Seleccionar reproductor', + 'externalPlayer.systemDefault' => 'Predeterminado del sistema', + 'externalPlayer.addCustomPlayer' => 'Añadir reproductor personalizado', + 'externalPlayer.playerName' => 'Nombre del reproductor', + 'externalPlayer.playerCommand' => 'Comando', + 'externalPlayer.playerPackage' => 'Nombre del paquete', + 'externalPlayer.playerUrlScheme' => 'Esquema URL', + 'externalPlayer.customPlayer' => 'Reproductor personalizado', + 'externalPlayer.off' => 'Desactivado', + 'externalPlayer.launchFailed' => 'No se pudo abrir el reproductor externo', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} no está instalado', + 'externalPlayer.playInExternalPlayer' => 'Reproducir en reproductor externo', _ => null, }; } diff --git a/lib/i18n/strings_fr.g.dart b/lib/i18n/strings_fr.g.dart index b4c0a902..7f6d1ee3 100644 --- a/lib/i18n/strings_fr.g.dart +++ b/lib/i18n/strings_fr.g.dart @@ -72,6 +72,7 @@ class TranslationsFr with BaseTranslations implements T @override late final _TranslationsShadersFr shaders = _TranslationsShadersFr._(_root); @override late final _TranslationsCompanionRemoteFr companionRemote = _TranslationsCompanionRemoteFr._(_root); @override late final _TranslationsVideoSettingsFr videoSettings = _TranslationsVideoSettingsFr._(_root); + @override late final _TranslationsExternalPlayerFr externalPlayer = _TranslationsExternalPlayerFr._(_root); } // Path: app @@ -961,6 +962,30 @@ class _TranslationsVideoSettingsFr implements TranslationsVideoSettingsEn { @override String get performanceOverlay => 'Superposition de performance'; } +// Path: externalPlayer +class _TranslationsExternalPlayerFr implements TranslationsExternalPlayerEn { + _TranslationsExternalPlayerFr._(this._root); + + final TranslationsFr _root; // ignore: unused_field + + // Translations + @override String get title => 'Lecteur externe'; + @override String get useExternalPlayer => 'Utiliser un lecteur externe'; + @override String get useExternalPlayerDescription => 'Ouvrir les vidéos dans une application externe au lieu du lecteur intégré'; + @override String get selectPlayer => 'Sélectionner le lecteur'; + @override String get systemDefault => 'Par défaut du système'; + @override String get addCustomPlayer => 'Ajouter un lecteur personnalisé'; + @override String get playerName => 'Nom du lecteur'; + @override String get playerCommand => 'Commande'; + @override String get playerPackage => 'Nom du paquet'; + @override String get playerUrlScheme => 'Schéma URL'; + @override String get customPlayer => 'Lecteur personnalisé'; + @override String get off => 'Désactivé'; + @override String get launchFailed => 'Impossible d\'ouvrir le lecteur externe'; + @override String appNotInstalled({required Object name}) => '${name} n\'est pas installé'; + @override String get playInExternalPlayer => 'Lire dans un lecteur externe'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsFr implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsFr._(this._root); @@ -1821,6 +1846,21 @@ extension on TranslationsFr { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Sortie audio', 'videoSettings.performanceOverlay' => 'Superposition de performance', + 'externalPlayer.title' => 'Lecteur externe', + 'externalPlayer.useExternalPlayer' => 'Utiliser un lecteur externe', + 'externalPlayer.useExternalPlayerDescription' => 'Ouvrir les vidéos dans une application externe au lieu du lecteur intégré', + 'externalPlayer.selectPlayer' => 'Sélectionner le lecteur', + 'externalPlayer.systemDefault' => 'Par défaut du système', + 'externalPlayer.addCustomPlayer' => 'Ajouter un lecteur personnalisé', + 'externalPlayer.playerName' => 'Nom du lecteur', + 'externalPlayer.playerCommand' => 'Commande', + 'externalPlayer.playerPackage' => 'Nom du paquet', + 'externalPlayer.playerUrlScheme' => 'Schéma URL', + 'externalPlayer.customPlayer' => 'Lecteur personnalisé', + 'externalPlayer.off' => 'Désactivé', + 'externalPlayer.launchFailed' => 'Impossible d\'ouvrir le lecteur externe', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} n\'est pas installé', + 'externalPlayer.playInExternalPlayer' => 'Lire dans un lecteur externe', _ => null, }; } diff --git a/lib/i18n/strings_it.g.dart b/lib/i18n/strings_it.g.dart index 6209e695..eca8118a 100644 --- a/lib/i18n/strings_it.g.dart +++ b/lib/i18n/strings_it.g.dart @@ -72,6 +72,7 @@ class TranslationsIt with BaseTranslations implements T @override late final _TranslationsShadersIt shaders = _TranslationsShadersIt._(_root); @override late final _TranslationsCompanionRemoteIt companionRemote = _TranslationsCompanionRemoteIt._(_root); @override late final _TranslationsVideoSettingsIt videoSettings = _TranslationsVideoSettingsIt._(_root); + @override late final _TranslationsExternalPlayerIt externalPlayer = _TranslationsExternalPlayerIt._(_root); } // Path: app @@ -961,6 +962,30 @@ class _TranslationsVideoSettingsIt implements TranslationsVideoSettingsEn { @override String get performanceOverlay => 'Overlay prestazioni'; } +// Path: externalPlayer +class _TranslationsExternalPlayerIt implements TranslationsExternalPlayerEn { + _TranslationsExternalPlayerIt._(this._root); + + final TranslationsIt _root; // ignore: unused_field + + // Translations + @override String get title => 'Lettore esterno'; + @override String get useExternalPlayer => 'Usa lettore esterno'; + @override String get useExternalPlayerDescription => 'Apri i video in un\'app esterna invece del lettore integrato'; + @override String get selectPlayer => 'Seleziona lettore'; + @override String get systemDefault => 'Predefinito di sistema'; + @override String get addCustomPlayer => 'Aggiungi lettore personalizzato'; + @override String get playerName => 'Nome lettore'; + @override String get playerCommand => 'Comando'; + @override String get playerPackage => 'Nome pacchetto'; + @override String get playerUrlScheme => 'Schema URL'; + @override String get customPlayer => 'Lettore personalizzato'; + @override String get off => 'Disattivato'; + @override String get launchFailed => 'Impossibile aprire il lettore esterno'; + @override String appNotInstalled({required Object name}) => '${name} non è installato'; + @override String get playInExternalPlayer => 'Riproduci in lettore esterno'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsIt implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsIt._(this._root); @@ -1821,6 +1846,21 @@ extension on TranslationsIt { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Uscita audio', 'videoSettings.performanceOverlay' => 'Overlay prestazioni', + 'externalPlayer.title' => 'Lettore esterno', + 'externalPlayer.useExternalPlayer' => 'Usa lettore esterno', + 'externalPlayer.useExternalPlayerDescription' => 'Apri i video in un\'app esterna invece del lettore integrato', + 'externalPlayer.selectPlayer' => 'Seleziona lettore', + 'externalPlayer.systemDefault' => 'Predefinito di sistema', + 'externalPlayer.addCustomPlayer' => 'Aggiungi lettore personalizzato', + 'externalPlayer.playerName' => 'Nome lettore', + 'externalPlayer.playerCommand' => 'Comando', + 'externalPlayer.playerPackage' => 'Nome pacchetto', + 'externalPlayer.playerUrlScheme' => 'Schema URL', + 'externalPlayer.customPlayer' => 'Lettore personalizzato', + 'externalPlayer.off' => 'Disattivato', + 'externalPlayer.launchFailed' => 'Impossibile aprire il lettore esterno', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} non è installato', + 'externalPlayer.playInExternalPlayer' => 'Riproduci in lettore esterno', _ => null, }; } diff --git a/lib/i18n/strings_ko.g.dart b/lib/i18n/strings_ko.g.dart index 1b1b606f..e23a0461 100644 --- a/lib/i18n/strings_ko.g.dart +++ b/lib/i18n/strings_ko.g.dart @@ -72,6 +72,7 @@ class TranslationsKo with BaseTranslations implements T @override late final _TranslationsShadersKo shaders = _TranslationsShadersKo._(_root); @override late final _TranslationsCompanionRemoteKo companionRemote = _TranslationsCompanionRemoteKo._(_root); @override late final _TranslationsVideoSettingsKo videoSettings = _TranslationsVideoSettingsKo._(_root); + @override late final _TranslationsExternalPlayerKo externalPlayer = _TranslationsExternalPlayerKo._(_root); } // Path: app @@ -961,6 +962,30 @@ class _TranslationsVideoSettingsKo implements TranslationsVideoSettingsEn { @override String get performanceOverlay => '성능 오버레이'; } +// Path: externalPlayer +class _TranslationsExternalPlayerKo implements TranslationsExternalPlayerEn { + _TranslationsExternalPlayerKo._(this._root); + + final TranslationsKo _root; // ignore: unused_field + + // Translations + @override String get title => '외부 플레이어'; + @override String get useExternalPlayer => '외부 플레이어 사용'; + @override String get useExternalPlayerDescription => '내장 플레이어 대신 외부 앱에서 동영상 열기'; + @override String get selectPlayer => '플레이어 선택'; + @override String get systemDefault => '시스템 기본값'; + @override String get addCustomPlayer => '사용자 정의 플레이어 추가'; + @override String get playerName => '플레이어 이름'; + @override String get playerCommand => '명령어'; + @override String get playerPackage => '패키지 이름'; + @override String get playerUrlScheme => 'URL 스킴'; + @override String get customPlayer => '사용자 정의 플레이어'; + @override String get off => '꺼짐'; + @override String get launchFailed => '외부 플레이어를 열 수 없습니다'; + @override String appNotInstalled({required Object name}) => '${name}이(가) 설치되어 있지 않습니다'; + @override String get playInExternalPlayer => '외부 플레이어에서 재생'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsKo implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsKo._(this._root); @@ -1821,6 +1846,21 @@ extension on TranslationsKo { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => '오디오 출력', 'videoSettings.performanceOverlay' => '성능 오버레이', + 'externalPlayer.title' => '외부 플레이어', + 'externalPlayer.useExternalPlayer' => '외부 플레이어 사용', + 'externalPlayer.useExternalPlayerDescription' => '내장 플레이어 대신 외부 앱에서 동영상 열기', + 'externalPlayer.selectPlayer' => '플레이어 선택', + 'externalPlayer.systemDefault' => '시스템 기본값', + 'externalPlayer.addCustomPlayer' => '사용자 정의 플레이어 추가', + 'externalPlayer.playerName' => '플레이어 이름', + 'externalPlayer.playerCommand' => '명령어', + 'externalPlayer.playerPackage' => '패키지 이름', + 'externalPlayer.playerUrlScheme' => 'URL 스킴', + 'externalPlayer.customPlayer' => '사용자 정의 플레이어', + 'externalPlayer.off' => '꺼짐', + 'externalPlayer.launchFailed' => '외부 플레이어를 열 수 없습니다', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name}이(가) 설치되어 있지 않습니다', + 'externalPlayer.playInExternalPlayer' => '외부 플레이어에서 재생', _ => null, }; } diff --git a/lib/i18n/strings_nl.g.dart b/lib/i18n/strings_nl.g.dart index 2597674a..53b5585d 100644 --- a/lib/i18n/strings_nl.g.dart +++ b/lib/i18n/strings_nl.g.dart @@ -72,6 +72,7 @@ class TranslationsNl with BaseTranslations implements T @override late final _TranslationsShadersNl shaders = _TranslationsShadersNl._(_root); @override late final _TranslationsCompanionRemoteNl companionRemote = _TranslationsCompanionRemoteNl._(_root); @override late final _TranslationsVideoSettingsNl videoSettings = _TranslationsVideoSettingsNl._(_root); + @override late final _TranslationsExternalPlayerNl externalPlayer = _TranslationsExternalPlayerNl._(_root); } // Path: app @@ -961,6 +962,30 @@ class _TranslationsVideoSettingsNl implements TranslationsVideoSettingsEn { @override String get performanceOverlay => 'Prestatie-overlay'; } +// Path: externalPlayer +class _TranslationsExternalPlayerNl implements TranslationsExternalPlayerEn { + _TranslationsExternalPlayerNl._(this._root); + + final TranslationsNl _root; // ignore: unused_field + + // Translations + @override String get title => 'Externe speler'; + @override String get useExternalPlayer => 'Externe speler gebruiken'; + @override String get useExternalPlayerDescription => 'Open video\'s in een externe app in plaats van de ingebouwde speler'; + @override String get selectPlayer => 'Speler selecteren'; + @override String get systemDefault => 'Systeemstandaard'; + @override String get addCustomPlayer => 'Aangepaste speler toevoegen'; + @override String get playerName => 'Spelernaam'; + @override String get playerCommand => 'Commando'; + @override String get playerPackage => 'Pakketnaam'; + @override String get playerUrlScheme => 'URL-schema'; + @override String get customPlayer => 'Aangepaste speler'; + @override String get off => 'Uit'; + @override String get launchFailed => 'Kan externe speler niet openen'; + @override String appNotInstalled({required Object name}) => '${name} is niet geïnstalleerd'; + @override String get playInExternalPlayer => 'Afspelen in externe speler'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsNl implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsNl._(this._root); @@ -1821,6 +1846,21 @@ extension on TranslationsNl { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Audio-uitvoer', 'videoSettings.performanceOverlay' => 'Prestatie-overlay', + 'externalPlayer.title' => 'Externe speler', + 'externalPlayer.useExternalPlayer' => 'Externe speler gebruiken', + 'externalPlayer.useExternalPlayerDescription' => 'Open video\'s in een externe app in plaats van de ingebouwde speler', + 'externalPlayer.selectPlayer' => 'Speler selecteren', + 'externalPlayer.systemDefault' => 'Systeemstandaard', + 'externalPlayer.addCustomPlayer' => 'Aangepaste speler toevoegen', + 'externalPlayer.playerName' => 'Spelernaam', + 'externalPlayer.playerCommand' => 'Commando', + 'externalPlayer.playerPackage' => 'Pakketnaam', + 'externalPlayer.playerUrlScheme' => 'URL-schema', + 'externalPlayer.customPlayer' => 'Aangepaste speler', + 'externalPlayer.off' => 'Uit', + 'externalPlayer.launchFailed' => 'Kan externe speler niet openen', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} is niet geïnstalleerd', + 'externalPlayer.playInExternalPlayer' => 'Afspelen in externe speler', _ => null, }; } diff --git a/lib/i18n/strings_sv.g.dart b/lib/i18n/strings_sv.g.dart index 48fbcf83..638329d1 100644 --- a/lib/i18n/strings_sv.g.dart +++ b/lib/i18n/strings_sv.g.dart @@ -72,6 +72,7 @@ class TranslationsSv with BaseTranslations implements T @override late final _TranslationsShadersSv shaders = _TranslationsShadersSv._(_root); @override late final _TranslationsCompanionRemoteSv companionRemote = _TranslationsCompanionRemoteSv._(_root); @override late final _TranslationsVideoSettingsSv videoSettings = _TranslationsVideoSettingsSv._(_root); + @override late final _TranslationsExternalPlayerSv externalPlayer = _TranslationsExternalPlayerSv._(_root); } // Path: app @@ -961,6 +962,30 @@ class _TranslationsVideoSettingsSv implements TranslationsVideoSettingsEn { @override String get performanceOverlay => 'Prestandaöverlägg'; } +// Path: externalPlayer +class _TranslationsExternalPlayerSv implements TranslationsExternalPlayerEn { + _TranslationsExternalPlayerSv._(this._root); + + final TranslationsSv _root; // ignore: unused_field + + // Translations + @override String get title => 'Extern spelare'; + @override String get useExternalPlayer => 'Använd extern spelare'; + @override String get useExternalPlayerDescription => 'Öppna videor i en extern app istället för den inbyggda spelaren'; + @override String get selectPlayer => 'Välj spelare'; + @override String get systemDefault => 'Systemstandard'; + @override String get addCustomPlayer => 'Lägg till anpassad spelare'; + @override String get playerName => 'Spelarnamn'; + @override String get playerCommand => 'Kommando'; + @override String get playerPackage => 'Paketnamn'; + @override String get playerUrlScheme => 'URL-schema'; + @override String get customPlayer => 'Anpassad spelare'; + @override String get off => 'Av'; + @override String get launchFailed => 'Kunde inte öppna extern spelare'; + @override String appNotInstalled({required Object name}) => '${name} är inte installerad'; + @override String get playInExternalPlayer => 'Spela i extern spelare'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsSv implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsSv._(this._root); @@ -1821,6 +1846,21 @@ extension on TranslationsSv { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Ljudutgång', 'videoSettings.performanceOverlay' => 'Prestandaöverlägg', + 'externalPlayer.title' => 'Extern spelare', + 'externalPlayer.useExternalPlayer' => 'Använd extern spelare', + 'externalPlayer.useExternalPlayerDescription' => 'Öppna videor i en extern app istället för den inbyggda spelaren', + 'externalPlayer.selectPlayer' => 'Välj spelare', + 'externalPlayer.systemDefault' => 'Systemstandard', + 'externalPlayer.addCustomPlayer' => 'Lägg till anpassad spelare', + 'externalPlayer.playerName' => 'Spelarnamn', + 'externalPlayer.playerCommand' => 'Kommando', + 'externalPlayer.playerPackage' => 'Paketnamn', + 'externalPlayer.playerUrlScheme' => 'URL-schema', + 'externalPlayer.customPlayer' => 'Anpassad spelare', + 'externalPlayer.off' => 'Av', + 'externalPlayer.launchFailed' => 'Kunde inte öppna extern spelare', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} är inte installerad', + 'externalPlayer.playInExternalPlayer' => 'Spela i extern spelare', _ => null, }; } diff --git a/lib/i18n/strings_zh.g.dart b/lib/i18n/strings_zh.g.dart index 3b1a6380..5b1e3f6c 100644 --- a/lib/i18n/strings_zh.g.dart +++ b/lib/i18n/strings_zh.g.dart @@ -72,6 +72,7 @@ class TranslationsZh with BaseTranslations implements T @override late final _TranslationsShadersZh shaders = _TranslationsShadersZh._(_root); @override late final _TranslationsCompanionRemoteZh companionRemote = _TranslationsCompanionRemoteZh._(_root); @override late final _TranslationsVideoSettingsZh videoSettings = _TranslationsVideoSettingsZh._(_root); + @override late final _TranslationsExternalPlayerZh externalPlayer = _TranslationsExternalPlayerZh._(_root); } // Path: app @@ -961,6 +962,30 @@ class _TranslationsVideoSettingsZh implements TranslationsVideoSettingsEn { @override String get performanceOverlay => '性能监控'; } +// Path: externalPlayer +class _TranslationsExternalPlayerZh implements TranslationsExternalPlayerEn { + _TranslationsExternalPlayerZh._(this._root); + + final TranslationsZh _root; // ignore: unused_field + + // Translations + @override String get title => '外部播放器'; + @override String get useExternalPlayer => '使用外部播放器'; + @override String get useExternalPlayerDescription => '在外部应用中打开视频,而不是使用内置播放器'; + @override String get selectPlayer => '选择播放器'; + @override String get systemDefault => '系统默认'; + @override String get addCustomPlayer => '添加自定义播放器'; + @override String get playerName => '播放器名称'; + @override String get playerCommand => '命令'; + @override String get playerPackage => '包名'; + @override String get playerUrlScheme => 'URL 方案'; + @override String get customPlayer => '自定义播放器'; + @override String get off => '关闭'; + @override String get launchFailed => '无法打开外部播放器'; + @override String appNotInstalled({required Object name}) => '${name} 未安装'; + @override String get playInExternalPlayer => '在外部播放器中播放'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsZh implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsZh._(this._root); @@ -1821,6 +1846,21 @@ extension on TranslationsZh { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => '音频输出', 'videoSettings.performanceOverlay' => '性能监控', + 'externalPlayer.title' => '外部播放器', + 'externalPlayer.useExternalPlayer' => '使用外部播放器', + 'externalPlayer.useExternalPlayerDescription' => '在外部应用中打开视频,而不是使用内置播放器', + 'externalPlayer.selectPlayer' => '选择播放器', + 'externalPlayer.systemDefault' => '系统默认', + 'externalPlayer.addCustomPlayer' => '添加自定义播放器', + 'externalPlayer.playerName' => '播放器名称', + 'externalPlayer.playerCommand' => '命令', + 'externalPlayer.playerPackage' => '包名', + 'externalPlayer.playerUrlScheme' => 'URL 方案', + 'externalPlayer.customPlayer' => '自定义播放器', + 'externalPlayer.off' => '关闭', + 'externalPlayer.launchFailed' => '无法打开外部播放器', + 'externalPlayer.appNotInstalled' => ({required Object name}) => '${name} 未安装', + 'externalPlayer.playInExternalPlayer' => '在外部播放器中播放', _ => null, }; } diff --git a/lib/i18n/sv.i18n.json b/lib/i18n/sv.i18n.json index bb23c980..d0590a67 100644 --- a/lib/i18n/sv.i18n.json +++ b/lib/i18n/sv.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "Ljudutgång", "performanceOverlay": "Prestandaöverlägg" + }, + "externalPlayer": { + "title": "Extern spelare", + "useExternalPlayer": "Använd extern spelare", + "useExternalPlayerDescription": "Öppna videor i en extern app istället för den inbyggda spelaren", + "selectPlayer": "Välj spelare", + "systemDefault": "Systemstandard", + "addCustomPlayer": "Lägg till anpassad spelare", + "playerName": "Spelarnamn", + "playerCommand": "Kommando", + "playerPackage": "Paketnamn", + "playerUrlScheme": "URL-schema", + "customPlayer": "Anpassad spelare", + "off": "Av", + "launchFailed": "Kunde inte öppna extern spelare", + "appNotInstalled": "${name} är inte installerad", + "playInExternalPlayer": "Spela i extern spelare" } } diff --git a/lib/i18n/zh.i18n.json b/lib/i18n/zh.i18n.json index f3c30837..3dff9b66 100644 --- a/lib/i18n/zh.i18n.json +++ b/lib/i18n/zh.i18n.json @@ -758,5 +758,22 @@ "hdr": "HDR", "audioOutput": "音频输出", "performanceOverlay": "性能监控" + }, + "externalPlayer": { + "title": "外部播放器", + "useExternalPlayer": "使用外部播放器", + "useExternalPlayerDescription": "在外部应用中打开视频,而不是使用内置播放器", + "selectPlayer": "选择播放器", + "systemDefault": "系统默认", + "addCustomPlayer": "添加自定义播放器", + "playerName": "播放器名称", + "playerCommand": "命令", + "playerPackage": "包名", + "playerUrlScheme": "URL 方案", + "customPlayer": "自定义播放器", + "off": "关闭", + "launchFailed": "无法打开外部播放器", + "appNotInstalled": "${name} 未安装", + "playInExternalPlayer": "在外部播放器中播放" } } diff --git a/lib/models/external_player_models.dart b/lib/models/external_player_models.dart new file mode 100644 index 00000000..9d6f59d9 --- /dev/null +++ b/lib/models/external_player_models.dart @@ -0,0 +1,238 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:url_launcher/url_launcher.dart'; + +import '../utils/app_logger.dart'; + +typedef PlayerLauncher = Future Function(String url); + +enum CustomPlayerType { command, urlScheme } + +class ExternalPlayer { + final String id; + final String name; + final String? iconAsset; + final bool isAvailable; + final PlayerLauncher launch; + final bool isCustom; + final String? customValue; // Only for custom player serialization + final CustomPlayerType? customType; + + ExternalPlayer({ + required this.id, + required this.name, + this.iconAsset, + this.isAvailable = true, + required this.launch, + this.isCustom = false, + this.customValue, + this.customType, + }); + + factory ExternalPlayer.custom({ + required String id, + required String name, + required String value, + required CustomPlayerType type, + }) { + return ExternalPlayer( + id: id, + name: name, + isCustom: true, + customValue: value, + customType: type, + launch: (url) => _launchCustom(value, url, type), + ); + } + + factory ExternalPlayer.fromJson(Map json) { + final id = json['id'] as String; + final known = KnownPlayers.findById(id); + if (known != null) return known; + return ExternalPlayer.custom( + id: id, + name: json['name'] as String, + value: json['customValue'] as String? ?? '', + type: json['customType'] == 'urlScheme' ? CustomPlayerType.urlScheme : CustomPlayerType.command, + ); + } + + Map toJson() => { + 'id': id, + 'name': name, + if (isCustom) 'isCustom': true, + if (customValue != null) 'customValue': customValue, + if (customType != null) 'customType': customType == CustomPlayerType.urlScheme ? 'urlScheme' : 'command', + }; + + String toJsonString() => json.encode(toJson()); + + static ExternalPlayer fromJsonString(String jsonString) => + ExternalPlayer.fromJson(json.decode(jsonString) as Map); + + @override + bool operator ==(Object other) => + identical(this, other) || other is ExternalPlayer && runtimeType == other.runtimeType && id == other.id; + + @override + int get hashCode => id.hashCode; +} + +// --- Launch helpers --- + +Future _launchWithUrl(String url) async { + return launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication); +} + +Future _launchAndroidIntent(String url, {required String package}) async { + final intentUri = Uri.parse( + 'intent:$url#Intent;' + 'action=android.intent.action.VIEW;' + 'type=video/*;' + 'package=$package;' + 'end', + ); + try { + return await launchUrl(intentUri, mode: LaunchMode.externalApplication); + } catch (_) { + return _launchWithUrl(url); + } +} + +Future _launchUrlScheme(String scheme, String url) async { + final playerUrl = scheme.contains('url=') ? '$scheme${Uri.encodeComponent(url)}' : '$scheme$url'; + final uri = Uri.parse(playerUrl); + if (await canLaunchUrl(uri)) { + return launchUrl(uri, mode: LaunchMode.externalApplication); + } + return false; +} + +Future _launchMacApp(String appName, String url) async { + try { + await Process.start('open', ['-a', appName, url], mode: ProcessStartMode.detached); + return true; + } catch (e) { + appLogger.w('Failed to launch $appName via open -a', error: e); + return false; + } +} + +Future _launchCommand(String command, String url) async { + try { + final result = await Process.start(command, [url], mode: ProcessStartMode.detached); + appLogger.d('Launched $command with PID: ${result.pid}'); + return true; + } catch (e) { + appLogger.w('Failed to launch $command', error: e); + return false; + } +} + +Future _launchCustom(String value, String url, CustomPlayerType type) async { + if (type == CustomPlayerType.urlScheme) { + return _launchUrlScheme(value, url); + } + // Command type + if (Platform.isAndroid) { + return _launchAndroidIntent(url, package: value); + } else if (Platform.isMacOS) { + // Try PATH first (e.g. mpv), fall back to open -a (e.g. VLC) + if (await _launchCommand(value, url)) return true; + return _launchMacApp(value, url); + } else { + return _launchCommand(value, url); + } +} + +// --- Known Players --- + +class KnownPlayers { + static final systemDefault = ExternalPlayer(id: 'system_default', name: 'System Default', launch: _launchWithUrl); + + static final _allPlayers = [ + systemDefault, + ExternalPlayer( + id: 'vlc', + name: 'VLC', + iconAsset: 'assets/player_icons/vlc.svg', + isAvailable: Platform.isAndroid || Platform.isIOS || Platform.isMacOS || Platform.isLinux || Platform.isWindows, + launch: (url) async { + if (Platform.isAndroid) return _launchAndroidIntent(url, package: 'org.videolan.vlc'); + if (Platform.isIOS) return _launchUrlScheme('vlc://', url); + if (Platform.isMacOS) return _launchMacApp('VLC', url); + return _launchCommand('vlc', url); + }, + ), + ExternalPlayer( + id: 'mpv', + name: 'mpv', + iconAsset: 'assets/player_icons/mpv.svg', + isAvailable: Platform.isAndroid || Platform.isMacOS || Platform.isLinux || Platform.isWindows, + launch: (url) async { + if (Platform.isAndroid) return _launchAndroidIntent(url, package: 'is.xyz.mpv'); + return _launchCommand('mpv', url); + }, + ), + ExternalPlayer( + id: 'iina', + name: 'IINA', + iconAsset: 'assets/player_icons/iina.png', + isAvailable: Platform.isMacOS, + launch: (url) => _launchUrlScheme('iina://weblink?url=', url), + ), + ExternalPlayer( + id: 'mx_player', + name: 'MX Player', + iconAsset: 'assets/player_icons/mx_player.svg', + isAvailable: Platform.isAndroid, + launch: (url) => _launchAndroidIntent(url, package: 'com.mxtech.videoplayer.ad'), + ), + ExternalPlayer( + id: 'just_player', + name: 'Just Player', + iconAsset: 'assets/player_icons/just_player.png', + isAvailable: Platform.isAndroid, + launch: (url) => _launchAndroidIntent(url, package: 'com.brouken.player'), + ), + ExternalPlayer( + id: 'infuse', + name: 'Infuse', + iconAsset: 'assets/player_icons/infuse.png', + isAvailable: Platform.isIOS, + launch: (url) => _launchUrlScheme('infuse://x-callback-url/play?url=', url), + ), + ExternalPlayer( + id: 'potplayer', + name: 'PotPlayer', + iconAsset: 'assets/player_icons/potplayer.png', + isAvailable: Platform.isWindows, + launch: (url) async { + if (await _launchUrlScheme('potplayer://', url)) return true; + return _launchCommand('PotPlayerMini64', url); + }, + ), + ExternalPlayer( + id: 'celluloid', + name: 'Celluloid', + iconAsset: 'assets/player_icons/celluloid.svg', + isAvailable: Platform.isLinux, + launch: (url) => _launchCommand('celluloid', url), + ), + ]; + + /// Get players available on the current platform + static List getForCurrentPlatform() { + return _allPlayers.where((p) => p.isAvailable).toList(); + } + + /// Find a known player by ID + static ExternalPlayer? findById(String id) { + try { + return _allPlayers.firstWhere((p) => p.id == id); + } catch (_) { + return null; + } + } +} diff --git a/lib/screens/settings/external_player_screen.dart b/lib/screens/settings/external_player_screen.dart new file mode 100644 index 00000000..a3ca5980 --- /dev/null +++ b/lib/screens/settings/external_player_screen.dart @@ -0,0 +1,265 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:plezy/widgets/app_icon.dart'; +import 'package:material_symbols_icons/symbols.dart'; +import '../../i18n/strings.g.dart'; +import '../../models/external_player_models.dart'; +import '../../services/settings_service.dart'; +import '../../widgets/desktop_app_bar.dart'; + +class ExternalPlayerScreen extends StatefulWidget { + const ExternalPlayerScreen({super.key}); + + @override + State createState() => _ExternalPlayerScreenState(); +} + +class _ExternalPlayerScreenState extends State { + late SettingsService _settingsService; + bool _isLoading = true; + + bool _useExternalPlayer = false; + ExternalPlayer _selectedPlayer = KnownPlayers.systemDefault; + List _customPlayers = []; + + @override + void initState() { + super.initState(); + _loadSettings(); + } + + Future _loadSettings() async { + _settingsService = await SettingsService.getInstance(); + + setState(() { + _useExternalPlayer = _settingsService.getUseExternalPlayer(); + _selectedPlayer = _settingsService.getSelectedExternalPlayer(); + _customPlayers = _settingsService.getCustomExternalPlayers(); + _isLoading = false; + }); + } + + @override + Widget build(BuildContext context) { + if (_isLoading) { + return const Scaffold(body: Center(child: CircularProgressIndicator())); + } + + final knownPlayers = KnownPlayers.getForCurrentPlatform(); + + return Scaffold( + body: CustomScrollView( + slivers: [ + CustomAppBar(title: Text(t.externalPlayer.title), pinned: true), + SliverPadding( + padding: const EdgeInsets.all(16), + sliver: SliverList( + delegate: SliverChildListDelegate([ + Card( + child: SwitchListTile( + secondary: const AppIcon(Symbols.open_in_new_rounded, fill: 1), + title: Text(t.externalPlayer.useExternalPlayer), + subtitle: Text(t.externalPlayer.useExternalPlayerDescription), + value: _useExternalPlayer, + onChanged: (value) async { + setState(() => _useExternalPlayer = value); + await _settingsService.setUseExternalPlayer(value); + }, + ), + ), + if (_useExternalPlayer) ...[ + const SizedBox(height: 16), + Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(16), + child: Text( + t.externalPlayer.selectPlayer, + style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), + ), + ), + // Known players + ...knownPlayers.map((player) => _buildPlayerTile(player)), + // Custom players + if (_customPlayers.isNotEmpty) const Divider(), + ..._customPlayers.map((player) => _buildPlayerTile(player, isCustom: true)), + // Add custom player button + const Divider(), + ListTile( + leading: const AppIcon(Symbols.add_rounded, fill: 1), + title: Text(t.externalPlayer.addCustomPlayer), + onTap: _showAddCustomPlayerDialog, + ), + ], + ), + ), + ], + ]), + ), + ), + ], + ), + ); + } + + Widget _buildPlayerTile(ExternalPlayer player, {bool isCustom = false}) { + final isSelected = _selectedPlayer.id == player.id; + + Widget leading; + if (player.iconAsset != null) { + leading = ClipRRect( + borderRadius: BorderRadius.circular(6), + child: player.iconAsset!.endsWith('.svg') + ? SvgPicture.asset(player.iconAsset!, width: 32, height: 32) + : Image.asset(player.iconAsset!, width: 32, height: 32, errorBuilder: (_, __, ___) { + return const AppIcon(Symbols.play_circle_rounded, fill: 1, size: 32); + }), + ); + } else if (player.id == 'system_default') { + leading = const AppIcon(Symbols.open_in_new_rounded, fill: 1, size: 32); + } else { + leading = const AppIcon(Symbols.play_circle_rounded, fill: 1, size: 32); + } + + return ListTile( + leading: leading, + title: Text(player.id == 'system_default' ? t.externalPlayer.systemDefault : player.name), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (isCustom) + IconButton( + icon: const AppIcon(Symbols.delete_rounded, fill: 1, size: 20), + onPressed: () => _deleteCustomPlayer(player), + ), + AppIcon( + isSelected ? Symbols.radio_button_checked_rounded : Symbols.radio_button_unchecked_rounded, + fill: 1, + color: isSelected ? Theme.of(context).colorScheme.primary : null, + ), + ], + ), + onTap: () async { + setState(() => _selectedPlayer = player); + await _settingsService.setSelectedExternalPlayer(player); + }, + ); + } + + Future _deleteCustomPlayer(ExternalPlayer player) async { + await _settingsService.removeCustomExternalPlayer(player.id); + setState(() { + _customPlayers.removeWhere((p) => p.id == player.id); + _selectedPlayer = _settingsService.getSelectedExternalPlayer(); + }); + } + + Future _showAddCustomPlayerDialog() async { + final nameController = TextEditingController(); + final valueController = TextEditingController(); + var selectedType = CustomPlayerType.command; + + final result = await showDialog( + context: context, + builder: (context) => StatefulBuilder( + builder: (context, setDialogState) { + final isUrlScheme = selectedType == CustomPlayerType.urlScheme; + final String fieldLabel; + final String fieldHint; + if (isUrlScheme) { + fieldLabel = t.externalPlayer.playerUrlScheme; + fieldHint = 'myplayer://play?url='; + } else if (Platform.isAndroid) { + fieldLabel = t.externalPlayer.playerPackage; + fieldHint = 'com.example.player'; + } else { + fieldLabel = t.externalPlayer.playerCommand; + fieldHint = Platform.isMacOS ? 'mpv' : '/usr/bin/player'; + } + + return AlertDialog( + title: Text(t.externalPlayer.addCustomPlayer), + content: SizedBox( + width: 300, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: nameController, + decoration: InputDecoration( + labelText: t.externalPlayer.playerName, + hintText: 'My Player', + ), + autofocus: true, + textInputAction: TextInputAction.next, + ), + const SizedBox(height: 16), + SizedBox( + width: double.infinity, + child: SegmentedButton( + segments: [ + ButtonSegment( + value: CustomPlayerType.command, + label: Text(Platform.isAndroid + ? t.externalPlayer.playerPackage + : t.externalPlayer.playerCommand), + ), + ButtonSegment( + value: CustomPlayerType.urlScheme, + label: Text(t.externalPlayer.playerUrlScheme), + ), + ], + selected: {selectedType}, + onSelectionChanged: (value) { + setDialogState(() => selectedType = value.first); + }, + ), + ), + const SizedBox(height: 16), + TextField( + controller: valueController, + decoration: InputDecoration( + labelText: fieldLabel, + hintText: fieldHint, + ), + textInputAction: TextInputAction.done, + ), + ], + ), + ), + actions: [ + TextButton(onPressed: () => Navigator.pop(context), child: Text(t.common.cancel)), + FilledButton( + onPressed: () { + if (nameController.text.isNotEmpty && valueController.text.isNotEmpty) { + Navigator.pop(context, true); + } + }, + child: Text(t.common.save), + ), + ], + ); + }, + ), + ); + + if (result != true) return; + + final id = 'custom_${DateTime.now().millisecondsSinceEpoch}'; + final newPlayer = ExternalPlayer.custom( + id: id, + name: nameController.text, + value: valueController.text, + type: selectedType, + ); + + await _settingsService.addCustomExternalPlayer(newPlayer); + setState(() { + _customPlayers.add(newPlayer); + }); + } +} diff --git a/lib/screens/settings/settings_screen.dart b/lib/screens/settings/settings_screen.dart index b4b796fd..79ff93c0 100644 --- a/lib/screens/settings/settings_screen.dart +++ b/lib/screens/settings/settings_screen.dart @@ -31,6 +31,7 @@ import '../../providers/companion_remote_provider.dart'; import '../../screens/companion_remote/mobile_remote_screen.dart'; import '../../widgets/companion_remote/remote_session_dialog.dart'; import 'about_screen.dart'; +import 'external_player_screen.dart'; import 'logs_screen.dart'; import 'mpv_config_screen.dart'; import 'subtitle_styling_screen.dart'; @@ -68,6 +69,7 @@ class _SettingsScreenState extends State with FocusableTab { static const _kShowUnwatchedCount = 'show_unwatched_count'; static const _kRequireProfileSelectionOnOpen = 'require_profile_selection_on_open'; static const _kPlayerBackend = 'player_backend'; + static const _kExternalPlayer = 'external_player'; static const _kHardwareDecoding = 'hardware_decoding'; static const _kMatchContentFrameRate = 'match_content_frame_rate'; static const _kBufferSize = 'buffer_size'; @@ -115,6 +117,8 @@ class _SettingsScreenState extends State with FocusableTab { bool _matchContentFrameRate = false; bool _useExoPlayer = true; // Android only: ExoPlayer vs MPV bool _requireProfileSelectionOnOpen = false; + bool _useExternalPlayer = false; + String _selectedExternalPlayerName = ''; // Update checking state bool _isCheckingForUpdate = false; @@ -182,6 +186,8 @@ class _SettingsScreenState extends State with FocusableTab { _matchContentFrameRate = _settingsService.getMatchContentFrameRate(); _useExoPlayer = _settingsService.getUseExoPlayer(); _requireProfileSelectionOnOpen = _settingsService.getRequireProfileSelectionOnOpen(); + _useExternalPlayer = _settingsService.getUseExternalPlayer(); + _selectedExternalPlayerName = _settingsService.getSelectedExternalPlayer().name; _isLoading = false; }); } @@ -410,6 +416,22 @@ class _SettingsScreenState extends State with FocusableTab { trailing: const AppIcon(Symbols.chevron_right_rounded, fill: 1), onTap: () => _showPlayerBackendDialog(), ), + ListTile( + focusNode: _focusTracker.get(_kExternalPlayer), + leading: const AppIcon(Symbols.open_in_new_rounded, fill: 1), + title: Text(t.externalPlayer.title), + subtitle: Text(_useExternalPlayer ? _selectedExternalPlayerName : t.externalPlayer.off), + trailing: const AppIcon(Symbols.chevron_right_rounded, fill: 1), + onTap: () async { + await Navigator.push(context, MaterialPageRoute(builder: (context) => const ExternalPlayerScreen())); + // Reload to reflect any changes + final s = await settings.SettingsService.getInstance(); + setState(() { + _useExternalPlayer = s.getUseExternalPlayer(); + _selectedExternalPlayerName = s.getSelectedExternalPlayer().name; + }); + }, + ), SwitchListTile( focusNode: _focusTracker.get(_kHardwareDecoding), secondary: const AppIcon(Symbols.hardware_rounded, fill: 1), diff --git a/lib/services/external_player_service.dart b/lib/services/external_player_service.dart new file mode 100644 index 00000000..1fbddbf9 --- /dev/null +++ b/lib/services/external_player_service.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +import '../models/external_player_models.dart'; +import '../models/plex_metadata.dart'; +import '../utils/app_logger.dart'; +import '../utils/snackbar_helper.dart'; +import '../i18n/strings.g.dart'; +import 'plex_client.dart'; +import 'settings_service.dart'; + +class ExternalPlayerService { + static Future launch({ + required BuildContext context, + required PlexMetadata metadata, + required PlexClient client, + int mediaIndex = 0, + }) async { + try { + final playbackData = await client.getVideoPlaybackData( + metadata.ratingKey, + mediaIndex: mediaIndex, + ); + + if (!playbackData.hasValidVideoUrl) { + if (context.mounted) { + showErrorSnackBar(context, t.messages.fileInfoNotAvailable); + } + return false; + } + + final videoUrl = playbackData.videoUrl!; + final settings = await SettingsService.getInstance(); + final player = settings.getSelectedExternalPlayer(); + + appLogger.d('Launching external player: ${player.name} with URL: $videoUrl'); + + final launched = await player.launch(videoUrl); + if (!launched && context.mounted) { + showErrorSnackBar(context, t.externalPlayer.appNotInstalled(name: player.name)); + } + return launched; + } catch (e) { + appLogger.e('Failed to launch external player', error: e); + if (context.mounted) { + showErrorSnackBar(context, t.externalPlayer.launchFailed); + } + return false; + } + } +} diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart index f488c917..7744c95e 100644 --- a/lib/services/settings_service.dart +++ b/lib/services/settings_service.dart @@ -4,6 +4,7 @@ import '../models/hotkey_model.dart'; import 'package:plezy/utils/app_logger.dart'; import '../i18n/strings.g.dart'; import '../models/mpv_config_models.dart'; +import '../models/external_player_models.dart'; import 'base_shared_preferences_service.dart'; import '../utils/platform_detector.dart'; @@ -70,6 +71,9 @@ class SettingsService extends BaseSharedPreferencesService { static const String _keyShowUnwatchedCount = 'show_unwatched_count'; static const String _keyGlobalShaderPreset = 'global_shader_preset'; static const String _keyRequireProfileSelectionOnOpen = 'require_profile_selection_on_open'; + static const String _keyUseExternalPlayer = 'use_external_player'; + static const String _keySelectedExternalPlayer = 'selected_external_player'; + static const String _keyCustomExternalPlayers = 'custom_external_players'; SettingsService._(); @@ -1048,6 +1052,61 @@ class SettingsService extends BaseSharedPreferencesService { return prefs.getBool(_keyRequireProfileSelectionOnOpen) ?? false; } + // External Player + Future setUseExternalPlayer(bool enabled) async { + await prefs.setBool(_keyUseExternalPlayer, enabled); + } + + bool getUseExternalPlayer() { + return prefs.getBool(_keyUseExternalPlayer) ?? false; + } + + Future setSelectedExternalPlayer(ExternalPlayer player) async { + await prefs.setString(_keySelectedExternalPlayer, player.toJsonString()); + } + + ExternalPlayer getSelectedExternalPlayer() { + final jsonString = prefs.getString(_keySelectedExternalPlayer); + if (jsonString == null) return KnownPlayers.systemDefault; + try { + return ExternalPlayer.fromJsonString(jsonString); + } catch (_) { + return KnownPlayers.systemDefault; + } + } + + Future setCustomExternalPlayers(List players) async { + final jsonString = json.encode(players.map((p) => p.toJson()).toList()); + await prefs.setString(_keyCustomExternalPlayers, jsonString); + } + + List getCustomExternalPlayers() { + final jsonString = prefs.getString(_keyCustomExternalPlayers); + if (jsonString == null) return []; + try { + final List decoded = json.decode(jsonString); + return decoded.map((e) => ExternalPlayer.fromJson(e as Map)).toList(); + } catch (_) { + return []; + } + } + + Future addCustomExternalPlayer(ExternalPlayer player) async { + final players = getCustomExternalPlayers(); + players.add(player); + await setCustomExternalPlayers(players); + } + + Future removeCustomExternalPlayer(String id) async { + final players = getCustomExternalPlayers(); + players.removeWhere((p) => p.id == id); + await setCustomExternalPlayers(players); + // If the removed player was selected, reset to system default + if (getSelectedExternalPlayer().id == id) { + await setSelectedExternalPlayer(KnownPlayers.systemDefault); + } + } + // Reset all settings to defaults Future resetAllSettings() async { await Future.wait([ @@ -1098,6 +1157,9 @@ class SettingsService extends BaseSharedPreferencesService { prefs.remove(_keyShowUnwatchedCount), prefs.remove(_keyGlobalShaderPreset), prefs.remove(_keyRequireProfileSelectionOnOpen), + prefs.remove(_keyUseExternalPlayer), + prefs.remove(_keySelectedExternalPlayer), + prefs.remove(_keyCustomExternalPlayers), ]); } diff --git a/lib/utils/video_player_navigation.dart b/lib/utils/video_player_navigation.dart index fa30aad3..979b6a06 100644 --- a/lib/utils/video_player_navigation.dart +++ b/lib/utils/video_player_navigation.dart @@ -3,7 +3,9 @@ import 'package:flutter/material.dart'; import '../mpv/mpv.dart'; import '../models/plex_metadata.dart'; import '../screens/video_player_screen.dart'; +import '../services/external_player_service.dart'; import '../services/settings_service.dart'; +import '../utils/provider_extensions.dart'; import 'app_logger.dart'; const String kVideoPlayerRouteName = '/video_player'; @@ -54,6 +56,26 @@ Future navigateToVideoPlayer( } } + // Check if external player is enabled (skip for offline mode) + if (!isOffline) { + try { + final settingsService = await SettingsService.getInstance(); + if (settingsService.getUseExternalPlayer()) { + final client = context.getClientForMetadata(metadata); + final launched = await ExternalPlayerService.launch( + context: context, + metadata: metadata, + client: client, + mediaIndex: mediaIndex, + ); + if (launched) return null; + // Fall through to built-in player on failure + } + } catch (e) { + appLogger.w('External player launch failed, falling back to built-in player', error: e); + } + } + // Prevent stacking an identical video player when already active if (!usePushReplacement && VideoPlayerScreenState.activeRatingKey == metadata.ratingKey && diff --git a/lib/widgets/media_context_menu.dart b/lib/widgets/media_context_menu.dart index 90e2e0d0..d141ffb8 100644 --- a/lib/widgets/media_context_menu.dart +++ b/lib/widgets/media_context_menu.dart @@ -16,6 +16,7 @@ import '../utils/library_refresh_notifier.dart'; import '../utils/snackbar_helper.dart'; import '../utils/dialogs.dart'; import '../utils/focus_utils.dart'; +import '../services/external_player_service.dart'; import '../focus/dpad_navigator.dart'; import '../screens/media_detail_screen.dart'; import '../screens/season_detail_screen.dart'; @@ -217,6 +218,17 @@ class MediaContextMenuState extends State { menuActions.add(_MenuAction(value: 'fileinfo', icon: Symbols.info_rounded, label: t.mediaMenu.fileInfo)); } + // Play in External Player (for episodes and movies) + if (mediaType == PlexMediaType.episode || mediaType == PlexMediaType.movie) { + menuActions.add( + _MenuAction( + value: 'play_external', + icon: Symbols.open_in_new_rounded, + label: t.externalPlayer.playInExternalPlayer, + ), + ); + } + // Download options (for episodes, movies, shows, and seasons) if (mediaType == PlexMediaType.episode || mediaType == PlexMediaType.movie || @@ -417,6 +429,10 @@ class MediaContextMenuState extends State { await _handleDelete(context, isCollection, isPlaylist); break; + case 'play_external': + await _handlePlayExternal(context); + break; + case 'download': await _handleDownload(context); break; @@ -981,6 +997,18 @@ class MediaContextMenuState extends State { } } + /// Handle play in external player action + Future _handlePlayExternal(BuildContext context) async { + final metadata = widget.item as PlexMetadata; + final client = _getClientForItem(); + + await ExternalPlayerService.launch( + context: context, + metadata: metadata, + client: client, + ); + } + /// Handle download action Future _handleDownload(BuildContext context) async { final downloadProvider = Provider.of(context, listen: false); diff --git a/pubspec.lock b/pubspec.lock index 42d82bf7..5a078048 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.4" + android_intent_plus: + dependency: "direct main" + description: + name: android_intent_plus + sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11" + url: "https://pub.dev" + source: hosted + version: "5.3.1" ansicolor: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 10cf5cb0..9289c2b9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -52,6 +52,7 @@ dependencies: dart_discord_presence: ^1.1.0 flutter_svg: ^2.2.3 mobile_scanner: ^6.0.2 + android_intent_plus: ^5.0.2 dev_dependencies: flutter_test: @@ -72,6 +73,7 @@ flutter: - assets/go-noto-current-regular.ttf - assets/shaders/nvscaler/ - assets/shaders/anime4k/ + - assets/player_icons/ - assets/rating_icons/ flutter_launcher_icons: