feat: harden recording lifecycle and refresh fnOS UI

This commit is contained in:
2026-08-03 23:45:26 +08:00
parent e5b50ea85c
commit ecc737f0bd
90 changed files with 6995 additions and 1826 deletions
@@ -16,6 +16,7 @@ public sealed class DashboardService
private readonly ISystemLogRepository _systemLogRepository;
private readonly ISystemSettingsService _systemSettingsService;
private readonly IStorageGuardService _storageGuardService;
private readonly IOperationsMetricsRepository _operationsMetricsRepository;
public DashboardService(
ILiveRoomRepository liveRoomRepository,
@@ -24,7 +25,8 @@ public sealed class DashboardService
IRecordResultRepository recordResultRepository,
ISystemLogRepository systemLogRepository,
ISystemSettingsService systemSettingsService,
IStorageGuardService storageGuardService)
IStorageGuardService storageGuardService,
IOperationsMetricsRepository operationsMetricsRepository)
{
_liveRoomRepository = liveRoomRepository;
_recordSessionRepository = recordSessionRepository;
@@ -33,6 +35,7 @@ public sealed class DashboardService
_systemLogRepository = systemLogRepository;
_systemSettingsService = systemSettingsService;
_storageGuardService = storageGuardService;
_operationsMetricsRepository = operationsMetricsRepository;
}
public async Task<DashboardDto> GetDashboardAsync(CancellationToken cancellationToken = default)
@@ -45,6 +48,7 @@ public sealed class DashboardService
var todayUtcStart = new DateTimeOffset(todayBeijingDate.ToDateTime(TimeOnly.MinValue), ChinaTime.Zone.GetUtcOffset(beijingNow.DateTime)).ToUniversalTime();
var todayUtcEnd = new DateTimeOffset(todayBeijingDate.ToDateTime(TimeOnly.MaxValue), ChinaTime.Zone.GetUtcOffset(beijingNow.DateTime)).ToUniversalTime();
var recentErrorSince = now.AddHours(-24);
var currentErrorSince = now.AddMinutes(-30);
// Run queries sequentially — DbContext is not thread-safe
var activeRecordingCount = await _recordSessionRepository.CountByStatusAsync(RecordSessionStatus.Running, cancellationToken);
@@ -53,6 +57,7 @@ public sealed class DashboardService
var totalRoomCount = await _liveRoomRepository.CountAsync(cancellationToken);
var activeSessionCount = await _recordSessionRepository.CountActiveAsync(cancellationToken);
var recentErrorCount = await _systemLogRepository.CountRecentErrorsAsync(recentErrorSince, cancellationToken);
var currentErrorCount = await _systemLogRepository.CountRecentErrorsAsync(currentErrorSince, cancellationToken);
var todayRecordingSeconds = await _recordTaskRepository.SumDurationSecondsAsync(todayUtcStart, todayUtcEnd, cancellationToken);
var (todayTotalBytes, todayTotalDanmaku) = await _recordResultRepository.GetTodayAggregateAsync(todayUtcStart, todayUtcEnd, cancellationToken);
var recentSessions = await _recordSessionRepository.ListRecentAsync(5, cancellationToken);
@@ -62,6 +67,7 @@ public sealed class DashboardService
var pendingTranscodeCount = await _recordTaskRepository.CountByStatusAsync(RecordTaskStatus.Processing, cancellationToken);
var pendingUploadCount = await _recordResultRepository.CountPendingUploadAsync(cancellationToken);
var queuedDataBytes = await _recordResultRepository.SumPendingUploadBytesAsync(cancellationToken);
var operationsMetrics = await _operationsMetricsRepository.GetAsync(cancellationToken);
return new DashboardDto
{
@@ -74,17 +80,31 @@ public sealed class DashboardService
TodayDanmakuCount = todayTotalDanmaku,
ActiveSessionCount = activeSessionCount,
RecentErrorCount = recentErrorCount,
CurrentErrorCount = currentErrorCount,
StorageStatus = new StorageStatusDto
{
IsEnabled = storageCheck.IsEnabled,
IsAvailable = storageCheck.IsAvailable,
HasEnoughSpace = storageCheck.HasEnoughSpace,
Message = storageCheck.Message ?? string.Empty,
CheckedPath = storageCheck.CheckedPath,
TotalBytes = storageCheck.TotalBytes,
UsedBytes = storageCheck.UsedBytes,
AvailableBytes = storageCheck.AvailableBytes,
RequiredBytes = storageCheck.RequiredBytes,
Tier = storageCheck.Tier.ToString(),
UsagePercent = storageCheck.UsagePercent
UsagePercent = storageCheck.UsagePercent,
FreePercent = storageCheck.FreePercent,
GreenThresholdPercent = storageCheck.GreenThresholdPercent,
RedThresholdPercent = storageCheck.RedThresholdPercent
},
PendingTranscodeCount = pendingTranscodeCount,
PendingUploadCount = pendingUploadCount,
QueuedDataBytes = queuedDataBytes,
OldestTranscodeUpdatedAt = operationsMetrics.OldestTranscodeUpdatedAt,
OldestUploadProgressAt = operationsMetrics.OldestUploadProgressAt,
StalledUploadCount = operationsMetrics.StalledUploadCount,
UploadCleanupFailureCount = operationsMetrics.CleanupFailureCount,
RecentSessions = recentSessions
.Select(MapRecentSession)
.ToList(),