Files
better-genshin-impact/BetterGenshinImpact/Core/Video/ObsRecorder.cs
2025-01-05 02:38:41 +08:00

249 lines
7.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
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;
private DateTime _lastRecordTime = DateTime.MinValue;
public string FileName { get; set; }
public ObsRecorder()
{
_obs64Process = StartObs();
obs = new OBSWebsocket();
// 注册连接事件处理
obs.Connected += OnConnected;
obs.Disconnected += OnDisconnected;
Connect();
}
public static Process? StartObs()
{
// 判断 OBS 是否已经启动
var list = Process.GetProcessesByName("obs64");
if (list.Length == 0)
{
// 启动 OBS 并等待启动完成
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = ObsPath,
Arguments = "--disable-shutdown-check --disable-missing-files-check --disable-updater",
WorkingDirectory = Path.GetDirectoryName(ObsPath)
};
var 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: 启动完成");
return obs64Process;
}
else
{
TaskControl.Logger.LogError("OBS: 启动失败");
throw new Exception("OBS启动失败");
return null;
}
}
return list[0];
}
// 连接到 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();
_lastRecordTime = DateTime.Now;
TaskControl.Logger.LogInformation("OBS: ws请求开始录制时间: {Time}", _lastRecordTime.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
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: ws请求开始录制失败: {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: 停止录制录制");
var name = Path.GetFileName(path);
TaskControl.Logger.LogInformation("OBS: 文件存储在 {Path}", name);
MoveFile(name);
}
}
private void MoveFile(string name)
{
Task.Run(() =>
{
try
{
var videoPath = Global.Absolute($@"video\{name}");
var folderPath = Global.Absolute($@"User\KeyMouseScript\{FileName}\");
if (File.Exists(videoPath))
{
int i = 0;
for (i = 0; i < 10; i++)
{
if (IsFileLocked(videoPath))
{
TaskControl.Logger.LogDebug("OBS: 等待文件保存完成...重试次数: {Count}", i + 1);
Thread.Sleep(1000);
}
else
{
var targetPath = Path.Combine(folderPath, "video" + Path.GetExtension(videoPath));
File.Move(videoPath, targetPath);
TaskControl.Logger.LogInformation("OBS: 录制结果文件已移动到 {Path}", targetPath);
break;
}
}
if (i == 10)
{
TaskControl.Logger.LogError("未能移动录制结果文件,文件可能被占用,请手动移动,文件路径: {Path}", videoPath);
}
}
else
{
TaskControl.Logger.LogError("OBS: 未找到录制结果文件");
}
// File.WriteAllText(Path.Combine(folderPath, "videoStartTime.txt"), (_lastRecordTime.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalNanoseconds.ToString("F0"));
}
catch (Exception e)
{
TaskControl.Logger.LogError("移动录制结果文件时出现错误: {Error}", e.Message);
}
});
}
static bool IsFileLocked(string filePath)
{
FileStream stream = null;
try
{
// 尝试以读取方式打开文件
stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException)
{
// 捕获IOException异常表示文件被占用
return true;
}
finally
{
// 关闭文件流
stream?.Close();
}
return false;
}
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();
}
}
}