diff --git a/OBSBlur/OBS/Blur.cs b/OBSBlur/OBS/Blur.cs new file mode 100644 index 0000000..a587a7c --- /dev/null +++ b/OBSBlur/OBS/Blur.cs @@ -0,0 +1,227 @@ +using Newtonsoft.Json.Linq; +using OBSBlur.Window; +using OBSWebsocketDotNet; +using OBSWebsocketDotNet.Communication; +using OBSWebsocketDotNet.Types; +using OBSWebsocketDotNet.Types.Events; + +namespace OBSBlur.OBS; + +public class Blur +{ + WindowManager windowManager = new (); + private OBSWebsocket _websocket = new (); + private string currentScene; + private string[] enabledScenes; + private string[] blurPrograms; + private Dictionary windowHandleSceneItems = new(); + + public Blur(string obsUrl, string obsPassword, string[] enabledScenes, string[] blurPrograms) + { + this.enabledScenes = enabledScenes; + this.blurPrograms = blurPrograms; + windowManager.UpdateInterval = 1; + _websocket.CurrentProgramSceneChanged += WebsocketOnCurrentProgramSceneChanged; + _websocket.Connected += WebsocketOnConnected; + _websocket.Disconnected += WebsocketOnDisconnected; + + _websocket.ConnectAsync(obsUrl, obsPassword); + + windowManager.WindowsChanged += WindowManagerOnWindowsChanged; + windowManager.WindowZOrderChanged += WindowManagerOnWindowZOrderChanged; + } + + private void UpdateBlurs(WindowInfo[]? windowInfos = null, IntPtr[]? zOrder = null) + { + if (!enabledScenes.Contains(currentScene)) + return; + if (!_websocket.IsConnected) + return; + windowInfos ??= windowManager.WindowInfos; + zOrder ??= windowManager.WindowZOrder; + + bool addRemove = true; + + foreach (IntPtr window in zOrder) + { + WindowInfo windowInfo = windowInfos.FirstOrDefault(w => w.WindowHandle == window); + if(windowInfo is {WindowHandle: 0x0}) + continue; + bool blur = false; + foreach(string program in blurPrograms) + if (windowInfo.ProcessInfo.ProcessName.Contains(program, StringComparison.OrdinalIgnoreCase)) + blur = true; + + if(blur && addRemove) + BlurWindow(windowInfo); + else if(blur && addRemove is false) + DeleteBlur(windowInfo); + + if (windowInfo.WindowPlacement.ShowCmd is ShowWindowCommands.Maximize) + addRemove = false; + } + + foreach(WindowInfo windowInfo in windowInfos) + if (windowInfo.WindowPlacement.ShowCmd is ShowWindowCommands.ShowMinimized && + windowHandleSceneItems.ContainsKey(windowInfo.WindowHandle)) + { + DeleteBlur(windowInfo); + windowHandleSceneItems.Remove(windowInfo.WindowHandle); + } + } + + private void BlurWindow(WindowInfo windowInfo) + { + if(windowHandleSceneItems.ContainsKey(windowInfo.WindowHandle)) + MoveBlur(windowInfo); + else + AddBlur(windowInfo); + } + + private void AddBlur(WindowInfo windowInfo) + { + Dictionary request = new() + { + {"sceneName", currentScene}, + {"sceneItemId", GetBlurSource()} + }; + try + { + JObject response = _websocket.SendRequest("DuplicateSceneItem", JObject.FromObject(request)); + windowHandleSceneItems.Add(windowInfo.WindowHandle, response["sceneItemId"]!.Value()); + MoveBlur(windowInfo); + } + catch (ErrorResponseException e) + { + Console.WriteLine("No Scene Item with name 'Blur' found."); + throw; + } + } + + private void MoveBlur(WindowInfo windowInfo) + { + if (!windowHandleSceneItems.ContainsKey(windowInfo.WindowHandle)) + return; + + SceneItemTransformInfo info = windowInfo.WindowPlacement.ShowCmd switch + { + ShowWindowCommands.Maximize => new () + { + X = 0, + Y = 0, + BoundsHeight = 1080, //TODO desktop res + BoundsWidth = 1920, + BoundsType = SceneItemBoundsType.OBS_BOUNDS_STRETCH, + Alignnment = 5 + }, + _ => new() + { + X = windowInfo.WindowPlacement.NormalPosition.Left, + Y = windowInfo.WindowPlacement.NormalPosition.Top, + BoundsHeight = windowInfo.WindowPlacement.NormalPosition.Height, + BoundsWidth = windowInfo.WindowPlacement.NormalPosition.Width, + BoundsType = SceneItemBoundsType.OBS_BOUNDS_STRETCH, + Alignnment = 5 + }, + }; + + Dictionary request = new() + { + {"sceneName", currentScene}, + {"sceneItemId", windowHandleSceneItems[windowInfo.WindowHandle]}, + {"sceneItemTransform", info} + }; + _websocket.SendRequest("SetSceneItemTransform", JObject.FromObject(request)); + + + Dictionary request2 = new() + { + {"sceneName", currentScene}, + {"sceneItemId", windowHandleSceneItems[windowInfo.WindowHandle]}, + {"sceneItemEnabled", true} + }; + _websocket.SendRequest("SetSceneItemEnabled", JObject.FromObject(request2)); + } + + private void DeleteBlur(WindowInfo windowInfo) + { + if (!windowHandleSceneItems.ContainsKey(windowInfo.WindowHandle)) + return; + Dictionary request = new() + { + {"sceneName", currentScene}, + {"sceneItemId", windowHandleSceneItems[windowInfo.WindowHandle]} + }; + _websocket.SendRequest("RemoveSceneItem", JObject.FromObject(request)); + windowHandleSceneItems.Remove(windowInfo.WindowHandle); + } + + private uint GetBlurSource() + { + Dictionary request = new() + { + {"sceneName", currentScene}, + {"sourceName", "Blur"} + }; + try + { + JObject response = _websocket.SendRequest("GetSceneItemId", JObject.FromObject(request)); + return response["sceneItemId"]!.Value(); + } + catch (ErrorResponseException e) + { + Console.WriteLine("No Scene Item with name 'Blur' found."); + throw; + } + } + + private void WindowManagerOnWindowZOrderChanged(IntPtr[] neworder) + { + /* + uint i = 0; + string prnt = ""; + foreach (IntPtr windowHandle in order) + { + WindowInfo windowInfo = windowManager.WindowInfos.FirstOrDefault(w => w.WindowHandle == windowHandle); + if(windowInfo.WindowHandle is 0x0) + continue; + prnt += $"{++i,3} {windowInfo}\n"; + } + + Console.Clear(); + Console.WriteLine(prnt);*/ + Console.WriteLine($"Z-order changed {DateTime.UtcNow:O}"); + UpdateBlurs(zOrder: neworder); + } + + private void WindowManagerOnWindowsChanged(WindowInfo[] before, WindowInfo[] after) + { + string prnt = ""; + foreach (WindowInfo windowInfo in after) + prnt += $"{windowInfo}\n"; + Console.WriteLine(prnt); + Console.WriteLine($"Windows changed {DateTime.UtcNow:O}"); + UpdateBlurs(windowInfos: after); + } + + private void WebsocketOnDisconnected(object? sender, ObsDisconnectionInfo e) + { + Console.WriteLine($"Obs Disconnected {DateTime.UtcNow:O}"); + } + + private void WebsocketOnConnected(object? sender, EventArgs e) + { + currentScene = _websocket.GetCurrentProgramScene(); + Console.WriteLine($"Obs Connected. Current Scene {currentScene} {DateTime.UtcNow:O}"); + UpdateBlurs(); + } + + private void WebsocketOnCurrentProgramSceneChanged(object? sender, ProgramSceneChangedEventArgs e) + { + currentScene = e.SceneName; + Console.WriteLine($"Obs Scene Changed -> {currentScene} {DateTime.UtcNow:O}"); + UpdateBlurs(); + } + + +} \ No newline at end of file diff --git a/OBSBlur/OBSBlur.csproj b/OBSBlur/OBSBlur.csproj index 2b14c81..b57e85e 100644 --- a/OBSBlur/OBSBlur.csproj +++ b/OBSBlur/OBSBlur.csproj @@ -7,4 +7,8 @@ enable + + + + diff --git a/OBSBlur/Program.cs b/OBSBlur/Program.cs index bd46a94..f415f12 100644 --- a/OBSBlur/Program.cs +++ b/OBSBlur/Program.cs @@ -1,3 +1,8 @@ -using OBSBlur.Window; +using OBSBlur.OBS; -new WindowManager(); \ No newline at end of file + + +Blur _ = new Blur("ws://localhost:4444", "", new []{"Desktop"}, new []{ "Discord", "VRCX" }); + +while (true) + Thread.Sleep(100); \ No newline at end of file