From c8e98bdb2a9ab464ed0dc32f3a9f87bef97a77e0 Mon Sep 17 00:00:00 2001 From: keyldev Date: Thu, 2 Jul 2026 20:35:08 +0300 Subject: [PATCH] feat(editor): multi-vendor RTSP URI templates - "Templates" flyout replaces the single XM button - OpenIPC, XM, Hikvision, Dahua, Reolink, TP-Link, Uniview - creds ride RTSP auth except XM (embedded in path per NETSurveillance) --- src/OpenIPC.Viewer.App/Services/Localizer.cs | 8 ++-- .../Dialogs/CameraEditorViewModel.cs | 38 ++++++++++++++++--- .../Views/Dialogs/CameraEditorContent.axaml | 19 ++++++++-- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/OpenIPC.Viewer.App/Services/Localizer.cs b/src/OpenIPC.Viewer.App/Services/Localizer.cs index e4d8d5b..12083d1 100644 --- a/src/OpenIPC.Viewer.App/Services/Localizer.cs +++ b/src/OpenIPC.Viewer.App/Services/Localizer.cs @@ -340,8 +340,8 @@ private static LangCode DetectSystem() ["CameraEditor.Placeholder.SshPort"] = "22", ["CameraEditor.NoGroup"] = "(no group)", ["CameraEditor.Button.AutoDeriveRtsp"] = "Auto from host", - ["CameraEditor.Button.AutoDeriveXmRtsp"] = "XM preset", - ["CameraEditor.Tooltip.AutoDeriveXmRtsp"] = "Fill in the RTSP URLs used by XM/Xiongmai (NETSurveillance) cameras", + ["CameraEditor.Button.RtspTemplates"] = "Templates ▾", + ["CameraEditor.Tooltip.RtspTemplates"] = "Fill in the RTSP URLs used by a specific camera vendor", ["CameraEditor.Button.TestConnection"] = "Test connection", ["CameraEditor.Status.Connecting"] = "Connecting…", ["CameraEditor.Status.OkFormat"] = "OK — {0}x{1}", @@ -811,8 +811,8 @@ private static LangCode DetectSystem() ["CameraEditor.Placeholder.SshPort"] = "22", ["CameraEditor.NoGroup"] = "(без группы)", ["CameraEditor.Button.AutoDeriveRtsp"] = "Подставить из хоста", - ["CameraEditor.Button.AutoDeriveXmRtsp"] = "Пресет XM", - ["CameraEditor.Tooltip.AutoDeriveXmRtsp"] = "Подставить RTSP-адреса камер XM/Xiongmai (NETSurveillance)", + ["CameraEditor.Button.RtspTemplates"] = "Шаблоны ▾", + ["CameraEditor.Tooltip.RtspTemplates"] = "Подставить RTSP-адреса под конкретного производителя камеры", ["CameraEditor.Button.TestConnection"] = "Проверить", ["CameraEditor.Status.Connecting"] = "Подключение…", ["CameraEditor.Status.OkFormat"] = "OK — {0}x{1}", diff --git a/src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs b/src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs index 8dde719..92bb3f6 100644 --- a/src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs +++ b/src/OpenIPC.Viewer.App/ViewModels/Dialogs/CameraEditorViewModel.cs @@ -159,17 +159,43 @@ private void AutoDeriveRtsp() RtspMainText = $"rtsp://{Host.Trim()}/"; } - // XM/Xiongmai (NETSurveillance) firmware embeds the login in the RTSP path - // and serves main/sub as stream=0/1. Uses the credential fields when set, - // falling back to the stock "admin" + empty password those cameras ship with. + // Vendor RTSP URI templates (camera-editor "Templates" flyout). Fills both + // main/sub from the host field. Credentials ride the RTSP auth handshake + // (the Username/Password fields), so they are NOT embedded in the URI — + // except XM/Xiongmai (NETSurveillance), whose firmware wants the login in + // the path itself; there the fields are used, falling back to the stock + // "admin" + empty password those cameras ship with. [RelayCommand] - private void AutoDeriveXmRtsp() + private void ApplyRtspTemplate(string vendor) { if (string.IsNullOrWhiteSpace(Host)) return; var host = Host.Trim(); var user = string.IsNullOrWhiteSpace(Username) ? "admin" : Username.Trim(); - RtspMainText = $"rtsp://{host}:554/user={user}&password={Password}&channel=1&stream=0.sdp?real_stream"; - RtspSubText = $"rtsp://{host}:554/user={user}&password={Password}&channel=1&stream=1.sdp?real_stream"; + (RtspMainText, RtspSubText) = vendor switch + { + "openipc" => ( + $"rtsp://{host}:554/stream0", + $"rtsp://{host}:554/stream1"), + "xm" => ( + $"rtsp://{host}:554/user={user}&password={Password}&channel=1&stream=0.sdp?real_stream", + $"rtsp://{host}:554/user={user}&password={Password}&channel=1&stream=1.sdp?real_stream"), + "hikvision" => ( + $"rtsp://{host}:554/Streaming/Channels/101", + $"rtsp://{host}:554/Streaming/Channels/102"), + "dahua" => ( + $"rtsp://{host}:554/cam/realmonitor?channel=1&subtype=0", + $"rtsp://{host}:554/cam/realmonitor?channel=1&subtype=1"), + "reolink" => ( + $"rtsp://{host}:554/h264Preview_01_main", + $"rtsp://{host}:554/h264Preview_01_sub"), + "tplink" => ( + $"rtsp://{host}:554/stream1", + $"rtsp://{host}:554/stream2"), + "uniview" => ( + $"rtsp://{host}:554/media/video1", + $"rtsp://{host}:554/media/video2"), + _ => (RtspMainText, RtspSubText), + }; } [RelayCommand(CanExecute = nameof(CanTestConnection))] diff --git a/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml b/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml index f6c02c0..6405022 100644 --- a/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml +++ b/src/OpenIPC.Viewer.App/Views/Dialogs/CameraEditorContent.axaml @@ -53,13 +53,24 @@ Padding="0" FontSize="{StaticResource FontSizeSm}" />