From b010ca03176337b582362be0a203e68bc2f77365 Mon Sep 17 00:00:00 2001 From: WolfwithSword <12175651+WolfwithSword@users.noreply.github.com> Date: Sun, 30 Aug 2026 19:47:14 -0300 Subject: [PATCH 1/2] Add OBS Canvas Sync selection, fix twitch raid points value --- SubathonManager.Integration/OBSService.cs | 49 +++++++++++++++++++ SubathonManager.Services/EventService.cs | 6 +++ .../EditRouteWindow.Handlers.cs | 40 +++++++++++++++ SubathonManager.UI/EditRouteWindow.axaml | 33 ++++++++----- 4 files changed, 117 insertions(+), 11 deletions(-) diff --git a/SubathonManager.Integration/OBSService.cs b/SubathonManager.Integration/OBSService.cs index 254a1f4..1547c49 100644 --- a/SubathonManager.Integration/OBSService.cs +++ b/SubathonManager.Integration/OBSService.cs @@ -97,6 +97,55 @@ public Task StopAsync(CancellationToken cancellationToken = default) { public event Action? BrowserSourcesChanged; + public Dictionary> GetCanvases() { + var canvases = new Dictionary>(); + if (!_obs.IsConnected) { + return canvases; + } + + var currentCanvas = _obs.GetVideoSettings(); + + canvases.Add("Default", new () { + {"Width", currentCanvas.BaseWidth}, + {"Height", currentCanvas.BaseHeight} + }); + + var v = _obs.GetVersion(); + + if (v.AvailableRequests.Contains("GetCanvasList")) { + try { + var response = _obs.SendRequest("GetCanvasList"); + if (response != null && response.TryGetValue("canvases", out JToken? _canvases)) { + foreach (var canvas in _canvases) { + string canvasName = (string)canvas["canvasName"]; + var videoSettings = canvas["canvasVideoSettings"]; + var flags = canvas["canvasFlags"]; + if ((bool)flags["MAIN"]) { + canvases.Remove("Default"); + } + canvases.Add(canvasName, new () { + {"Width", (int)videoSettings["baseWidth"]}, + {"Height", (int)videoSettings["baseHeight"]} + }); + + } + } + } + catch (Exception ex) { + _logger?.LogWarning(ex, "[OBSService] GetCanvasList request failed"); + } + } + + if (canvases.Count == 0) { + canvases.Add("Default", new () { + {"Width", currentCanvas.BaseWidth}, + {"Height", currentCanvas.BaseHeight} + }); + } + + return canvases; + } + public List GetScenes() { return _obs.GetSceneList().Scenes .Select(s => s.Name) diff --git a/SubathonManager.Services/EventService.cs b/SubathonManager.Services/EventService.cs index d6a4b0f..12ce91c 100644 --- a/SubathonManager.Services/EventService.cs +++ b/SubathonManager.Services/EventService.cs @@ -186,6 +186,7 @@ private async Task LoopAsync() { /////////////////////////////////////////////////////////////// ev.PointsValue = (int)Math.Floor(subathonValue!.Points); if (double.TryParse(ev.Value, out double parsedValue) + && ev.Currency != "viewers" && ev.Currency != "sub" && ev.Currency != "member" && ev.Currency != "order" // allow items from orders && !_currencyService.IsValidCurrency(ev.Currency) && !string.IsNullOrEmpty(ev.Value.Trim())) { @@ -215,6 +216,11 @@ private async Task LoopAsync() { ev.SecondsValue = subathonValue.Seconds; } + if (ev.EventType.IsRaid()) { + // All raid types are always points per raid never viewer + ev.PointsValue = (int)Math.Floor(subathonValue!.Points); + } + if (ev.EventType.IsCurrencyDonation() && (string.IsNullOrEmpty(ev.Currency) || !_currencyService.IsValidCurrency(ev.Currency))) { ev.PointsValue = 0; diff --git a/SubathonManager.UI/EditRouteWindow.Handlers.cs b/SubathonManager.UI/EditRouteWindow.Handlers.cs index f7e498b..8b0fc1d 100644 --- a/SubathonManager.UI/EditRouteWindow.Handlers.cs +++ b/SubathonManager.UI/EditRouteWindow.Handlers.cs @@ -21,6 +21,7 @@ using SubathonManager.Data; using SubathonManager.Data.Widgets; using SubathonManager.UI.Controls; +using SubathonManager.UI.Services; using SubathonManager.UI.UiUtils; using SubathonManager.UI.Validation; using SubathonManager.UI.Views; @@ -29,6 +30,8 @@ namespace SubathonManager.UI; public partial class EditRouteWindow { + private MenuFlyout? _statusFlyout; + #region GeneralHandlers private void WidgetDirtyBorder_Loaded(object? sender, RoutedEventArgs e) { @@ -145,6 +148,38 @@ private async void CopyOverlayUrl_Click(object? sender, RoutedEventArgs e) { _logger?.LogError(ex, "Failed to copy overlay URL"); } } + + private void ShowObsCanvasSelection_Click(object? sender, RoutedEventArgs e) { + var flyout = new MenuFlyout { Placement = PlacementMode.Bottom }; + + FillObsCanvases(flyout.Items);/////// + flyout.Closed += (_, _) => { + if (ReferenceEquals(_statusFlyout, flyout)) _statusFlyout = null; + }; + _statusFlyout = flyout; + flyout.ShowAt(OBSCanvasSyncBtn); + } + + private void FillObsCanvases(ItemCollection items) { + items.Clear(); + var canvases = ServiceManager.OBS.GetCanvases(); + if (canvases.Count == 0) return; + + foreach (var canvasData in canvases) { + var width = canvasData.Value["Width"]; + var height = canvasData.Value["Height"]; + var name = $"{canvasData.Key} (WxH {width}x{height})"; + var groupItem = new MenuItem { + Header = name + }; + groupItem.Click += async (_, _) => { + RouteHeightBox.Text = $"{height}"; + RouteWidthBox.Text = $"{width}"; + await SaveCurrentRoute(); + }; + items.Add(groupItem); + } + } private void OpenOverlayInBrowser_Click(object? sender, RoutedEventArgs e) { if (_route == null) return; @@ -900,6 +935,11 @@ private async void MoveDown_Click(object? sender, RoutedEventArgs e) { } private async void SaveRouteButton_Click(object? sender, RoutedEventArgs e) { + if (_route == null) return; + await SaveCurrentRoute(); + } + + private async Task SaveCurrentRoute() { if (_route == null) return; try { await SaveAllPendingWidgetChangesAsync(); diff --git a/SubathonManager.UI/EditRouteWindow.axaml b/SubathonManager.UI/EditRouteWindow.axaml index 4698a5b..a445e39 100644 --- a/SubathonManager.UI/EditRouteWindow.axaml +++ b/SubathonManager.UI/EditRouteWindow.axaml @@ -356,18 +356,29 @@ - - - - - - - - + + + + + + + + + + + - + + + From 727e3fa17356d96f2e8f95db04dba5f6c2edbde4 Mon Sep 17 00:00:00 2001 From: WolfwithSword <12175651+WolfwithSword@users.noreply.github.com> Date: Sun, 30 Aug 2026 19:51:50 -0300 Subject: [PATCH 2/2] remove safety warnings bc we are bad --- SubathonManager.Integration/OBSService.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/SubathonManager.Integration/OBSService.cs b/SubathonManager.Integration/OBSService.cs index 1547c49..32284be 100644 --- a/SubathonManager.Integration/OBSService.cs +++ b/SubathonManager.Integration/OBSService.cs @@ -115,19 +115,23 @@ public Dictionary> GetCanvases() { if (v.AvailableRequests.Contains("GetCanvasList")) { try { var response = _obs.SendRequest("GetCanvasList"); + var count = 1; if (response != null && response.TryGetValue("canvases", out JToken? _canvases)) { foreach (var canvas in _canvases) { - string canvasName = (string)canvas["canvasName"]; + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + string canvasName = (string)canvas["canvasName"] ?? $"Canvas {count}"; + var videoSettings = canvas["canvasVideoSettings"]; var flags = canvas["canvasFlags"]; - if ((bool)flags["MAIN"]) { + if ((bool)(flags?["MAIN"] ?? false)) { canvases.Remove("Default"); } canvases.Add(canvasName, new () { - {"Width", (int)videoSettings["baseWidth"]}, - {"Height", (int)videoSettings["baseHeight"]} + {"Width", (int)(videoSettings?["baseWidth"] ?? 1920)}, + {"Height", (int)(videoSettings?["baseHeight"] ?? 1080)} }); - +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } } }