121 lines
4.3 KiB
C#
121 lines
4.3 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|