From ca2c5595550e498c5eff529490ce95e1f145bffd Mon Sep 17 00:00:00 2001 From: nanxun Date: Sun, 26 Apr 2026 21:16:26 +0800 Subject: [PATCH] fix: improve event script controls and daily reviews --- frontend/src/types.ts | 3 ++ frontend/src/views/DailyReviewsView.vue | 17 +++---- frontend/src/views/SettingsView.vue | 10 ++++ .../Models/Settings/SettingsModels.cs | 12 +++++ .../Services/SystemSettingsService.cs | 48 +++++++++++++++++++ .../Services/EventScriptService.cs | 6 +-- src/LiveRecorder.WebApi/Dockerfile | 2 +- 7 files changed, 86 insertions(+), 12 deletions(-) diff --git a/frontend/src/types.ts b/frontend/src/types.ts index e81bb2d..c92fd7b 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -383,12 +383,15 @@ export interface SystemSettings { webDavUpload: WebDavUploadSettings; s3Upload: S3UploadSettings; enableEventScripts: boolean; + enableLiveStartedScript: boolean; liveStartedScriptMode: string; liveStartedScriptPath: string; liveStartedScriptContent: string; + enableLiveEndedScript: boolean; liveEndedScriptMode: string; liveEndedScriptPath: string; liveEndedScriptContent: string; + enableSegmentCompletedScript: boolean; segmentCompletedScriptMode: string; segmentCompletedScriptPath: string; segmentCompletedScriptContent: string; diff --git a/frontend/src/views/DailyReviewsView.vue b/frontend/src/views/DailyReviewsView.vue index 32be7f9..449204e 100644 --- a/frontend/src/views/DailyReviewsView.vue +++ b/frontend/src/views/DailyReviewsView.vue @@ -86,9 +86,10 @@ onMounted(loadReport);
@@ -203,15 +204,15 @@ onMounted(loadReport); {{ formatDuration(item.durationSeconds) }}
- 鍒嗙墖 {{ item.segmentCount }} - 寮瑰箷 {{ item.danmakuCount }} - 璀﹀憡 {{ item.warningCount }} - 閿欒 {{ item.errorCount }} + 分片 {{ item.segmentCount }} + 弹幕 {{ item.danmakuCount }} + 警告 {{ item.warningCount }} + 错误 {{ item.errorCount }}
{{ item.summary || "-" }}
diff --git a/frontend/src/views/SettingsView.vue b/frontend/src/views/SettingsView.vue index 5325711..b36be6a 100644 --- a/frontend/src/views/SettingsView.vue +++ b/frontend/src/views/SettingsView.vue @@ -95,12 +95,15 @@ const form = reactive({ forcePathStyle: false }, enableEventScripts: false, + enableLiveStartedScript: false, liveStartedScriptMode: "path", liveStartedScriptPath: "", liveStartedScriptContent: "", + enableLiveEndedScript: false, liveEndedScriptMode: "path", liveEndedScriptPath: "", liveEndedScriptContent: "", + enableSegmentCompletedScript: false, segmentCompletedScriptMode: "path", segmentCompletedScriptPath: "", segmentCompletedScriptContent: "", @@ -986,6 +989,7 @@ onMounted(loadSettings);

房间首次进入在线状态时触发。

+ 房间从在线切回离线时触发。

+ MP4 转码完成并且分片状态变成 completed 后触发。

+ LIVE_RECORDER_SCRIPT_LOG_PATH 指向的临时文件。
+
+ 官方 Docker 镜像默认内置 curljq;如果你使用宿主机直跑或自定义镜像,实际可用命令以运行环境为准。 +
+
环境变量示例值
diff --git a/src/LiveRecorder.Application/Models/Settings/SettingsModels.cs b/src/LiveRecorder.Application/Models/Settings/SettingsModels.cs index 65e38e5..3712ac0 100644 --- a/src/LiveRecorder.Application/Models/Settings/SettingsModels.cs +++ b/src/LiveRecorder.Application/Models/Settings/SettingsModels.cs @@ -116,18 +116,24 @@ public sealed class SystemSettingsDto public bool EnableEventScripts { get; set; } = false; + public bool EnableLiveStartedScript { get; set; } = false; + public string LiveStartedScriptMode { get; set; } = EventScriptSourceModes.Path; public string LiveStartedScriptPath { get; set; } = string.Empty; public string LiveStartedScriptContent { get; set; } = string.Empty; + public bool EnableLiveEndedScript { get; set; } = false; + public string LiveEndedScriptMode { get; set; } = EventScriptSourceModes.Path; public string LiveEndedScriptPath { get; set; } = string.Empty; public string LiveEndedScriptContent { get; set; } = string.Empty; + public bool EnableSegmentCompletedScript { get; set; } = false; + public string SegmentCompletedScriptMode { get; set; } = EventScriptSourceModes.Path; public string SegmentCompletedScriptPath { get; set; } = string.Empty; @@ -291,18 +297,24 @@ public sealed class UpdateSystemSettingsRequest public bool EnableEventScripts { get; set; } = false; + public bool EnableLiveStartedScript { get; set; } = false; + public string LiveStartedScriptMode { get; set; } = EventScriptSourceModes.Path; public string LiveStartedScriptPath { get; set; } = string.Empty; public string LiveStartedScriptContent { get; set; } = string.Empty; + public bool EnableLiveEndedScript { get; set; } = false; + public string LiveEndedScriptMode { get; set; } = EventScriptSourceModes.Path; public string LiveEndedScriptPath { get; set; } = string.Empty; public string LiveEndedScriptContent { get; set; } = string.Empty; + public bool EnableSegmentCompletedScript { get; set; } = false; + public string SegmentCompletedScriptMode { get; set; } = EventScriptSourceModes.Path; public string SegmentCompletedScriptPath { get; set; } = string.Empty; diff --git a/src/LiveRecorder.Application/Services/SystemSettingsService.cs b/src/LiveRecorder.Application/Services/SystemSettingsService.cs index 4ea1aa1..454d54c 100644 --- a/src/LiveRecorder.Application/Services/SystemSettingsService.cs +++ b/src/LiveRecorder.Application/Services/SystemSettingsService.cs @@ -55,12 +55,15 @@ public sealed class SystemSettingsService : ISystemSettingsService private const string HuyaProxyEnabledKey = "platform_proxy.huya.enabled"; private const string HuyaProxyUrlKey = "platform_proxy.huya.url"; private const string EnableEventScriptsKey = "event_scripts.enabled"; + private const string EnableLiveStartedScriptKey = "event_scripts.live_started.enabled"; private const string LiveStartedScriptModeKey = "event_scripts.live_started.mode"; private const string LiveStartedScriptPathKey = "event_scripts.live_started.path"; private const string LiveStartedScriptContentKey = "event_scripts.live_started.content"; + private const string EnableLiveEndedScriptKey = "event_scripts.live_ended.enabled"; private const string LiveEndedScriptModeKey = "event_scripts.live_ended.mode"; private const string LiveEndedScriptPathKey = "event_scripts.live_ended.path"; private const string LiveEndedScriptContentKey = "event_scripts.live_ended.content"; + private const string EnableSegmentCompletedScriptKey = "event_scripts.segment_completed.enabled"; private const string SegmentCompletedScriptModeKey = "event_scripts.segment_completed.mode"; private const string SegmentCompletedScriptPathKey = "event_scripts.segment_completed.path"; private const string SegmentCompletedScriptContentKey = "event_scripts.segment_completed.content"; @@ -179,12 +182,30 @@ public sealed class SystemSettingsService : ISystemSettingsService ForcePathStyle = bool.TryParse(GetValue(lookup, S3ForcePathStyleKey, "false"), out var s3ForcePathStyle) && s3ForcePathStyle }, EnableEventScripts = bool.TryParse(GetValue(lookup, EnableEventScriptsKey, "false"), out var enableEventScripts) && enableEventScripts, + EnableLiveStartedScript = GetEventScriptEnabled( + lookup, + EnableLiveStartedScriptKey, + enableEventScripts, + LiveStartedScriptPathKey, + LiveStartedScriptContentKey), LiveStartedScriptMode = GetEventScriptMode(lookup, LiveStartedScriptModeKey, LiveStartedScriptPathKey, LiveStartedScriptContentKey), LiveStartedScriptPath = GetValue(lookup, LiveStartedScriptPathKey, string.Empty), LiveStartedScriptContent = GetValue(lookup, LiveStartedScriptContentKey, string.Empty), + EnableLiveEndedScript = GetEventScriptEnabled( + lookup, + EnableLiveEndedScriptKey, + enableEventScripts, + LiveEndedScriptPathKey, + LiveEndedScriptContentKey), LiveEndedScriptMode = GetEventScriptMode(lookup, LiveEndedScriptModeKey, LiveEndedScriptPathKey, LiveEndedScriptContentKey), LiveEndedScriptPath = GetValue(lookup, LiveEndedScriptPathKey, string.Empty), LiveEndedScriptContent = GetValue(lookup, LiveEndedScriptContentKey, string.Empty), + EnableSegmentCompletedScript = GetEventScriptEnabled( + lookup, + EnableSegmentCompletedScriptKey, + enableEventScripts, + SegmentCompletedScriptPathKey, + SegmentCompletedScriptContentKey), SegmentCompletedScriptMode = GetEventScriptMode(lookup, SegmentCompletedScriptModeKey, SegmentCompletedScriptPathKey, SegmentCompletedScriptContentKey), SegmentCompletedScriptPath = GetValue(lookup, SegmentCompletedScriptPathKey, string.Empty), SegmentCompletedScriptContent = GetValue(lookup, SegmentCompletedScriptContentKey, string.Empty), @@ -329,12 +350,15 @@ public sealed class SystemSettingsService : ISystemSettingsService await UpsertAsync(HuyaProxyEnabledKey, huyaProxy.Enabled.ToString(), now, cancellationToken); await UpsertAsync(HuyaProxyUrlKey, huyaProxy.ProxyUrl.Trim(), now, cancellationToken); await UpsertAsync(EnableEventScriptsKey, request.EnableEventScripts.ToString(), now, cancellationToken); + await UpsertAsync(EnableLiveStartedScriptKey, request.EnableLiveStartedScript.ToString(), now, cancellationToken); await UpsertAsync(LiveStartedScriptModeKey, NormalizeEventScriptMode(request.LiveStartedScriptMode), now, cancellationToken); await UpsertAsync(LiveStartedScriptPathKey, request.LiveStartedScriptPath.Trim(), now, cancellationToken); await UpsertAsync(LiveStartedScriptContentKey, request.LiveStartedScriptContent, now, cancellationToken); + await UpsertAsync(EnableLiveEndedScriptKey, request.EnableLiveEndedScript.ToString(), now, cancellationToken); await UpsertAsync(LiveEndedScriptModeKey, NormalizeEventScriptMode(request.LiveEndedScriptMode), now, cancellationToken); await UpsertAsync(LiveEndedScriptPathKey, request.LiveEndedScriptPath.Trim(), now, cancellationToken); await UpsertAsync(LiveEndedScriptContentKey, request.LiveEndedScriptContent, now, cancellationToken); + await UpsertAsync(EnableSegmentCompletedScriptKey, request.EnableSegmentCompletedScript.ToString(), now, cancellationToken); await UpsertAsync(SegmentCompletedScriptModeKey, NormalizeEventScriptMode(request.SegmentCompletedScriptMode), now, cancellationToken); await UpsertAsync(SegmentCompletedScriptPathKey, request.SegmentCompletedScriptPath.Trim(), now, cancellationToken); await UpsertAsync(SegmentCompletedScriptContentKey, request.SegmentCompletedScriptContent, now, cancellationToken); @@ -425,4 +449,28 @@ public sealed class SystemSettingsService : ISystemSettingsService existing.Update(value, updatedAt); _appSettingRepository.Update(existing); } + + private static bool GetEventScriptEnabled( + IReadOnlyDictionary lookup, + string enabledKey, + bool legacyGlobalEnabled, + string pathKey, + string contentKey) + { + if (lookup.TryGetValue(enabledKey, out var configured) && bool.TryParse(configured, out var enabled)) + { + return enabled; + } + + return legacyGlobalEnabled && HasAnyConfiguredValue(lookup, pathKey, contentKey); + } + + private static bool HasAnyConfiguredValue( + IReadOnlyDictionary lookup, + string pathKey, + string contentKey) + { + return !string.IsNullOrWhiteSpace(GetValue(lookup, pathKey, string.Empty)) + || !string.IsNullOrWhiteSpace(GetValue(lookup, contentKey, string.Empty)); + } } diff --git a/src/LiveRecorder.Infrastructure/Services/EventScriptService.cs b/src/LiveRecorder.Infrastructure/Services/EventScriptService.cs index 082e9a3..603f196 100644 --- a/src/LiveRecorder.Infrastructure/Services/EventScriptService.cs +++ b/src/LiveRecorder.Infrastructure/Services/EventScriptService.cs @@ -35,7 +35,7 @@ public sealed class EventScriptService : IEventScriptService var environment = BuildLiveRoomEnvironment(liveRoom, occurredAt); environment["LIVE_RECORDER_EVENT"] = "live_started"; await RunAsync( - settings.EnableEventScripts, + settings.EnableEventScripts && settings.EnableLiveStartedScript, settings.LiveStartedScriptMode, settings.LiveStartedScriptPath, settings.LiveStartedScriptContent, @@ -55,7 +55,7 @@ public sealed class EventScriptService : IEventScriptService var environment = BuildLiveRoomEnvironment(liveRoom, occurredAt); environment["LIVE_RECORDER_EVENT"] = "live_ended"; await RunAsync( - settings.EnableEventScripts, + settings.EnableEventScripts && settings.EnableLiveEndedScript, settings.LiveEndedScriptMode, settings.LiveEndedScriptPath, settings.LiveEndedScriptContent, @@ -92,7 +92,7 @@ public sealed class EventScriptService : IEventScriptService environment["LIVE_RECORDER_SESSION_STATUS"] = recordSession.Status.ToString(); await RunAsync( - settings.EnableEventScripts, + settings.EnableEventScripts && settings.EnableSegmentCompletedScript, settings.SegmentCompletedScriptMode, settings.SegmentCompletedScriptPath, settings.SegmentCompletedScriptContent, diff --git a/src/LiveRecorder.WebApi/Dockerfile b/src/LiveRecorder.WebApi/Dockerfile index 16f89bb..674d556 100644 --- a/src/LiveRecorder.WebApi/Dockerfile +++ b/src/LiveRecorder.WebApi/Dockerfile @@ -19,7 +19,7 @@ FROM ${DOTNET_RUNTIME_IMAGE} AS runtime RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list.d/debian.sources RUN apt-get update -o Acquire::ForceIPv4=true \ - && apt-get install -o Acquire::ForceIPv4=true -y --no-install-recommends ffmpeg nodejs ca-certificates \ + && apt-get install -o Acquire::ForceIPv4=true -y --no-install-recommends ffmpeg nodejs ca-certificates curl jq \ && rm -rf /var/lib/apt/lists/* WORKDIR /app