diff --git a/SubathonManager.Integration/OBSService.cs b/SubathonManager.Integration/OBSService.cs index 254a1f4..32284be 100644 --- a/SubathonManager.Integration/OBSService.cs +++ b/SubathonManager.Integration/OBSService.cs @@ -97,6 +97,59 @@ 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"); + var count = 1; + if (response != null && response.TryGetValue("canvases", out JToken? _canvases)) { + foreach (var canvas in _canvases) { + +#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"] ?? false)) { + canvases.Remove("Default"); + } + canvases.Add(canvasName, new () { + {"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. + } + } + } + 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 @@ - - - - - - - - + + + + + + + + + + + - + + +