diff --git a/BililiveRecorder.Core/BililiveRecorder.Core.csproj b/BililiveRecorder.Core/BililiveRecorder.Core.csproj
index a5f8668..b5352b7 100644
--- a/BililiveRecorder.Core/BililiveRecorder.Core.csproj
+++ b/BililiveRecorder.Core/BililiveRecorder.Core.csproj
@@ -11,6 +11,7 @@
2.0
+ true
none
@@ -18,6 +19,7 @@
+
diff --git a/BililiveRecorder.Core/RecordedRoom.cs b/BililiveRecorder.Core/RecordedRoom.cs
index ed08aa5..680e702 100644
--- a/BililiveRecorder.Core/RecordedRoom.cs
+++ b/BililiveRecorder.Core/RecordedRoom.cs
@@ -1,7 +1,9 @@
using BililiveRecorder.Core.Config;
using BililiveRecorder.FlvProcessor;
+using DnsClient;
using NLog;
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
@@ -18,6 +20,11 @@ namespace BililiveRecorder.Core
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
private static readonly Random random = new Random();
+ private static readonly LookupClient lookupClient = new LookupClient()
+ {
+ ThrowDnsErrors = true,
+ };
+
private int _roomid;
private int _realRoomid;
private string _streamerName;
@@ -142,7 +149,7 @@ namespace BililiveRecorder.Core
private void StreamMonitor_StreamStatusChanged(object sender, StreamStatusChangedArgs e)
{
// if (StartupTask?.IsCompleted ?? true)
- if (!IsRecording)
+ if (!IsRecording && (StartupTask?.IsCompleted ?? true))
{
StartupTask = _StartRecordAsync();
}
@@ -208,7 +215,11 @@ namespace BililiveRecorder.Core
{
using (var client = new HttpClient())
{
+ var raw_uri = new Uri(BililiveAPI.GetPlayUrl(RealRoomid));
+
client.Timeout = TimeSpan.FromMilliseconds(_config.TimingStreamConnect);
+
+ client.DefaultRequestHeaders.Host = raw_uri.Host;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
client.DefaultRequestHeaders.UserAgent.Clear();
@@ -216,11 +227,13 @@ namespace BililiveRecorder.Core
client.DefaultRequestHeaders.Referrer = new Uri("https://live.bilibili.com");
client.DefaultRequestHeaders.Add("Origin", "https://live.bilibili.com");
- string flv_path = BililiveAPI.GetPlayUrl(RealRoomid);
- logger.Log(RealRoomid, LogLevel.Info, "连接直播服务器 " + new Uri(flv_path).Host);
- logger.Log(RealRoomid, LogLevel.Debug, "直播流地址: " + flv_path);
+ var ips = lookupClient.Query(raw_uri.DnsSafeHost, QueryType.A).Answers?.ARecords()?.ToArray();
+ var ip = ips[random.Next(0, ips.Count())].Address;
- _response = await client.GetAsync(flv_path, HttpCompletionOption.ResponseHeadersRead);
+ logger.Log(RealRoomid, LogLevel.Info, "连接直播服务器 " + raw_uri.Host + " (" + ip + ")");
+ logger.Log(RealRoomid, LogLevel.Debug, "直播流地址: " + raw_uri.ToString());
+
+ _response = await client.GetAsync(new UriBuilder(raw_uri) { Host = ip.ToString() }.Uri, HttpCompletionOption.ResponseHeadersRead);
}
if (_response.StatusCode != HttpStatusCode.OK)
@@ -238,6 +251,28 @@ namespace BililiveRecorder.Core
Processor.ClipLengthFuture = _config.ClipLengthFuture;
Processor.ClipLengthPast = _config.ClipLengthPast;
Processor.CuttingNumber = _config.CuttingNumber;
+ Processor.OnMetaData += (sender, e) =>
+ {
+ e.Metadata["BililiveRecorder"] = new Dictionary()
+ {
+ {
+ "starttime",
+ DateTime.UtcNow
+ },
+ {
+ "version",
+ "TEST"
+ },
+ {
+ "roomid",
+ RealRoomid.ToString()
+ },
+ {
+ "streamername",
+ StreamerName
+ },
+ };
+ };
_stream = await _response.Content.ReadAsStreamAsync();
_stream.ReadTimeout = 3 * 1000;
diff --git a/BililiveRecorder.FlvProcessor/Enums.cs b/BililiveRecorder.FlvProcessor/Enums.cs
index 08ff0f2..ab30cd0 100644
--- a/BililiveRecorder.FlvProcessor/Enums.cs
+++ b/BililiveRecorder.FlvProcessor/Enums.cs
@@ -7,16 +7,63 @@
DATA = 18,
}
- public enum AMFTypes
+ public enum AMFTypes : byte
{
- Number = 0x00, // (Encoded as IEEE 64-bit double-precision floating point number)
- Boolean = 0x01, // (Encoded as a single byte of value 0x00 or 0x01)
- String = 0x02, //(ASCII encoded)
- Object = 0x03, // (Set of key/value pairs)
- Null = 0x05,
- Array = 0x08,
- End = 0x09,
+ ///
+ /// 非标准类型。在 Decode 过程中作为函数参数使用
+ ///
+ Any = 0xFF,
+ ///
+ /// Double
+ ///
+ Number = 0,
+ ///
+ /// 8 bit unsigned integer
+ ///
+ Boolean = 1,
+ ///
+ /// ScriptDataString
+ ///
+ String = 2,
+ ///
+ /// ScriptDataObject
+ ///
+ Object = 3,
+ ///
+ /// Not Supported
+ ///
+ MovieClip = 4,
+ ///
+ /// Nothing
+ ///
+ Null = 5,
+ ///
+ /// Nothing
+ ///
+ Undefined = 6,
+ ///
+ /// Not Supported
+ ///
+ Reference = 7,
+ ///
+ /// ScriptDataEcmaArray
+ ///
+ ECMAArray = 8,
+ ///
+ /// Nothing
+ ///
+ ObjectEndMarker = 9,
+ ///
+ /// ScriptDataStrictArray
+ ///
+ StrictArray = 10,
+ ///
+ /// ScriptDataDate
+ ///
+ Date = 11,
+ ///
+ /// ScriptDataLongString
+ ///
+ LongString = 12
}
-
-
}
diff --git a/BililiveRecorder.FlvProcessor/Events.cs b/BililiveRecorder.FlvProcessor/Events.cs
index 79a065a..0ed1c1c 100644
--- a/BililiveRecorder.FlvProcessor/Events.cs
+++ b/BililiveRecorder.FlvProcessor/Events.cs
@@ -1,11 +1,17 @@
namespace BililiveRecorder.FlvProcessor
{
+ public delegate void FlvMetadataEvent(object sender, FlvMetadataArgs e);
+ public class FlvMetadataArgs
+ {
+ public IFlvMetadata Metadata;
+ }
+
public delegate void TagProcessedEvent(object sender, TagProcessedArgs e);
public class TagProcessedArgs
{
public IFlvTag Tag;
}
-
+
public delegate void ClipFinalizedEvent(object sender, ClipFinalizedArgs e);
public class ClipFinalizedArgs
{
diff --git a/BililiveRecorder.FlvProcessor/FlvClipProcessor.cs b/BililiveRecorder.FlvProcessor/FlvClipProcessor.cs
index 38946e1..f633b83 100644
--- a/BililiveRecorder.FlvProcessor/FlvClipProcessor.cs
+++ b/BililiveRecorder.FlvProcessor/FlvClipProcessor.cs
@@ -9,14 +9,17 @@ namespace BililiveRecorder.FlvProcessor
{
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
+ private readonly Func funcFlvTag;
+
public IFlvMetadata Header { get; private set; }
public List HTags { get; private set; }
public List Tags { get; private set; }
private int target = -1;
private string path;
- public FlvClipProcessor()
+ public FlvClipProcessor(Func funcFlvTag)
{
+ this.funcFlvTag = funcFlvTag;
}
public IFlvClipProcessor Initialize(string path, IFlvMetadata metadata, List head, List data, uint seconds)
@@ -54,14 +57,18 @@ namespace BililiveRecorder.FlvProcessor
fs.Write(FlvStreamProcessor.FLV_HEADER_BYTES, 0, FlvStreamProcessor.FLV_HEADER_BYTES.Length);
fs.Write(new byte[] { 0, 0, 0, 0, }, 0, 4);
- Header.Meta["duration"] = (Tags[Tags.Count - 1].TimeStamp - Tags[0].TimeStamp) / 1000d;
- Header.Meta["lasttimestamp"] = (Tags[Tags.Count - 1].TimeStamp - Tags[0].TimeStamp);
+ Header["duration"] = (Tags[Tags.Count - 1].TimeStamp - Tags[0].TimeStamp) / 1000d;
+ Header["lasttimestamp"] = (Tags[Tags.Count - 1].TimeStamp - Tags[0].TimeStamp);
- var t = new FlvTag
+ var t = funcFlvTag();
+ t.TagType = TagType.DATA;
+
+ if (Header.ContainsKey("BililiveRecorder"))
{
- TagType = TagType.DATA,
- Data = Header.ToBytes()
- };
+ // TODO: 更好的写法
+ (Header["BililiveRecorder"] as Dictionary)["starttime"] = DateTime.UtcNow;
+ }
+ t.Data = Header.ToBytes();
t.WriteTo(fs);
int offset = Tags[0].TimeStamp;
diff --git a/BililiveRecorder.FlvProcessor/FlvMetadata.cs b/BililiveRecorder.FlvProcessor/FlvMetadata.cs
index 7a83141..bfa2e8e 100644
--- a/BililiveRecorder.FlvProcessor/FlvMetadata.cs
+++ b/BililiveRecorder.FlvProcessor/FlvMetadata.cs
@@ -1,14 +1,25 @@
using System;
+using System.Collections;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Text;
namespace BililiveRecorder.FlvProcessor
{
public class FlvMetadata : IFlvMetadata
{
- public IDictionary Meta { get; set; } = new Dictionary();
+ private IDictionary Meta { get; set; } = new Dictionary();
+
+ public ICollection Keys => Meta.Keys;
+
+ public ICollection