feat: crash log reporting
This commit is contained in:
@@ -30,6 +30,13 @@ android {
|
|||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
|
|
||||||
|
if (System.getenv("AMAZON") != null) {
|
||||||
|
versionCode = (flutter.versionCode ?: 0) + 3000
|
||||||
|
ndk {
|
||||||
|
abiFilters += listOf("armeabi-v7a", "arm64-v8a")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
|
|||||||
@@ -22,17 +22,17 @@ platform :android do
|
|||||||
debug_info_dir = "./debug-info/#{version_name}+#{version_code}"
|
debug_info_dir = "./debug-info/#{version_name}+#{version_code}"
|
||||||
|
|
||||||
# Build the Flutter app
|
# Build the Flutter app
|
||||||
sh("cd #{ENV['PWD']}/.. && flutter build appbundle --dart-define=ENABLE_IN_APP_REVIEW=true --obfuscate --split-debug-info=#{debug_info_dir}/aab")
|
# sh("cd #{ENV['PWD']}/.. && flutter build appbundle --dart-define=ENABLE_IN_APP_REVIEW=true --obfuscate --split-debug-info=#{debug_info_dir}/aab")
|
||||||
|
|
||||||
upload_to_play_store(
|
# upload_to_play_store(
|
||||||
track: "production",
|
# track: "production",
|
||||||
release_status: "completed",
|
# release_status: "completed",
|
||||||
version_code: version_code,
|
# version_code: version_code,
|
||||||
aab: "../build/app/outputs/bundle/release/app-release.aab"
|
# aab: "../build/app/outputs/bundle/release/app-release.aab"
|
||||||
)
|
# )
|
||||||
|
|
||||||
# Build universal APK for Amazon Appstore (doesn't accept AABs, doesn't auto-target by ABI)
|
# Build universal APK for Amazon Appstore (doesn't accept AABs, excludes x86 via env var)
|
||||||
sh("cd #{ENV['PWD']}/.. && flutter build apk --release --target-platform android-arm,android-arm64 --obfuscate --split-debug-info=#{debug_info_dir}/apk")
|
sh("cd #{ENV['PWD']}/.. && AMAZON=1 flutter build apk --release --obfuscate --split-debug-info=#{debug_info_dir}/apk")
|
||||||
|
|
||||||
upload_to_amazon_appstore(
|
upload_to_amazon_appstore(
|
||||||
apk_paths: [
|
apk_paths: [
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- PromisesObjC (2.4.0)
|
- PromisesObjC (2.4.0)
|
||||||
|
- Sentry/HybridSDK (8.46.0)
|
||||||
|
- sentry_flutter (8.14.2):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- Sentry/HybridSDK (= 8.46.0)
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
@@ -117,6 +122,7 @@ DEPENDENCIES:
|
|||||||
- os_media_controls (from `.symlinks/plugins/os_media_controls/ios`)
|
- os_media_controls (from `.symlinks/plugins/os_media_controls/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
|
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
||||||
@@ -138,6 +144,7 @@ SPEC REPOS:
|
|||||||
- MLKitVision
|
- MLKitVision
|
||||||
- nanopb
|
- nanopb
|
||||||
- PromisesObjC
|
- PromisesObjC
|
||||||
|
- Sentry
|
||||||
- sqlite3
|
- sqlite3
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
@@ -161,6 +168,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
|
sentry_flutter:
|
||||||
|
:path: ".symlinks/plugins/sentry_flutter/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
sqflite_darwin:
|
sqflite_darwin:
|
||||||
@@ -198,6 +207,8 @@ SPEC CHECKSUMS:
|
|||||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||||
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
|
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
|
||||||
|
sentry_flutter: 27892878729f42701297c628eb90e7c6529f3684
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
|
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "Tastenkürzel anpassen",
|
"keyboardShortcutsDescription": "Tastenkürzel anpassen",
|
||||||
"videoPlayerNavigation": "Videoplayer-Navigation",
|
"videoPlayerNavigation": "Videoplayer-Navigation",
|
||||||
"videoPlayerNavigationDescription": "Pfeiltasten zur Navigation der Videoplayer-Steuerung verwenden",
|
"videoPlayerNavigationDescription": "Pfeiltasten zur Navigation der Videoplayer-Steuerung verwenden",
|
||||||
|
"crashReporting": "Absturzberichte",
|
||||||
|
"crashReportingDescription": "Absturzberichte senden, um die App zu verbessern",
|
||||||
"debugLogging": "Debug-Protokollierung",
|
"debugLogging": "Debug-Protokollierung",
|
||||||
"debugLoggingDescription": "Detaillierte Protokolle zur Fehleranalyse aktivieren",
|
"debugLoggingDescription": "Detaillierte Protokolle zur Fehleranalyse aktivieren",
|
||||||
"viewLogs": "Protokolle anzeigen",
|
"viewLogs": "Protokolle anzeigen",
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "Customize keyboard shortcuts",
|
"keyboardShortcutsDescription": "Customize keyboard shortcuts",
|
||||||
"videoPlayerNavigation": "Video Player Navigation",
|
"videoPlayerNavigation": "Video Player Navigation",
|
||||||
"videoPlayerNavigationDescription": "Use arrow keys to navigate video player controls",
|
"videoPlayerNavigationDescription": "Use arrow keys to navigate video player controls",
|
||||||
|
"crashReporting": "Crash Reporting",
|
||||||
|
"crashReportingDescription": "Send crash reports to help improve the app",
|
||||||
"debugLogging": "Debug Logging",
|
"debugLogging": "Debug Logging",
|
||||||
"debugLoggingDescription": "Enable detailed logging for troubleshooting",
|
"debugLoggingDescription": "Enable detailed logging for troubleshooting",
|
||||||
"viewLogs": "View Logs",
|
"viewLogs": "View Logs",
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "Personalizar los atajos de teclado",
|
"keyboardShortcutsDescription": "Personalizar los atajos de teclado",
|
||||||
"videoPlayerNavigation": "Navegación del Reproductor de Video",
|
"videoPlayerNavigation": "Navegación del Reproductor de Video",
|
||||||
"videoPlayerNavigationDescription": "Usar las teclas de flecha para navegar por los controles del reproductor",
|
"videoPlayerNavigationDescription": "Usar las teclas de flecha para navegar por los controles del reproductor",
|
||||||
|
"crashReporting": "Informes de Errores",
|
||||||
|
"crashReportingDescription": "Enviar informes de errores para mejorar la aplicación",
|
||||||
"debugLogging": "Registro de Depuración",
|
"debugLogging": "Registro de Depuración",
|
||||||
"debugLoggingDescription": "Habilitar registros detallados para resolución de problemas",
|
"debugLoggingDescription": "Habilitar registros detallados para resolución de problemas",
|
||||||
"viewLogs": "Ver Logs",
|
"viewLogs": "Ver Logs",
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "Personnaliser les raccourcis clavier",
|
"keyboardShortcutsDescription": "Personnaliser les raccourcis clavier",
|
||||||
"videoPlayerNavigation": "Navigation dans le lecteur vidéo",
|
"videoPlayerNavigation": "Navigation dans le lecteur vidéo",
|
||||||
"videoPlayerNavigationDescription": "Utilisez les touches fléchées pour naviguer dans les commandes du lecteur vidéo.",
|
"videoPlayerNavigationDescription": "Utilisez les touches fléchées pour naviguer dans les commandes du lecteur vidéo.",
|
||||||
|
"crashReporting": "Rapports de plantage",
|
||||||
|
"crashReportingDescription": "Envoyer des rapports de plantage pour améliorer l'application",
|
||||||
"debugLogging": "Journalisation de débogage",
|
"debugLogging": "Journalisation de débogage",
|
||||||
"debugLoggingDescription": "Activer la journalisation détaillée pour le dépannage",
|
"debugLoggingDescription": "Activer la journalisation détaillée pour le dépannage",
|
||||||
"viewLogs": "Voir les logs",
|
"viewLogs": "Voir les logs",
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "Personalizza le scorciatoie da tastiera",
|
"keyboardShortcutsDescription": "Personalizza le scorciatoie da tastiera",
|
||||||
"videoPlayerNavigation": "Navigazione del lettore video",
|
"videoPlayerNavigation": "Navigazione del lettore video",
|
||||||
"videoPlayerNavigationDescription": "Usa i tasti freccia per navigare nei controlli del lettore video",
|
"videoPlayerNavigationDescription": "Usa i tasti freccia per navigare nei controlli del lettore video",
|
||||||
|
"crashReporting": "Segnalazione errori",
|
||||||
|
"crashReportingDescription": "Invia segnalazioni di errori per migliorare l'app",
|
||||||
"debugLogging": "Log di debug",
|
"debugLogging": "Log di debug",
|
||||||
"debugLoggingDescription": "Abilita il logging dettagliato per la risoluzione dei problemi",
|
"debugLoggingDescription": "Abilita il logging dettagliato per la risoluzione dei problemi",
|
||||||
"viewLogs": "Visualizza log",
|
"viewLogs": "Visualizza log",
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "사용자 정의 키보드 단축키",
|
"keyboardShortcutsDescription": "사용자 정의 키보드 단축키",
|
||||||
"videoPlayerNavigation": "비디오 플레이어 탐색",
|
"videoPlayerNavigation": "비디오 플레이어 탐색",
|
||||||
"videoPlayerNavigationDescription": "방향 키를 사용하여 비디오 플레이어 컨트롤 탐색",
|
"videoPlayerNavigationDescription": "방향 키를 사용하여 비디오 플레이어 컨트롤 탐색",
|
||||||
|
"crashReporting": "충돌 보고",
|
||||||
|
"crashReportingDescription": "앱 개선을 위해 충돌 보고서 전송",
|
||||||
"debugLogging": "디버그 로깅",
|
"debugLogging": "디버그 로깅",
|
||||||
"debugLoggingDescription": "문제 해결을 위해 상세 로깅 활성화",
|
"debugLoggingDescription": "문제 해결을 위해 상세 로깅 활성화",
|
||||||
"viewLogs": "로그 보기",
|
"viewLogs": "로그 보기",
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "Pas toetsenbord sneltoetsen aan",
|
"keyboardShortcutsDescription": "Pas toetsenbord sneltoetsen aan",
|
||||||
"videoPlayerNavigation": "Videospeler navigatie",
|
"videoPlayerNavigation": "Videospeler navigatie",
|
||||||
"videoPlayerNavigationDescription": "Gebruik pijltjestoetsen om door de videospeler bediening te navigeren",
|
"videoPlayerNavigationDescription": "Gebruik pijltjestoetsen om door de videospeler bediening te navigeren",
|
||||||
|
"crashReporting": "Crashrapportage",
|
||||||
|
"crashReportingDescription": "Crashrapporten verzenden om de app te verbeteren",
|
||||||
"debugLogging": "Debug logging",
|
"debugLogging": "Debug logging",
|
||||||
"debugLoggingDescription": "Schakel gedetailleerde logging in voor probleemoplossing",
|
"debugLoggingDescription": "Schakel gedetailleerde logging in voor probleemoplossing",
|
||||||
"viewLogs": "Bekijk logs",
|
"viewLogs": "Bekijk logs",
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
/// To regenerate, run: `dart run slang`
|
/// To regenerate, run: `dart run slang`
|
||||||
///
|
///
|
||||||
/// Locales: 9
|
/// Locales: 9
|
||||||
/// Strings: 7173 (797 per locale)
|
/// Strings: 7245 (805 per locale)
|
||||||
///
|
///
|
||||||
/// Built on 2026-02-24 at 21:50 UTC
|
/// Built on 2026-03-02 at 06:26 UTC
|
||||||
|
|
||||||
// coverage:ignore-file
|
// coverage:ignore-file
|
||||||
// ignore_for_file: type=lint, unused_import
|
// ignore_for_file: type=lint, unused_import
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ class _TranslationsSettingsDe implements TranslationsSettingsEn {
|
|||||||
@override String get keyboardShortcutsDescription => 'Tastenkürzel anpassen';
|
@override String get keyboardShortcutsDescription => 'Tastenkürzel anpassen';
|
||||||
@override String get videoPlayerNavigation => 'Videoplayer-Navigation';
|
@override String get videoPlayerNavigation => 'Videoplayer-Navigation';
|
||||||
@override String get videoPlayerNavigationDescription => 'Pfeiltasten zur Navigation der Videoplayer-Steuerung verwenden';
|
@override String get videoPlayerNavigationDescription => 'Pfeiltasten zur Navigation der Videoplayer-Steuerung verwenden';
|
||||||
|
@override String get crashReporting => 'Absturzberichte';
|
||||||
|
@override String get crashReportingDescription => 'Absturzberichte senden, um die App zu verbessern';
|
||||||
@override String get debugLogging => 'Debug-Protokollierung';
|
@override String get debugLogging => 'Debug-Protokollierung';
|
||||||
@override String get debugLoggingDescription => 'Detaillierte Protokolle zur Fehleranalyse aktivieren';
|
@override String get debugLoggingDescription => 'Detaillierte Protokolle zur Fehleranalyse aktivieren';
|
||||||
@override String get viewLogs => 'Protokolle anzeigen';
|
@override String get viewLogs => 'Protokolle anzeigen';
|
||||||
@@ -1441,6 +1443,8 @@ extension on TranslationsDe {
|
|||||||
'settings.keyboardShortcutsDescription' => 'Tastenkürzel anpassen',
|
'settings.keyboardShortcutsDescription' => 'Tastenkürzel anpassen',
|
||||||
'settings.videoPlayerNavigation' => 'Videoplayer-Navigation',
|
'settings.videoPlayerNavigation' => 'Videoplayer-Navigation',
|
||||||
'settings.videoPlayerNavigationDescription' => 'Pfeiltasten zur Navigation der Videoplayer-Steuerung verwenden',
|
'settings.videoPlayerNavigationDescription' => 'Pfeiltasten zur Navigation der Videoplayer-Steuerung verwenden',
|
||||||
|
'settings.crashReporting' => 'Absturzberichte',
|
||||||
|
'settings.crashReportingDescription' => 'Absturzberichte senden, um die App zu verbessern',
|
||||||
'settings.debugLogging' => 'Debug-Protokollierung',
|
'settings.debugLogging' => 'Debug-Protokollierung',
|
||||||
'settings.debugLoggingDescription' => 'Detaillierte Protokolle zur Fehleranalyse aktivieren',
|
'settings.debugLoggingDescription' => 'Detaillierte Protokolle zur Fehleranalyse aktivieren',
|
||||||
'settings.viewLogs' => 'Protokolle anzeigen',
|
'settings.viewLogs' => 'Protokolle anzeigen',
|
||||||
@@ -1487,6 +1491,8 @@ extension on TranslationsDe {
|
|||||||
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
||||||
'settings.discordRichPresence' => 'Discord Rich Presence',
|
'settings.discordRichPresence' => 'Discord Rich Presence',
|
||||||
'settings.discordRichPresenceDescription' => 'Zeige auf Discord, was du gerade schaust',
|
'settings.discordRichPresenceDescription' => 'Zeige auf Discord, was du gerade schaust',
|
||||||
|
'settings.autoPip' => 'Automatisches Bild-in-Bild',
|
||||||
|
'settings.autoPipDescription' => 'Automatisch Bild-in-Bild aktivieren, wenn die App während der Wiedergabe verlassen wird',
|
||||||
'settings.matchContentFrameRate' => 'Inhalts-Bildrate anpassen',
|
'settings.matchContentFrameRate' => 'Inhalts-Bildrate anpassen',
|
||||||
'settings.matchContentFrameRateDescription' => 'Bildwiederholfrequenz des Displays an den Videoinhalt anpassen, reduziert Ruckeln und spart Akku',
|
'settings.matchContentFrameRateDescription' => 'Bildwiederholfrequenz des Displays an den Videoinhalt anpassen, reduziert Ruckeln und spart Akku',
|
||||||
'settings.tunneledPlayback' => 'Tunneled Playback',
|
'settings.tunneledPlayback' => 'Tunneled Playback',
|
||||||
@@ -1808,6 +1814,8 @@ extension on TranslationsDe {
|
|||||||
'liveTv.nowPlaying' => 'Läuft gerade',
|
'liveTv.nowPlaying' => 'Läuft gerade',
|
||||||
'liveTv.noPrograms' => 'Keine Programmdaten verfügbar',
|
'liveTv.noPrograms' => 'Keine Programmdaten verfügbar',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => 'Kanal ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => 'Kanal ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => 'LIVE',
|
'liveTv.live' => 'LIVE',
|
||||||
'liveTv.hd' => 'HD',
|
'liveTv.hd' => 'HD',
|
||||||
'liveTv.premiere' => 'NEU',
|
'liveTv.premiere' => 'NEU',
|
||||||
@@ -1822,8 +1830,6 @@ extension on TranslationsDe {
|
|||||||
'liveTv.evening' => 'Abend',
|
'liveTv.evening' => 'Abend',
|
||||||
'liveTv.lateNight' => 'Spätnacht',
|
'liveTv.lateNight' => 'Spätnacht',
|
||||||
'liveTv.whatsOn' => 'Jetzt im TV',
|
'liveTv.whatsOn' => 'Jetzt im TV',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => 'Kanal ansehen',
|
'liveTv.watchChannel' => 'Kanal ansehen',
|
||||||
'downloads.title' => 'Downloads',
|
'downloads.title' => 'Downloads',
|
||||||
'downloads.manage' => 'Verwalten',
|
'downloads.manage' => 'Verwalten',
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ class TranslationsSettingsEn {
|
|||||||
/// en: 'Hide Spoilers for Unwatched Episodes'
|
/// en: 'Hide Spoilers for Unwatched Episodes'
|
||||||
String get hideSpoilers => 'Hide Spoilers for Unwatched Episodes';
|
String get hideSpoilers => 'Hide Spoilers for Unwatched Episodes';
|
||||||
|
|
||||||
/// en: 'Blur thumbnails and hide descriptions for episodes you haven\'t watched yet'
|
/// en: 'Blur thumbnails and hide descriptions for episodes you haven't watched yet'
|
||||||
String get hideSpoilersDescription => 'Blur thumbnails and hide descriptions for episodes you haven\'t watched yet';
|
String get hideSpoilersDescription => 'Blur thumbnails and hide descriptions for episodes you haven\'t watched yet';
|
||||||
|
|
||||||
/// en: 'Player Backend'
|
/// en: 'Player Backend'
|
||||||
@@ -556,6 +556,12 @@ class TranslationsSettingsEn {
|
|||||||
/// en: 'Use arrow keys to navigate video player controls'
|
/// en: 'Use arrow keys to navigate video player controls'
|
||||||
String get videoPlayerNavigationDescription => 'Use arrow keys to navigate video player controls';
|
String get videoPlayerNavigationDescription => 'Use arrow keys to navigate video player controls';
|
||||||
|
|
||||||
|
/// en: 'Crash Reporting'
|
||||||
|
String get crashReporting => 'Crash Reporting';
|
||||||
|
|
||||||
|
/// en: 'Send crash reports to help improve the app'
|
||||||
|
String get crashReportingDescription => 'Send crash reports to help improve the app';
|
||||||
|
|
||||||
/// en: 'Debug Logging'
|
/// en: 'Debug Logging'
|
||||||
String get debugLogging => 'Debug Logging';
|
String get debugLogging => 'Debug Logging';
|
||||||
|
|
||||||
@@ -2807,7 +2813,6 @@ class TranslationsCompanionRemotePairingEn {
|
|||||||
|
|
||||||
/// en: 'Failed to connect: ${error}'
|
/// en: 'Failed to connect: ${error}'
|
||||||
String failedToConnect({required Object error}) => 'Failed to connect: ${error}';
|
String failedToConnect({required Object error}) => 'Failed to connect: ${error}';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: companionRemote.remote
|
// Path: companionRemote.remote
|
||||||
@@ -3055,6 +3060,8 @@ extension on Translations {
|
|||||||
'settings.keyboardShortcutsDescription' => 'Customize keyboard shortcuts',
|
'settings.keyboardShortcutsDescription' => 'Customize keyboard shortcuts',
|
||||||
'settings.videoPlayerNavigation' => 'Video Player Navigation',
|
'settings.videoPlayerNavigation' => 'Video Player Navigation',
|
||||||
'settings.videoPlayerNavigationDescription' => 'Use arrow keys to navigate video player controls',
|
'settings.videoPlayerNavigationDescription' => 'Use arrow keys to navigate video player controls',
|
||||||
|
'settings.crashReporting' => 'Crash Reporting',
|
||||||
|
'settings.crashReportingDescription' => 'Send crash reports to help improve the app',
|
||||||
'settings.debugLogging' => 'Debug Logging',
|
'settings.debugLogging' => 'Debug Logging',
|
||||||
'settings.debugLoggingDescription' => 'Enable detailed logging for troubleshooting',
|
'settings.debugLoggingDescription' => 'Enable detailed logging for troubleshooting',
|
||||||
'settings.viewLogs' => 'View Logs',
|
'settings.viewLogs' => 'View Logs',
|
||||||
@@ -3424,6 +3431,8 @@ extension on Translations {
|
|||||||
'liveTv.nowPlaying' => 'Now Playing',
|
'liveTv.nowPlaying' => 'Now Playing',
|
||||||
'liveTv.noPrograms' => 'No program data available',
|
'liveTv.noPrograms' => 'No program data available',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => 'Ch. ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => 'Ch. ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => 'LIVE',
|
'liveTv.live' => 'LIVE',
|
||||||
'liveTv.hd' => 'HD',
|
'liveTv.hd' => 'HD',
|
||||||
'liveTv.premiere' => 'NEW',
|
'liveTv.premiere' => 'NEW',
|
||||||
@@ -3438,8 +3447,6 @@ extension on Translations {
|
|||||||
'liveTv.evening' => 'Evening',
|
'liveTv.evening' => 'Evening',
|
||||||
'liveTv.lateNight' => 'Late Night',
|
'liveTv.lateNight' => 'Late Night',
|
||||||
'liveTv.whatsOn' => 'What\'s On',
|
'liveTv.whatsOn' => 'What\'s On',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => 'Watch Channel',
|
'liveTv.watchChannel' => 'Watch Channel',
|
||||||
'collections.title' => 'Collections',
|
'collections.title' => 'Collections',
|
||||||
'collections.collection' => 'Collection',
|
'collections.collection' => 'Collection',
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ class _TranslationsSettingsEs implements TranslationsSettingsEn {
|
|||||||
@override String get keyboardShortcutsDescription => 'Personalizar los atajos de teclado';
|
@override String get keyboardShortcutsDescription => 'Personalizar los atajos de teclado';
|
||||||
@override String get videoPlayerNavigation => 'Navegación del Reproductor de Video';
|
@override String get videoPlayerNavigation => 'Navegación del Reproductor de Video';
|
||||||
@override String get videoPlayerNavigationDescription => 'Usar las teclas de flecha para navegar por los controles del reproductor';
|
@override String get videoPlayerNavigationDescription => 'Usar las teclas de flecha para navegar por los controles del reproductor';
|
||||||
|
@override String get crashReporting => 'Informes de Errores';
|
||||||
|
@override String get crashReportingDescription => 'Enviar informes de errores para mejorar la aplicación';
|
||||||
@override String get debugLogging => 'Registro de Depuración';
|
@override String get debugLogging => 'Registro de Depuración';
|
||||||
@override String get debugLoggingDescription => 'Habilitar registros detallados para resolución de problemas';
|
@override String get debugLoggingDescription => 'Habilitar registros detallados para resolución de problemas';
|
||||||
@override String get viewLogs => 'Ver Logs';
|
@override String get viewLogs => 'Ver Logs';
|
||||||
@@ -1441,6 +1443,8 @@ extension on TranslationsEs {
|
|||||||
'settings.keyboardShortcutsDescription' => 'Personalizar los atajos de teclado',
|
'settings.keyboardShortcutsDescription' => 'Personalizar los atajos de teclado',
|
||||||
'settings.videoPlayerNavigation' => 'Navegación del Reproductor de Video',
|
'settings.videoPlayerNavigation' => 'Navegación del Reproductor de Video',
|
||||||
'settings.videoPlayerNavigationDescription' => 'Usar las teclas de flecha para navegar por los controles del reproductor',
|
'settings.videoPlayerNavigationDescription' => 'Usar las teclas de flecha para navegar por los controles del reproductor',
|
||||||
|
'settings.crashReporting' => 'Informes de Errores',
|
||||||
|
'settings.crashReportingDescription' => 'Enviar informes de errores para mejorar la aplicación',
|
||||||
'settings.debugLogging' => 'Registro de Depuración',
|
'settings.debugLogging' => 'Registro de Depuración',
|
||||||
'settings.debugLoggingDescription' => 'Habilitar registros detallados para resolución de problemas',
|
'settings.debugLoggingDescription' => 'Habilitar registros detallados para resolución de problemas',
|
||||||
'settings.viewLogs' => 'Ver Logs',
|
'settings.viewLogs' => 'Ver Logs',
|
||||||
@@ -1487,6 +1491,8 @@ extension on TranslationsEs {
|
|||||||
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
||||||
'settings.discordRichPresence' => 'Presencia de Discord',
|
'settings.discordRichPresence' => 'Presencia de Discord',
|
||||||
'settings.discordRichPresenceDescription' => 'Mostrar lo que estás viendo en Discord',
|
'settings.discordRichPresenceDescription' => 'Mostrar lo que estás viendo en Discord',
|
||||||
|
'settings.autoPip' => 'Imagen en imagen automática',
|
||||||
|
'settings.autoPipDescription' => 'Activar automáticamente imagen en imagen al salir de la app durante la reproducción',
|
||||||
'settings.matchContentFrameRate' => 'Ajustar frecuencia de actualización',
|
'settings.matchContentFrameRate' => 'Ajustar frecuencia de actualización',
|
||||||
'settings.matchContentFrameRateDescription' => 'Ajustar la frecuencia de actualización de la pantalla para que coincida con el video, reduciendo tirones y ahorrando batería',
|
'settings.matchContentFrameRateDescription' => 'Ajustar la frecuencia de actualización de la pantalla para que coincida con el video, reduciendo tirones y ahorrando batería',
|
||||||
'settings.tunneledPlayback' => 'Tunneled Playback',
|
'settings.tunneledPlayback' => 'Tunneled Playback',
|
||||||
@@ -1808,6 +1814,8 @@ extension on TranslationsEs {
|
|||||||
'liveTv.nowPlaying' => 'Reproduciendo ahora',
|
'liveTv.nowPlaying' => 'Reproduciendo ahora',
|
||||||
'liveTv.noPrograms' => 'No hay datos de programación disponibles',
|
'liveTv.noPrograms' => 'No hay datos de programación disponibles',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => 'Canal ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => 'Canal ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => 'EN VIVO',
|
'liveTv.live' => 'EN VIVO',
|
||||||
'liveTv.hd' => 'HD',
|
'liveTv.hd' => 'HD',
|
||||||
'liveTv.premiere' => 'NUEVO',
|
'liveTv.premiere' => 'NUEVO',
|
||||||
@@ -1822,8 +1830,6 @@ extension on TranslationsEs {
|
|||||||
'liveTv.evening' => 'Noche',
|
'liveTv.evening' => 'Noche',
|
||||||
'liveTv.lateNight' => 'Trasnoche',
|
'liveTv.lateNight' => 'Trasnoche',
|
||||||
'liveTv.whatsOn' => 'En emisión',
|
'liveTv.whatsOn' => 'En emisión',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => 'Ver canal',
|
'liveTv.watchChannel' => 'Ver canal',
|
||||||
'collections.title' => 'Colecciones',
|
'collections.title' => 'Colecciones',
|
||||||
'collections.collection' => 'Colección',
|
'collections.collection' => 'Colección',
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ class _TranslationsSettingsFr implements TranslationsSettingsEn {
|
|||||||
@override String get keyboardShortcutsDescription => 'Personnaliser les raccourcis clavier';
|
@override String get keyboardShortcutsDescription => 'Personnaliser les raccourcis clavier';
|
||||||
@override String get videoPlayerNavigation => 'Navigation dans le lecteur vidéo';
|
@override String get videoPlayerNavigation => 'Navigation dans le lecteur vidéo';
|
||||||
@override String get videoPlayerNavigationDescription => 'Utilisez les touches fléchées pour naviguer dans les commandes du lecteur vidéo.';
|
@override String get videoPlayerNavigationDescription => 'Utilisez les touches fléchées pour naviguer dans les commandes du lecteur vidéo.';
|
||||||
|
@override String get crashReporting => 'Rapports de plantage';
|
||||||
|
@override String get crashReportingDescription => 'Envoyer des rapports de plantage pour améliorer l\'application';
|
||||||
@override String get debugLogging => 'Journalisation de débogage';
|
@override String get debugLogging => 'Journalisation de débogage';
|
||||||
@override String get debugLoggingDescription => 'Activer la journalisation détaillée pour le dépannage';
|
@override String get debugLoggingDescription => 'Activer la journalisation détaillée pour le dépannage';
|
||||||
@override String get viewLogs => 'Voir les logs';
|
@override String get viewLogs => 'Voir les logs';
|
||||||
@@ -1441,6 +1443,8 @@ extension on TranslationsFr {
|
|||||||
'settings.keyboardShortcutsDescription' => 'Personnaliser les raccourcis clavier',
|
'settings.keyboardShortcutsDescription' => 'Personnaliser les raccourcis clavier',
|
||||||
'settings.videoPlayerNavigation' => 'Navigation dans le lecteur vidéo',
|
'settings.videoPlayerNavigation' => 'Navigation dans le lecteur vidéo',
|
||||||
'settings.videoPlayerNavigationDescription' => 'Utilisez les touches fléchées pour naviguer dans les commandes du lecteur vidéo.',
|
'settings.videoPlayerNavigationDescription' => 'Utilisez les touches fléchées pour naviguer dans les commandes du lecteur vidéo.',
|
||||||
|
'settings.crashReporting' => 'Rapports de plantage',
|
||||||
|
'settings.crashReportingDescription' => 'Envoyer des rapports de plantage pour améliorer l\'application',
|
||||||
'settings.debugLogging' => 'Journalisation de débogage',
|
'settings.debugLogging' => 'Journalisation de débogage',
|
||||||
'settings.debugLoggingDescription' => 'Activer la journalisation détaillée pour le dépannage',
|
'settings.debugLoggingDescription' => 'Activer la journalisation détaillée pour le dépannage',
|
||||||
'settings.viewLogs' => 'Voir les logs',
|
'settings.viewLogs' => 'Voir les logs',
|
||||||
@@ -1487,6 +1491,8 @@ extension on TranslationsFr {
|
|||||||
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
||||||
'settings.discordRichPresence' => 'Discord Rich Presence',
|
'settings.discordRichPresence' => 'Discord Rich Presence',
|
||||||
'settings.discordRichPresenceDescription' => 'Montrez ce que vous regardez sur Discord',
|
'settings.discordRichPresenceDescription' => 'Montrez ce que vous regardez sur Discord',
|
||||||
|
'settings.autoPip' => 'Image dans l\'image automatique',
|
||||||
|
'settings.autoPipDescription' => 'Activer automatiquement l\'image dans l\'image en quittant l\'application pendant la lecture',
|
||||||
'settings.matchContentFrameRate' => 'Fréquence d\'images du contenu correspondant',
|
'settings.matchContentFrameRate' => 'Fréquence d\'images du contenu correspondant',
|
||||||
'settings.matchContentFrameRateDescription' => 'Ajustez la fréquence de rafraîchissement de l\'écran en fonction du contenu vidéo, ce qui réduit les saccades et économise la batterie',
|
'settings.matchContentFrameRateDescription' => 'Ajustez la fréquence de rafraîchissement de l\'écran en fonction du contenu vidéo, ce qui réduit les saccades et économise la batterie',
|
||||||
'settings.tunneledPlayback' => 'Tunneled Playback',
|
'settings.tunneledPlayback' => 'Tunneled Playback',
|
||||||
@@ -1808,6 +1814,8 @@ extension on TranslationsFr {
|
|||||||
'liveTv.nowPlaying' => 'En cours de lecture',
|
'liveTv.nowPlaying' => 'En cours de lecture',
|
||||||
'liveTv.noPrograms' => 'Aucune donnée de programme disponible',
|
'liveTv.noPrograms' => 'Aucune donnée de programme disponible',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => 'Ch. ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => 'Ch. ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => 'EN DIRECT',
|
'liveTv.live' => 'EN DIRECT',
|
||||||
'liveTv.hd' => 'HD',
|
'liveTv.hd' => 'HD',
|
||||||
'liveTv.premiere' => 'NOUVEAU',
|
'liveTv.premiere' => 'NOUVEAU',
|
||||||
@@ -1822,8 +1830,6 @@ extension on TranslationsFr {
|
|||||||
'liveTv.evening' => 'Soirée',
|
'liveTv.evening' => 'Soirée',
|
||||||
'liveTv.lateNight' => 'Nuit tardive',
|
'liveTv.lateNight' => 'Nuit tardive',
|
||||||
'liveTv.whatsOn' => 'En ce moment',
|
'liveTv.whatsOn' => 'En ce moment',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => 'Regarder la chaîne',
|
'liveTv.watchChannel' => 'Regarder la chaîne',
|
||||||
'collections.title' => 'Collections',
|
'collections.title' => 'Collections',
|
||||||
'collections.collection' => 'Collection',
|
'collections.collection' => 'Collection',
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ class _TranslationsSettingsIt implements TranslationsSettingsEn {
|
|||||||
@override String get keyboardShortcutsDescription => 'Personalizza le scorciatoie da tastiera';
|
@override String get keyboardShortcutsDescription => 'Personalizza le scorciatoie da tastiera';
|
||||||
@override String get videoPlayerNavigation => 'Navigazione del lettore video';
|
@override String get videoPlayerNavigation => 'Navigazione del lettore video';
|
||||||
@override String get videoPlayerNavigationDescription => 'Usa i tasti freccia per navigare nei controlli del lettore video';
|
@override String get videoPlayerNavigationDescription => 'Usa i tasti freccia per navigare nei controlli del lettore video';
|
||||||
|
@override String get crashReporting => 'Segnalazione errori';
|
||||||
|
@override String get crashReportingDescription => 'Invia segnalazioni di errori per migliorare l\'app';
|
||||||
@override String get debugLogging => 'Log di debug';
|
@override String get debugLogging => 'Log di debug';
|
||||||
@override String get debugLoggingDescription => 'Abilita il logging dettagliato per la risoluzione dei problemi';
|
@override String get debugLoggingDescription => 'Abilita il logging dettagliato per la risoluzione dei problemi';
|
||||||
@override String get viewLogs => 'Visualizza log';
|
@override String get viewLogs => 'Visualizza log';
|
||||||
@@ -1441,6 +1443,8 @@ extension on TranslationsIt {
|
|||||||
'settings.keyboardShortcutsDescription' => 'Personalizza le scorciatoie da tastiera',
|
'settings.keyboardShortcutsDescription' => 'Personalizza le scorciatoie da tastiera',
|
||||||
'settings.videoPlayerNavigation' => 'Navigazione del lettore video',
|
'settings.videoPlayerNavigation' => 'Navigazione del lettore video',
|
||||||
'settings.videoPlayerNavigationDescription' => 'Usa i tasti freccia per navigare nei controlli del lettore video',
|
'settings.videoPlayerNavigationDescription' => 'Usa i tasti freccia per navigare nei controlli del lettore video',
|
||||||
|
'settings.crashReporting' => 'Segnalazione errori',
|
||||||
|
'settings.crashReportingDescription' => 'Invia segnalazioni di errori per migliorare l\'app',
|
||||||
'settings.debugLogging' => 'Log di debug',
|
'settings.debugLogging' => 'Log di debug',
|
||||||
'settings.debugLoggingDescription' => 'Abilita il logging dettagliato per la risoluzione dei problemi',
|
'settings.debugLoggingDescription' => 'Abilita il logging dettagliato per la risoluzione dei problemi',
|
||||||
'settings.viewLogs' => 'Visualizza log',
|
'settings.viewLogs' => 'Visualizza log',
|
||||||
@@ -1487,6 +1491,8 @@ extension on TranslationsIt {
|
|||||||
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
||||||
'settings.discordRichPresence' => 'Discord Rich Presence',
|
'settings.discordRichPresence' => 'Discord Rich Presence',
|
||||||
'settings.discordRichPresenceDescription' => 'Mostra su Discord cosa stai guardando',
|
'settings.discordRichPresenceDescription' => 'Mostra su Discord cosa stai guardando',
|
||||||
|
'settings.autoPip' => 'Picture-in-Picture automatico',
|
||||||
|
'settings.autoPipDescription' => 'Attiva automaticamente il picture-in-picture quando si esce dall\'app durante la riproduzione',
|
||||||
'settings.matchContentFrameRate' => 'Adatta frequenza fotogrammi',
|
'settings.matchContentFrameRate' => 'Adatta frequenza fotogrammi',
|
||||||
'settings.matchContentFrameRateDescription' => 'Regola la frequenza di aggiornamento del display in base al contenuto video, riducendo i tremolii e risparmiando batteria',
|
'settings.matchContentFrameRateDescription' => 'Regola la frequenza di aggiornamento del display in base al contenuto video, riducendo i tremolii e risparmiando batteria',
|
||||||
'settings.tunneledPlayback' => 'Tunneled Playback',
|
'settings.tunneledPlayback' => 'Tunneled Playback',
|
||||||
@@ -1808,6 +1814,8 @@ extension on TranslationsIt {
|
|||||||
'liveTv.nowPlaying' => 'In riproduzione',
|
'liveTv.nowPlaying' => 'In riproduzione',
|
||||||
'liveTv.noPrograms' => 'Nessun dato di programma disponibile',
|
'liveTv.noPrograms' => 'Nessun dato di programma disponibile',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => 'Canale ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => 'Canale ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => 'IN DIRETTA',
|
'liveTv.live' => 'IN DIRETTA',
|
||||||
'liveTv.hd' => 'HD',
|
'liveTv.hd' => 'HD',
|
||||||
'liveTv.premiere' => 'NUOVO',
|
'liveTv.premiere' => 'NUOVO',
|
||||||
@@ -1822,8 +1830,6 @@ extension on TranslationsIt {
|
|||||||
'liveTv.evening' => 'Sera',
|
'liveTv.evening' => 'Sera',
|
||||||
'liveTv.lateNight' => 'Notte tarda',
|
'liveTv.lateNight' => 'Notte tarda',
|
||||||
'liveTv.whatsOn' => 'In onda ora',
|
'liveTv.whatsOn' => 'In onda ora',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => 'Guarda canale',
|
'liveTv.watchChannel' => 'Guarda canale',
|
||||||
'downloads.title' => 'Download',
|
'downloads.title' => 'Download',
|
||||||
'downloads.manage' => 'Gestisci',
|
'downloads.manage' => 'Gestisci',
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ class _TranslationsSettingsKo implements TranslationsSettingsEn {
|
|||||||
@override String get keyboardShortcutsDescription => '사용자 정의 키보드 단축키';
|
@override String get keyboardShortcutsDescription => '사용자 정의 키보드 단축키';
|
||||||
@override String get videoPlayerNavigation => '비디오 플레이어 탐색';
|
@override String get videoPlayerNavigation => '비디오 플레이어 탐색';
|
||||||
@override String get videoPlayerNavigationDescription => '방향 키를 사용하여 비디오 플레이어 컨트롤 탐색';
|
@override String get videoPlayerNavigationDescription => '방향 키를 사용하여 비디오 플레이어 컨트롤 탐색';
|
||||||
|
@override String get crashReporting => '충돌 보고';
|
||||||
|
@override String get crashReportingDescription => '앱 개선을 위해 충돌 보고서 전송';
|
||||||
@override String get debugLogging => '디버그 로깅';
|
@override String get debugLogging => '디버그 로깅';
|
||||||
@override String get debugLoggingDescription => '문제 해결을 위해 상세 로깅 활성화';
|
@override String get debugLoggingDescription => '문제 해결을 위해 상세 로깅 활성화';
|
||||||
@override String get viewLogs => '로그 보기';
|
@override String get viewLogs => '로그 보기';
|
||||||
@@ -1441,6 +1443,8 @@ extension on TranslationsKo {
|
|||||||
'settings.keyboardShortcutsDescription' => '사용자 정의 키보드 단축키',
|
'settings.keyboardShortcutsDescription' => '사용자 정의 키보드 단축키',
|
||||||
'settings.videoPlayerNavigation' => '비디오 플레이어 탐색',
|
'settings.videoPlayerNavigation' => '비디오 플레이어 탐색',
|
||||||
'settings.videoPlayerNavigationDescription' => '방향 키를 사용하여 비디오 플레이어 컨트롤 탐색',
|
'settings.videoPlayerNavigationDescription' => '방향 키를 사용하여 비디오 플레이어 컨트롤 탐색',
|
||||||
|
'settings.crashReporting' => '충돌 보고',
|
||||||
|
'settings.crashReportingDescription' => '앱 개선을 위해 충돌 보고서 전송',
|
||||||
'settings.debugLogging' => '디버그 로깅',
|
'settings.debugLogging' => '디버그 로깅',
|
||||||
'settings.debugLoggingDescription' => '문제 해결을 위해 상세 로깅 활성화',
|
'settings.debugLoggingDescription' => '문제 해결을 위해 상세 로깅 활성화',
|
||||||
'settings.viewLogs' => '로그 보기',
|
'settings.viewLogs' => '로그 보기',
|
||||||
@@ -1487,6 +1491,8 @@ extension on TranslationsKo {
|
|||||||
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
||||||
'settings.discordRichPresence' => 'Discord Rich Presence',
|
'settings.discordRichPresence' => 'Discord Rich Presence',
|
||||||
'settings.discordRichPresenceDescription' => 'Discord에서 시청 중인 콘텐츠 표시',
|
'settings.discordRichPresenceDescription' => 'Discord에서 시청 중인 콘텐츠 표시',
|
||||||
|
'settings.autoPip' => '자동 PIP 모드',
|
||||||
|
'settings.autoPipDescription' => '재생 중 앱을 나갈 때 자동으로 PIP 모드로 전환',
|
||||||
'settings.matchContentFrameRate' => '콘텐츠 프레임 레이트 맞춤',
|
'settings.matchContentFrameRate' => '콘텐츠 프레임 레이트 맞춤',
|
||||||
'settings.matchContentFrameRateDescription' => '비디오 콘텐츠에 맞게 디스플레이 주사율을 조정하여 떨림을 줄이고 배터리를 절약합니다',
|
'settings.matchContentFrameRateDescription' => '비디오 콘텐츠에 맞게 디스플레이 주사율을 조정하여 떨림을 줄이고 배터리를 절약합니다',
|
||||||
'settings.tunneledPlayback' => 'Tunneled Playback',
|
'settings.tunneledPlayback' => 'Tunneled Playback',
|
||||||
@@ -1808,6 +1814,8 @@ extension on TranslationsKo {
|
|||||||
'liveTv.nowPlaying' => '현재 재생 중',
|
'liveTv.nowPlaying' => '현재 재생 중',
|
||||||
'liveTv.noPrograms' => '프로그램 데이터가 없습니다',
|
'liveTv.noPrograms' => '프로그램 데이터가 없습니다',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => '채널 ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => '채널 ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => '실시간',
|
'liveTv.live' => '실시간',
|
||||||
'liveTv.hd' => 'HD',
|
'liveTv.hd' => 'HD',
|
||||||
'liveTv.premiere' => '신규',
|
'liveTv.premiere' => '신규',
|
||||||
@@ -1822,8 +1830,6 @@ extension on TranslationsKo {
|
|||||||
'liveTv.evening' => '저녁',
|
'liveTv.evening' => '저녁',
|
||||||
'liveTv.lateNight' => '심야 방송',
|
'liveTv.lateNight' => '심야 방송',
|
||||||
'liveTv.whatsOn' => '지금 방송 중',
|
'liveTv.whatsOn' => '지금 방송 중',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => '채널 시청',
|
'liveTv.watchChannel' => '채널 시청',
|
||||||
'collections.title' => '컬렉션',
|
'collections.title' => '컬렉션',
|
||||||
'collections.collection' => '컬렉션',
|
'collections.collection' => '컬렉션',
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ class _TranslationsSettingsNl implements TranslationsSettingsEn {
|
|||||||
@override String get keyboardShortcutsDescription => 'Pas toetsenbord sneltoetsen aan';
|
@override String get keyboardShortcutsDescription => 'Pas toetsenbord sneltoetsen aan';
|
||||||
@override String get videoPlayerNavigation => 'Videospeler navigatie';
|
@override String get videoPlayerNavigation => 'Videospeler navigatie';
|
||||||
@override String get videoPlayerNavigationDescription => 'Gebruik pijltjestoetsen om door de videospeler bediening te navigeren';
|
@override String get videoPlayerNavigationDescription => 'Gebruik pijltjestoetsen om door de videospeler bediening te navigeren';
|
||||||
|
@override String get crashReporting => 'Crashrapportage';
|
||||||
|
@override String get crashReportingDescription => 'Crashrapporten verzenden om de app te verbeteren';
|
||||||
@override String get debugLogging => 'Debug logging';
|
@override String get debugLogging => 'Debug logging';
|
||||||
@override String get debugLoggingDescription => 'Schakel gedetailleerde logging in voor probleemoplossing';
|
@override String get debugLoggingDescription => 'Schakel gedetailleerde logging in voor probleemoplossing';
|
||||||
@override String get viewLogs => 'Bekijk logs';
|
@override String get viewLogs => 'Bekijk logs';
|
||||||
@@ -1441,6 +1443,8 @@ extension on TranslationsNl {
|
|||||||
'settings.keyboardShortcutsDescription' => 'Pas toetsenbord sneltoetsen aan',
|
'settings.keyboardShortcutsDescription' => 'Pas toetsenbord sneltoetsen aan',
|
||||||
'settings.videoPlayerNavigation' => 'Videospeler navigatie',
|
'settings.videoPlayerNavigation' => 'Videospeler navigatie',
|
||||||
'settings.videoPlayerNavigationDescription' => 'Gebruik pijltjestoetsen om door de videospeler bediening te navigeren',
|
'settings.videoPlayerNavigationDescription' => 'Gebruik pijltjestoetsen om door de videospeler bediening te navigeren',
|
||||||
|
'settings.crashReporting' => 'Crashrapportage',
|
||||||
|
'settings.crashReportingDescription' => 'Crashrapporten verzenden om de app te verbeteren',
|
||||||
'settings.debugLogging' => 'Debug logging',
|
'settings.debugLogging' => 'Debug logging',
|
||||||
'settings.debugLoggingDescription' => 'Schakel gedetailleerde logging in voor probleemoplossing',
|
'settings.debugLoggingDescription' => 'Schakel gedetailleerde logging in voor probleemoplossing',
|
||||||
'settings.viewLogs' => 'Bekijk logs',
|
'settings.viewLogs' => 'Bekijk logs',
|
||||||
@@ -1487,6 +1491,8 @@ extension on TranslationsNl {
|
|||||||
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
||||||
'settings.discordRichPresence' => 'Discord Rich Presence',
|
'settings.discordRichPresence' => 'Discord Rich Presence',
|
||||||
'settings.discordRichPresenceDescription' => 'Toon op Discord wat je aan het kijken bent',
|
'settings.discordRichPresenceDescription' => 'Toon op Discord wat je aan het kijken bent',
|
||||||
|
'settings.autoPip' => 'Automatische beeld-in-beeld',
|
||||||
|
'settings.autoPipDescription' => 'Automatisch beeld-in-beeld activeren bij het verlaten van de app tijdens afspelen',
|
||||||
'settings.matchContentFrameRate' => 'Inhoudsframesnelheid afstemmen',
|
'settings.matchContentFrameRate' => 'Inhoudsframesnelheid afstemmen',
|
||||||
'settings.matchContentFrameRateDescription' => 'Pas de schermverversingssnelheid aan op de video-inhoud, vermindert haperingen en bespaart batterij',
|
'settings.matchContentFrameRateDescription' => 'Pas de schermverversingssnelheid aan op de video-inhoud, vermindert haperingen en bespaart batterij',
|
||||||
'settings.tunneledPlayback' => 'Tunneled Playback',
|
'settings.tunneledPlayback' => 'Tunneled Playback',
|
||||||
@@ -1808,6 +1814,8 @@ extension on TranslationsNl {
|
|||||||
'liveTv.nowPlaying' => 'Nu aan het afspelen',
|
'liveTv.nowPlaying' => 'Nu aan het afspelen',
|
||||||
'liveTv.noPrograms' => 'Geen programmagegevens beschikbaar',
|
'liveTv.noPrograms' => 'Geen programmagegevens beschikbaar',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => 'Kanaal ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => 'Kanaal ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => 'LIVE',
|
'liveTv.live' => 'LIVE',
|
||||||
'liveTv.hd' => 'HD',
|
'liveTv.hd' => 'HD',
|
||||||
'liveTv.premiere' => 'NIEUW',
|
'liveTv.premiere' => 'NIEUW',
|
||||||
@@ -1822,8 +1830,6 @@ extension on TranslationsNl {
|
|||||||
'liveTv.evening' => 'Avond',
|
'liveTv.evening' => 'Avond',
|
||||||
'liveTv.lateNight' => 'Late avond',
|
'liveTv.lateNight' => 'Late avond',
|
||||||
'liveTv.whatsOn' => 'Nu op TV',
|
'liveTv.whatsOn' => 'Nu op TV',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => 'Kanaal bekijken',
|
'liveTv.watchChannel' => 'Kanaal bekijken',
|
||||||
'downloads.title' => 'Downloads',
|
'downloads.title' => 'Downloads',
|
||||||
'downloads.manage' => 'Beheren',
|
'downloads.manage' => 'Beheren',
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ class _TranslationsSettingsSv implements TranslationsSettingsEn {
|
|||||||
@override String get keyboardShortcutsDescription => 'Anpassa tangentbordsgenvägar';
|
@override String get keyboardShortcutsDescription => 'Anpassa tangentbordsgenvägar';
|
||||||
@override String get videoPlayerNavigation => 'Navigering i videospelaren';
|
@override String get videoPlayerNavigation => 'Navigering i videospelaren';
|
||||||
@override String get videoPlayerNavigationDescription => 'Använd piltangenter för att navigera videospelarens kontroller';
|
@override String get videoPlayerNavigationDescription => 'Använd piltangenter för att navigera videospelarens kontroller';
|
||||||
|
@override String get crashReporting => 'Kraschrapportering';
|
||||||
|
@override String get crashReportingDescription => 'Skicka kraschrapporter för att förbättra appen';
|
||||||
@override String get debugLogging => 'Felsökningsloggning';
|
@override String get debugLogging => 'Felsökningsloggning';
|
||||||
@override String get debugLoggingDescription => 'Aktivera detaljerad loggning för felsökning';
|
@override String get debugLoggingDescription => 'Aktivera detaljerad loggning för felsökning';
|
||||||
@override String get viewLogs => 'Visa loggar';
|
@override String get viewLogs => 'Visa loggar';
|
||||||
@@ -1441,6 +1443,8 @@ extension on TranslationsSv {
|
|||||||
'settings.keyboardShortcutsDescription' => 'Anpassa tangentbordsgenvägar',
|
'settings.keyboardShortcutsDescription' => 'Anpassa tangentbordsgenvägar',
|
||||||
'settings.videoPlayerNavigation' => 'Navigering i videospelaren',
|
'settings.videoPlayerNavigation' => 'Navigering i videospelaren',
|
||||||
'settings.videoPlayerNavigationDescription' => 'Använd piltangenter för att navigera videospelarens kontroller',
|
'settings.videoPlayerNavigationDescription' => 'Använd piltangenter för att navigera videospelarens kontroller',
|
||||||
|
'settings.crashReporting' => 'Kraschrapportering',
|
||||||
|
'settings.crashReportingDescription' => 'Skicka kraschrapporter för att förbättra appen',
|
||||||
'settings.debugLogging' => 'Felsökningsloggning',
|
'settings.debugLogging' => 'Felsökningsloggning',
|
||||||
'settings.debugLoggingDescription' => 'Aktivera detaljerad loggning för felsökning',
|
'settings.debugLoggingDescription' => 'Aktivera detaljerad loggning för felsökning',
|
||||||
'settings.viewLogs' => 'Visa loggar',
|
'settings.viewLogs' => 'Visa loggar',
|
||||||
@@ -1487,6 +1491,8 @@ extension on TranslationsSv {
|
|||||||
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
||||||
'settings.discordRichPresence' => 'Discord Rich Presence',
|
'settings.discordRichPresence' => 'Discord Rich Presence',
|
||||||
'settings.discordRichPresenceDescription' => 'Visa vad du tittar på i Discord',
|
'settings.discordRichPresenceDescription' => 'Visa vad du tittar på i Discord',
|
||||||
|
'settings.autoPip' => 'Automatisk bild-i-bild',
|
||||||
|
'settings.autoPipDescription' => 'Aktivera bild-i-bild automatiskt när appen lämnas under uppspelning',
|
||||||
'settings.matchContentFrameRate' => 'Matcha innehållets bildfrekvens',
|
'settings.matchContentFrameRate' => 'Matcha innehållets bildfrekvens',
|
||||||
'settings.matchContentFrameRateDescription' => 'Justera skärmens uppdateringsfrekvens för att matcha videoinnehållet, minskar hackighet och sparar batteri',
|
'settings.matchContentFrameRateDescription' => 'Justera skärmens uppdateringsfrekvens för att matcha videoinnehållet, minskar hackighet och sparar batteri',
|
||||||
'settings.tunneledPlayback' => 'Tunneled Playback',
|
'settings.tunneledPlayback' => 'Tunneled Playback',
|
||||||
@@ -1808,6 +1814,8 @@ extension on TranslationsSv {
|
|||||||
'liveTv.nowPlaying' => 'Spelas nu',
|
'liveTv.nowPlaying' => 'Spelas nu',
|
||||||
'liveTv.noPrograms' => 'Ingen programdata tillgänglig',
|
'liveTv.noPrograms' => 'Ingen programdata tillgänglig',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => 'Kanal ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => 'Kanal ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => 'LIVE',
|
'liveTv.live' => 'LIVE',
|
||||||
'liveTv.hd' => 'HD',
|
'liveTv.hd' => 'HD',
|
||||||
'liveTv.premiere' => 'NY',
|
'liveTv.premiere' => 'NY',
|
||||||
@@ -1822,8 +1830,6 @@ extension on TranslationsSv {
|
|||||||
'liveTv.evening' => 'Kväll',
|
'liveTv.evening' => 'Kväll',
|
||||||
'liveTv.lateNight' => 'Sen kväll',
|
'liveTv.lateNight' => 'Sen kväll',
|
||||||
'liveTv.whatsOn' => 'På TV nu',
|
'liveTv.whatsOn' => 'På TV nu',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => 'Titta på kanal',
|
'liveTv.watchChannel' => 'Titta på kanal',
|
||||||
'downloads.title' => 'Nedladdningar',
|
'downloads.title' => 'Nedladdningar',
|
||||||
'downloads.manage' => 'Hantera',
|
'downloads.manage' => 'Hantera',
|
||||||
|
|||||||
@@ -270,6 +270,8 @@ class _TranslationsSettingsZh implements TranslationsSettingsEn {
|
|||||||
@override String get keyboardShortcutsDescription => '自定义键盘快捷键';
|
@override String get keyboardShortcutsDescription => '自定义键盘快捷键';
|
||||||
@override String get videoPlayerNavigation => '视频播放器导航';
|
@override String get videoPlayerNavigation => '视频播放器导航';
|
||||||
@override String get videoPlayerNavigationDescription => '使用方向键导航视频播放器控件';
|
@override String get videoPlayerNavigationDescription => '使用方向键导航视频播放器控件';
|
||||||
|
@override String get crashReporting => '崩溃报告';
|
||||||
|
@override String get crashReportingDescription => '发送崩溃报告以帮助改进应用';
|
||||||
@override String get debugLogging => '调试日志';
|
@override String get debugLogging => '调试日志';
|
||||||
@override String get debugLoggingDescription => '启用详细日志记录以便故障排除';
|
@override String get debugLoggingDescription => '启用详细日志记录以便故障排除';
|
||||||
@override String get viewLogs => '查看日志';
|
@override String get viewLogs => '查看日志';
|
||||||
@@ -1441,6 +1443,8 @@ extension on TranslationsZh {
|
|||||||
'settings.keyboardShortcutsDescription' => '自定义键盘快捷键',
|
'settings.keyboardShortcutsDescription' => '自定义键盘快捷键',
|
||||||
'settings.videoPlayerNavigation' => '视频播放器导航',
|
'settings.videoPlayerNavigation' => '视频播放器导航',
|
||||||
'settings.videoPlayerNavigationDescription' => '使用方向键导航视频播放器控件',
|
'settings.videoPlayerNavigationDescription' => '使用方向键导航视频播放器控件',
|
||||||
|
'settings.crashReporting' => '崩溃报告',
|
||||||
|
'settings.crashReportingDescription' => '发送崩溃报告以帮助改进应用',
|
||||||
'settings.debugLogging' => '调试日志',
|
'settings.debugLogging' => '调试日志',
|
||||||
'settings.debugLoggingDescription' => '启用详细日志记录以便故障排除',
|
'settings.debugLoggingDescription' => '启用详细日志记录以便故障排除',
|
||||||
'settings.viewLogs' => '查看日志',
|
'settings.viewLogs' => '查看日志',
|
||||||
@@ -1487,6 +1491,8 @@ extension on TranslationsZh {
|
|||||||
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
'settings.maxVolumePercent' => ({required Object percent}) => '${percent}%',
|
||||||
'settings.discordRichPresence' => 'Discord 动态状态',
|
'settings.discordRichPresence' => 'Discord 动态状态',
|
||||||
'settings.discordRichPresenceDescription' => '在 Discord 上显示您正在观看的内容',
|
'settings.discordRichPresenceDescription' => '在 Discord 上显示您正在观看的内容',
|
||||||
|
'settings.autoPip' => '自动画中画',
|
||||||
|
'settings.autoPipDescription' => '在播放期间离开应用时自动进入画中画模式',
|
||||||
'settings.matchContentFrameRate' => '匹配内容帧率',
|
'settings.matchContentFrameRate' => '匹配内容帧率',
|
||||||
'settings.matchContentFrameRateDescription' => '调整显示刷新率以匹配视频内容,减少画面抖动并节省电量',
|
'settings.matchContentFrameRateDescription' => '调整显示刷新率以匹配视频内容,减少画面抖动并节省电量',
|
||||||
'settings.tunneledPlayback' => 'Tunneled Playback',
|
'settings.tunneledPlayback' => 'Tunneled Playback',
|
||||||
@@ -1808,6 +1814,8 @@ extension on TranslationsZh {
|
|||||||
'liveTv.nowPlaying' => '正在播放',
|
'liveTv.nowPlaying' => '正在播放',
|
||||||
'liveTv.noPrograms' => '没有可用的节目数据',
|
'liveTv.noPrograms' => '没有可用的节目数据',
|
||||||
'liveTv.channelNumber' => ({required Object number}) => '频道 ${number}',
|
'liveTv.channelNumber' => ({required Object number}) => '频道 ${number}',
|
||||||
|
_ => null,
|
||||||
|
} ?? switch (path) {
|
||||||
'liveTv.live' => '直播',
|
'liveTv.live' => '直播',
|
||||||
'liveTv.hd' => '高清',
|
'liveTv.hd' => '高清',
|
||||||
'liveTv.premiere' => '新',
|
'liveTv.premiere' => '新',
|
||||||
@@ -1822,8 +1830,6 @@ extension on TranslationsZh {
|
|||||||
'liveTv.evening' => '晚上',
|
'liveTv.evening' => '晚上',
|
||||||
'liveTv.lateNight' => '深夜',
|
'liveTv.lateNight' => '深夜',
|
||||||
'liveTv.whatsOn' => '正在播出',
|
'liveTv.whatsOn' => '正在播出',
|
||||||
_ => null,
|
|
||||||
} ?? switch (path) {
|
|
||||||
'liveTv.watchChannel' => '观看频道',
|
'liveTv.watchChannel' => '观看频道',
|
||||||
'downloads.title' => '下载',
|
'downloads.title' => '下载',
|
||||||
'downloads.manage' => '管理',
|
'downloads.manage' => '管理',
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "Anpassa tangentbordsgenvägar",
|
"keyboardShortcutsDescription": "Anpassa tangentbordsgenvägar",
|
||||||
"videoPlayerNavigation": "Navigering i videospelaren",
|
"videoPlayerNavigation": "Navigering i videospelaren",
|
||||||
"videoPlayerNavigationDescription": "Använd piltangenter för att navigera videospelarens kontroller",
|
"videoPlayerNavigationDescription": "Använd piltangenter för att navigera videospelarens kontroller",
|
||||||
|
"crashReporting": "Kraschrapportering",
|
||||||
|
"crashReportingDescription": "Skicka kraschrapporter för att förbättra appen",
|
||||||
"debugLogging": "Felsökningsloggning",
|
"debugLogging": "Felsökningsloggning",
|
||||||
"debugLoggingDescription": "Aktivera detaljerad loggning för felsökning",
|
"debugLoggingDescription": "Aktivera detaljerad loggning för felsökning",
|
||||||
"viewLogs": "Visa loggar",
|
"viewLogs": "Visa loggar",
|
||||||
|
|||||||
@@ -151,6 +151,8 @@
|
|||||||
"keyboardShortcutsDescription": "自定义键盘快捷键",
|
"keyboardShortcutsDescription": "自定义键盘快捷键",
|
||||||
"videoPlayerNavigation": "视频播放器导航",
|
"videoPlayerNavigation": "视频播放器导航",
|
||||||
"videoPlayerNavigationDescription": "使用方向键导航视频播放器控件",
|
"videoPlayerNavigationDescription": "使用方向键导航视频播放器控件",
|
||||||
|
"crashReporting": "崩溃报告",
|
||||||
|
"crashReportingDescription": "发送崩溃报告以帮助改进应用",
|
||||||
"debugLogging": "调试日志",
|
"debugLogging": "调试日志",
|
||||||
"debugLoggingDescription": "启用详细日志记录以便故障排除",
|
"debugLoggingDescription": "启用详细日志记录以便故障排除",
|
||||||
"viewLogs": "查看日志",
|
"viewLogs": "查看日志",
|
||||||
|
|||||||
+104
-54
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
@@ -5,6 +7,7 @@ import 'dart:io' show Platform;
|
|||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'screens/main_screen.dart';
|
import 'screens/main_screen.dart';
|
||||||
import 'screens/auth_screen.dart';
|
import 'screens/auth_screen.dart';
|
||||||
import 'services/storage_service.dart';
|
import 'services/storage_service.dart';
|
||||||
@@ -48,6 +51,7 @@ import 'focus/input_mode_tracker.dart';
|
|||||||
import 'focus/key_event_utils.dart';
|
import 'focus/key_event_utils.dart';
|
||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'utils/navigation_transitions.dart';
|
import 'utils/navigation_transitions.dart';
|
||||||
|
import 'utils/log_redaction_manager.dart';
|
||||||
|
|
||||||
// Workaround for Flutter bug #177992: iPadOS 26.1+ misinterprets fake touch events
|
// Workaround for Flutter bug #177992: iPadOS 26.1+ misinterprets fake touch events
|
||||||
// at (0,0) as barrier taps, causing modals to dismiss immediately.
|
// at (0,0) as barrier taps, causing modals to dismiss immediately.
|
||||||
@@ -70,69 +74,115 @@ void main() async {
|
|||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
_installZeroOffsetPointerGuard(); // Workaround for iPadOS 26.1+ modal dismissal bug
|
_installZeroOffsetPointerGuard(); // Workaround for iPadOS 26.1+ modal dismissal bug
|
||||||
|
|
||||||
// Initialize settings first to get saved locale
|
await SentryFlutter.init(
|
||||||
final settings = await SettingsService.getInstance();
|
(options) {
|
||||||
final savedLocale = settings.getAppLocale();
|
options.dsn = 'https://7aa61595518d4770a4d5ea412982dcd7@bugs.plezy.app/1';
|
||||||
|
options.sendDefaultPii = true;
|
||||||
|
options.tracesSampleRate = 0;
|
||||||
|
options.anrEnabled = true;
|
||||||
|
options.anrTimeoutInterval = const Duration(seconds: 5);
|
||||||
|
options.attachStacktrace = true;
|
||||||
|
options.beforeSend = _beforeSend;
|
||||||
|
},
|
||||||
|
appRunner: () async {
|
||||||
|
// Initialize settings first to get saved locale
|
||||||
|
final settings = await SettingsService.getInstance();
|
||||||
|
final savedLocale = settings.getAppLocale();
|
||||||
|
|
||||||
// Initialize localization with saved locale
|
// Initialize localization with saved locale
|
||||||
LocaleSettings.setLocale(savedLocale);
|
LocaleSettings.setLocale(savedLocale);
|
||||||
|
|
||||||
// Needed for formatting dates in different locales
|
// Needed for formatting dates in different locales
|
||||||
await initializeDateFormatting(savedLocale.languageCode, null);
|
await initializeDateFormatting(savedLocale.languageCode, null);
|
||||||
|
|
||||||
// Configure image cache for large libraries
|
// Configure image cache for large libraries
|
||||||
PaintingBinding.instance.imageCache.maximumSize = 2000; // default 1000
|
PaintingBinding.instance.imageCache.maximumSize = 2000; // default 1000
|
||||||
PaintingBinding.instance.imageCache.maximumSizeBytes = 300 << 20; // 300MB
|
PaintingBinding.instance.imageCache.maximumSizeBytes = 300 << 20; // 300MB
|
||||||
|
|
||||||
// Initialize services in parallel where possible
|
// Initialize services in parallel where possible
|
||||||
final futures = <Future<void>>[];
|
final futures = <Future<void>>[];
|
||||||
|
|
||||||
// Initialize window_manager for desktop platforms
|
// Initialize window_manager for desktop platforms
|
||||||
if (Platform.isMacOS || Platform.isWindows || Platform.isLinux) {
|
if (Platform.isMacOS || Platform.isWindows || Platform.isLinux) {
|
||||||
futures.add(windowManager.ensureInitialized());
|
futures.add(windowManager.ensureInitialized());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize TV detection and PiP service for Android
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
futures.add(TvDetectionService.getInstance());
|
||||||
|
// Initialize PiP service to listen for PiP state changes
|
||||||
|
PipService();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure macOS window with custom titlebar (depends on window manager)
|
||||||
|
futures.add(MacOSWindowService.setupCustomTitlebar());
|
||||||
|
|
||||||
|
// Initialize storage service
|
||||||
|
futures.add(StorageService.getInstance());
|
||||||
|
|
||||||
|
// Initialize language codes for track selection
|
||||||
|
futures.add(LanguageCodes.initialize());
|
||||||
|
|
||||||
|
// Wait for all parallel services to complete
|
||||||
|
await Future.wait(futures);
|
||||||
|
|
||||||
|
// Initialize logger level based on debug setting
|
||||||
|
final debugEnabled = settings.getEnableDebugLogging();
|
||||||
|
setLoggerLevel(debugEnabled);
|
||||||
|
|
||||||
|
// Initialize download storage service with settings
|
||||||
|
await DownloadStorageService.instance.initialize(settings);
|
||||||
|
|
||||||
|
// Start global fullscreen state monitoring
|
||||||
|
FullscreenStateManager().startMonitoring();
|
||||||
|
|
||||||
|
// Initialize gamepad service for desktop platforms
|
||||||
|
if (Platform.isMacOS || Platform.isWindows || Platform.isLinux) {
|
||||||
|
GamepadService.instance.start();
|
||||||
|
DiscordRPCService.instance.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// DTD service is available for MCP tooling connection if needed
|
||||||
|
|
||||||
|
// Register bundled shader licenses
|
||||||
|
_registerShaderLicenses();
|
||||||
|
|
||||||
|
runApp(const MainApp());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureOr<SentryEvent?> _beforeSend(SentryEvent event, Hint hint) {
|
||||||
|
// Drop event if user opted out of crash reporting
|
||||||
|
final instance = SettingsService.instanceOrNull;
|
||||||
|
if (instance != null && !instance.getCrashReporting()) return null;
|
||||||
|
|
||||||
|
// Scrub Plex tokens and server URLs from exception messages
|
||||||
|
var exceptions = event.exceptions;
|
||||||
|
if (exceptions != null) {
|
||||||
|
exceptions = exceptions.map((e) {
|
||||||
|
final value = e.value;
|
||||||
|
if (value != null) {
|
||||||
|
return e.copyWith(value: LogRedactionManager.redact(value));
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize TV detection and PiP service for Android
|
// Scrub breadcrumb messages and data
|
||||||
if (Platform.isAndroid) {
|
var breadcrumbs = event.breadcrumbs;
|
||||||
futures.add(TvDetectionService.getInstance());
|
if (breadcrumbs != null) {
|
||||||
// Initialize PiP service to listen for PiP state changes
|
breadcrumbs = breadcrumbs.map((b) {
|
||||||
PipService();
|
final message = b.message;
|
||||||
|
final data = b.data;
|
||||||
|
return b.copyWith(
|
||||||
|
message: message != null ? LogRedactionManager.redact(message) : null,
|
||||||
|
data: data?.map((k, v) => MapEntry(k, v is String ? LogRedactionManager.redact(v) : v)),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure macOS window with custom titlebar (depends on window manager)
|
return event.copyWith(exceptions: exceptions, breadcrumbs: breadcrumbs);
|
||||||
futures.add(MacOSWindowService.setupCustomTitlebar());
|
|
||||||
|
|
||||||
// Initialize storage service
|
|
||||||
futures.add(StorageService.getInstance());
|
|
||||||
|
|
||||||
// Initialize language codes for track selection
|
|
||||||
futures.add(LanguageCodes.initialize());
|
|
||||||
|
|
||||||
// Wait for all parallel services to complete
|
|
||||||
await Future.wait(futures);
|
|
||||||
|
|
||||||
// Initialize logger level based on debug setting
|
|
||||||
final debugEnabled = settings.getEnableDebugLogging();
|
|
||||||
setLoggerLevel(debugEnabled);
|
|
||||||
|
|
||||||
// Initialize download storage service with settings
|
|
||||||
await DownloadStorageService.instance.initialize(settings);
|
|
||||||
|
|
||||||
// Start global fullscreen state monitoring
|
|
||||||
FullscreenStateManager().startMonitoring();
|
|
||||||
|
|
||||||
// Initialize gamepad service for desktop platforms
|
|
||||||
if (Platform.isMacOS || Platform.isWindows || Platform.isLinux) {
|
|
||||||
GamepadService.instance.start();
|
|
||||||
DiscordRPCService.instance.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// DTD service is available for MCP tooling connection if needed
|
|
||||||
|
|
||||||
// Register bundled shader licenses
|
|
||||||
_registerShaderLicenses();
|
|
||||||
|
|
||||||
runApp(const MainApp());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _registerShaderLicenses() {
|
void _registerShaderLicenses() {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:plezy/widgets/app_icon.dart';
|
import 'package:plezy/widgets/app_icon.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import '../../models/hotkey_model.dart';
|
import '../../models/hotkey_model.dart';
|
||||||
@@ -97,6 +99,7 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab {
|
|||||||
static const _kDownloadOnWifiOnly = 'download_on_wifi_only';
|
static const _kDownloadOnWifiOnly = 'download_on_wifi_only';
|
||||||
static const _kVideoPlayerControls = 'video_player_controls';
|
static const _kVideoPlayerControls = 'video_player_controls';
|
||||||
static const _kVideoPlayerNavigation = 'video_player_navigation';
|
static const _kVideoPlayerNavigation = 'video_player_navigation';
|
||||||
|
static const _kCrashReporting = 'crash_reporting';
|
||||||
static const _kDebugLogging = 'debug_logging';
|
static const _kDebugLogging = 'debug_logging';
|
||||||
static const _kViewLogs = 'view_logs';
|
static const _kViewLogs = 'view_logs';
|
||||||
static const _kClearCache = 'clear_cache';
|
static const _kClearCache = 'clear_cache';
|
||||||
@@ -107,6 +110,7 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab {
|
|||||||
late final bool _keyboardShortcutsSupported = KeyboardShortcutsService.isPlatformSupported();
|
late final bool _keyboardShortcutsSupported = KeyboardShortcutsService.isPlatformSupported();
|
||||||
bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
|
|
||||||
|
bool _crashReporting = true;
|
||||||
bool _enableDebugLogging = false;
|
bool _enableDebugLogging = false;
|
||||||
bool _enableHardwareDecoding = true;
|
bool _enableHardwareDecoding = true;
|
||||||
int _bufferSize = 0;
|
int _bufferSize = 0;
|
||||||
@@ -183,6 +187,7 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab {
|
|||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
|
_crashReporting = _settingsService.getCrashReporting();
|
||||||
_enableDebugLogging = _settingsService.getEnableDebugLogging();
|
_enableDebugLogging = _settingsService.getEnableDebugLogging();
|
||||||
_enableHardwareDecoding = _settingsService.getEnableHardwareDecoding();
|
_enableHardwareDecoding = _settingsService.getEnableHardwareDecoding();
|
||||||
_bufferSize = _settingsService.getBufferSize();
|
_bufferSize = _settingsService.getBufferSize();
|
||||||
@@ -490,7 +495,7 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab {
|
|||||||
await _settingsService.setEnableHardwareDecoding(value);
|
await _settingsService.setEnableHardwareDecoding(value);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (Platform.isAndroid)
|
if (Platform.isAndroid || Platform.isIOS)
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
focusNode: _focusTracker.get(_kAutoPip),
|
focusNode: _focusTracker.get(_kAutoPip),
|
||||||
secondary: const AppIcon(Symbols.picture_in_picture_alt_rounded, fill: 1),
|
secondary: const AppIcon(Symbols.picture_in_picture_alt_rounded, fill: 1),
|
||||||
@@ -935,6 +940,19 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab {
|
|||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SwitchListTile(
|
||||||
|
focusNode: _focusTracker.get(_kCrashReporting),
|
||||||
|
secondary: const AppIcon(Symbols.monitoring_rounded, fill: 1),
|
||||||
|
title: Text(t.settings.crashReporting),
|
||||||
|
subtitle: Text(t.settings.crashReportingDescription),
|
||||||
|
value: _crashReporting,
|
||||||
|
onChanged: (value) async {
|
||||||
|
setState(() {
|
||||||
|
_crashReporting = value;
|
||||||
|
});
|
||||||
|
await _settingsService.setCrashReporting(value);
|
||||||
|
},
|
||||||
|
),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
focusNode: _focusTracker.get(_kDebugLogging),
|
focusNode: _focusTracker.get(_kDebugLogging),
|
||||||
secondary: const AppIcon(Symbols.bug_report_rounded, fill: 1),
|
secondary: const AppIcon(Symbols.bug_report_rounded, fill: 1),
|
||||||
@@ -974,6 +992,17 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab {
|
|||||||
trailing: const AppIcon(Symbols.chevron_right_rounded, fill: 1),
|
trailing: const AppIcon(Symbols.chevron_right_rounded, fill: 1),
|
||||||
onTap: () => _showResetSettingsDialog(),
|
onTap: () => _showResetSettingsDialog(),
|
||||||
),
|
),
|
||||||
|
if (kDebugMode)
|
||||||
|
ListTile(
|
||||||
|
leading: const AppIcon(Symbols.error_rounded, fill: 1),
|
||||||
|
title: const Text('Test Sentry'),
|
||||||
|
subtitle: const Text('Send a test error to Bugsink'),
|
||||||
|
trailing: const AppIcon(Symbols.chevron_right_rounded, fill: 1),
|
||||||
|
onTap: () {
|
||||||
|
Sentry.captureException(Exception('Sentry test from settings'));
|
||||||
|
showSnackBar(context, 'Test error sent to Sentry');
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:material_symbols_icons/symbols.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:os_media_controls/os_media_controls.dart';
|
import 'package:os_media_controls/os_media_controls.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
@@ -581,6 +582,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
|||||||
_playbackRestartSubscription = player!.streams.playbackRestart.listen((_) async {
|
_playbackRestartSubscription = player!.streams.playbackRestart.listen((_) async {
|
||||||
if (!_hasFirstFrame.value) {
|
if (!_hasFirstFrame.value) {
|
||||||
_hasFirstFrame.value = true;
|
_hasFirstFrame.value = true;
|
||||||
|
Sentry.addBreadcrumb(Breadcrumb(message: 'First frame ready', category: 'player'));
|
||||||
|
|
||||||
// Apply frame rate matching on Android if enabled
|
// Apply frame rate matching on Android if enabled
|
||||||
if (Platform.isAndroid && settingsService.getMatchContentFrameRate()) {
|
if (Platform.isAndroid && settingsService.getMatchContentFrameRate()) {
|
||||||
@@ -648,6 +650,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
|||||||
// Set MPV video-sync mode for smoother playback when display is synced
|
// Set MPV video-sync mode for smoother playback when display is synced
|
||||||
await player!.setProperty('video-sync', 'display-tempo');
|
await player!.setProperty('video-sync', 'display-tempo');
|
||||||
|
|
||||||
|
Sentry.addBreadcrumb(Breadcrumb(message: 'Frame rate matching: ${fps}fps', category: 'player'));
|
||||||
appLogger.d('Frame rate matching: Set display to ${fps}fps (duration: ${durationMs}ms)');
|
appLogger.d('Frame rate matching: Set display to ${fps}fps (duration: ${durationMs}ms)');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
appLogger.w('Failed to apply frame rate matching', error: e);
|
appLogger.w('Failed to apply frame rate matching', error: e);
|
||||||
@@ -661,6 +664,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
|||||||
try {
|
try {
|
||||||
await player!.clearVideoFrameRate();
|
await player!.clearVideoFrameRate();
|
||||||
await player!.setProperty('video-sync', 'audio');
|
await player!.setProperty('video-sync', 'audio');
|
||||||
|
Sentry.addBreadcrumb(Breadcrumb(message: 'Frame rate matching cleared', category: 'player'));
|
||||||
appLogger.d('Frame rate matching: Cleared, restored default display mode');
|
appLogger.d('Frame rate matching: Cleared, restored default display mode');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
appLogger.d('Failed to clear frame rate matching', error: e);
|
appLogger.d('Failed to clear frame rate matching', error: e);
|
||||||
@@ -1764,6 +1768,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sentry.addBreadcrumb(Breadcrumb(message: 'Player dispose', category: 'player'));
|
||||||
player?.dispose();
|
player?.dispose();
|
||||||
if (_activeRatingKey == widget.metadata.ratingKey) {
|
if (_activeRatingKey == widget.metadata.ratingKey) {
|
||||||
_activeRatingKey = null;
|
_activeRatingKey = null;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ enum EpisodePosterMode { seriesPoster, seasonPoster, episodeThumbnail }
|
|||||||
class SettingsService extends BaseSharedPreferencesService {
|
class SettingsService extends BaseSharedPreferencesService {
|
||||||
static const String _keyThemeMode = 'theme_mode';
|
static const String _keyThemeMode = 'theme_mode';
|
||||||
static const String _keyEnableDebugLogging = 'enable_debug_logging';
|
static const String _keyEnableDebugLogging = 'enable_debug_logging';
|
||||||
|
static const String _keyCrashReporting = 'crash_reporting';
|
||||||
static const String _keyBufferSize = 'buffer_size';
|
static const String _keyBufferSize = 'buffer_size';
|
||||||
static const String _keyBufferSizeMigratedToAuto = 'buffer_size_migrated_to_auto';
|
static const String _keyBufferSizeMigratedToAuto = 'buffer_size_migrated_to_auto';
|
||||||
static const String _keyKeyboardShortcuts = 'keyboard_shortcuts';
|
static const String _keyKeyboardShortcuts = 'keyboard_shortcuts';
|
||||||
@@ -85,10 +86,16 @@ class SettingsService extends BaseSharedPreferencesService {
|
|||||||
|
|
||||||
SettingsService._();
|
SettingsService._();
|
||||||
|
|
||||||
static Future<SettingsService> getInstance() {
|
static SettingsService? _cachedInstance;
|
||||||
return BaseSharedPreferencesService.initializeInstance(() => SettingsService._());
|
|
||||||
|
static Future<SettingsService> getInstance() async {
|
||||||
|
_cachedInstance ??= await BaseSharedPreferencesService.initializeInstance(() => SettingsService._());
|
||||||
|
return _cachedInstance!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Synchronous access to the singleton, or null if not yet initialized.
|
||||||
|
static SettingsService? get instanceOrNull => _cachedInstance;
|
||||||
|
|
||||||
/// Generic helper to get an enum value from preferences
|
/// Generic helper to get an enum value from preferences
|
||||||
T _getEnumValue<T extends Enum>(String key, List<T> values, T defaultValue) {
|
T _getEnumValue<T extends Enum>(String key, List<T> values, T defaultValue) {
|
||||||
final stored = prefs.getString(key);
|
final stored = prefs.getString(key);
|
||||||
@@ -121,6 +128,15 @@ class SettingsService extends BaseSharedPreferencesService {
|
|||||||
return prefs.getBool(_keyEnableDebugLogging) ?? false;
|
return prefs.getBool(_keyEnableDebugLogging) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Crash Reporting
|
||||||
|
Future<void> setCrashReporting(bool enabled) async {
|
||||||
|
await prefs.setBool(_keyCrashReporting, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getCrashReporting() {
|
||||||
|
return prefs.getBool(_keyCrashReporting) ?? true; // Default enabled
|
||||||
|
}
|
||||||
|
|
||||||
// Buffer Size (in MB)
|
// Buffer Size (in MB)
|
||||||
Future<void> setBufferSize(int sizeInMB) async {
|
Future<void> setBufferSize(int sizeInMB) async {
|
||||||
await prefs.setInt(_keyBufferSize, sizeInMB);
|
await prefs.setInt(_keyBufferSize, sizeInMB);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <os_media_controls/os_media_controls_plugin.h>
|
#include <os_media_controls/os_media_controls_plugin.h>
|
||||||
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
|
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
|
||||||
|
#include <sentry_flutter/sentry_flutter_plugin.h>
|
||||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||||
#include <universal_gamepad/gamepad_plugin.h>
|
#include <universal_gamepad/gamepad_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
@@ -20,6 +21,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
|||||||
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
|
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
|
||||||
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);
|
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) sentry_flutter_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin");
|
||||||
|
sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
|
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
|
||||||
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
|
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
os_media_controls
|
os_media_controls
|
||||||
screen_retriever_linux
|
screen_retriever_linux
|
||||||
|
sentry_flutter
|
||||||
sqlite3_flutter_libs
|
sqlite3_flutter_libs
|
||||||
universal_gamepad
|
universal_gamepad
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import os_media_controls
|
|||||||
import package_info_plus
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import screen_retriever_macos
|
import screen_retriever_macos
|
||||||
|
import sentry_flutter
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import sqflite_darwin
|
import sqflite_darwin
|
||||||
import sqlite3_flutter_libs
|
import sqlite3_flutter_libs
|
||||||
@@ -34,6 +35,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
|
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
|
||||||
|
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ PODS:
|
|||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- screen_retriever_macos (0.0.1):
|
- screen_retriever_macos (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- Sentry/HybridSDK (8.46.0)
|
||||||
|
- sentry_flutter (8.14.2):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- Sentry/HybridSDK (= 8.46.0)
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
@@ -75,6 +80,7 @@ DEPENDENCIES:
|
|||||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
|
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
|
||||||
|
- sentry_flutter (from `Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos`)
|
||||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
|
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
||||||
@@ -85,6 +91,7 @@ DEPENDENCIES:
|
|||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
|
- Sentry
|
||||||
- Sparkle
|
- Sparkle
|
||||||
- sqlite3
|
- sqlite3
|
||||||
|
|
||||||
@@ -111,6 +118,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||||
screen_retriever_macos:
|
screen_retriever_macos:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
|
||||||
|
sentry_flutter:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||||
sqflite_darwin:
|
sqflite_darwin:
|
||||||
@@ -138,6 +147,8 @@ SPEC CHECKSUMS:
|
|||||||
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
|
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
|
||||||
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
||||||
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
|
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
|
||||||
|
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
|
||||||
|
sentry_flutter: 27892878729f42701297c628eb90e7c6529f3684
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||||
Sparkle: f4355f9ebbe9b7d932df4980d70f13922ac97b2a
|
Sparkle: f4355f9ebbe9b7d932df4980d70f13922ac97b2a
|
||||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
|
|||||||
@@ -1008,6 +1008,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.2.0"
|
||||||
|
sentry:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sentry
|
||||||
|
sha256: "599701ca0693a74da361bc780b0752e1abc98226cf5095f6b069648116c896bb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.14.2"
|
||||||
|
sentry_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sentry_flutter
|
||||||
|
sha256: "5ba2cf40646a77d113b37a07bd69f61bb3ec8a73cbabe5537b05a7c89d2656f8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.14.2"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ dependencies:
|
|||||||
mobile_scanner: ^6.0.2
|
mobile_scanner: ^6.0.2
|
||||||
android_intent_plus: ^5.0.2
|
android_intent_plus: ^5.0.2
|
||||||
background_downloader: ^9.5.2
|
background_downloader: ^9.5.2
|
||||||
|
sentry_flutter: ^8.12.0
|
||||||
auto_updater:
|
auto_updater:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/edde746/auto_updater
|
url: https://github.com/edde746/auto_updater
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
ice.plezy.app {
|
||||||
|
reverse_proxy relay:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
bugs.plezy.app {
|
||||||
|
reverse_proxy bugsink:8000 {
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
FROM golang:1.22-alpine AS build
|
||||||
|
WORKDIR /src
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /relay .
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=build /relay /relay
|
||||||
|
VOLUME /data/logs
|
||||||
|
EXPOSE 8080
|
||||||
|
ENV GOMEMLIMIT=64MiB
|
||||||
|
ENTRYPOINT ["/relay"]
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
services:
|
||||||
|
relay:
|
||||||
|
build: .
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- logs:/data/logs
|
||||||
|
expose:
|
||||||
|
- "8080"
|
||||||
|
|
||||||
|
caddy:
|
||||||
|
image: caddy:2-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
|
||||||
|
bugsink:
|
||||||
|
image: bugsink/bugsink
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file: .env
|
||||||
|
environment:
|
||||||
|
SECRET_KEY: ${BUGSINK_SECRET_KEY}
|
||||||
|
CREATE_SUPERUSER: ${BUGSINK_SUPERUSER}
|
||||||
|
PORT: 8000
|
||||||
|
BEHIND_HTTPS_PROXY: "True"
|
||||||
|
expose:
|
||||||
|
- "8000"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
logs:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
+1
-9
@@ -2,12 +2,4 @@ module github.com/edde746/plezy-relay
|
|||||||
|
|
||||||
go 1.22
|
go 1.22
|
||||||
|
|
||||||
require (
|
require github.com/gorilla/websocket v1.5.3
|
||||||
github.com/gorilla/websocket v1.5.3
|
|
||||||
golang.org/x/crypto v0.31.0
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
golang.org/x/net v0.33.0 // indirect
|
|
||||||
golang.org/x/text v0.21.0 // indirect
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,8 +1,2 @@
|
|||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
|
||||||
|
|||||||
+57
-38
@@ -9,12 +9,14 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"golang.org/x/crypto/acme/autocert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -29,13 +31,16 @@ const (
|
|||||||
pingInterval = 30 * time.Second
|
pingInterval = 30 * time.Second
|
||||||
maxMessageSize = 64 * 1024
|
maxMessageSize = 64 * 1024
|
||||||
maxLogSize = 1 * 1024 * 1024 // 1MB
|
maxLogSize = 1 * 1024 * 1024 // 1MB
|
||||||
logMaxAge = 7 * 24 * time.Hour
|
logMaxAge = 3 * 24 * time.Hour
|
||||||
logIDLength = 5
|
logIDLength = 5
|
||||||
logRateInterval = 1 * time.Minute
|
logRateInterval = 1 * time.Minute
|
||||||
|
maxLogEntries = 500
|
||||||
)
|
)
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool { return true },
|
ReadBufferSize: 1024,
|
||||||
|
WriteBufferSize: 1024,
|
||||||
|
CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Rate limiter (token bucket) ---
|
// --- Rate limiter (token bucket) ---
|
||||||
@@ -150,21 +155,36 @@ func (r *Room) sendTo(targetID string, msg serverMsg) bool {
|
|||||||
// --- Log store ---
|
// --- Log store ---
|
||||||
|
|
||||||
type logEntry struct {
|
type logEntry struct {
|
||||||
Text string
|
Size int
|
||||||
ExpiresAt time.Time
|
ExpiresAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type logStore struct {
|
type logStore struct {
|
||||||
entries map[string]logEntry
|
entries map[string]logEntry
|
||||||
rateLimit map[string]time.Time // IP -> last upload time
|
rateLimit map[string]time.Time // IP -> last upload time
|
||||||
|
dir string
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLogStore() *logStore {
|
func newLogStore(dir string) *logStore {
|
||||||
return &logStore{
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||||
|
log.Fatalf("failed to create log dir %s: %v", dir, err)
|
||||||
|
}
|
||||||
|
ls := &logStore{
|
||||||
entries: make(map[string]logEntry),
|
entries: make(map[string]logEntry),
|
||||||
rateLimit: make(map[string]time.Time),
|
rateLimit: make(map[string]time.Time),
|
||||||
|
dir: dir,
|
||||||
}
|
}
|
||||||
|
// Clean orphaned files from prior runs
|
||||||
|
files, _ := os.ReadDir(dir)
|
||||||
|
for _, f := range files {
|
||||||
|
os.Remove(filepath.Join(dir, f.Name()))
|
||||||
|
}
|
||||||
|
return ls
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *logStore) filePath(id string) string {
|
||||||
|
return filepath.Join(ls.dir, id+".log")
|
||||||
}
|
}
|
||||||
|
|
||||||
const logIDChars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
const logIDChars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
@@ -184,6 +204,7 @@ func (ls *logStore) cleanup() {
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
for id, entry := range ls.entries {
|
for id, entry := range ls.entries {
|
||||||
if now.After(entry.ExpiresAt) {
|
if now.After(entry.ExpiresAt) {
|
||||||
|
os.Remove(ls.filePath(id))
|
||||||
delete(ls.entries, id)
|
delete(ls.entries, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,8 +223,8 @@ type Server struct {
|
|||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newServer() *Server {
|
func newServer(logDir string) *Server {
|
||||||
s := &Server{rooms: make(map[string]*Room), logs: newLogStore()}
|
s := &Server{rooms: make(map[string]*Room), logs: newLogStore(logDir)}
|
||||||
go s.cleanupLoop()
|
go s.cleanupLoop()
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@@ -271,10 +292,24 @@ func (s *Server) handlePostLogs(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.logs.mu.Lock()
|
||||||
|
if len(s.logs.entries) >= maxLogEntries {
|
||||||
|
s.logs.mu.Unlock()
|
||||||
|
http.Error(w, "Log store full", http.StatusServiceUnavailable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.logs.mu.Unlock()
|
||||||
|
|
||||||
id := generateLogID()
|
id := generateLogID()
|
||||||
|
if err := os.WriteFile(s.logs.filePath(id), body, 0644); err != nil {
|
||||||
|
log.Printf("logs: failed to write %s: %v", id, err)
|
||||||
|
http.Error(w, "Failed to store log", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.logs.mu.Lock()
|
s.logs.mu.Lock()
|
||||||
s.logs.entries[id] = logEntry{
|
s.logs.entries[id] = logEntry{
|
||||||
Text: string(body),
|
Size: len(body),
|
||||||
ExpiresAt: time.Now().Add(logMaxAge),
|
ExpiresAt: time.Now().Add(logMaxAge),
|
||||||
}
|
}
|
||||||
s.logs.mu.Unlock()
|
s.logs.mu.Unlock()
|
||||||
@@ -306,8 +341,15 @@ func (s *Server) handleGetLogs(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(s.logs.filePath(id))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
w.Write([]byte(entry.Text))
|
w.Header().Set("Content-Length", strconv.Itoa(entry.Size))
|
||||||
|
w.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) sendError(conn *websocket.Conn, code, message string) {
|
func (s *Server) sendError(conn *websocket.Conn, code, message string) {
|
||||||
@@ -485,11 +527,11 @@ func (s *Server) handleWS(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
dev := flag.Bool("dev", false, "Run in development mode (plain HTTP on :8080)")
|
addr := flag.String("addr", ":8080", "Listen address")
|
||||||
host := flag.String("host", "ice.plezy.app", "Hostname for TLS autocert")
|
logDir := flag.String("log-dir", "/data/logs", "Directory for log file storage")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
srv := newServer()
|
srv := newServer(*logDir)
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/relay", srv.handleWS)
|
mux.HandleFunc("/relay", srv.handleWS)
|
||||||
@@ -500,29 +542,6 @@ func main() {
|
|||||||
mux.HandleFunc("/logs", srv.handlePostLogs)
|
mux.HandleFunc("/logs", srv.handlePostLogs)
|
||||||
mux.HandleFunc("/logs/", srv.handleGetLogs)
|
mux.HandleFunc("/logs/", srv.handleGetLogs)
|
||||||
|
|
||||||
if *dev {
|
log.Printf("Starting relay server on %s", *addr)
|
||||||
log.Println("Starting dev server on :8080")
|
log.Fatal(http.ListenAndServe(*addr, mux))
|
||||||
log.Fatal(http.ListenAndServe(":8080", mux))
|
|
||||||
} else {
|
|
||||||
certManager := autocert.Manager{
|
|
||||||
Prompt: autocert.AcceptTOS,
|
|
||||||
HostPolicy: autocert.HostWhitelist(*host),
|
|
||||||
Cache: autocert.DirCache("/var/lib/plezy-relay/certs"),
|
|
||||||
}
|
|
||||||
|
|
||||||
server := &http.Server{
|
|
||||||
Addr: ":443",
|
|
||||||
Handler: mux,
|
|
||||||
TLSConfig: certManager.TLSConfig(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP challenge server for Let's Encrypt
|
|
||||||
go func() {
|
|
||||||
log.Println("Starting HTTP challenge server on :80")
|
|
||||||
log.Fatal(http.ListenAndServe(":80", certManager.HTTPHandler(nil)))
|
|
||||||
}()
|
|
||||||
|
|
||||||
log.Printf("Starting relay server on :443 (host=%s)", *host)
|
|
||||||
log.Fatal(server.ListenAndServeTLS("", ""))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||||
#include <os_media_controls/os_media_controls_plugin_c_api.h>
|
#include <os_media_controls/os_media_controls_plugin_c_api.h>
|
||||||
#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
|
#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
|
||||||
|
#include <sentry_flutter/sentry_flutter_plugin.h>
|
||||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||||
#include <universal_gamepad/gamepad_plugin_c_api.h>
|
#include <universal_gamepad/gamepad_plugin_c_api.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
@@ -24,6 +25,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||||||
registry->GetRegistrarForPlugin("OsMediaControlsPluginCApi"));
|
registry->GetRegistrarForPlugin("OsMediaControlsPluginCApi"));
|
||||||
ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
|
ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi"));
|
registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi"));
|
||||||
|
SentryFlutterPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("SentryFlutterPlugin"));
|
||||||
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
||||||
GamepadPluginCApiRegisterWithRegistrar(
|
GamepadPluginCApiRegisterWithRegistrar(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||||||
connectivity_plus
|
connectivity_plus
|
||||||
os_media_controls
|
os_media_controls
|
||||||
screen_retriever_windows
|
screen_retriever_windows
|
||||||
|
sentry_flutter
|
||||||
sqlite3_flutter_libs
|
sqlite3_flutter_libs
|
||||||
universal_gamepad
|
universal_gamepad
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
|
|||||||
Reference in New Issue
Block a user