OBSBlur/OBSBlur/OBS/Blur.cs
2024-04-16 20:59:42 +02:00

251 lines
8.4 KiB
C#

using Microsoft.Extensions.Logging;
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
{
private readonly WindowManager _windowManager = new ();
private readonly OBSWebsocket _websocket = new ();
private string _currentObsScene = "";
private readonly List<string> _enabledObsScenes = new();
private readonly List<string> _blurPrograms = new();
private readonly Dictionary<IntPtr, uint> _windowHandleSceneItems = new();
private readonly ILogger? _logger;
public Blur(string obsUrl, string obsPassword, string[] enabledObsScenes, string[] blurPrograms, ILogger? logger = null)
{
this._logger = logger;
this._enabledObsScenes.AddRange(enabledObsScenes);
this._blurPrograms.AddRange(blurPrograms);
_websocket.CurrentProgramSceneChanged += WebsocketOnCurrentProgramSceneChanged;
_websocket.Connected += WebsocketOnConnected;
_websocket.Disconnected += WebsocketOnDisconnected;
_websocket.ConnectAsync(obsUrl, obsPassword);
_windowManager.WindowsChanged += WindowManagerOnWindowsChanged;
_windowManager.ZOrderChanged += WindowManagerOnWindowZOrderChanged;
}
private void UpdateBlurs()
{
if (!_enabledObsScenes.Contains(_currentObsScene))
return;
if (!_websocket.IsConnected)
return;
WindowInfo[] windowInfos = _windowManager.WindowInfos;
IntPtr[] zOrder = _windowManager.WindowZOrder;
bool maximixedWindowReached = false;
foreach (IntPtr window in zOrder)
{
WindowInfo windowInfo = windowInfos.FirstOrDefault(w => w.WindowHandle == window);
if(windowInfo is {WindowHandle: 0x0})//No WindowInfo found
continue;
if(GetBlurWindow(windowInfo))
if(!maximixedWindowReached)
BlurWindow(windowInfo);
else if(maximixedWindowReached)
DeleteBlur(windowInfo);
if (windowInfo.WindowCommands is ShowWindowCommands.Maximize or ShowWindowCommands.ShowMaximized)
maximixedWindowReached = true;
}
foreach(IntPtr blurredWindow in _windowHandleSceneItems.Keys.ToArray())
if(windowInfos.All(w => w.WindowHandle != blurredWindow))
DeleteBlur(blurredWindow);
}
private bool GetBlurWindow(WindowInfo windowInfo)
{
foreach(string program in _blurPrograms)
if (windowInfo.ProcessInfo.ProcessName.Contains(program, StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
private void BlurWindow(WindowInfo windowInfo)
{
if(_windowHandleSceneItems.ContainsKey(windowInfo.WindowHandle))
MoveBlur(windowInfo);
else
AddBlur(windowInfo);
}
private void AddBlur(WindowInfo windowInfo)
{
Dictionary<string, object> duplicateSceneItemRequest = new()
{
{"sceneName", _currentObsScene},
{"sceneItemId", GetBlurSource()}
};
try
{
JObject response = _websocket.SendRequest("DuplicateSceneItem", JObject.FromObject(duplicateSceneItemRequest));
if (!response.ContainsKey("sceneItemId"))
{
_logger?.LogWarning("Request DuplicateSceneItem: Response did not include 'sceneItemId'.");
return;
}
_windowHandleSceneItems.Add(windowInfo.WindowHandle, response["sceneItemId"]!.Value<uint>());
MoveBlur(windowInfo);
}
catch (ErrorResponseException e)
{
_logger?.LogError(e, "Request 'DuplicateSceneItem'");
throw;
}
}
private void MoveBlur(WindowInfo windowInfo)
{
if (!_windowHandleSceneItems.ContainsKey(windowInfo.WindowHandle))
return;
SceneItemTransformInfo info = new()
{
X = windowInfo.WindowRectangle.X,
Y = windowInfo.WindowRectangle.Y,
BoundsHeight = windowInfo.WindowRectangle.Height,
BoundsWidth = windowInfo.WindowRectangle.Width,
BoundsType = SceneItemBoundsType.OBS_BOUNDS_STRETCH,
Alignnment = 5
};
Dictionary<string, object> setSceneItemTransformRequest = new()
{
{"sceneName", _currentObsScene},
{"sceneItemId", _windowHandleSceneItems[windowInfo.WindowHandle]},
{"sceneItemTransform", info}
};
try
{
_websocket.SendRequest("SetSceneItemTransform", JObject.FromObject(setSceneItemTransformRequest));
}
catch (ErrorResponseException e)
{
_logger?.LogError(e, "Request 'SetSceneItemTransform'");
throw;
}
Dictionary<string, object> setSceneItemEnabledRequest = new()
{
{"sceneName", _currentObsScene},
{"sceneItemId", _windowHandleSceneItems[windowInfo.WindowHandle]},
{"sceneItemEnabled", true}
};
try
{
_websocket.SendRequest("SetSceneItemEnabled", JObject.FromObject(setSceneItemEnabledRequest));
}
catch (ErrorResponseException e)
{
_logger?.LogError(e, "Request 'SetSceneItemEnabled'");
throw;
}
}
private void DeleteBlur(IntPtr windowHandle)
{
if (!_windowHandleSceneItems.TryGetValue(windowHandle, out uint sceneItemId))
return;
Dictionary<string, object> removeSceneItemRequest = new()
{
{"sceneName", _currentObsScene},
{"sceneItemId", sceneItemId}
};
try
{
_websocket.SendRequest("RemoveSceneItem", JObject.FromObject(removeSceneItemRequest));
_windowHandleSceneItems.Remove(windowHandle);
}
catch (ErrorResponseException e)
{
_logger?.LogError(e, "Request 'RemoveSceneItem'");
throw;
}
}
private void DeleteBlur(WindowInfo windowInfo)
{
DeleteBlur(windowInfo.WindowHandle);
}
private uint GetBlurSource()
{
Dictionary<string, string> request = new()
{
{"sceneName", _currentObsScene},
{"sourceName", "Blur"}
};
try
{
JObject response = _websocket.SendRequest("GetSceneItemId", JObject.FromObject(request));
if (!response.ContainsKey("sceneItemId"))
throw new KeyNotFoundException("sceneItemId not in response.");
return response["sceneItemId"]!.Value<uint>();
}
catch (Exception e)
{
_logger?.LogError(e, "Request 'GetSceneItemId'");
throw;
}
}
private void WindowManagerOnWindowZOrderChanged(IntPtr[] neworder)
{
uint i = 0;
string prnt = $"Z-order changed\n{"Z",-3} | {"hWnd",-8} | {"PID",-8} | {"Name",-17} | {"Window Title",-17} | {"State",-13} | BBox\n";
foreach (IntPtr windowHandle in neworder)
{
WindowInfo windowInfo = _windowManager.WindowInfos.FirstOrDefault(w => w.WindowHandle == windowHandle);
if (windowInfo.WindowHandle is 0x0)
continue;
prnt += $"{++i,3} | {windowInfo}\n";
}
_logger?.LogInformation(prnt);
UpdateBlurs();
}
private void WindowManagerOnWindowsChanged(WindowInfo[] before, WindowInfo[] after)
{
string prnt = "Window changed\n";
foreach (WindowInfo windowInfo in after)
prnt += $"{windowInfo}\n";
_logger?.LogInformation(prnt);
UpdateBlurs();
}
private void WebsocketOnDisconnected(object? sender, ObsDisconnectionInfo e)
{
_logger?.LogInformation("Obs Disconnected");
}
private void WebsocketOnConnected(object? sender, EventArgs e)
{
_currentObsScene = _websocket.GetCurrentProgramScene();
_logger?.LogInformation($"Obs Connected. Current Scene '{_currentObsScene}'");
UpdateBlurs();
}
private void WebsocketOnCurrentProgramSceneChanged(object? sender, ProgramSceneChangedEventArgs e)
{
_currentObsScene = e.SceneName;
_logger?.LogInformation($"Obs Scene Changed -> '{_currentObsScene}'");
UpdateBlurs();
}
}