feat: improve recording automation and task workflows

This commit is contained in:
2026-04-23 23:18:11 +08:00
parent 1c892259a9
commit 23ead56781
88 changed files with 9579 additions and 1581 deletions
@@ -17,6 +17,11 @@ public sealed class SystemSettingsService : ISystemSettingsService
private const string SaveModeKey = "recording.save_mode";
private const string RecordingTemplateKey = "recording.template";
private const string SegmentDurationMinutesKey = "recording.segment_duration_minutes";
private const string MaxConcurrentFfmpegTranscodeTasksKey = "recording.max_concurrent_ffmpeg_transcode_tasks";
private const string Mp4FinalizeTimeoutMinutesKey = "recording.mp4_finalize_timeout_minutes";
private const string EnableStorageGuardKey = "storage.guard.enabled";
private const string PauseRecordingWhenFreeSpaceBelowMegabytesKey = "storage.guard.pause_recording_below_mb";
private const string ResumeRecordingWhenFreeSpaceAboveMegabytesKey = "storage.guard.resume_recording_above_mb";
private const string EnableReconnectKey = "recording.enable_auto_reconnect";
private const string ReconnectDelayMaxSecondsKey = "recording.reconnect_delay_max_seconds";
private const string ReadWriteTimeoutMillisecondsKey = "recording.read_write_timeout_milliseconds";
@@ -27,6 +32,11 @@ public sealed class SystemSettingsService : ISystemSettingsService
private const string EnableBackgroundPollingKey = "scheduler.enable_background_polling";
private const string AutoStartRecordingOnLiveKey = "scheduler.auto_start_recording_on_live";
private const string PollingIntervalSecondsKey = "scheduler.polling_interval_seconds";
private const string EnableEventScriptsKey = "event_scripts.enabled";
private const string LiveStartedScriptPathKey = "event_scripts.live_started.path";
private const string LiveEndedScriptPathKey = "event_scripts.live_ended.path";
private const string SegmentCompletedScriptPathKey = "event_scripts.segment_completed.path";
private const string EventScriptTimeoutSecondsKey = "event_scripts.timeout_seconds";
private const string EnableEmailNotificationKey = "notification.email.enabled";
private const string EmailSmtpHostKey = "notification.email.smtp_host";
private const string EmailSmtpPortKey = "notification.email.smtp_port";
@@ -77,6 +87,11 @@ public sealed class SystemSettingsService : ISystemSettingsService
? recordingTemplate
: RecordingTemplateType.StreamCopy,
SegmentDurationMinutes = GetIntValue(lookup, SegmentDurationMinutesKey, 30, 1, 720),
MaxConcurrentFfmpegTranscodeTasks = GetIntValue(lookup, MaxConcurrentFfmpegTranscodeTasksKey, 1, 1, 16),
Mp4FinalizeTimeoutMinutes = GetIntValue(lookup, Mp4FinalizeTimeoutMinutesKey, 60, 1, 1440),
EnableStorageGuard = bool.TryParse(GetValue(lookup, EnableStorageGuardKey, "true"), out var enableStorageGuard) && enableStorageGuard,
PauseRecordingWhenFreeSpaceBelowMegabytes = GetIntValue(lookup, PauseRecordingWhenFreeSpaceBelowMegabytesKey, 1024, 0, 1048576),
ResumeRecordingWhenFreeSpaceAboveMegabytes = GetIntValue(lookup, ResumeRecordingWhenFreeSpaceAboveMegabytesKey, 4096, 0, 1048576),
EnableAutoReconnect = bool.TryParse(GetValue(lookup, EnableReconnectKey, "true"), out var enableReconnect) && enableReconnect,
ReconnectDelayMaxSeconds = GetIntValue(lookup, ReconnectDelayMaxSecondsKey, 5, 1, 300),
ReadWriteTimeoutMilliseconds = GetIntValue(lookup, ReadWriteTimeoutMillisecondsKey, 15000000, 1000, 60000000),
@@ -87,6 +102,11 @@ public sealed class SystemSettingsService : ISystemSettingsService
EnableBackgroundPolling = bool.TryParse(GetValue(lookup, EnableBackgroundPollingKey, "true"), out var enableBackgroundPolling) && enableBackgroundPolling,
AutoStartRecordingOnLive = bool.TryParse(GetValue(lookup, AutoStartRecordingOnLiveKey, "true"), out var autoStartRecordingOnLive) && autoStartRecordingOnLive,
PollingIntervalSeconds = GetIntValue(lookup, PollingIntervalSecondsKey, 60, 10, 3600),
EnableEventScripts = bool.TryParse(GetValue(lookup, EnableEventScriptsKey, "false"), out var enableEventScripts) && enableEventScripts,
LiveStartedScriptPath = GetValue(lookup, LiveStartedScriptPathKey, string.Empty),
LiveEndedScriptPath = GetValue(lookup, LiveEndedScriptPathKey, string.Empty),
SegmentCompletedScriptPath = GetValue(lookup, SegmentCompletedScriptPathKey, string.Empty),
EventScriptTimeoutSeconds = GetIntValue(lookup, EventScriptTimeoutSecondsKey, 60, 1, 3600),
EnableEmailNotification = bool.TryParse(GetValue(lookup, EnableEmailNotificationKey, "false"), out var enableEmailNotification) && enableEmailNotification,
EmailSmtpHost = GetValue(lookup, EmailSmtpHostKey, string.Empty),
EmailSmtpPort = GetIntValue(lookup, EmailSmtpPortKey, 587, 1, 65535),
@@ -159,6 +179,27 @@ public sealed class SystemSettingsService : ISystemSettingsService
await UpsertAsync(SaveModeKey, request.SaveMode.ToString(), now, cancellationToken);
await UpsertAsync(RecordingTemplateKey, request.RecordingTemplate.ToString(), now, cancellationToken);
await UpsertAsync(SegmentDurationMinutesKey, request.SegmentDurationMinutes.ToString(), now, cancellationToken);
await UpsertAsync(
MaxConcurrentFfmpegTranscodeTasksKey,
Math.Clamp(request.MaxConcurrentFfmpegTranscodeTasks, 1, 16).ToString(),
now,
cancellationToken);
await UpsertAsync(
Mp4FinalizeTimeoutMinutesKey,
Math.Clamp(request.Mp4FinalizeTimeoutMinutes, 1, 1440).ToString(),
now,
cancellationToken);
await UpsertAsync(EnableStorageGuardKey, request.EnableStorageGuard.ToString(), now, cancellationToken);
await UpsertAsync(
PauseRecordingWhenFreeSpaceBelowMegabytesKey,
Math.Clamp(request.PauseRecordingWhenFreeSpaceBelowMegabytes, 0, 1048576).ToString(),
now,
cancellationToken);
await UpsertAsync(
ResumeRecordingWhenFreeSpaceAboveMegabytesKey,
Math.Clamp(request.ResumeRecordingWhenFreeSpaceAboveMegabytes, 0, 1048576).ToString(),
now,
cancellationToken);
await UpsertAsync(EnableReconnectKey, request.EnableAutoReconnect.ToString(), now, cancellationToken);
await UpsertAsync(ReconnectDelayMaxSecondsKey, request.ReconnectDelayMaxSeconds.ToString(), now, cancellationToken);
await UpsertAsync(ReadWriteTimeoutMillisecondsKey, request.ReadWriteTimeoutMilliseconds.ToString(), now, cancellationToken);
@@ -169,6 +210,11 @@ public sealed class SystemSettingsService : ISystemSettingsService
await UpsertAsync(EnableBackgroundPollingKey, request.EnableBackgroundPolling.ToString(), now, cancellationToken);
await UpsertAsync(AutoStartRecordingOnLiveKey, request.AutoStartRecordingOnLive.ToString(), now, cancellationToken);
await UpsertAsync(PollingIntervalSecondsKey, request.PollingIntervalSeconds.ToString(), now, cancellationToken);
await UpsertAsync(EnableEventScriptsKey, request.EnableEventScripts.ToString(), now, cancellationToken);
await UpsertAsync(LiveStartedScriptPathKey, request.LiveStartedScriptPath.Trim(), now, cancellationToken);
await UpsertAsync(LiveEndedScriptPathKey, request.LiveEndedScriptPath.Trim(), now, cancellationToken);
await UpsertAsync(SegmentCompletedScriptPathKey, request.SegmentCompletedScriptPath.Trim(), now, cancellationToken);
await UpsertAsync(EventScriptTimeoutSecondsKey, Math.Clamp(request.EventScriptTimeoutSeconds, 1, 3600).ToString(), now, cancellationToken);
await UpsertAsync(EnableEmailNotificationKey, request.EnableEmailNotification.ToString(), now, cancellationToken);
await UpsertAsync(EmailSmtpHostKey, request.EmailSmtpHost.Trim(), now, cancellationToken);
await UpsertAsync(EmailSmtpPortKey, request.EmailSmtpPort.ToString(), now, cancellationToken);