diff --git a/BililiveRecorder.Core/Config/V3/Config.gen.cs b/BililiveRecorder.Core/Config/V3/Config.gen.cs index 1a7d4f3..43454c1 100644 --- a/BililiveRecorder.Core/Config/V3/Config.gen.cs +++ b/BililiveRecorder.Core/Config/V3/Config.gen.cs @@ -107,12 +107,12 @@ namespace BililiveRecorder.Core.Config.V3 public string? FileNameRecordTemplate => this.GetPropertyValue(); /// - /// 录制文件写入结束 Webhook 地址 每行一个 + /// WebhookV1 /// public string? WebHookUrls => this.GetPropertyValue(); /// - /// Webhook v2 地址 每行一个 + /// WebhookV2 /// public string? WebHookUrlsV2 => this.GetPropertyValue(); @@ -122,17 +122,17 @@ namespace BililiveRecorder.Core.Config.V3 public bool WpfShowTitleAndArea => this.GetPropertyValue(); /// - /// 请求 API 时使用的 Cookie + /// Cookie /// public string? Cookie => this.GetPropertyValue(); /// - /// 替换 api.live.bilibili.com 服务器为其他反代,可以支持在云服务器上录制 + /// API Host /// public string? LiveApiHost => this.GetPropertyValue(); /// - /// HTTP API 检查时间间隔 秒 + /// 主动检查时间间隔 秒 /// public uint TimingCheckInterval => this.GetPropertyValue(); @@ -157,12 +157,12 @@ namespace BililiveRecorder.Core.Config.V3 public uint TimingDanmakuRetry => this.GetPropertyValue(); /// - /// 最大允许未收到直播数据时间 毫秒 + /// 最大未收到直播数据时间 毫秒 /// public uint TimingWatchdogTimeout => this.GetPropertyValue(); /// - /// 触发 的弹幕个数 + /// 触发刷新弹幕写入缓冲的个数 /// public uint RecordDanmakuFlushInterval => this.GetPropertyValue(); @@ -267,7 +267,7 @@ namespace BililiveRecorder.Core.Config.V3 public Optional OptionalFileNameRecordTemplate { get => this.GetPropertyValueOptional(nameof(this.FileNameRecordTemplate)); set => this.SetPropertyValueOptional(value, nameof(this.FileNameRecordTemplate)); } /// - /// 录制文件写入结束 Webhook 地址 每行一个 + /// WebhookV1 /// public string? WebHookUrls { get => this.GetPropertyValue(); set => this.SetPropertyValue(value); } public bool HasWebHookUrls { get => this.GetPropertyHasValue(nameof(this.WebHookUrls)); set => this.SetPropertyHasValue(value, nameof(this.WebHookUrls)); } @@ -275,7 +275,7 @@ namespace BililiveRecorder.Core.Config.V3 public Optional OptionalWebHookUrls { get => this.GetPropertyValueOptional(nameof(this.WebHookUrls)); set => this.SetPropertyValueOptional(value, nameof(this.WebHookUrls)); } /// - /// Webhook v2 地址 每行一个 + /// WebhookV2 /// public string? WebHookUrlsV2 { get => this.GetPropertyValue(); set => this.SetPropertyValue(value); } public bool HasWebHookUrlsV2 { get => this.GetPropertyHasValue(nameof(this.WebHookUrlsV2)); set => this.SetPropertyHasValue(value, nameof(this.WebHookUrlsV2)); } @@ -291,7 +291,7 @@ namespace BililiveRecorder.Core.Config.V3 public Optional OptionalWpfShowTitleAndArea { get => this.GetPropertyValueOptional(nameof(this.WpfShowTitleAndArea)); set => this.SetPropertyValueOptional(value, nameof(this.WpfShowTitleAndArea)); } /// - /// 请求 API 时使用的 Cookie + /// Cookie /// public string? Cookie { get => this.GetPropertyValue(); set => this.SetPropertyValue(value); } public bool HasCookie { get => this.GetPropertyHasValue(nameof(this.Cookie)); set => this.SetPropertyHasValue(value, nameof(this.Cookie)); } @@ -299,7 +299,7 @@ namespace BililiveRecorder.Core.Config.V3 public Optional OptionalCookie { get => this.GetPropertyValueOptional(nameof(this.Cookie)); set => this.SetPropertyValueOptional(value, nameof(this.Cookie)); } /// - /// 替换 api.live.bilibili.com 服务器为其他反代,可以支持在云服务器上录制 + /// API Host /// public string? LiveApiHost { get => this.GetPropertyValue(); set => this.SetPropertyValue(value); } public bool HasLiveApiHost { get => this.GetPropertyHasValue(nameof(this.LiveApiHost)); set => this.SetPropertyHasValue(value, nameof(this.LiveApiHost)); } @@ -307,7 +307,7 @@ namespace BililiveRecorder.Core.Config.V3 public Optional OptionalLiveApiHost { get => this.GetPropertyValueOptional(nameof(this.LiveApiHost)); set => this.SetPropertyValueOptional(value, nameof(this.LiveApiHost)); } /// - /// HTTP API 检查时间间隔 秒 + /// 主动检查时间间隔 秒 /// public uint TimingCheckInterval { get => this.GetPropertyValue(); set => this.SetPropertyValue(value); } public bool HasTimingCheckInterval { get => this.GetPropertyHasValue(nameof(this.TimingCheckInterval)); set => this.SetPropertyHasValue(value, nameof(this.TimingCheckInterval)); } @@ -347,7 +347,7 @@ namespace BililiveRecorder.Core.Config.V3 public Optional OptionalTimingDanmakuRetry { get => this.GetPropertyValueOptional(nameof(this.TimingDanmakuRetry)); set => this.SetPropertyValueOptional(value, nameof(this.TimingDanmakuRetry)); } /// - /// 最大允许未收到直播数据时间 毫秒 + /// 最大未收到直播数据时间 毫秒 /// public uint TimingWatchdogTimeout { get => this.GetPropertyValue(); set => this.SetPropertyValue(value); } public bool HasTimingWatchdogTimeout { get => this.GetPropertyHasValue(nameof(this.TimingWatchdogTimeout)); set => this.SetPropertyHasValue(value, nameof(this.TimingWatchdogTimeout)); } @@ -355,7 +355,7 @@ namespace BililiveRecorder.Core.Config.V3 public Optional OptionalTimingWatchdogTimeout { get => this.GetPropertyValueOptional(nameof(this.TimingWatchdogTimeout)); set => this.SetPropertyValueOptional(value, nameof(this.TimingWatchdogTimeout)); } /// - /// 触发 的弹幕个数 + /// 触发刷新弹幕写入缓冲的个数 /// public uint RecordDanmakuFlushInterval { get => this.GetPropertyValue(); set => this.SetPropertyValue(value); } public bool HasRecordDanmakuFlushInterval { get => this.GetPropertyHasValue(nameof(this.RecordDanmakuFlushInterval)); set => this.SetPropertyHasValue(value, nameof(this.RecordDanmakuFlushInterval)); } @@ -409,31 +409,31 @@ namespace BililiveRecorder.Core.Config.V3 public bool RecordDanmakuGuard => true; - public string RecordingQuality => "10000"; + public string RecordingQuality => @"10000"; - public string FileNameRecordTemplate => "{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ \"now\" | time_zone: \"Asia/Shanghai\" | format_date: \"yyyyMMdd-HHmmss-fff\" }}-{{ title }}.flv"; + public string FileNameRecordTemplate => @"{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ ""now"" | time_zone: ""Asia/Shanghai"" | format_date: ""yyyyMMdd-HHmmss-fff"" }}-{{ title }}.flv"; - public string WebHookUrls => string.Empty; + public string WebHookUrls => @""; - public string WebHookUrlsV2 => string.Empty; + public string WebHookUrlsV2 => @""; public bool WpfShowTitleAndArea => true; - public string Cookie => string.Empty; + public string Cookie => @""; - public string LiveApiHost => "https://api.live.bilibili.com"; + public string LiveApiHost => @"https://api.live.bilibili.com"; - public uint TimingCheckInterval => 10 * 60; + public uint TimingCheckInterval => 600; - public uint TimingStreamRetry => 6 * 1000; + public uint TimingStreamRetry => 6000; public uint TimingStreamRetryNoQn => 90; - public uint TimingStreamConnect => 5 * 1000; + public uint TimingStreamConnect => 5000; - public uint TimingDanmakuRetry => 9 * 1000; + public uint TimingDanmakuRetry => 9000; - public uint TimingWatchdogTimeout => 10 * 1000; + public uint TimingWatchdogTimeout => 10000; public uint RecordDanmakuFlushInterval => 20; @@ -441,7 +441,7 @@ namespace BililiveRecorder.Core.Config.V3 public AllowedAddressFamily NetworkTransportAllowedAddressFamily => AllowedAddressFamily.Any; - public string UserScript => string.Empty; + public string UserScript => @""; } diff --git a/configV3.schema.json b/configV3.schema.json index 89cf0ea..98be67d 100644 --- a/configV3.schema.json +++ b/configV3.schema.json @@ -7,8 +7,8 @@ "additionalProperties": false, "properties": { "FileNameRecordTemplate": { - "description": "录制文件名模板\n默认: \"{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ \"now\" | time_zone: \"Asia/Shanghai\" | format_date: \"yyyyMMdd-HHmmss-fff\" }}-{{ title }}.flv\"", - "markdownDescription": "录制文件名模板 \n默认: `\"{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ \"now\" | time_zone: \"Asia/Shanghai\" | format_date: \"yyyyMMdd-HHmmss-fff\" }}-{{ title }}.flv\" `\n\nTODO: config v3 新的文件名模板系统的文档还没有写", + "description": "录制文件名模板\n默认: {{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ \"now\" | time_zone: \"Asia/Shanghai\" | format_date: \"yyyyMMdd-HHmmss-fff\" }}-{{ title }}.flv", + "markdownDescription": "录制文件名模板 \n默认: `{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ \"now\" | time_zone: \"Asia/Shanghai\" | format_date: \"yyyyMMdd-HHmmss-fff\" }}-{{ title }}.flv `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -24,7 +24,7 @@ }, "WebHookUrls": { "description": "WebhookV1\n默认: ", - "markdownDescription": "WebhookV1 \n默认: ` `\n\n具体文档见 [Webhook](/docs/basic/webhook/)", + "markdownDescription": "WebhookV1 \n默认: ` `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -40,7 +40,7 @@ }, "WebHookUrlsV2": { "description": "WebhookV2\n默认: ", - "markdownDescription": "WebhookV2 \n默认: ` `\n\n具体文档见 [Webhook](/docs/basic/webhook/)", + "markdownDescription": "WebhookV2 \n默认: ` `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -56,7 +56,7 @@ }, "WpfShowTitleAndArea": { "description": "在界面显示标题和分区\n默认: true", - "markdownDescription": "在界面显示标题和分区 \n默认: `true `\n\n只在桌面版(WPF版)有效", + "markdownDescription": "在界面显示标题和分区 \n默认: `true `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -71,8 +71,8 @@ } }, "Cookie": { - "description": "请求 API 时使用的 Cookie\n默认: (空字符串)", - "markdownDescription": "请求 API 时使用的 Cookie \n默认: `(空字符串) `\n\n", + "description": "Cookie\n默认: ", + "markdownDescription": "Cookie \n默认: ` `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -88,8 +88,8 @@ } }, "LiveApiHost": { - "description": "请求的 API Host\n默认: https://api.live.bilibili.com", - "markdownDescription": "请求的 API Host \n默认: `https://api.live.bilibili.com `\n\n", + "description": "API Host\n默认: https://api.live.bilibili.com", + "markdownDescription": "API Host \n默认: `https://api.live.bilibili.com `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -104,8 +104,8 @@ } }, "TimingCheckInterval": { - "description": "HTTP API 检查时间间隔 秒\n默认: 600 (10分)", - "markdownDescription": "HTTP API 检查时间间隔 秒 \n默认: `600 (10分) `\n\n", + "description": "主动检查时间间隔 秒\n默认: 600", + "markdownDescription": "主动检查时间间隔 秒 \n默认: `600 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -122,8 +122,8 @@ } }, "TimingStreamRetry": { - "description": "录制断开重连时间间隔 毫秒\n默认: 6000 (6秒)", - "markdownDescription": "录制断开重连时间间隔 毫秒 \n默认: `6000 (6秒) `\n\n", + "description": "录制断开重连时间间隔 毫秒\n默认: 6000", + "markdownDescription": "录制断开重连时间间隔 毫秒 \n默认: `6000 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -140,8 +140,8 @@ } }, "TimingStreamRetryNoQn": { - "description": "录制无指定画质重连时间间隔 秒\n默认: 90 (1.5分钟)", - "markdownDescription": "录制无指定画质重连时间间隔 秒 \n默认: `90 (1.5分钟) `\n\n", + "description": "录制无指定画质重连时间间隔 秒\n默认: 90", + "markdownDescription": "录制无指定画质重连时间间隔 秒 \n默认: `90 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -158,8 +158,8 @@ } }, "TimingStreamConnect": { - "description": "连接直播服务器超时时间 毫秒\n默认: 5000 (5秒)", - "markdownDescription": "连接直播服务器超时时间 毫秒 \n默认: `5000 (5秒) `\n\n", + "description": "连接直播服务器超时时间 毫秒\n默认: 5000", + "markdownDescription": "连接直播服务器超时时间 毫秒 \n默认: `5000 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -176,8 +176,8 @@ } }, "TimingDanmakuRetry": { - "description": "弹幕服务器重连时间间隔 毫秒\n默认: 9000 (9秒)", - "markdownDescription": "弹幕服务器重连时间间隔 毫秒 \n默认: `9000 (9秒) `\n\n", + "description": "弹幕服务器重连时间间隔 毫秒\n默认: 9000", + "markdownDescription": "弹幕服务器重连时间间隔 毫秒 \n默认: `9000 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -194,8 +194,8 @@ } }, "TimingWatchdogTimeout": { - "description": "最大允许未收到直播数据时间 毫秒\n默认: 10000 (10秒)", - "markdownDescription": "最大允许未收到直播数据时间 毫秒 \n默认: `10000 (10秒) `\n\n", + "description": "最大未收到直播数据时间 毫秒\n默认: 10000", + "markdownDescription": "最大未收到直播数据时间 毫秒 \n默认: `10000 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -256,8 +256,15 @@ "default": true }, "Value": { - "type": "AllowedAddressFamily", - "default": "AllowedAddressFamily.Any" + "type": "integer", + "default": 0, + "enum": [ + -1, + 0, + 1, + 2 + ], + "description": "-1: 由系统决定\n0: 任意 IPv4 或 IPv6\n1: 仅 IPv4\n2: IPv6" } } }, @@ -279,7 +286,7 @@ }, "RecordMode": { "description": "录制模式\n默认: RecordMode.Standard", - "markdownDescription": "录制模式 \n默认: `RecordMode.Standard `\n\n本设置项是一个 enum,键值对应如下:\n\n| 键 | 值 |\n|:--:|:--:|\n| RecordMode.Standard | 0 |\n| RecordMode.RawData | 1 |\n\n关于录制模式的说明见 [录制模式](/docs/basic/record_mode/)", + "markdownDescription": "录制模式 \n默认: `RecordMode.Standard `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -300,7 +307,7 @@ }, "CuttingMode": { "description": "自动分段模式\n默认: CuttingMode.Disabled", - "markdownDescription": "自动分段模式 \n默认: `CuttingMode.Disabled `\n\n本设置项是一个 enum,键值对应如下:\n\n| 键 | 值 |\n|:--:|:--:|\n| CuttingMode.Disabled | 0 |\n| CuttingMode.ByTime | 1 |\n| CuttingMode.BySize | 2 |", + "markdownDescription": "自动分段模式 \n默认: `CuttingMode.Disabled `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -322,7 +329,7 @@ }, "CuttingNumber": { "description": "自动分段数值\n默认: 100", - "markdownDescription": "自动分段数值 \n默认: `100 `\n\n根据 CuttingMode 设置的不同: \n当按时长分段时,本设置的单位为分钟。 \n当按大小分段时,本设置的单位为MiB。", + "markdownDescription": "自动分段数值 \n默认: `100 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -340,7 +347,7 @@ }, "RecordDanmaku": { "description": "弹幕录制\n默认: false", - "markdownDescription": "弹幕录制 \n默认: `false `\n\n是否录制弹幕,`true` 为录制,`false` 为不录制。\n\n本设置同时是所有“弹幕录制”的总开关,当本设置为 `false` 时其他所有“弹幕录制”设置无效,不会写入弹幕XML文件。", + "markdownDescription": "弹幕录制 \n默认: `false `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -356,7 +363,7 @@ }, "RecordDanmakuRaw": { "description": "弹幕录制-原始数据\n默认: false", - "markdownDescription": "弹幕录制-原始数据 \n默认: `false `\n\n是否记录原始 JSON 数据。\n\n弹幕原始数据会保存到 XML 文件每一条弹幕数据的 `raw` attribute 上。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。", + "markdownDescription": "弹幕录制-原始数据 \n默认: `false `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -372,7 +379,7 @@ }, "RecordDanmakuSuperChat": { "description": "弹幕录制-SuperChat\n默认: true", - "markdownDescription": "弹幕录制-SuperChat \n默认: `true `\n\n是否记录 SuperChat。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。", + "markdownDescription": "弹幕录制-SuperChat \n默认: `true `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -388,7 +395,7 @@ }, "RecordDanmakuGift": { "description": "弹幕录制-礼物\n默认: false", - "markdownDescription": "弹幕录制-礼物 \n默认: `false `\n\n是否记录礼物。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。", + "markdownDescription": "弹幕录制-礼物 \n默认: `false `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -404,7 +411,7 @@ }, "RecordDanmakuGuard": { "description": "弹幕录制-上船\n默认: true", - "markdownDescription": "弹幕录制-上船 \n默认: `true `\n\n是否记录上船(购买舰长)。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。", + "markdownDescription": "弹幕录制-上船 \n默认: `true `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -420,7 +427,7 @@ }, "RecordingQuality": { "description": "直播画质\n默认: 10000", - "markdownDescription": "直播画质 \n默认: `10000 `\n\n录制的直播画质 qn 值,以英文逗号分割,靠前的优先。\n\n**注意**(从录播姬 1.3.10 开始):\n\n- 所有主播刚开播时都是只有“原画”的,如果选择不录原画会导致直播开头漏录。\n- 如果设置的录制画质里没有原画,但是主播只有原画画质,会导致不能录制直播。\n- 录播姬不会为了切换录制的画质主动断开录制。\n\n画质 | qn 值\n:--:|:--:\n4K | 20000\n原画 | 10000\n蓝光(杜比) | 401\n蓝光 | 400\n超清 | 250\n高清 | 150\n流畅 | 80", + "markdownDescription": "直播画质 \n默认: `10000 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -441,8 +448,8 @@ "additionalProperties": false, "properties": { "RoomId": { - "description": "房间号\n默认: default", - "markdownDescription": "房间号 \n默认: `default `\n\n", + "description": "房间号\n默认: ", + "markdownDescription": "房间号 \n默认: ` `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -453,13 +460,14 @@ "Value": { "type": "integer", "minimum": -2147483648, - "maximum": 2147483647 + "maximum": 2147483647, + "default": "" } } }, "AutoRecord": { - "description": "自动录制\n默认: default", - "markdownDescription": "自动录制 \n默认: `default `\n\n设为 `true` 为启用自动录制,`false` 为不自动录制。", + "description": "自动录制\n默认: ", + "markdownDescription": "自动录制 \n默认: ` `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -468,13 +476,14 @@ "default": true }, "Value": { - "type": "boolean" + "type": "boolean", + "default": "" } } }, "RecordMode": { "description": "录制模式\n默认: RecordMode.Standard", - "markdownDescription": "录制模式 \n默认: `RecordMode.Standard `\n\n本设置项是一个 enum,键值对应如下:\n\n| 键 | 值 |\n|:--:|:--:|\n| RecordMode.Standard | 0 |\n| RecordMode.RawData | 1 |\n\n关于录制模式的说明见 [录制模式](/docs/basic/record_mode/)", + "markdownDescription": "录制模式 \n默认: `RecordMode.Standard `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -495,7 +504,7 @@ }, "CuttingMode": { "description": "自动分段模式\n默认: CuttingMode.Disabled", - "markdownDescription": "自动分段模式 \n默认: `CuttingMode.Disabled `\n\n本设置项是一个 enum,键值对应如下:\n\n| 键 | 值 |\n|:--:|:--:|\n| CuttingMode.Disabled | 0 |\n| CuttingMode.ByTime | 1 |\n| CuttingMode.BySize | 2 |", + "markdownDescription": "自动分段模式 \n默认: `CuttingMode.Disabled `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -517,7 +526,7 @@ }, "CuttingNumber": { "description": "自动分段数值\n默认: 100", - "markdownDescription": "自动分段数值 \n默认: `100 `\n\n根据 CuttingMode 设置的不同: \n当按时长分段时,本设置的单位为分钟。 \n当按大小分段时,本设置的单位为MiB。", + "markdownDescription": "自动分段数值 \n默认: `100 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -535,7 +544,7 @@ }, "RecordDanmaku": { "description": "弹幕录制\n默认: false", - "markdownDescription": "弹幕录制 \n默认: `false `\n\n是否录制弹幕,`true` 为录制,`false` 为不录制。\n\n本设置同时是所有“弹幕录制”的总开关,当本设置为 `false` 时其他所有“弹幕录制”设置无效,不会写入弹幕XML文件。", + "markdownDescription": "弹幕录制 \n默认: `false `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -551,7 +560,7 @@ }, "RecordDanmakuRaw": { "description": "弹幕录制-原始数据\n默认: false", - "markdownDescription": "弹幕录制-原始数据 \n默认: `false `\n\n是否记录原始 JSON 数据。\n\n弹幕原始数据会保存到 XML 文件每一条弹幕数据的 `raw` attribute 上。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。", + "markdownDescription": "弹幕录制-原始数据 \n默认: `false `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -567,7 +576,7 @@ }, "RecordDanmakuSuperChat": { "description": "弹幕录制-SuperChat\n默认: true", - "markdownDescription": "弹幕录制-SuperChat \n默认: `true `\n\n是否记录 SuperChat。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。", + "markdownDescription": "弹幕录制-SuperChat \n默认: `true `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -583,7 +592,7 @@ }, "RecordDanmakuGift": { "description": "弹幕录制-礼物\n默认: false", - "markdownDescription": "弹幕录制-礼物 \n默认: `false `\n\n是否记录礼物。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。", + "markdownDescription": "弹幕录制-礼物 \n默认: `false `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -599,7 +608,7 @@ }, "RecordDanmakuGuard": { "description": "弹幕录制-上船\n默认: true", - "markdownDescription": "弹幕录制-上船 \n默认: `true `\n\n是否记录上船(购买舰长)。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。", + "markdownDescription": "弹幕录制-上船 \n默认: `true `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -615,7 +624,7 @@ }, "RecordingQuality": { "description": "直播画质\n默认: 10000", - "markdownDescription": "直播画质 \n默认: `10000 `\n\n录制的直播画质 qn 值,以英文逗号分割,靠前的优先。\n\n**注意**(从录播姬 1.3.10 开始):\n\n- 所有主播刚开播时都是只有“原画”的,如果选择不录原画会导致直播开头漏录。\n- 如果设置的录制画质里没有原画,但是主播只有原画画质,会导致不能录制直播。\n- 录播姬不会为了切换录制的画质主动断开录制。\n\n画质 | qn 值\n:--:|:--:\n4K | 20000\n原画 | 10000\n蓝光(杜比) | 401\n蓝光 | 400\n超清 | 250\n高清 | 150\n流畅 | 80", + "markdownDescription": "直播画质 \n默认: `10000 `\n\n", "type": "object", "additionalProperties": false, "properties": { @@ -641,10 +650,10 @@ "properties": { "$schema": { "type": "string", - "default": "https://raw.githubusercontent.com/Bililive/BililiveRecorder/dev-1.3/configV2.schema.json" + "default": "https://raw.githubusercontent.com/BililiveRecorder/BililiveRecorder/dev/configV3.schema.json" }, "version": { - "const": 2 + "const": 3 }, "global": { "$ref": "#/definitions/global-config" diff --git a/config_gen/data.ts b/config_gen/data.ts index dd780f8..02d1eac 100644 --- a/config_gen/data.ts +++ b/config_gen/data.ts @@ -1,246 +1,206 @@ -import { ConfigEntry, ConfigEntryType } from './types' +import { ConfigEntry } from './types' export const data: Array = [ { - name: "RoomId", - description: "房间号", + id: "RoomId", + name: "房间号", type: "int", configType: "roomOnly", - defaultValue: "default", - webReadonly: true, - markdown: "" + default: "", + webReadonly: true }, { - name: "AutoRecord", - description: "自动录制", + id: "AutoRecord", + name: "自动录制", type: "bool", configType: "roomOnly", - defaultValue: "default", - markdown: "设为 `true` 为启用自动录制,`false` 为不自动录制。" + default: "" }, { - name: "RecordMode", - description: "录制模式", + id: "RecordMode", + name: "录制模式", type: "RecordMode", configType: "room", - defaultValue: "RecordMode.Standard", - markdown: "本设置项是一个 enum,键值对应如下:\n\n| 键 | 值 |\n|:--:|:--:|\n| RecordMode.Standard | 0 |\n| RecordMode.RawData | 1 |\n\n关于录制模式的说明见 [录制模式](/docs/basic/record_mode/)" + default: "RecordMode.Standard" }, { - name: "CuttingMode", - description: "自动分段模式", + id: "CuttingMode", + name: "自动分段模式", type: "CuttingMode", configType: "room", - defaultValue: "CuttingMode.Disabled", - markdown: "本设置项是一个 enum,键值对应如下:\n\n| 键 | 值 |\n|:--:|:--:|\n| CuttingMode.Disabled | 0 |\n| CuttingMode.ByTime | 1 |\n| CuttingMode.BySize | 2 |" + default: "CuttingMode.Disabled" }, { - name: "CuttingNumber", - description: "自动分段数值", + id: "CuttingNumber", + name: "自动分段数值", type: "uint", configType: "room", - defaultValue: "100", - markdown: "根据 CuttingMode 设置的不同: \n当按时长分段时,本设置的单位为分钟。 \n当按大小分段时,本设置的单位为MiB。" + default: 100 }, { - name: "RecordDanmaku", - description: "弹幕录制", + id: "RecordDanmaku", + name: "弹幕录制", type: "bool", configType: "room", - defaultValue: "false", - markdown: "是否录制弹幕,`true` 为录制,`false` 为不录制。\n\n本设置同时是所有“弹幕录制”的总开关,当本设置为 `false` 时其他所有“弹幕录制”设置无效,不会写入弹幕XML文件。" + default: false }, { - name: "RecordDanmakuRaw", - description: "弹幕录制-原始数据", + id: "RecordDanmakuRaw", + name: "弹幕录制-原始数据", type: "bool", configType: "room", - defaultValue: "false", - markdown: "是否记录原始 JSON 数据。\n\n弹幕原始数据会保存到 XML 文件每一条弹幕数据的 `raw` attribute 上。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。" + default: false }, { - name: "RecordDanmakuSuperChat", - description: "弹幕录制-SuperChat", + id: "RecordDanmakuSuperChat", + name: "弹幕录制-SuperChat", type: "bool", configType: "room", - defaultValue: "true", - markdown: "是否记录 SuperChat。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。" + default: true }, { - name: "RecordDanmakuGift", - description: "弹幕录制-礼物", + id: "RecordDanmakuGift", + name: "弹幕录制-礼物", type: "bool", configType: "room", - defaultValue: "false", - markdown: "是否记录礼物。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。" + default: false }, { - name: "RecordDanmakuGuard", - description: "弹幕录制-上船", + id: "RecordDanmakuGuard", + name: "弹幕录制-上船", type: "bool", configType: "room", - defaultValue: "true", - markdown: "是否记录上船(购买舰长)。\n\n当 `RecordDanmaku` 为 `false` 时本项设置无效。" + default: true }, { - name: "RecordingQuality", + id: "RecordingQuality", + name: "直播画质", type: "string?", configType: "room", - description: "直播画质", - defaultValue: "\"10000\"", - defaultValueDescription: "10000", - markdown: "录制的直播画质 qn 值,以英文逗号分割,靠前的优先。\n\n**注意**(从录播姬 1.3.10 开始):\n\n- 所有主播刚开播时都是只有“原画”的,如果选择不录原画会导致直播开头漏录。\n- 如果设置的录制画质里没有原画,但是主播只有原画画质,会导致不能录制直播。\n- 录播姬不会为了切换录制的画质主动断开录制。\n\n画质 | qn 值\n:--:|:--:\n4K | 20000\n原画 | 10000\n蓝光(杜比) | 401\n蓝光 | 400\n超清 | 250\n高清 | 150\n流畅 | 80" + default: "10000", }, { - name: "FileNameRecordTemplate", - description: "录制文件名模板", + id: "FileNameRecordTemplate", + name: "录制文件名模板", type: "string?", configType: "globalOnly", - defaultValue: "\"{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ \\\"now\\\" | time_zone: \\\"Asia/Shanghai\\\" | format_date: \\\"yyyyMMdd-HHmmss-fff\\\" }}-{{ title }}.flv\"", - defaultValueDescription: "\"{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ \"now\" | time_zone: \"Asia/Shanghai\" | format_date: \"yyyyMMdd-HHmmss-fff\" }}-{{ title }}.flv\"", - markdown: "TODO: config v3 新的文件名模板系统的文档还没有写" + default: '{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ "now" | time_zone: "Asia/Shanghai" | format_date: "yyyyMMdd-HHmmss-fff" }}-{{ title }}.flv', }, { - name: "WebHookUrls", - description: "WebhookV1", + id: "WebHookUrls", + name: "WebhookV1", type: "string?", configType: "globalOnly", - defaultValue: "string.Empty", - xmlComment: "录制文件写入结束 Webhook 地址 每行一个", - markdown: "具体文档见 [Webhook](/docs/basic/webhook/)" + default: "", }, { - name: "WebHookUrlsV2", - description: "WebhookV2", + id: "WebHookUrlsV2", + name: "WebhookV2", type: "string?", configType: "globalOnly", - defaultValue: "string.Empty", - xmlComment: "Webhook v2 地址 每行一个", - markdown: "具体文档见 [Webhook](/docs/basic/webhook/)" + default: "", }, { - name: "WpfShowTitleAndArea", - description: "在界面显示标题和分区", + id: "WpfShowTitleAndArea", + name: "在界面显示标题和分区", type: "bool", configType: "globalOnly", - defaultValue: "true", - markdown: "只在桌面版(WPF版)有效" + default: true }, { + id: "Cookie", name: "Cookie", - description: "请求 API 时使用的 Cookie", type: "string?", configType: "globalOnly", advancedConfig: true, - defaultValue: "string.Empty", - defaultValueDescription: "(空字符串)", - markdown: "" + default: "", }, { - name: "LiveApiHost", - description: "请求的 API Host", + id: "LiveApiHost", + name: "API Host", type: "string?", configType: "globalOnly", advancedConfig: true, - defaultValue: "\"https://api.live.bilibili.com\"", - xmlComment: "替换 api.live.bilibili.com 服务器为其他反代,可以支持在云服务器上录制", - markdown: "" + default: "https://api.live.bilibili.com", }, { - name: "TimingCheckInterval", - description: "HTTP API 检查时间间隔 秒", + id: "TimingCheckInterval", + name: "主动检查时间间隔 秒", type: "uint", configType: "globalOnly", advancedConfig: true, - defaultValue: "10 * 60", - defaultValueDescription: "600 (10分)", - markdown: "" + default: 10 * 60, }, { - name: "TimingStreamRetry", - description: "录制断开重连时间间隔 毫秒", + id: "TimingStreamRetry", + name: "录制断开重连时间间隔 毫秒", type: "uint", configType: "globalOnly", advancedConfig: true, - defaultValue: "6 * 1000", - defaultValueDescription: "6000 (6秒)", - markdown: "" + default: 6 * 1000, }, { - name: "TimingStreamRetryNoQn", - description: "录制无指定画质重连时间间隔 秒", + id: "TimingStreamRetryNoQn", + name: "录制无指定画质重连时间间隔 秒", type: "uint", configType: "globalOnly", advancedConfig: true, - defaultValue: "90", - defaultValueDescription: "90 (1.5分钟)", - markdown: "" + default: 90, }, { - name: "TimingStreamConnect", - description: "连接直播服务器超时时间 毫秒", + id: "TimingStreamConnect", + name: "连接直播服务器超时时间 毫秒", type: "uint", configType: "globalOnly", advancedConfig: true, - defaultValue: "5 * 1000", - defaultValueDescription: "5000 (5秒)", - markdown: "" + default: 5 * 1000, }, { - name: "TimingDanmakuRetry", - description: "弹幕服务器重连时间间隔 毫秒", + id: "TimingDanmakuRetry", + name: "弹幕服务器重连时间间隔 毫秒", type: "uint", configType: "globalOnly", advancedConfig: true, - defaultValue: "9 * 1000", - defaultValueDescription: "9000 (9秒)", - markdown: "" + default: 9 * 1000, }, { - name: "TimingWatchdogTimeout", - description: "最大允许未收到直播数据时间 毫秒", + id: "TimingWatchdogTimeout", + name: "最大未收到直播数据时间 毫秒", type: "uint", configType: "globalOnly", advancedConfig: true, - defaultValue: "10 * 1000", - defaultValueDescription: "10000 (10秒)", - markdown: "" + default: 10 * 1000, }, { - name: "RecordDanmakuFlushInterval", - description: "触发刷新弹幕写入缓冲的个数", + id: "RecordDanmakuFlushInterval", + name: "触发刷新弹幕写入缓冲的个数", type: "uint", configType: "globalOnly", advancedConfig: true, - defaultValue: "20", - xmlComment: "触发 的弹幕个数", - markdown: "" + default: 20, }, { - name: "NetworkTransportUseSystemProxy", - description: "是否使用系统代理", + id: "NetworkTransportUseSystemProxy", + name: "是否使用系统代理", type: "bool", - defaultValue: "false", + default: false, configType: "globalOnly", - advancedConfig: true, - markdown: "" + advancedConfig: true }, { - name: "NetworkTransportAllowedAddressFamily", - description: "允许使用的 IP 网络类型", + id: "NetworkTransportAllowedAddressFamily", + name: "允许使用的 IP 网络类型", type: "AllowedAddressFamily", - defaultValue: "AllowedAddressFamily.Any", + default: "AllowedAddressFamily.Any", configType: "globalOnly", - advancedConfig: true, - markdown: "" + advancedConfig: true }, { - name: "UserScript", - description: "自定义脚本", + id: "UserScript", + name: "自定义脚本", type: "string?", - defaultValue: "string.Empty", + default: "", configType: "globalOnly", - advancedConfig: true, - markdown: "" + advancedConfig: true }, ]; diff --git a/config_gen/generators/codeCli.ts b/config_gen/generators/codeCli.ts index 95396fa..6ab6955 100644 --- a/config_gen/generators/codeCli.ts +++ b/config_gen/generators/codeCli.ts @@ -15,7 +15,7 @@ export default function (data: ConfigEntry[]): string { { [Description("[grey]Exit[/]")] Exit, - ${data.filter(x => x.configType != 'roomOnly').map(x => x.name).join(",\n")} + ${data.filter(x => x.configType != 'roomOnly').map(x => x.id).join(",\n")} }`; result += ` @@ -23,7 +23,7 @@ export default function (data: ConfigEntry[]): string { { [Description("[grey]Exit[/]")] Exit, - ${data.filter(x => x.configType != 'globalOnly').map(x => x.name).join(",\n")} + ${data.filter(x => x.configType != 'globalOnly').map(x => x.id).join(",\n")} }`; @@ -37,11 +37,11 @@ export default function (data: ConfigEntry[]): string { { ${data .filter(x => x.configType != 'roomOnly') - .map(r => `GlobalConfig.Add(GlobalConfigProperties.${r.name}, new ConfigInstruction(config => config.Has${r.name} = false, (config, value) => config.${r.name} = value) { Name = "${r.name}", CanBeOptional = true });`) + .map(r => `GlobalConfig.Add(GlobalConfigProperties.${r.id}, new ConfigInstruction(config => config.Has${r.id} = false, (config, value) => config.${r.id} = value) { Name = "${r.id}", CanBeOptional = true });`) .join("\n") } - ${data.filter(x => x.configType != 'globalOnly').map(r => `RoomConfig.Add(RoomConfigProperties.${r.name}, new ConfigInstruction(config => config.Has${r.name} = false, (config, value) => config.${r.name} = value) { Name = "${r.name}", CanBeOptional = ${r.configType != 'roomOnly'} });`).join("\n")} + ${data.filter(x => x.configType != 'globalOnly').map(r => `RoomConfig.Add(RoomConfigProperties.${r.id}, new ConfigInstruction(config => config.Has${r.id} = false, (config, value) => config.${r.id} = value) { Name = "${r.id}", CanBeOptional = ${r.configType != 'roomOnly'} });`).join("\n")} } } ` diff --git a/config_gen/generators/codeCore.ts b/config_gen/generators/codeCore.ts index a09b5e6..04852a9 100644 --- a/config_gen/generators/codeCore.ts +++ b/config_gen/generators/codeCore.ts @@ -1,5 +1,6 @@ import { ConfigEntry, ConfigEntryType } from "../types" import { trimEnd } from "../utils"; +import { getConfigDefaultValueText } from "../utils"; export default function (data: ConfigEntry[]): string { let result = `using System.ComponentModel; @@ -12,16 +13,16 @@ namespace BililiveRecorder.Core.Config.V3 `; function write_property(r: ConfigEntry) { - result += `/// \n/// ${r.xmlComment ?? r.description}\n/// \n`; - result += `public ${r.type} ${r.name} { get => this.GetPropertyValue<${trimEnd(r.type, '?')}>(); set => this.SetPropertyValue(value); }\n`; - result += `public bool Has${r.name} { get => this.GetPropertyHasValue(nameof(this.${r.name})); set => this.SetPropertyHasValue<${trimEnd(r.type, '?')}>(value, nameof(this.${r.name})); }\n`; - result += `[JsonProperty(nameof(${r.name})), EditorBrowsable(EditorBrowsableState.Never)]\n`; - result += `public Optional<${r.type}> Optional${r.name} { get => this.GetPropertyValueOptional<${trimEnd(r.type, '?')}>(nameof(this.${r.name})); set => this.SetPropertyValueOptional(value, nameof(this.${r.name})); }\n\n`; + result += `/// \n/// ${r.name}\n/// \n`; + result += `public ${r.type} ${r.id} { get => this.GetPropertyValue<${trimEnd(r.type, '?')}>(); set => this.SetPropertyValue(value); }\n`; + result += `public bool Has${r.id} { get => this.GetPropertyHasValue(nameof(this.${r.id})); set => this.SetPropertyHasValue<${trimEnd(r.type, '?')}>(value, nameof(this.${r.id})); }\n`; + result += `[JsonProperty(nameof(${r.id})), EditorBrowsable(EditorBrowsableState.Never)]\n`; + result += `public Optional<${r.type}> Optional${r.id} { get => this.GetPropertyValueOptional<${trimEnd(r.type, '?')}>(nameof(this.${r.id})); set => this.SetPropertyValueOptional(value, nameof(this.${r.id})); }\n\n`; } function write_readonly_property(r: ConfigEntry) { - result += `/// \n/// ${r.xmlComment ?? r.description}\n/// \n`; - result += `public ${r.type} ${r.name} => this.GetPropertyValue<${trimEnd(r.type, '?')}>();\n\n`; + result += `/// \n/// ${r.name}\n/// \n`; + result += `public ${r.type} ${r.id} => this.GetPropertyValue<${trimEnd(r.type, '?')}>();\n\n`; } { @@ -54,7 +55,7 @@ private DefaultConfig() {}\n\n`; data .filter(x => x.configType != 'roomOnly') .forEach(r => { - result += `public ${trimEnd(r.type, '?')} ${r.name} => ${r.defaultValue};\n\n`; + result += `public ${trimEnd(r.type, '?')} ${r.id} => ${getConfigDefaultValueText(r)};\n\n`; }); result += "}\n\n"; diff --git a/config_gen/generators/codeSchema.ts b/config_gen/generators/codeSchema.ts index 78a0436..5f41457 100644 --- a/config_gen/generators/codeSchema.ts +++ b/config_gen/generators/codeSchema.ts @@ -1,49 +1,42 @@ import { ConfigEntry, ConfigEntryType } from "../types" -function tryEvalValue(str: string) { - try { - return eval(str); - } catch { - return str; - } -} -const mapCSharpString = (text: string): string => text === 'string.Empty' ? '' : tryEvalValue(text.replace(/^@/, '')); - -function mapTypeToJsonSchema(name: string, type: string, defaultValue: string) { +function mapTypeToJsonSchema(id: string, type: string, defaultValue: any) { switch (type) { case "RecordMode": return { type: "integer", default: 0, enum: [0, 1], "description": "0: Standard\n1: Raw" }; case "CuttingMode": return { type: "integer", default: 0, enum: [0, 1, 2], "description": "0: 禁用\n1: 根据时间切割\n2: 根据文件大小切割" }; + case "AllowedAddressFamily": + return { type: "integer", default: 0, enum: [-1, 0, 1, 2], "description": "-1: 由系统决定\n0: 任意 IPv4 或 IPv6\n1: 仅 IPv4\n2: IPv6" }; case "uint": - return { type: "integer", minimum: 0, maximum: 4294967295, default: tryEvalValue(defaultValue) }; + return { type: "integer", minimum: 0, maximum: 4294967295, default: defaultValue }; case "int": - return { type: "integer", minimum: -2147483648, maximum: 2147483647, default: tryEvalValue(defaultValue) }; + return { type: "integer", minimum: -2147483648, maximum: 2147483647, default: defaultValue }; case "bool": - return { type: "boolean", default: tryEvalValue(defaultValue) }; + return { type: "boolean", default: defaultValue }; case "string": case "string?": - if (name === 'Cookie') { + if (id === 'Cookie') { return { type: "string", pattern: "^(\S+=\S+;? ?)*$", maxLength: 4096, }; } - return { type: "string", default: mapCSharpString(defaultValue) }; + return { type: "string", default: defaultValue }; default: return { type, default: defaultValue }; } } function buildProperty(target: { [i: string]: any }, config: ConfigEntry) { - const typeObj = mapTypeToJsonSchema(config.name, config.type, config.defaultValue); + const typeObj = mapTypeToJsonSchema(config.id, config.type, config.default); - if (config.defaultValue === 'default') + if (config.default === 'default') delete typeObj['default']; - target[config.name] = { - description: config.description - + '\n默认: ' + (!config.defaultValueDescription ? mapCSharpString(config.defaultValue) : config.defaultValueDescription), - markdownDescription: config.description - + ' \n默认: `' + (!config.defaultValueDescription ? mapCSharpString(config.defaultValue) : config.defaultValueDescription) - + ' `\n\n' + config.markdown, + target[config.id] = { + description: config.name + + '\n默认: ' + config.default, + markdownDescription: config.name + + ' \n默认: `' + config.default + + ' `\n\n', type: "object", additionalProperties: false, properties: { @@ -89,10 +82,10 @@ export default function (data: ConfigEntry[]): string { "properties": { "$schema": { "type": "string", - "default": "https://raw.githubusercontent.com/Bililive/BililiveRecorder/dev-1.3/configV2.schema.json" + "default": "https://raw.githubusercontent.com/BililiveRecorder/BililiveRecorder/dev/configV3.schema.json" }, "version": { - "const": 2 + "const": 3 }, "global": { "$ref": "#/definitions/global-config" diff --git a/config_gen/generators/codeWeb.ts b/config_gen/generators/codeWeb.ts index fafb1c9..2c714bf 100644 --- a/config_gen/generators/codeWeb.ts +++ b/config_gen/generators/codeWeb.ts @@ -10,41 +10,41 @@ using HierarchicalPropertyDefault; `; function write_query_graphType_property(r: ConfigEntry) { if (r.configType == "roomOnly") { - result += `this.Field(x => x.${r.name});\n`; + result += `this.Field(x => x.${r.id});\n`; } else { - result += `this.Field(x => x.Optional${r.name}, type: typeof(HierarchicalOptionalType<${trimEnd(r.type, '?')}>));\n`; + result += `this.Field(x => x.Optional${r.id}, type: typeof(HierarchicalOptionalType<${trimEnd(r.type, '?')}>));\n`; } } function write_rest_dto_property(r: ConfigEntry) { if (r.configType == "roomOnly") { - result += `public ${r.type} ${r.name} { get; set; }\n`; + result += `public ${r.type} ${r.id} { get; set; }\n`; } else { - result += `public Optional<${r.type}> Optional${r.name} { get; set; }\n`; + result += `public Optional<${r.type}> Optional${r.id} { get; set; }\n`; } } function write_mutation_graphType_property(r: ConfigEntry) { if (r.configType == "roomOnly") { - result += `this.Field(x => x.${r.name}, nullable: true);\n`; + result += `this.Field(x => x.${r.id}, nullable: true);\n`; } else { - result += `this.Field(x => x.Optional${r.name}, nullable: true, type: typeof(HierarchicalOptionalInputType<${trimEnd(r.type, '?')}>));\n`; + result += `this.Field(x => x.Optional${r.id}, nullable: true, type: typeof(HierarchicalOptionalInputType<${trimEnd(r.type, '?')}>));\n`; } } function write_mutation_dataType_property(r: ConfigEntry) { if (r.configType == "roomOnly") { - result += `public ${r.type}? ${r.name} { get; set; }\n`; + result += `public ${r.type}? ${r.id} { get; set; }\n`; } else { - result += `public Optional<${r.type}>? Optional${r.name} { get; set; }\n`; + result += `public Optional<${r.type}>? Optional${r.id} { get; set; }\n`; } } function write_mutation_apply_method(r: ConfigEntry) { if (r.configType == "roomOnly") { - result += `if (this.${r.name}.HasValue) config.${r.name} = this.${r.name}.Value;\n`; + result += `if (this.${r.id}.HasValue) config.${r.id} = this.${r.id}.Value;\n`; } else { - result += `if (this.Optional${r.name}.HasValue) config.Optional${r.name} = this.Optional${r.name}.Value;\n`; + result += `if (this.Optional${r.id}.HasValue) config.Optional${r.id} = this.Optional${r.id}.Value;\n`; } } @@ -129,7 +129,7 @@ using HierarchicalPropertyDefault; data.filter(r => r.configType != "roomOnly") .forEach(r => { - result += `this.Field(x => x.${r.name});\n`; + result += `this.Field(x => x.${r.id});\n`; }); result += "}\n}\n\n"; diff --git a/config_gen/generators/doc.ts b/config_gen/generators/doc.ts index b17aa2b..802c780 100644 --- a/config_gen/generators/doc.ts +++ b/config_gen/generators/doc.ts @@ -1,61 +1,26 @@ import { ConfigEntry } from "../types" -import fs from "fs" +import { statSync, writeFileSync } from "fs"; import { resolve } from "path" import { data } from "../data"; import { trimEnd } from "../utils"; export default function doc(path: string): void { - if (!fs.statSync(resolve(path, '_config.yml'))) { + if (!statSync(resolve(path, 'mkdocs.yml'))) { console.error('Check your path'); return; } - if (!fs.statSync(resolve(path, 'index.html'))) { + if (!statSync(resolve(path, 'docs/user/settings.md'))) { console.error('Check your path'); return; } - const targetPath = resolve(path, '_includes/generated_settings_list.md') + const targetPath = resolve(path, 'data/brec_settings.json') - const text = buildMarkdown(data) + const text = buildJson(data) - fs.writeFileSync(targetPath, text, { encoding: 'utf8' }); + writeFileSync(targetPath, text, { encoding: 'utf8' }); } -function buildMarkdown(data: ConfigEntry[]): string { - let result = ''; - - // 目录 - result += "## 目录\n\n" - result += data.filter(x => !x.advancedConfig).map(x => `- [${x.description}](#${x.description})`).join('\n') - result += '\n\n' - - // 一般设置项目列表 - result += data.filter(x => !x.advancedConfig).map(x => - `### ${x.description} - -键名: \`${x.name}\` -类型: \`${trimEnd(x.type, '?')}\` -默认设置: \`${x.defaultValueDescription ?? x.defaultValue}\` - -${x.markdown} -`).join('\n') - result += '\n\n' - - // 高级设置说明 - result += "## 高级设置\n\n" - result += "重要说明:一般用户通常不需要也不应该修改高级设置。 \n对各个 Timing 的修改可能会导致被B站服务器屏蔽、不能及时开始录制等问题。\n\n" - result += "显示高级设置的方法:右键双击界面左下角的设置按钮\n\n" - - // 高级设置项目列表 - result += data.filter(x => x.advancedConfig).map(x => - `### ${x.description} - -键名: \`${x.name}\` -类型: \`${trimEnd(x.type, '?')}\` -默认设置: \`${x.defaultValueDescription ?? x.defaultValue}\` - -${x.markdown} -`).join('\n') - - return result; +function buildJson(data: ConfigEntry[]): string { + return JSON.stringify(data, null, 2); } diff --git a/config_gen/package-lock.json b/config_gen/package-lock.json index 703b3e1..3d76fe3 100644 --- a/config_gen/package-lock.json +++ b/config_gen/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "devDependencies": { - "@types/node": "^16.11.26", + "@types/node": "^16.11.39", "ts-node": "^10.2.0", "tslib": "^2.3.1", "typescript": "^4.3.5" @@ -57,9 +57,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.11.26", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-16.11.26.tgz", - "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==", + "version": "16.11.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz", + "integrity": "sha512-K0MsdV42vPwm9L6UwhIxMAOmcvH/1OoVkZyCgEtVu4Wx7sElGloy/W7kMBNe/oJ7V/jW9BVt1F6RahH6e7tPXw==", "dev": true }, "node_modules/acorn": { @@ -224,9 +224,9 @@ "dev": true }, "@types/node": { - "version": "16.11.26", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-16.11.26.tgz", - "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==", + "version": "16.11.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz", + "integrity": "sha512-K0MsdV42vPwm9L6UwhIxMAOmcvH/1OoVkZyCgEtVu4Wx7sElGloy/W7kMBNe/oJ7V/jW9BVt1F6RahH6e7tPXw==", "dev": true }, "acorn": { diff --git a/config_gen/package.json b/config_gen/package.json index 16c874f..c81f834 100644 --- a/config_gen/package.json +++ b/config_gen/package.json @@ -3,7 +3,7 @@ "build": "ts-node index.ts" }, "devDependencies": { - "@types/node": "^16.11.26", + "@types/node": "^16.11.39", "ts-node": "^10.2.0", "tslib": "^2.3.1", "typescript": "^4.3.5" diff --git a/config_gen/tsconfig.json b/config_gen/tsconfig.json new file mode 100644 index 0000000..fa8af71 --- /dev/null +++ b/config_gen/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "lib": [ + "ES2021" + ], + "typeRoots": [ + "@types", + "node_modules/@types" + ], + }, +} diff --git a/config_gen/types.ts b/config_gen/types.ts index 25dbf19..1249a1b 100644 --- a/config_gen/types.ts +++ b/config_gen/types.ts @@ -7,13 +7,22 @@ export type ConfigEntryType = /** 只能单独房间设置 */ | "roomOnly" +export type ConfigValueType = + "string?" + | "int" + | "uint" + | "bool" + | "RecordMode" + | "CuttingMode" + | "AllowedAddressFamily" + export interface ConfigEntry { /** 名字 */ - readonly name: string, + readonly id: string, /** 说明 */ - readonly description: string, + readonly name: string, /** 代码类型 */ - readonly type: string, + readonly type: ConfigValueType, /** 设置类型 */ readonly configType: ConfigEntryType /** Web API 只读属性 */ @@ -21,11 +30,5 @@ export interface ConfigEntry { /** 是否为高级设置(隐藏设置),默认为 false */ readonly advancedConfig?: boolean, /** 默认值 */ - readonly defaultValue: string, - /** 文档显示用默认值,默认使用 defaultValue */ - readonly defaultValueDescription?: string, - /** XML 注释,默认使用 description */ - readonly xmlComment?: string, - /** Markdown 格式的说明文档 */ - readonly markdown: string, -} \ No newline at end of file + readonly default: string | number | boolean, +} diff --git a/config_gen/utils.ts b/config_gen/utils.ts index 85081b1..4898449 100644 --- a/config_gen/utils.ts +++ b/config_gen/utils.ts @@ -1,5 +1,15 @@ +import { ConfigEntry } from "./types"; + export function trimEnd(text: string, trimChar: string): string { return text.slice(-1) === trimChar ? text.slice(0, -1) : text; -} \ No newline at end of file +} + +export function getConfigDefaultValueText(config: ConfigEntry): string { + if (config.type != "string?") { + return config.default.toString(); + } else { + return `@"${config.default.toString().replaceAll('"', '""')}"`; + } +}