Files
DanMuRead/BarrageGrab/Server/KsBarrageGrab.cs
T

121 lines
4.3 KiB
C#
Raw Normal View History

2026-08-04 00:10:33 +08:00
using System;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
using BarrageGrab.Modles.KsProtoEntity;
using BarrageGrab.Proxy.ProxyEventArgs;
using ProtoBuf;
namespace BarrageGrab
{
public class KsBarrageGrab
{
// 2026-05 快手WS域名变更为 livejs-ws.kuaishou.cn
private readonly Regex kuaishouWsReg = new Regex(@"livejs-ws\.kuaishou\.cn|(?:livemate|pclivemate)\.pull\.yximgs\.com", RegexOptions.IgnoreCase);
private const string KUAISHOU_LIVE_HOST = "live.kuaishou.com";
public event EventHandler<KsRoomMessageEventArgs<KsWebCommentFeed>> OnChatMessage;
public event EventHandler<KsRoomMessageEventArgs<KsWebLikeFeed>> OnLikeMessage;
public event EventHandler<KsRoomMessageEventArgs<KsWebGiftFeed>> OnGiftMessage;
public event EventHandler<KsRoomMessageEventArgs<KsWebShareFeed>> OnShareMessage;
public event EventHandler<KsRoomMessageEventArgs<KsSCWebFeedPush>> OnRoomStatsMessage;
public KsBarrageGrab()
{
}
public bool IsKuaishouHost(string hostname)
{
if (string.IsNullOrWhiteSpace(hostname)) return false;
hostname = hostname.Trim().ToLower();
return kuaishouWsReg.IsMatch(hostname) || hostname == KUAISHOU_LIVE_HOST;
}
public bool IsKuaishouWebSocket(string uri)
{
if (string.IsNullOrWhiteSpace(uri)) return false;
return kuaishouWsReg.IsMatch(uri);
}
public void HandleWebSocketData(WsMessageEventArgs e)
{
var buff = e.Payload;
if (buff == null || buff.Length == 0) return;
try
{
var socketMsg = Serializer.Deserialize<KsSocketMessage>(new ReadOnlyMemory<byte>(buff));
if (socketMsg == null) return;
if (socketMsg.PayloadType != KsPayloadType.SC_FEED_PUSH) return;
byte[] payload = socketMsg.Payload;
if (socketMsg.CompressionType == KsCompressionType.GZIP)
{
payload = Decompress(payload);
}
var feedPush = Serializer.Deserialize<KsSCWebFeedPush>(new ReadOnlyMemory<byte>(payload));
if (feedPush == null) return;
foreach (var comment in feedPush.CommentFeeds)
{
OnChatMessage?.Invoke(this, new KsRoomMessageEventArgs<KsWebCommentFeed>(e.ProcessName, comment));
}
foreach (var like in feedPush.LikeFeeds)
{
OnLikeMessage?.Invoke(this, new KsRoomMessageEventArgs<KsWebLikeFeed>(e.ProcessName, like));
}
foreach (var gift in feedPush.GiftFeeds)
{
OnGiftMessage?.Invoke(this, new KsRoomMessageEventArgs<KsWebGiftFeed>(e.ProcessName, gift));
}
foreach (var share in feedPush.ShareFeeds)
{
OnShareMessage?.Invoke(this, new KsRoomMessageEventArgs<KsWebShareFeed>(e.ProcessName, share));
}
OnRoomStatsMessage?.Invoke(this, new KsRoomMessageEventArgs<KsSCWebFeedPush>(e.ProcessName, feedPush));
}
catch (Exception ex)
{
Logger.LogError(ex, $"处理快手弹幕数据包时出错:{ex.Message}");
}
}
private byte[] Decompress(byte[] zippedData)
{
using (var ms = new MemoryStream(zippedData))
using (var gzip = new GZipStream(ms, CompressionMode.Decompress))
using (var outBuffer = new MemoryStream())
{
byte[] block = new byte[1024];
while (true)
{
int bytesRead = gzip.Read(block, 0, block.Length);
if (bytesRead <= 0) break;
outBuffer.Write(block, 0, bytesRead);
}
return outBuffer.ToArray();
}
}
}
public class KsRoomMessageEventArgs<T> : EventArgs where T : class
{
public string Process { get; set; }
public T Message { get; set; }
public KsRoomMessageEventArgs() { }
public KsRoomMessageEventArgs(string process, T data)
{
this.Process = process;
this.Message = data;
}
}
}