mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-15 19:22:19 +08:00
parent
bcbd1597c6
commit
d6c642de6e
|
@ -22,6 +22,7 @@ namespace BililiveRecorder.Cli.Configure
|
|||
RecordDanmakuSuperChat,
|
||||
RecordDanmakuGift,
|
||||
RecordDanmakuGuard,
|
||||
SaveStreamCover,
|
||||
RecordingQuality,
|
||||
FileNameRecordTemplate,
|
||||
FlvProcessorSplitOnScriptTag,
|
||||
|
@ -58,6 +59,7 @@ namespace BililiveRecorder.Cli.Configure
|
|||
RecordDanmakuSuperChat,
|
||||
RecordDanmakuGift,
|
||||
RecordDanmakuGuard,
|
||||
SaveStreamCover,
|
||||
RecordingQuality,
|
||||
FlvProcessorSplitOnScriptTag
|
||||
}
|
||||
|
@ -76,6 +78,7 @@ namespace BililiveRecorder.Cli.Configure
|
|||
GlobalConfig.Add(GlobalConfigProperties.RecordDanmakuSuperChat, new ConfigInstruction<GlobalConfig, bool>(config => config.HasRecordDanmakuSuperChat = false, (config, value) => config.RecordDanmakuSuperChat = value) { Name = "RecordDanmakuSuperChat", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.RecordDanmakuGift, new ConfigInstruction<GlobalConfig, bool>(config => config.HasRecordDanmakuGift = false, (config, value) => config.RecordDanmakuGift = value) { Name = "RecordDanmakuGift", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.RecordDanmakuGuard, new ConfigInstruction<GlobalConfig, bool>(config => config.HasRecordDanmakuGuard = false, (config, value) => config.RecordDanmakuGuard = value) { Name = "RecordDanmakuGuard", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.SaveStreamCover, new ConfigInstruction<GlobalConfig, bool>(config => config.HasSaveStreamCover = false, (config, value) => config.SaveStreamCover = value) { Name = "SaveStreamCover", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.RecordingQuality, new ConfigInstruction<GlobalConfig, string>(config => config.HasRecordingQuality = false, (config, value) => config.RecordingQuality = value) { Name = "RecordingQuality", CanBeOptional = true });
|
||||
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 });
|
||||
|
@ -108,6 +111,7 @@ namespace BililiveRecorder.Cli.Configure
|
|||
RoomConfig.Add(RoomConfigProperties.RecordDanmakuSuperChat, new ConfigInstruction<RoomConfig, bool>(config => config.HasRecordDanmakuSuperChat = false, (config, value) => config.RecordDanmakuSuperChat = value) { Name = "RecordDanmakuSuperChat", CanBeOptional = true });
|
||||
RoomConfig.Add(RoomConfigProperties.RecordDanmakuGift, new ConfigInstruction<RoomConfig, bool>(config => config.HasRecordDanmakuGift = false, (config, value) => config.RecordDanmakuGift = value) { Name = "RecordDanmakuGift", CanBeOptional = true });
|
||||
RoomConfig.Add(RoomConfigProperties.RecordDanmakuGuard, new ConfigInstruction<RoomConfig, bool>(config => config.HasRecordDanmakuGuard = false, (config, value) => config.RecordDanmakuGuard = value) { Name = "RecordDanmakuGuard", CanBeOptional = true });
|
||||
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 });
|
||||
}
|
||||
|
|
|
@ -93,6 +93,14 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
[JsonProperty(nameof(RecordDanmakuGuard)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<bool> OptionalRecordDanmakuGuard { get => this.GetPropertyValueOptional<bool>(nameof(this.RecordDanmakuGuard)); set => this.SetPropertyValueOptional(value, nameof(this.RecordDanmakuGuard)); }
|
||||
|
||||
/// <summary>
|
||||
/// 保存直播封面
|
||||
/// </summary>
|
||||
public bool SaveStreamCover { get => this.GetPropertyValue<bool>(); set => this.SetPropertyValue(value); }
|
||||
public bool HasSaveStreamCover { get => this.GetPropertyHasValue(nameof(this.SaveStreamCover)); set => this.SetPropertyHasValue<bool>(value, nameof(this.SaveStreamCover)); }
|
||||
[JsonProperty(nameof(SaveStreamCover)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<bool> OptionalSaveStreamCover { get => this.GetPropertyValueOptional<bool>(nameof(this.SaveStreamCover)); set => this.SetPropertyValueOptional(value, nameof(this.SaveStreamCover)); }
|
||||
|
||||
/// <summary>
|
||||
/// 直播画质
|
||||
/// </summary>
|
||||
|
@ -273,6 +281,14 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
[JsonProperty(nameof(RecordDanmakuGuard)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<bool> OptionalRecordDanmakuGuard { get => this.GetPropertyValueOptional<bool>(nameof(this.RecordDanmakuGuard)); set => this.SetPropertyValueOptional(value, nameof(this.RecordDanmakuGuard)); }
|
||||
|
||||
/// <summary>
|
||||
/// 保存直播封面
|
||||
/// </summary>
|
||||
public bool SaveStreamCover { get => this.GetPropertyValue<bool>(); set => this.SetPropertyValue(value); }
|
||||
public bool HasSaveStreamCover { get => this.GetPropertyHasValue(nameof(this.SaveStreamCover)); set => this.SetPropertyHasValue<bool>(value, nameof(this.SaveStreamCover)); }
|
||||
[JsonProperty(nameof(SaveStreamCover)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<bool> OptionalSaveStreamCover { get => this.GetPropertyValueOptional<bool>(nameof(this.SaveStreamCover)); set => this.SetPropertyValueOptional(value, nameof(this.SaveStreamCover)); }
|
||||
|
||||
/// <summary>
|
||||
/// 直播画质
|
||||
/// </summary>
|
||||
|
@ -464,6 +480,8 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
|
||||
public bool RecordDanmakuGuard => true;
|
||||
|
||||
public bool SaveStreamCover => false;
|
||||
|
||||
public string RecordingQuality => @"10000";
|
||||
|
||||
public string FileNameRecordTemplate => @"{{ roomId }}-{{ name }}/录制-{{ roomId }}-{{ ""now"" | time_zone: ""Asia/Shanghai"" | format_date: ""yyyyMMdd-HHmmss-fff"" }}-{{ title }}.flv";
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -420,6 +421,39 @@ namespace BililiveRecorder.Core
|
|||
else
|
||||
this.basicDanmakuWriter.Disable();
|
||||
|
||||
if (this.RoomConfig.SaveStreamCover)
|
||||
{
|
||||
// 保存直播间封面
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var coverUrl = this.RawBilibiliApiJsonData?["room_info"]?["cover"]?.ToObject<string>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(coverUrl))
|
||||
{
|
||||
this.logger.Information("没有直播间封面信息");
|
||||
return;
|
||||
}
|
||||
|
||||
var targetPath = Path.ChangeExtension(e.FullPath, "cover" + Path.GetExtension(coverUrl));
|
||||
|
||||
using var http = new HttpClient();
|
||||
http.DefaultRequestHeaders.UserAgent.Clear();
|
||||
|
||||
var stream = await http.GetStreamAsync(coverUrl).ConfigureAwait(false);
|
||||
using var file = new FileStream(targetPath, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
await stream.CopyToAsync(file).ConfigureAwait(false);
|
||||
|
||||
this.logger.Debug("直播间封面已成功从 {CoverUrl} 保存到 {FilePath}", coverUrl, targetPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.logger.Warning(ex, "保存直播间封面时出错");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RecordFileOpening?.Invoke(this, e);
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,11 @@
|
|||
</local:SettingWithDefault>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="直播封面">
|
||||
<local:SettingWithDefault IsSettingNotUsingDefault="{Binding HasSaveStreamCover}">
|
||||
<ui:ToggleSwitch IsOn="{Binding SaveStreamCover}" OnContent="录制时同时保存直播封面" OffContent="录制时同时保存直播封面"/>
|
||||
</local:SettingWithDefault>
|
||||
</GroupBox>
|
||||
<GroupBox Header="录制画质">
|
||||
<StackPanel>
|
||||
<TextBlock Text="逗号分割的录制画质ID"/>
|
||||
|
|
|
@ -80,6 +80,9 @@
|
|||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="直播封面">
|
||||
<ui:ToggleSwitch IsOn="{Binding SaveStreamCover}" OnContent="录制时同时保存直播封面" OffContent="录制时同时保存直播封面"/>
|
||||
</GroupBox>
|
||||
<GroupBox Header="{l:Loc Settings_FileName_Title}">
|
||||
<StackPanel MaxWidth="500" HorizontalAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace BililiveRecorder.Web.Models
|
|||
public Optional<bool>? OptionalRecordDanmakuSuperChat { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuGift { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuGuard { get; set; }
|
||||
public Optional<bool>? OptionalSaveStreamCover { get; set; }
|
||||
public Optional<string?>? OptionalRecordingQuality { get; set; }
|
||||
public Optional<bool>? OptionalFlvProcessorSplitOnScriptTag { get; set; }
|
||||
|
||||
|
@ -35,6 +36,7 @@ namespace BililiveRecorder.Web.Models
|
|||
if (this.OptionalRecordDanmakuSuperChat.HasValue) config.OptionalRecordDanmakuSuperChat = this.OptionalRecordDanmakuSuperChat.Value;
|
||||
if (this.OptionalRecordDanmakuGift.HasValue) config.OptionalRecordDanmakuGift = this.OptionalRecordDanmakuGift.Value;
|
||||
if (this.OptionalRecordDanmakuGuard.HasValue) config.OptionalRecordDanmakuGuard = this.OptionalRecordDanmakuGuard.Value;
|
||||
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;
|
||||
}
|
||||
|
@ -50,6 +52,7 @@ namespace BililiveRecorder.Web.Models
|
|||
public Optional<bool>? OptionalRecordDanmakuSuperChat { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuGift { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuGuard { get; set; }
|
||||
public Optional<bool>? OptionalSaveStreamCover { get; set; }
|
||||
public Optional<string?>? OptionalRecordingQuality { get; set; }
|
||||
public Optional<string?>? OptionalFileNameRecordTemplate { get; set; }
|
||||
public Optional<bool>? OptionalFlvProcessorSplitOnScriptTag { get; set; }
|
||||
|
@ -82,6 +85,7 @@ namespace BililiveRecorder.Web.Models
|
|||
if (this.OptionalRecordDanmakuSuperChat.HasValue) config.OptionalRecordDanmakuSuperChat = this.OptionalRecordDanmakuSuperChat.Value;
|
||||
if (this.OptionalRecordDanmakuGift.HasValue) config.OptionalRecordDanmakuGift = this.OptionalRecordDanmakuGift.Value;
|
||||
if (this.OptionalRecordDanmakuGuard.HasValue) config.OptionalRecordDanmakuGuard = this.OptionalRecordDanmakuGuard.Value;
|
||||
if (this.OptionalSaveStreamCover.HasValue) config.OptionalSaveStreamCover = this.OptionalSaveStreamCover.Value;
|
||||
if (this.OptionalRecordingQuality.HasValue) config.OptionalRecordingQuality = this.OptionalRecordingQuality.Value;
|
||||
if (this.OptionalFileNameRecordTemplate.HasValue) config.OptionalFileNameRecordTemplate = this.OptionalFileNameRecordTemplate.Value;
|
||||
if (this.OptionalFlvProcessorSplitOnScriptTag.HasValue) config.OptionalFlvProcessorSplitOnScriptTag = this.OptionalFlvProcessorSplitOnScriptTag.Value;
|
||||
|
@ -121,6 +125,7 @@ namespace BililiveRecorder.Web.Models.Rest
|
|||
public Optional<bool> OptionalRecordDanmakuSuperChat { get; set; }
|
||||
public Optional<bool> OptionalRecordDanmakuGift { get; set; }
|
||||
public Optional<bool> OptionalRecordDanmakuGuard { get; set; }
|
||||
public Optional<bool> OptionalSaveStreamCover { get; set; }
|
||||
public Optional<string?> OptionalRecordingQuality { get; set; }
|
||||
public Optional<bool> OptionalFlvProcessorSplitOnScriptTag { get; set; }
|
||||
}
|
||||
|
@ -135,6 +140,7 @@ namespace BililiveRecorder.Web.Models.Rest
|
|||
public Optional<bool> OptionalRecordDanmakuSuperChat { get; set; }
|
||||
public Optional<bool> OptionalRecordDanmakuGift { get; set; }
|
||||
public Optional<bool> OptionalRecordDanmakuGuard { get; set; }
|
||||
public Optional<bool> OptionalSaveStreamCover { get; set; }
|
||||
public Optional<string?> OptionalRecordingQuality { get; set; }
|
||||
public Optional<string?> OptionalFileNameRecordTemplate { get; set; }
|
||||
public Optional<bool> OptionalFlvProcessorSplitOnScriptTag { get; set; }
|
||||
|
@ -176,6 +182,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalRecordDanmakuSuperChat, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGift, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGuard, type: typeof(HierarchicalOptionalType<bool>));
|
||||
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>));
|
||||
}
|
||||
|
@ -193,6 +200,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalRecordDanmakuSuperChat, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGift, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGuard, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalSaveStreamCover, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordingQuality, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalFileNameRecordTemplate, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalFlvProcessorSplitOnScriptTag, type: typeof(HierarchicalOptionalType<bool>));
|
||||
|
@ -229,6 +237,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.RecordDanmakuSuperChat);
|
||||
this.Field(x => x.RecordDanmakuGift);
|
||||
this.Field(x => x.RecordDanmakuGuard);
|
||||
this.Field(x => x.SaveStreamCover);
|
||||
this.Field(x => x.RecordingQuality);
|
||||
this.Field(x => x.FileNameRecordTemplate);
|
||||
this.Field(x => x.FlvProcessorSplitOnScriptTag);
|
||||
|
@ -266,6 +275,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalRecordDanmakuSuperChat, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGift, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGuard, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
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>));
|
||||
}
|
||||
|
@ -283,6 +293,7 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalRecordDanmakuSuperChat, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGift, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGuard, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
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.OptionalFileNameRecordTemplate, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalFlvProcessorSplitOnScriptTag, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
|
|
|
@ -482,6 +482,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"SaveStreamCover": {
|
||||
"description": "保存直播封面\n默认: false",
|
||||
"markdownDescription": "保存直播封面 \n默认: `false `\n\n",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"HasValue": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"Value": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"RecordingQuality": {
|
||||
"description": "直播画质\n默认: 10000",
|
||||
"markdownDescription": "直播画质 \n默认: `10000 `\n\n",
|
||||
|
@ -695,6 +711,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"SaveStreamCover": {
|
||||
"description": "保存直播封面\n默认: false",
|
||||
"markdownDescription": "保存直播封面 \n默认: `false `\n\n",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"HasValue": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"Value": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"RecordingQuality": {
|
||||
"description": "直播画质\n默认: 10000",
|
||||
"markdownDescription": "直播画质 \n默认: `10000 `\n\n",
|
||||
|
|
|
@ -72,6 +72,13 @@ export const data: Array<ConfigEntry> = [
|
|||
configType: "room",
|
||||
default: true
|
||||
},
|
||||
{
|
||||
id: "SaveStreamCover",
|
||||
name: "保存直播封面",
|
||||
type: "bool",
|
||||
configType: "room",
|
||||
default: false
|
||||
},
|
||||
{
|
||||
id: "RecordingQuality",
|
||||
name: "直播画质",
|
||||
|
|
Loading…
Reference in New Issue
Block a user