mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-15 19:22:19 +08:00
feat(cli/core): add TitleFilterPatterns option (#619)
* add custom title filter * Use regex instead of string matching * feat(ui): add title filter settings for recording conditions --------- Co-authored-by: genteure <genteure@gmail.com>
This commit is contained in:
parent
629e24488c
commit
f05d8c3c0e
|
@ -28,6 +28,7 @@ namespace BililiveRecorder.Cli.Configure
|
|||
FileNameRecordTemplate,
|
||||
FlvProcessorSplitOnScriptTag,
|
||||
FlvWriteMetadata,
|
||||
TitleFilterPatterns,
|
||||
WebHookUrls,
|
||||
WebHookUrlsV2,
|
||||
WpfShowTitleAndArea,
|
||||
|
@ -65,7 +66,8 @@ namespace BililiveRecorder.Cli.Configure
|
|||
RecordDanmakuGuard,
|
||||
SaveStreamCover,
|
||||
RecordingQuality,
|
||||
FlvProcessorSplitOnScriptTag
|
||||
FlvProcessorSplitOnScriptTag,
|
||||
TitleFilterPatterns
|
||||
}
|
||||
public static class ConfigInstructions
|
||||
{
|
||||
|
@ -88,6 +90,7 @@ namespace BililiveRecorder.Cli.Configure
|
|||
GlobalConfig.Add(GlobalConfigProperties.FileNameRecordTemplate, new ConfigInstruction<GlobalConfig, string>(config => config.HasFileNameRecordTemplate = false, (config, value) => config.FileNameRecordTemplate = value) { Name = "FileNameRecordTemplate", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.FlvProcessorSplitOnScriptTag, new ConfigInstruction<GlobalConfig, bool>(config => config.HasFlvProcessorSplitOnScriptTag = false, (config, value) => config.FlvProcessorSplitOnScriptTag = value) { Name = "FlvProcessorSplitOnScriptTag", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.FlvWriteMetadata, new ConfigInstruction<GlobalConfig, bool>(config => config.HasFlvWriteMetadata = false, (config, value) => config.FlvWriteMetadata = value) { Name = "FlvWriteMetadata", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.TitleFilterPatterns, new ConfigInstruction<GlobalConfig, string>(config => config.HasTitleFilterPatterns = false, (config, value) => config.TitleFilterPatterns = value) { Name = "TitleFilterPatterns", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.WebHookUrls, new ConfigInstruction<GlobalConfig, string>(config => config.HasWebHookUrls = false, (config, value) => config.WebHookUrls = value) { Name = "WebHookUrls", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.WebHookUrlsV2, new ConfigInstruction<GlobalConfig, string>(config => config.HasWebHookUrlsV2 = false, (config, value) => config.WebHookUrlsV2 = value) { Name = "WebHookUrlsV2", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.WpfShowTitleAndArea, new ConfigInstruction<GlobalConfig, bool>(config => config.HasWpfShowTitleAndArea = false, (config, value) => config.WpfShowTitleAndArea = value) { Name = "WpfShowTitleAndArea", CanBeOptional = true });
|
||||
|
@ -122,6 +125,7 @@ namespace BililiveRecorder.Cli.Configure
|
|||
RoomConfig.Add(RoomConfigProperties.SaveStreamCover, new ConfigInstruction<RoomConfig, bool>(config => config.HasSaveStreamCover = false, (config, value) => config.SaveStreamCover = value) { Name = "SaveStreamCover", CanBeOptional = true });
|
||||
RoomConfig.Add(RoomConfigProperties.RecordingQuality, new ConfigInstruction<RoomConfig, string>(config => config.HasRecordingQuality = false, (config, value) => config.RecordingQuality = value) { Name = "RecordingQuality", CanBeOptional = true });
|
||||
RoomConfig.Add(RoomConfigProperties.FlvProcessorSplitOnScriptTag, new ConfigInstruction<RoomConfig, bool>(config => config.HasFlvProcessorSplitOnScriptTag = false, (config, value) => config.FlvProcessorSplitOnScriptTag = value) { Name = "FlvProcessorSplitOnScriptTag", CanBeOptional = true });
|
||||
RoomConfig.Add(RoomConfigProperties.TitleFilterPatterns, new ConfigInstruction<RoomConfig, string>(config => config.HasTitleFilterPatterns = false, (config, value) => config.TitleFilterPatterns = value) { Name = "TitleFilterPatterns", CanBeOptional = true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,14 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
[JsonProperty(nameof(FlvProcessorSplitOnScriptTag)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<bool> OptionalFlvProcessorSplitOnScriptTag { get => this.GetPropertyValueOptional<bool>(nameof(this.FlvProcessorSplitOnScriptTag)); set => this.SetPropertyValueOptional(value, nameof(this.FlvProcessorSplitOnScriptTag)); }
|
||||
|
||||
/// <summary>
|
||||
/// 不录制的标题匹配正则
|
||||
/// </summary>
|
||||
public string? TitleFilterPatterns { get => this.GetPropertyValue<string>(); set => this.SetPropertyValue(value); }
|
||||
public bool HasTitleFilterPatterns { get => this.GetPropertyHasValue(nameof(this.TitleFilterPatterns)); set => this.SetPropertyHasValue<string>(value, nameof(this.TitleFilterPatterns)); }
|
||||
[JsonProperty(nameof(TitleFilterPatterns)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<string?> OptionalTitleFilterPatterns { get => this.GetPropertyValueOptional<string>(nameof(this.TitleFilterPatterns)); set => this.SetPropertyValueOptional(value, nameof(this.TitleFilterPatterns)); }
|
||||
|
||||
/// <summary>
|
||||
/// 录制文件名模板
|
||||
/// </summary>
|
||||
|
@ -347,6 +355,14 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
[JsonProperty(nameof(FlvWriteMetadata)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<bool> OptionalFlvWriteMetadata { get => this.GetPropertyValueOptional<bool>(nameof(this.FlvWriteMetadata)); set => this.SetPropertyValueOptional(value, nameof(this.FlvWriteMetadata)); }
|
||||
|
||||
/// <summary>
|
||||
/// 不录制的标题匹配正则
|
||||
/// </summary>
|
||||
public string? TitleFilterPatterns { get => this.GetPropertyValue<string>(); set => this.SetPropertyValue(value); }
|
||||
public bool HasTitleFilterPatterns { get => this.GetPropertyHasValue(nameof(this.TitleFilterPatterns)); set => this.SetPropertyHasValue<string>(value, nameof(this.TitleFilterPatterns)); }
|
||||
[JsonProperty(nameof(TitleFilterPatterns)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<string?> OptionalTitleFilterPatterns { get => this.GetPropertyValueOptional<string>(nameof(this.TitleFilterPatterns)); set => this.SetPropertyValueOptional(value, nameof(this.TitleFilterPatterns)); }
|
||||
|
||||
/// <summary>
|
||||
/// WebhookV1
|
||||
/// </summary>
|
||||
|
@ -534,6 +550,8 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
|
||||
public bool FlvWriteMetadata => true;
|
||||
|
||||
public string TitleFilterPatterns => @"";
|
||||
|
||||
public string WebHookUrls => @"";
|
||||
|
||||
public string WebHookUrlsV2 => @"";
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.ComponentModel;
|
|||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BililiveRecorder.Core.Api;
|
||||
|
@ -228,6 +229,27 @@ namespace BililiveRecorder.Core
|
|||
}
|
||||
}
|
||||
|
||||
private static readonly TimeSpan TitleRegexMatchTimeout = TimeSpan.FromSeconds(0.5);
|
||||
|
||||
/// <exception cref="ArgumentException" />
|
||||
/// <exception cref="RegexMatchTimeoutException" />
|
||||
private bool DoesTitleAllowRecord()
|
||||
{
|
||||
// 按新行分割的正则表达式
|
||||
var patterns = this.RoomConfig.TitleFilterPatterns?.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (patterns is null || patterns.Length == 0)
|
||||
return true;
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
if (Regex.IsMatch(input: this.Title, pattern: pattern, options: RegexOptions.None, matchTimeout: TitleRegexMatchTimeout))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
private void CreateAndStartNewRecordTask(bool skipFetchRoomInfo = false)
|
||||
{
|
||||
|
@ -242,6 +264,19 @@ namespace BililiveRecorder.Core
|
|||
if (this.recordTask != null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
if (!this.DoesTitleAllowRecord())
|
||||
{
|
||||
this.logger.Information("标题匹配到跳过录制设置中的规则,不录制");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.logger.Warning(ex, "检查标题是否匹配跳过录制正则表达式时出错");
|
||||
}
|
||||
|
||||
var task = this.recordTaskFactory.CreateRecordTask(this);
|
||||
task.IOStats += this.RecordTask_IOStats;
|
||||
task.RecordingStats += this.RecordTask_RecordingStats;
|
||||
|
@ -653,6 +688,7 @@ retry:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void Room_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
|
@ -670,7 +706,8 @@ retry:
|
|||
}
|
||||
break;
|
||||
case nameof(this.Title):
|
||||
if (this.RoomConfig.CuttingByTitle){
|
||||
if (this.RoomConfig.CuttingByTitle)
|
||||
{
|
||||
this.SplitOutput();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -113,6 +113,15 @@
|
|||
</local:SettingWithDefault>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="录制条件">
|
||||
<StackPanel>
|
||||
<TextBlock Margin="5" Text="跳过录制的直播标题正则匹配表达式,每行一个" />
|
||||
<local:SettingWithDefault IsSettingNotUsingDefault="{Binding HasTitleFilterPatterns}">
|
||||
<TextBox Margin="5" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"
|
||||
Text="{Binding TitleFilterPatterns,UpdateSourceTrigger=PropertyChanged,Delay=1000}" ui:TextBoxHelper.IsDeleteButtonVisible="False"/>
|
||||
</local:SettingWithDefault>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</ui:SimpleStackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
|
|
@ -131,6 +131,13 @@
|
|||
</c:SettingWithDefault>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="录制条件">
|
||||
<StackPanel>
|
||||
<TextBlock Margin="5" Text="跳过录制的直播标题正则匹配表达式,每行一个" />
|
||||
<TextBox Margin="5" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"
|
||||
Text="{Binding TitleFilterPatterns,UpdateSourceTrigger=PropertyChanged,Delay=1000}" ui:TextBoxHelper.IsDeleteButtonVisible="False"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="{l:Loc Settings_Webhook_Title}">
|
||||
<StackPanel MaxWidth="400" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{l:Loc Settings_Webhook_Address}" Margin="0,0,0,10"/>
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace BililiveRecorder.Web.Models
|
|||
public Optional<bool>? OptionalSaveStreamCover { get; set; }
|
||||
public Optional<string?>? OptionalRecordingQuality { get; set; }
|
||||
public Optional<bool>? OptionalFlvProcessorSplitOnScriptTag { get; set; }
|
||||
public Optional<string?>? OptionalTitleFilterPatterns { get; set; }
|
||||
|
||||
public void ApplyTo(RoomConfig config)
|
||||
{
|
||||
|
@ -41,6 +42,7 @@ namespace BililiveRecorder.Web.Models
|
|||
if (this.OptionalSaveStreamCover.HasValue) config.OptionalSaveStreamCover = this.OptionalSaveStreamCover.Value;
|
||||
if (this.OptionalRecordingQuality.HasValue) config.OptionalRecordingQuality = this.OptionalRecordingQuality.Value;
|
||||
if (this.OptionalFlvProcessorSplitOnScriptTag.HasValue) config.OptionalFlvProcessorSplitOnScriptTag = this.OptionalFlvProcessorSplitOnScriptTag.Value;
|
||||
if (this.OptionalTitleFilterPatterns.HasValue) config.OptionalTitleFilterPatterns = this.OptionalTitleFilterPatterns.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,6 +62,7 @@ namespace BililiveRecorder.Web.Models
|
|||
public Optional<string?>? OptionalFileNameRecordTemplate { get; set; }
|
||||
public Optional<bool>? OptionalFlvProcessorSplitOnScriptTag { get; set; }
|
||||
public Optional<bool>? OptionalFlvWriteMetadata { get; set; }
|
||||
public Optional<string?>? OptionalTitleFilterPatterns { get; set; }
|
||||
public Optional<string?>? OptionalWebHookUrls { get; set; }
|
||||
public Optional<string?>? OptionalWebHookUrlsV2 { get; set; }
|
||||
public Optional<bool>? OptionalWpfShowTitleAndArea { get; set; }
|
||||
|
@ -96,6 +99,7 @@ namespace BililiveRecorder.Web.Models
|
|||
if (this.OptionalFileNameRecordTemplate.HasValue) config.OptionalFileNameRecordTemplate = this.OptionalFileNameRecordTemplate.Value;
|
||||
if (this.OptionalFlvProcessorSplitOnScriptTag.HasValue) config.OptionalFlvProcessorSplitOnScriptTag = this.OptionalFlvProcessorSplitOnScriptTag.Value;
|
||||
if (this.OptionalFlvWriteMetadata.HasValue) config.OptionalFlvWriteMetadata = this.OptionalFlvWriteMetadata.Value;
|
||||
if (this.OptionalTitleFilterPatterns.HasValue) config.OptionalTitleFilterPatterns = this.OptionalTitleFilterPatterns.Value;
|
||||
if (this.OptionalWebHookUrls.HasValue) config.OptionalWebHookUrls = this.OptionalWebHookUrls.Value;
|
||||
if (this.OptionalWebHookUrlsV2.HasValue) config.OptionalWebHookUrlsV2 = this.OptionalWebHookUrlsV2.Value;
|
||||
if (this.OptionalWpfShowTitleAndArea.HasValue) config.OptionalWpfShowTitleAndArea = this.OptionalWpfShowTitleAndArea.Value;
|
||||
|
@ -137,6 +141,7 @@ namespace BililiveRecorder.Web.Models.Rest
|
|||
public Optional<bool> OptionalSaveStreamCover { get; set; }
|
||||
public Optional<string?> OptionalRecordingQuality { get; set; }
|
||||
public Optional<bool> OptionalFlvProcessorSplitOnScriptTag { get; set; }
|
||||
public Optional<string?> OptionalTitleFilterPatterns { get; set; }
|
||||
}
|
||||
|
||||
public class GlobalConfigDto
|
||||
|
@ -155,6 +160,7 @@ namespace BililiveRecorder.Web.Models.Rest
|
|||
public Optional<string?> OptionalFileNameRecordTemplate { get; set; }
|
||||
public Optional<bool> OptionalFlvProcessorSplitOnScriptTag { get; set; }
|
||||
public Optional<bool> OptionalFlvWriteMetadata { get; set; }
|
||||
public Optional<string?> OptionalTitleFilterPatterns { get; set; }
|
||||
public Optional<string?> OptionalWebHookUrls { get; set; }
|
||||
public Optional<string?> OptionalWebHookUrlsV2 { get; set; }
|
||||
public Optional<bool> OptionalWpfShowTitleAndArea { get; set; }
|
||||
|
@ -198,6 +204,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalSaveStreamCover, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordingQuality, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalFlvProcessorSplitOnScriptTag, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalTitleFilterPatterns, type: typeof(HierarchicalOptionalType<string>));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,6 +226,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalFileNameRecordTemplate, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalFlvProcessorSplitOnScriptTag, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalFlvWriteMetadata, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalTitleFilterPatterns, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalWebHookUrls, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalWebHookUrlsV2, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalWpfShowTitleAndArea, type: typeof(HierarchicalOptionalType<bool>));
|
||||
|
@ -259,6 +267,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.FileNameRecordTemplate);
|
||||
this.Field(x => x.FlvProcessorSplitOnScriptTag);
|
||||
this.Field(x => x.FlvWriteMetadata);
|
||||
this.Field(x => x.TitleFilterPatterns);
|
||||
this.Field(x => x.WebHookUrls);
|
||||
this.Field(x => x.WebHookUrlsV2);
|
||||
this.Field(x => x.WpfShowTitleAndArea);
|
||||
|
@ -298,6 +307,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalSaveStreamCover, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordingQuality, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalFlvProcessorSplitOnScriptTag, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalTitleFilterPatterns, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,6 +329,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalFileNameRecordTemplate, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalFlvProcessorSplitOnScriptTag, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalFlvWriteMetadata, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalTitleFilterPatterns, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalWebHookUrls, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalWebHookUrlsV2, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalWpfShowTitleAndArea, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
|
|
|
@ -577,6 +577,22 @@
|
|||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"TitleFilterPatterns": {
|
||||
"description": "不录制的标题匹配正则\n默认: ",
|
||||
"markdownDescription": "不录制的标题匹配正则 \n默认: ` `\n\n",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"HasValue": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"Value": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -822,6 +838,22 @@
|
|||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"TitleFilterPatterns": {
|
||||
"description": "不录制的标题匹配正则\n默认: ",
|
||||
"markdownDescription": "不录制的标题匹配正则 \n默认: ` `\n\n",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"HasValue": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"Value": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,13 @@ export const data: Array<ConfigEntry> = [
|
|||
advancedConfig: true,
|
||||
default: true
|
||||
},
|
||||
{
|
||||
id: "TitleFilterPatterns",
|
||||
name: "不录制的标题匹配正则",
|
||||
type: "string?",
|
||||
configType: "room",
|
||||
default: ""
|
||||
},
|
||||
{
|
||||
id: "WebHookUrls",
|
||||
name: "WebhookV1",
|
||||
|
|
Loading…
Reference in New Issue
Block a user