mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-16 11:42:22 +08:00
Core: Add danmaku filter to userscript
This commit is contained in:
parent
54e64d108d
commit
69914d6791
|
@ -155,15 +155,17 @@ namespace BililiveRecorder.Core.Api.Danmaku
|
|||
/// <summary>
|
||||
/// 原始数据
|
||||
/// </summary>
|
||||
public string? RawString { get; set; }
|
||||
public string RawString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始数据
|
||||
/// </summary>
|
||||
public JObject? RawObject { get; set; }
|
||||
|
||||
public DanmakuModel()
|
||||
{ }
|
||||
private DanmakuModel()
|
||||
{
|
||||
this.RawString = string.Empty;
|
||||
}
|
||||
|
||||
public DanmakuModel(string json)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
|||
using System.Xml;
|
||||
using BililiveRecorder.Core.Api.Danmaku;
|
||||
using BililiveRecorder.Core.Config.V3;
|
||||
using BililiveRecorder.Core.Scripting;
|
||||
using Serilog;
|
||||
|
||||
#nullable enable
|
||||
|
@ -34,10 +35,12 @@ namespace BililiveRecorder.Core.Danmaku
|
|||
|
||||
private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
private readonly ILogger logger;
|
||||
private readonly UserScriptRunner userScriptRunner;
|
||||
|
||||
public BasicDanmakuWriter(ILogger logger)
|
||||
public BasicDanmakuWriter(ILogger logger, UserScriptRunner userScriptRunner)
|
||||
{
|
||||
this.logger = logger?.ForContext<BasicDanmakuWriter>() ?? throw new ArgumentNullException(nameof(logger));
|
||||
this.userScriptRunner = userScriptRunner ?? throw new ArgumentNullException(nameof(userScriptRunner));
|
||||
}
|
||||
|
||||
public void EnableWithPath(string path, IRoom room)
|
||||
|
@ -105,89 +108,98 @@ namespace BililiveRecorder.Core.Danmaku
|
|||
|
||||
public async Task WriteAsync(DanmakuModel danmakuModel)
|
||||
{
|
||||
if (this.disposedValue) return;
|
||||
if (this.config is null) return;
|
||||
if (this.disposedValue)
|
||||
return;
|
||||
|
||||
if (this.xmlWriter is null || this.config is null)
|
||||
return;
|
||||
|
||||
if (danmakuModel.MsgType is not (DanmakuMsgType.Comment or DanmakuMsgType.SuperChat or DanmakuMsgType.GiftSend or DanmakuMsgType.GuardBuy))
|
||||
return;
|
||||
|
||||
if (!this.userScriptRunner.CallOnDanmaku(this.logger, danmakuModel.RawString))
|
||||
return;
|
||||
|
||||
await this.semaphoreSlim.WaitAsync();
|
||||
try
|
||||
{
|
||||
if (this.xmlWriter != null)
|
||||
if (this.xmlWriter is null)
|
||||
return;
|
||||
|
||||
var write = true;
|
||||
var recordDanmakuRaw = this.config.RecordDanmakuRaw;
|
||||
switch (danmakuModel.MsgType)
|
||||
{
|
||||
var write = true;
|
||||
var recordDanmakuRaw = this.config.RecordDanmakuRaw;
|
||||
switch (danmakuModel.MsgType)
|
||||
{
|
||||
case DanmakuMsgType.Comment:
|
||||
{
|
||||
var type = danmakuModel.RawObject?["info"]?[0]?[1]?.ToObject<int>() ?? 1;
|
||||
var size = danmakuModel.RawObject?["info"]?[0]?[2]?.ToObject<int>() ?? 25;
|
||||
var color = danmakuModel.RawObject?["info"]?[0]?[3]?.ToObject<int>() ?? 0XFFFFFF;
|
||||
var st = danmakuModel.RawObject?["info"]?[0]?[4]?.ToObject<long>() ?? 0L;
|
||||
case DanmakuMsgType.Comment:
|
||||
{
|
||||
var type = danmakuModel.RawObject?["info"]?[0]?[1]?.ToObject<int>() ?? 1;
|
||||
var size = danmakuModel.RawObject?["info"]?[0]?[2]?.ToObject<int>() ?? 25;
|
||||
var color = danmakuModel.RawObject?["info"]?[0]?[3]?.ToObject<int>() ?? 0XFFFFFF;
|
||||
var st = danmakuModel.RawObject?["info"]?[0]?[4]?.ToObject<long>() ?? 0L;
|
||||
|
||||
var ts = Math.Max((DateTimeOffset.UtcNow - this.offset).TotalSeconds, 0d);
|
||||
var ts = Math.Max((DateTimeOffset.UtcNow - this.offset).TotalSeconds, 0d);
|
||||
|
||||
await this.xmlWriter.WriteStartElementAsync(null, "d", null).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "p", null, $"{ts:F3},{type},{size},{color},{st},0,{danmakuModel.UserID},0").ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "user", null, RemoveInvalidXMLChars(danmakuModel.UserName)).ConfigureAwait(false);
|
||||
if (recordDanmakuRaw)
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "raw", null, RemoveInvalidXMLChars(danmakuModel.RawObject?["info"]?.ToString(Newtonsoft.Json.Formatting.None))).ConfigureAwait(false);
|
||||
this.xmlWriter.WriteValue(RemoveInvalidXMLChars(danmakuModel.CommentText));
|
||||
await this.xmlWriter.WriteEndElementAsync().ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
case DanmakuMsgType.SuperChat:
|
||||
if (this.config.RecordDanmakuSuperChat)
|
||||
{
|
||||
await this.xmlWriter.WriteStartElementAsync(null, "sc", null).ConfigureAwait(false);
|
||||
var ts = Math.Max((DateTimeOffset.UtcNow - this.offset).TotalSeconds, 0d);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "ts", null, ts.ToString("F3")).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "user", null, RemoveInvalidXMLChars(danmakuModel.UserName)).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "price", null, danmakuModel.Price.ToString()).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "time", null, danmakuModel.SCKeepTime.ToString()).ConfigureAwait(false);
|
||||
if (recordDanmakuRaw)
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "raw", null, RemoveInvalidXMLChars(danmakuModel.RawObject?["data"]?.ToString(Newtonsoft.Json.Formatting.None))).ConfigureAwait(false);
|
||||
this.xmlWriter.WriteValue(RemoveInvalidXMLChars(danmakuModel.CommentText));
|
||||
await this.xmlWriter.WriteEndElementAsync().ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
case DanmakuMsgType.GiftSend:
|
||||
if (this.config.RecordDanmakuGift)
|
||||
{
|
||||
await this.xmlWriter.WriteStartElementAsync(null, "gift", null).ConfigureAwait(false);
|
||||
var ts = Math.Max((DateTimeOffset.UtcNow - this.offset).TotalSeconds, 0d);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "ts", null, ts.ToString("F3")).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "user", null, RemoveInvalidXMLChars(danmakuModel.UserName)).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "giftname", null, RemoveInvalidXMLChars(danmakuModel.GiftName)).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "giftcount", null, danmakuModel.GiftCount.ToString()).ConfigureAwait(false);
|
||||
if (recordDanmakuRaw)
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "raw", null, RemoveInvalidXMLChars(danmakuModel.RawObject?["data"]?.ToString(Newtonsoft.Json.Formatting.None))).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteEndElementAsync().ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
case DanmakuMsgType.GuardBuy:
|
||||
if (this.config.RecordDanmakuGuard)
|
||||
{
|
||||
await this.xmlWriter.WriteStartElementAsync(null, "guard", null).ConfigureAwait(false);
|
||||
var ts = Math.Max((DateTimeOffset.UtcNow - this.offset).TotalSeconds, 0d);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "ts", null, ts.ToString("F3")).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "user", null, RemoveInvalidXMLChars(danmakuModel.UserName)).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "level", null, danmakuModel.UserGuardLevel.ToString()).ConfigureAwait(false); ;
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "count", null, danmakuModel.GiftCount.ToString()).ConfigureAwait(false);
|
||||
if (recordDanmakuRaw)
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "raw", null, RemoveInvalidXMLChars(danmakuModel.RawObject?["data"]?.ToString(Newtonsoft.Json.Formatting.None))).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteEndElementAsync().ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
write = false;
|
||||
break;
|
||||
}
|
||||
await this.xmlWriter.WriteStartElementAsync(null, "d", null).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "p", null, $"{ts:F3},{type},{size},{color},{st},0,{danmakuModel.UserID},0").ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "user", null, RemoveInvalidXMLChars(danmakuModel.UserName)).ConfigureAwait(false);
|
||||
if (recordDanmakuRaw)
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "raw", null, RemoveInvalidXMLChars(danmakuModel.RawObject?["info"]?.ToString(Newtonsoft.Json.Formatting.None))).ConfigureAwait(false);
|
||||
this.xmlWriter.WriteValue(RemoveInvalidXMLChars(danmakuModel.CommentText));
|
||||
await this.xmlWriter.WriteEndElementAsync().ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
case DanmakuMsgType.SuperChat:
|
||||
if (this.config.RecordDanmakuSuperChat)
|
||||
{
|
||||
await this.xmlWriter.WriteStartElementAsync(null, "sc", null).ConfigureAwait(false);
|
||||
var ts = Math.Max((DateTimeOffset.UtcNow - this.offset).TotalSeconds, 0d);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "ts", null, ts.ToString("F3")).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "user", null, RemoveInvalidXMLChars(danmakuModel.UserName)).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "price", null, danmakuModel.Price.ToString()).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "time", null, danmakuModel.SCKeepTime.ToString()).ConfigureAwait(false);
|
||||
if (recordDanmakuRaw)
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "raw", null, RemoveInvalidXMLChars(danmakuModel.RawObject?["data"]?.ToString(Newtonsoft.Json.Formatting.None))).ConfigureAwait(false);
|
||||
this.xmlWriter.WriteValue(RemoveInvalidXMLChars(danmakuModel.CommentText));
|
||||
await this.xmlWriter.WriteEndElementAsync().ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
case DanmakuMsgType.GiftSend:
|
||||
if (this.config.RecordDanmakuGift)
|
||||
{
|
||||
await this.xmlWriter.WriteStartElementAsync(null, "gift", null).ConfigureAwait(false);
|
||||
var ts = Math.Max((DateTimeOffset.UtcNow - this.offset).TotalSeconds, 0d);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "ts", null, ts.ToString("F3")).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "user", null, RemoveInvalidXMLChars(danmakuModel.UserName)).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "giftname", null, RemoveInvalidXMLChars(danmakuModel.GiftName)).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "giftcount", null, danmakuModel.GiftCount.ToString()).ConfigureAwait(false);
|
||||
if (recordDanmakuRaw)
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "raw", null, RemoveInvalidXMLChars(danmakuModel.RawObject?["data"]?.ToString(Newtonsoft.Json.Formatting.None))).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteEndElementAsync().ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
case DanmakuMsgType.GuardBuy:
|
||||
if (this.config.RecordDanmakuGuard)
|
||||
{
|
||||
await this.xmlWriter.WriteStartElementAsync(null, "guard", null).ConfigureAwait(false);
|
||||
var ts = Math.Max((DateTimeOffset.UtcNow - this.offset).TotalSeconds, 0d);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "ts", null, ts.ToString("F3")).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "user", null, RemoveInvalidXMLChars(danmakuModel.UserName)).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "level", null, danmakuModel.UserGuardLevel.ToString()).ConfigureAwait(false); ;
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "count", null, danmakuModel.GiftCount.ToString()).ConfigureAwait(false);
|
||||
if (recordDanmakuRaw)
|
||||
await this.xmlWriter.WriteAttributeStringAsync(null, "raw", null, RemoveInvalidXMLChars(danmakuModel.RawObject?["data"]?.ToString(Newtonsoft.Json.Formatting.None))).ConfigureAwait(false);
|
||||
await this.xmlWriter.WriteEndElementAsync().ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
write = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (write && this.writeCount++ >= this.config.RecordDanmakuFlushInterval)
|
||||
{
|
||||
await this.xmlWriter.FlushAsync();
|
||||
this.writeCount = 0;
|
||||
}
|
||||
if (write && this.writeCount++ >= this.config.RecordDanmakuFlushInterval)
|
||||
{
|
||||
await this.xmlWriter.FlushAsync();
|
||||
this.writeCount = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -481,7 +481,7 @@ namespace BililiveRecorder.Core
|
|||
break;
|
||||
}
|
||||
|
||||
_ = this.basicDanmakuWriter.WriteAsync(d);
|
||||
_ = Task.Run(async () => await this.basicDanmakuWriter.WriteAsync(d));
|
||||
}
|
||||
|
||||
private void DanmakuClient_StatusChanged(object sender, Api.Danmaku.StatusChangedEventArgs e)
|
||||
|
|
|
@ -135,6 +135,32 @@ globalThis.recorderEvents = {};
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 过滤保存的弹幕
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="json">弹幕 JSON 文本</param>
|
||||
/// <returns>是否保存弹幕</returns>
|
||||
public bool CallOnDanmaku(ILogger logger, string json)
|
||||
{
|
||||
const string callbackName = "onDanmaku";
|
||||
var log = BuildLogger(logger);
|
||||
try
|
||||
{
|
||||
var func = this.ExecuteScriptThenGetEventHandler(log, callbackName);
|
||||
if (func is null) return true;
|
||||
|
||||
var result = func.Engine.Call(func, json);
|
||||
|
||||
return result.IsLooselyEqual(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Error(ex, $"执行脚本 {callbackName} 时发生错误");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取直播流 URL
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in New Issue
Block a user