mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-15 19:22:19 +08:00
Core: Add config options to ignore system proxy, use IPv4 and/or IPv6
This commit is contained in:
parent
2fe47fd6f1
commit
43d1c6f2ef
|
@ -35,7 +35,9 @@ namespace BililiveRecorder.Cli.Configure
|
|||
TimingStreamConnect,
|
||||
TimingDanmakuRetry,
|
||||
TimingWatchdogTimeout,
|
||||
RecordDanmakuFlushInterval
|
||||
RecordDanmakuFlushInterval,
|
||||
NetworkTransportUseSystemProxy,
|
||||
NetworkTransportAllowedAddressFamily
|
||||
}
|
||||
public enum RoomConfigProperties
|
||||
{
|
||||
|
@ -82,6 +84,8 @@ namespace BililiveRecorder.Cli.Configure
|
|||
GlobalConfig.Add(GlobalConfigProperties.TimingDanmakuRetry, new ConfigInstruction<GlobalConfig, uint>(config => config.HasTimingDanmakuRetry = false, (config, value) => config.TimingDanmakuRetry = value) { Name = "TimingDanmakuRetry", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.TimingWatchdogTimeout, new ConfigInstruction<GlobalConfig, uint>(config => config.HasTimingWatchdogTimeout = false, (config, value) => config.TimingWatchdogTimeout = value) { Name = "TimingWatchdogTimeout", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.RecordDanmakuFlushInterval, new ConfigInstruction<GlobalConfig, uint>(config => config.HasRecordDanmakuFlushInterval = false, (config, value) => config.RecordDanmakuFlushInterval = value) { Name = "RecordDanmakuFlushInterval", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.NetworkTransportUseSystemProxy, new ConfigInstruction<GlobalConfig, bool>(config => config.HasNetworkTransportUseSystemProxy = false, (config, value) => config.NetworkTransportUseSystemProxy = value) { Name = "NetworkTransportUseSystemProxy", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.NetworkTransportAllowedAddressFamily, new ConfigInstruction<GlobalConfig, AllowedAddressFamily>(config => config.HasNetworkTransportAllowedAddressFamily = false, (config, value) => config.NetworkTransportAllowedAddressFamily = value) { Name = "NetworkTransportAllowedAddressFamily", CanBeOptional = true });
|
||||
|
||||
RoomConfig.Add(RoomConfigProperties.RoomId, new ConfigInstruction<RoomConfig, int>(config => config.HasRoomId = false, (config, value) => config.RoomId = value) { Name = "RoomId", CanBeOptional = false });
|
||||
RoomConfig.Add(RoomConfigProperties.AutoRecord, new ConfigInstruction<RoomConfig, bool>(config => config.HasAutoRecord = false, (config, value) => config.AutoRecord = value) { Name = "AutoRecord", CanBeOptional = false });
|
||||
|
|
|
@ -4,9 +4,10 @@ using System.CommandLine;
|
|||
using System.CommandLine.Invocation;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using BililiveRecorder.Cli.Configure;
|
||||
using System.Threading.Tasks;
|
||||
using BililiveRecorder.Cli.Configure;
|
||||
using BililiveRecorder.Core;
|
||||
using BililiveRecorder.Core.Config;
|
||||
using BililiveRecorder.Core.Config.V3;
|
||||
|
@ -217,6 +218,7 @@ namespace BililiveRecorder.Cli
|
|||
.Enrich.WithThreadName()
|
||||
.Enrich.FromLogContext()
|
||||
.Enrich.WithExceptionDetails()
|
||||
.Destructure.AsScalar<IPAddress>()
|
||||
.Destructure.ByTransforming<Flv.Xml.XmlFlvFile.XmlFlvFileMeta>(x => new
|
||||
{
|
||||
x.Version,
|
||||
|
|
10
BililiveRecorder.Core/Config/AllowedAddressFamily.cs
Normal file
10
BililiveRecorder.Core/Config/AllowedAddressFamily.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace BililiveRecorder.Core.Config
|
||||
{
|
||||
public enum AllowedAddressFamily
|
||||
{
|
||||
System = -1,
|
||||
Any = 0,
|
||||
Ipv4 = 1,
|
||||
Ipv6 = 2,
|
||||
}
|
||||
}
|
|
@ -166,6 +166,16 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
/// </summary>
|
||||
public uint RecordDanmakuFlushInterval => this.GetPropertyValue<uint>();
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用系统代理
|
||||
/// </summary>
|
||||
public bool NetworkTransportUseSystemProxy => this.GetPropertyValue<bool>();
|
||||
|
||||
/// <summary>
|
||||
/// 允许使用的 IP 网络类型
|
||||
/// </summary>
|
||||
public AllowedAddressFamily NetworkTransportAllowedAddressFamily => this.GetPropertyValue<AllowedAddressFamily>();
|
||||
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
|
@ -347,6 +357,22 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
[JsonProperty(nameof(RecordDanmakuFlushInterval)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<uint> OptionalRecordDanmakuFlushInterval { get => this.GetPropertyValueOptional<uint>(nameof(this.RecordDanmakuFlushInterval)); set => this.SetPropertyValueOptional(value, nameof(this.RecordDanmakuFlushInterval)); }
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用系统代理
|
||||
/// </summary>
|
||||
public bool NetworkTransportUseSystemProxy { get => this.GetPropertyValue<bool>(); set => this.SetPropertyValue(value); }
|
||||
public bool HasNetworkTransportUseSystemProxy { get => this.GetPropertyHasValue(nameof(this.NetworkTransportUseSystemProxy)); set => this.SetPropertyHasValue<bool>(value, nameof(this.NetworkTransportUseSystemProxy)); }
|
||||
[JsonProperty(nameof(NetworkTransportUseSystemProxy)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<bool> OptionalNetworkTransportUseSystemProxy { get => this.GetPropertyValueOptional<bool>(nameof(this.NetworkTransportUseSystemProxy)); set => this.SetPropertyValueOptional(value, nameof(this.NetworkTransportUseSystemProxy)); }
|
||||
|
||||
/// <summary>
|
||||
/// 允许使用的 IP 网络类型
|
||||
/// </summary>
|
||||
public AllowedAddressFamily NetworkTransportAllowedAddressFamily { get => this.GetPropertyValue<AllowedAddressFamily>(); set => this.SetPropertyValue(value); }
|
||||
public bool HasNetworkTransportAllowedAddressFamily { get => this.GetPropertyHasValue(nameof(this.NetworkTransportAllowedAddressFamily)); set => this.SetPropertyHasValue<AllowedAddressFamily>(value, nameof(this.NetworkTransportAllowedAddressFamily)); }
|
||||
[JsonProperty(nameof(NetworkTransportAllowedAddressFamily)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<AllowedAddressFamily> OptionalNetworkTransportAllowedAddressFamily { get => this.GetPropertyValueOptional<AllowedAddressFamily>(nameof(this.NetworkTransportAllowedAddressFamily)); set => this.SetPropertyValueOptional(value, nameof(this.NetworkTransportAllowedAddressFamily)); }
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class DefaultConfig
|
||||
|
@ -398,6 +424,10 @@ namespace BililiveRecorder.Core.Config.V3
|
|||
|
||||
public uint RecordDanmakuFlushInterval => 20;
|
||||
|
||||
public bool NetworkTransportUseSystemProxy => false;
|
||||
|
||||
public AllowedAddressFamily NetworkTransportAllowedAddressFamily => AllowedAddressFamily.Any;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,11 +2,13 @@ using System;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using BililiveRecorder.Core.Api;
|
||||
using BililiveRecorder.Core.Config;
|
||||
using BililiveRecorder.Core.Event;
|
||||
using BililiveRecorder.Core.Templating;
|
||||
using Serilog;
|
||||
|
@ -19,7 +21,7 @@ namespace BililiveRecorder.Core.Recording
|
|||
private const string HttpHeaderAccept = "*/*";
|
||||
private const string HttpHeaderOrigin = "https://live.bilibili.com";
|
||||
private const string HttpHeaderReferer = "https://live.bilibili.com/";
|
||||
private const string HttpHeaderUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36";
|
||||
private const string HttpHeaderUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36";
|
||||
|
||||
private const int timer_inverval = 2;
|
||||
protected readonly Timer timer = new Timer(1000 * timer_inverval);
|
||||
|
@ -199,11 +201,12 @@ namespace BililiveRecorder.Core.Recording
|
|||
|
||||
#region Api Requests
|
||||
|
||||
private static HttpClient CreateHttpClient()
|
||||
private HttpClient CreateHttpClient()
|
||||
{
|
||||
var httpClient = new HttpClient(new HttpClientHandler
|
||||
{
|
||||
AllowAutoRedirect = false
|
||||
AllowAutoRedirect = false,
|
||||
UseProxy = this.room.RoomConfig.NetworkTransportUseSystemProxy,
|
||||
});
|
||||
var headers = httpClient.DefaultRequestHeaders;
|
||||
headers.Add("Accept", HttpHeaderAccept);
|
||||
|
@ -273,25 +276,64 @@ namespace BililiveRecorder.Core.Recording
|
|||
|
||||
protected async Task<Stream> GetStreamAsync(string fullUrl, int timeout)
|
||||
{
|
||||
var client = CreateHttpClient();
|
||||
var client = this.CreateHttpClient();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var resp = await client.GetAsync(fullUrl,
|
||||
var originalUri = new Uri(fullUrl);
|
||||
var allowedAddressFamily = this.room.RoomConfig.NetworkTransportAllowedAddressFamily;
|
||||
HttpRequestMessage request;
|
||||
|
||||
if (allowedAddressFamily == AllowedAddressFamily.System)
|
||||
{
|
||||
this.logger.Debug("NetworkTransportAllowedAddressFamily is System");
|
||||
request = new HttpRequestMessage(HttpMethod.Get, originalUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ips = await Dns.GetHostAddressesAsync(originalUri.DnsSafeHost);
|
||||
|
||||
var filtered = ips.Where(x => allowedAddressFamily switch
|
||||
{
|
||||
AllowedAddressFamily.Ipv4 => x.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork,
|
||||
AllowedAddressFamily.Ipv6 => x.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6,
|
||||
AllowedAddressFamily.Any => true,
|
||||
_ => false
|
||||
}).ToArray();
|
||||
|
||||
var selected = filtered[this.random.Next(filtered.Length)];
|
||||
|
||||
this.logger.Debug("指定直播服务器地址 {DnsHost}: {SelectedIp}, Allowed: {AllowedAddressFamily}, {IPAddresses}", originalUri.DnsSafeHost, selected, allowedAddressFamily, ips);
|
||||
|
||||
if (selected is null)
|
||||
{
|
||||
throw new Exception("DNS 没有返回符合要求的 IP 地址");
|
||||
}
|
||||
|
||||
var builder = new UriBuilder(originalUri)
|
||||
{
|
||||
Host = selected.ToString()
|
||||
};
|
||||
|
||||
request = new HttpRequestMessage(HttpMethod.Get, builder.Uri);
|
||||
request.Headers.Host = originalUri.IsDefaultPort ? originalUri.Host : originalUri.Host + ":" + originalUri.Port;
|
||||
}
|
||||
|
||||
var resp = await client.SendAsync(request,
|
||||
HttpCompletionOption.ResponseHeadersRead,
|
||||
new CancellationTokenSource(timeout).Token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
switch (resp.StatusCode)
|
||||
{
|
||||
case System.Net.HttpStatusCode.OK:
|
||||
case HttpStatusCode.OK:
|
||||
{
|
||||
this.logger.Information("开始接收直播流");
|
||||
var stream = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
return stream;
|
||||
}
|
||||
case System.Net.HttpStatusCode.Moved:
|
||||
case System.Net.HttpStatusCode.Redirect:
|
||||
case HttpStatusCode.Moved:
|
||||
case HttpStatusCode.Redirect:
|
||||
{
|
||||
fullUrl = resp.Headers.Location.OriginalString;
|
||||
this.logger.Debug("跳转到 {Url}", fullUrl);
|
||||
|
@ -303,7 +345,6 @@ namespace BililiveRecorder.Core.Recording
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,6 +213,7 @@ namespace BililiveRecorder.WPF
|
|||
.Enrich.WithThreadName()
|
||||
.Enrich.FromLogContext()
|
||||
.Enrich.WithExceptionDetails()
|
||||
.Destructure.AsScalar<IPAddress>()
|
||||
.Destructure.ByTransforming<Flv.Xml.XmlFlvFile.XmlFlvFileMeta>(x => new
|
||||
{
|
||||
x.Version,
|
||||
|
@ -221,7 +222,6 @@ namespace BililiveRecorder.WPF
|
|||
x.FileCreationTime,
|
||||
x.FileModificationTime,
|
||||
})
|
||||
.Destructure.AsScalar<IPAddress>()
|
||||
.WriteTo.Console(levelSwitch: levelSwitchConsole)
|
||||
#if DEBUG
|
||||
.WriteTo.Debug()
|
||||
|
|
|
@ -62,6 +62,8 @@ namespace BililiveRecorder.Web.Models
|
|||
public Optional<uint>? OptionalTimingDanmakuRetry { get; set; }
|
||||
public Optional<uint>? OptionalTimingWatchdogTimeout { get; set; }
|
||||
public Optional<uint>? OptionalRecordDanmakuFlushInterval { get; set; }
|
||||
public Optional<bool>? OptionalNetworkTransportUseSystemProxy { get; set; }
|
||||
public Optional<AllowedAddressFamily>? OptionalNetworkTransportAllowedAddressFamily { get; set; }
|
||||
|
||||
public void ApplyTo(GlobalConfig config)
|
||||
{
|
||||
|
@ -87,6 +89,8 @@ namespace BililiveRecorder.Web.Models
|
|||
if (this.OptionalTimingDanmakuRetry.HasValue) config.OptionalTimingDanmakuRetry = this.OptionalTimingDanmakuRetry.Value;
|
||||
if (this.OptionalTimingWatchdogTimeout.HasValue) config.OptionalTimingWatchdogTimeout = this.OptionalTimingWatchdogTimeout.Value;
|
||||
if (this.OptionalRecordDanmakuFlushInterval.HasValue) config.OptionalRecordDanmakuFlushInterval = this.OptionalRecordDanmakuFlushInterval.Value;
|
||||
if (this.OptionalNetworkTransportUseSystemProxy.HasValue) config.OptionalNetworkTransportUseSystemProxy = this.OptionalNetworkTransportUseSystemProxy.Value;
|
||||
if (this.OptionalNetworkTransportAllowedAddressFamily.HasValue) config.OptionalNetworkTransportAllowedAddressFamily = this.OptionalNetworkTransportAllowedAddressFamily.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +136,8 @@ namespace BililiveRecorder.Web.Models.Rest
|
|||
public Optional<uint> OptionalTimingDanmakuRetry { get; set; }
|
||||
public Optional<uint> OptionalTimingWatchdogTimeout { get; set; }
|
||||
public Optional<uint> OptionalRecordDanmakuFlushInterval { get; set; }
|
||||
public Optional<bool> OptionalNetworkTransportUseSystemProxy { get; set; }
|
||||
public Optional<AllowedAddressFamily> OptionalNetworkTransportAllowedAddressFamily { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -182,6 +188,8 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalTimingDanmakuRetry, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalTimingWatchdogTimeout, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalRecordDanmakuFlushInterval, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalNetworkTransportUseSystemProxy, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalNetworkTransportAllowedAddressFamily, type: typeof(HierarchicalOptionalType<AllowedAddressFamily>));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,6 +219,8 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.TimingDanmakuRetry);
|
||||
this.Field(x => x.TimingWatchdogTimeout);
|
||||
this.Field(x => x.RecordDanmakuFlushInterval);
|
||||
this.Field(x => x.NetworkTransportUseSystemProxy);
|
||||
this.Field(x => x.NetworkTransportAllowedAddressFamily);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,6 +267,8 @@ namespace BililiveRecorder.Web.Models.Graphql
|
|||
this.Field(x => x.OptionalTimingDanmakuRetry, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalTimingWatchdogTimeout, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalRecordDanmakuFlushInterval, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalNetworkTransportUseSystemProxy, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalNetworkTransportAllowedAddressFamily, nullable: true, type: typeof(HierarchicalOptionalInputType<AllowedAddressFamily>));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -229,6 +229,38 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"NetworkTransportUseSystemProxy": {
|
||||
"description": "是否使用系统代理\n默认: false",
|
||||
"markdownDescription": "是否使用系统代理 \n默认: `false `\n\n",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"HasValue": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"Value": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"NetworkTransportAllowedAddressFamily": {
|
||||
"description": "允许使用的 IP 网络类型\n默认: AllowedAddressFamily.Any",
|
||||
"markdownDescription": "允许使用的 IP 网络类型 \n默认: `AllowedAddressFamily.Any `\n\n",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"HasValue": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"Value": {
|
||||
"type": "AllowedAddressFamily",
|
||||
"default": "AllowedAddressFamily.Any"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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/)",
|
||||
|
|
|
@ -216,4 +216,22 @@ export const data: Array<ConfigEntry> = [
|
|||
xmlComment: "触发 <see cref=\"System.Xml.XmlWriter.Flush\"/> 的弹幕个数",
|
||||
markdown: ""
|
||||
},
|
||||
{
|
||||
name: "NetworkTransportUseSystemProxy",
|
||||
description: "是否使用系统代理",
|
||||
type: "bool",
|
||||
defaultValue: "false",
|
||||
configType: "globalOnly",
|
||||
advancedConfig: true,
|
||||
markdown: ""
|
||||
},
|
||||
{
|
||||
name: "NetworkTransportAllowedAddressFamily",
|
||||
description: "允许使用的 IP 网络类型",
|
||||
type: "AllowedAddressFamily",
|
||||
defaultValue: "AllowedAddressFamily.Any",
|
||||
configType: "globalOnly",
|
||||
advancedConfig: true,
|
||||
markdown: ""
|
||||
},
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue
Block a user