This commit is contained in:
辉鸭蛋
2024-12-28 14:11:16 +08:00
parent 03f0e46784
commit cbd33a15ef
12 changed files with 309 additions and 19 deletions

View File

@@ -49,6 +49,7 @@
<PackageReference Include="Microsoft.ML.OnnxRuntime.Managed" Version="1.18.1" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2592.51" />
<PackageReference Include="NAudio" Version="2.2.1" />
<PackageReference Include="obs-websocket-dotnet" Version="5.0.0.3" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
<PackageReference Include="OpenCvSharp4.WpfExtensions" Version="4.8.0.20230708" />
<PackageReference Include="OpenCvSharp4.Extensions" Version="4.8.0.20230708" />

View File

@@ -42,4 +42,8 @@ public partial class CommonConfig : ObservableObject
// 关闭时还原分辨率
[ObservableProperty]
private bool _restoreResolutionOnExit;
// 录制工具 ffmpeg/obs
[ObservableProperty]
private string _recorder = "ffmpeg";
}

View File

@@ -29,7 +29,7 @@ public class GlobalKeyMouseRecord : Singleton<GlobalKeyMouseRecord>
// private SharpAviRecorder _sharpAviRecorder;
private FfmpegRecorder? _ffmpegRecorder;
private IVideoRecorder? _videoRecorder;
private readonly Dictionary<Keys, bool> _keyDownState = [];
@@ -64,6 +64,11 @@ public class GlobalKeyMouseRecord : Singleton<GlobalKeyMouseRecord>
Toast.Warning("已经在录制状态,请不要重复启动录制功能");
return;
}
if (TaskContext.Instance().Config.CommonConfig.Recorder == "obs")
{
TaskControl.Logger.LogInformation("当前选择使用OBS录制OBS启动较慢请耐心等待...");
}
_keyMouseMacroRecordHotkey = TaskContext.Instance().Config.HotKeyConfig.KeyMouseMacroRecordHotkey;
_paimonSwitchEnabled = TaskContext.Instance().Config.RecordConfig.PaimonSwitchEnabled;
@@ -80,7 +85,7 @@ public class GlobalKeyMouseRecord : Singleton<GlobalKeyMouseRecord>
// _sharpAviRecorder = new SharpAviRecorder( Path.Combine(videoPath, $"{DateTime.Now:yyyyMMddHH_mmssffff.avi}"),
// CodecIds.MotionJpeg, 90, 0, SupportedWaveFormat.WAVE_FORMAT_44M16, false, 0);
_ffmpegRecorder = new FfmpegRecorder(fileName);
_videoRecorder = VideoRecorderFactory.Create(TaskContext.Instance().Config.CommonConfig.Recorder, fileName);
_directInputMonitor = new DirectInputMonitor();
// TaskTriggerDispatcher.Instance().StopTimer();
@@ -98,7 +103,8 @@ public class GlobalKeyMouseRecord : Singleton<GlobalKeyMouseRecord>
}
_ffmpegRecorder.Start();
var videoEnabled = _videoRecorder.Start();
_directInputMonitor.Start();
_recorder = new KeyMouseRecorderJsonLine(fileName);
@@ -120,7 +126,7 @@ public class GlobalKeyMouseRecord : Singleton<GlobalKeyMouseRecord>
_directInputMonitor?.Dispose();
_directInputMonitor = null;
_ffmpegRecorder?.Stop();
_videoRecorder?.Stop();
if (_timer.Enabled)
{

View File

@@ -13,7 +13,7 @@ using Serilog.Core;
namespace BetterGenshinImpact.Core.Video;
public class FfmpegRecorder
public class FfmpegRecorder : IVideoRecorder
{
// ffmpeg进程
private readonly Process _process;
@@ -132,4 +132,9 @@ public class FfmpegRecorder
TaskControl.Logger.LogError("ffmpeg录制: 停止时异常:{Text}", e.Message);
}
}
public void Dispose()
{
}
}

View File

@@ -0,0 +1,10 @@
using System;
namespace BetterGenshinImpact.Core.Video;
public interface IVideoRecorder : IDisposable
{
public bool Start();
public void Stop();
}

View File

@@ -0,0 +1,159 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.GameTask.Common;
using Microsoft.Extensions.Logging;
using OBSWebsocketDotNet;
using OBSWebsocketDotNet.Communication;
namespace BetterGenshinImpact.Core.Video;
public class ObsRecorder : IVideoRecorder
{
private static readonly string ObsPath = Global.Absolute(@"video\bin\OBS-Studio-31.0.0-Windows\bin\64bit\obs64.exe");
private Process? _obs64Process;
private OBSWebsocket obs;
private bool isConnected = false;
public ObsRecorder()
{
// 判断 OBS 是否已经启动
if (Process.GetProcessesByName("obs64").Length == 0)
{
// 启动 OBS 并等待启动完成
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = ObsPath,
Arguments = "--disable-shutdown-check --disable-missing-files-check --disable-updater",
WorkingDirectory = Path.GetDirectoryName(ObsPath)
};
_obs64Process = Process.Start(startInfo);
if (_obs64Process != null)
{
_obs64Process.WaitForInputIdle(); // Wait for the process to be ready for input
Debug.WriteLine("OBS has started and is ready for input.");
TaskControl.Logger.LogInformation("OBS: 启动完成");
}
else
{
TaskControl.Logger.LogError("OBS: 启动失败");
throw new Exception("OBS启动失败");
}
}
obs = new OBSWebsocket();
// 注册连接事件处理
obs.Connected += OnConnected;
obs.Disconnected += OnDisconnected;
Connect();
}
// 连接到 OBS
public void Connect(string url = "ws://localhost:44557", string password = "huiyadanli@789")
{
try
{
obs.ConnectAsync(url, password);
}
catch (AuthFailureException)
{
TaskControl.Logger.LogError("OBS: 验证失败 - 密码错误");
throw;
}
catch (ErrorResponseException ex)
{
TaskControl.Logger.LogError($"连接失败: {ex.Message}");
throw;
}
catch (Exception ex)
{
TaskControl.Logger.LogError($"连接失败: {ex.Message}");
throw;
}
}
// 开始录制
public bool Start()
{
for (int i = 0; i < 10; i++)
{
if (obs.IsConnected)
{
try
{
obs.StartRecord();
TaskControl.Logger.LogInformation("OBS: 开始录制");
return true;
}
catch (ErrorResponseException ex)
{
if (ex.ErrorCode == 207)
{
TaskControl.Logger.LogInformation("207错误等待连接 OBS 就绪...重试次数: {Count}", i + 1);
Thread.Sleep(1000);
}
else
{
TaskControl.Logger.LogError($"OBS: 开始录制失败: {ex.Message}");
throw;
}
}
}
else
{
Thread.Sleep(1000);
TaskControl.Logger.LogInformation("等待连接 OBS 连接...重试次数: {Count}", i + 1);
}
}
TaskControl.Logger.LogError("OBS: 启动录制失败,未连接到 OBS");
return false;
}
// 停止录制
public void Stop()
{
if (obs.IsConnected)
{
var path = obs.StopRecord();
TaskControl.Logger.LogInformation("OBS: 停止录制录制");
TaskControl.Logger.LogInformation("OBS: 文件存储在 {Path}", path);
}
}
private void OnConnected(object? sender, EventArgs e)
{
isConnected = true;
TaskControl.Logger.LogInformation("OBS: 成功连接");
}
private void OnDisconnected(object? sender, ObsDisconnectionInfo e)
{
if (isConnected)
{
TaskControl.Logger.LogWarning("OBS: 断开连接, 原因: {Reason}", e.DisconnectReason);
}
else
{
TaskControl.Logger.LogError("OBS: 断开连接, 原因: {Reason}", e.DisconnectReason);
}
isConnected = false;
}
public void Dispose()
{
if (obs.IsConnected)
{
obs.Disconnect();
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using BetterGenshinImpact.GameTask.Common;
using Microsoft.Extensions.Logging;
namespace BetterGenshinImpact.Core.Video;
public class VideoRecorderFactory
{
private static ObsRecorder? _obsRecorder;
public static IVideoRecorder Create(string recorderType, string fileName)
{
switch (recorderType)
{
case "ffmpeg":
return new FfmpegRecorder(fileName);
case "obs":
_obsRecorder ??= new ObsRecorder();
return _obsRecorder;
default:
throw new ArgumentException("不支持的录制工具");
}
}
}

View File

@@ -103,14 +103,20 @@ public static class TouchpadManager
public static bool HasTouchInput()
{
foreach (TabletDevice tabletDevice in Tablet.TabletDevices)
bool hasTouchInput = false;
UIDispatcherHelper.Invoke(()=>
{
//Only detect if it is a touch Screen not how many touches (i.e. Single touch or Multi-touch)
if(tabletDevice.Type == TabletDeviceType.Touch)
return true;
}
foreach (TabletDevice tabletDevice in Tablet.TabletDevices)
{
//Only detect if it is a touch Screen not how many touches (i.e. Single touch or Multi-touch)
if(tabletDevice.Type == TabletDeviceType.Touch)
{
hasTouchInput= true;
}
}
});
return false;
return hasTouchInput;
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.Core.Config;
@@ -68,6 +70,16 @@ public class StartEndSingleton: Singleton<StartEndSingleton>
SysDpi.Instance.ResetDpi();
}
try
{
Process.GetProcessesByName("obs64").ToList().ForEach(p => p.Kill());
Process.GetProcessesByName("ffmpeg").ToList().ForEach(p => p.Kill());
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}

View File

@@ -501,6 +501,33 @@
Margin="0,0,36,0"
IsChecked="{Binding Config.CommonConfig.RestoreResolutionOnExit, Mode=TwoWay}" />
</Grid>
<Grid Margin="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ui:TextBlock Grid.Row="0"
Grid.Column="0"
FontTypography="Body"
Text="显示实时任务启用状态"
TextWrapping="Wrap" />
<ui:TextBlock Grid.Row="1"
Grid.Column="0"
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
Text="在遮罩内显示实时任务启用状态"
TextWrapping="Wrap" />
<ComboBox Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
Margin="0,0,36,0"
ItemsSource="{Binding RecorderTypes, Mode=OneWay}"
SelectedItem="{Binding Config.CommonConfig.Recorder, Mode=TwoWay}">
</ComboBox>
</Grid>
</StackPanel>
</ui:CardExpander>

View File

@@ -28,7 +28,10 @@ public partial class CommonSettingsPageViewModel : ObservableObject, INavigation
[ObservableProperty] private bool _isLoading;
[ObservableProperty] private string _webhookStatus = string.Empty;
[ObservableProperty]
private string[] _recorderTypes = ["ffmpeg", "obs"];
public CommonSettingsPageViewModel(IConfigService configService, INavigationService navigationService, NotificationService notificationService)
{

View File

@@ -128,10 +128,10 @@ public partial class KeyMouseRecordPageViewModel : ObservableObject, INavigation
return;
}
}
fileName = $"{DateTime.Now:yyyy_MM_dd_HH_mm_ss}";
await Task.Run(() =>
{
try
@@ -139,7 +139,11 @@ public partial class KeyMouseRecordPageViewModel : ObservableObject, INavigation
var pcFolder = Global.Absolute(@$"User/KeyMouseScript/{fileName}");
Directory.CreateDirectory(pcFolder);
// 移动PC信息
File.Copy(Global.Absolute(@$"User/pc.json"), Path.Combine(pcFolder, "pc.json"), true);
var src= Global.Absolute(@$"User/pc.json");
if (File.Exists(src))
{
File.Copy(Global.Absolute(@$"User/pc.json"), Path.Combine(pcFolder, "pc.json"), true);
}
}
catch (Exception e)
{
@@ -148,15 +152,22 @@ public partial class KeyMouseRecordPageViewModel : ObservableObject, INavigation
});
if (!IsRecording)
{
IsRecording = true;
SystemSettingsManager.GetSystemSettings();
SystemSettingsManager.SetSystemSettings();
await GlobalKeyMouseRecord.Instance.StartRecord(fileName);
try
{
await GlobalKeyMouseRecord.Instance.StartRecord(fileName);
}
catch (Exception e)
{
_logger.LogDebug(e, "启动录制时发生异常");
_logger.LogError(e.Message);
IsRecording = false;
}
}
}
@@ -177,9 +188,30 @@ public partial class KeyMouseRecordPageViewModel : ObservableObject, INavigation
catch (Exception e)
{
_logger.LogDebug(e, "停止录制时发生异常");
_logger.LogWarning(e.Message);
_logger.LogError(e.Message);
}
SystemSettingsManager.RestoreSystemSettings();
Task.Run(() =>
{
try
{
var pcFolder = Global.Absolute(@$"User/KeyMouseScript/{fileName}");
Directory.CreateDirectory(pcFolder);
// 移动PC信息
var src= Global.Absolute(@$"User/pc.json");
if (File.Exists(src))
{
File.Copy(Global.Absolute(@$"User/pc.json"), Path.Combine(pcFolder, "pc.json"), true);
}
}
catch (Exception e)
{
TaskControl.Logger.LogDebug("移动PC信息失败" + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message);
}
});
}
}