From 2f2e130c8beaf721bbc4171cc92637f3f010d18f Mon Sep 17 00:00:00 2001 From: xiaoyaocz Date: Wed, 15 May 2024 17:43:49 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=93=94=E5=93=A9=E5=93=94?= =?UTF-8?q?=E5=93=A9=E5=BC=B9=E5=B9=95=E6=96=AD=E5=BC=80=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20#52?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Properties/launchSettings.json | 2 +- AllLive.Core/AllLive.Core.csproj | 3 +- AllLive.Core/Danmaku/BiliBiliDanmaku.cs | 144 ++++++++++++++++-- AllLive.UWP/Package.appxmanifest | 2 +- 4 files changed, 134 insertions(+), 17 deletions(-) diff --git a/AllLive.Console/Properties/launchSettings.json b/AllLive.Console/Properties/launchSettings.json index 7b32961..8226484 100644 --- a/AllLive.Console/Properties/launchSettings.json +++ b/AllLive.Console/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "AllLive.ConsoleApp": { "commandName": "Project", - "commandLineArgs": "-i https://www.huya.com/660000" + "commandLineArgs": "-d https://www.bilibili.com/7734200" } } } \ No newline at end of file diff --git a/AllLive.Core/AllLive.Core.csproj b/AllLive.Core/AllLive.Core.csproj index 2774409..f4566bd 100644 --- a/AllLive.Core/AllLive.Core.csproj +++ b/AllLive.Core/AllLive.Core.csproj @@ -14,9 +14,10 @@ + - + all diff --git a/AllLive.Core/Danmaku/BiliBiliDanmaku.cs b/AllLive.Core/Danmaku/BiliBiliDanmaku.cs index 8004909..aa7d695 100644 --- a/AllLive.Core/Danmaku/BiliBiliDanmaku.cs +++ b/AllLive.Core/Danmaku/BiliBiliDanmaku.cs @@ -1,12 +1,15 @@ using AllLive.Core.Helper; using AllLive.Core.Interface; using AllLive.Core.Models; +using BrotliSharpLib; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.IO; +using System.IO.Compression; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -29,15 +32,11 @@ public class BiliBiliDanmaku : ILiveDanmaku private readonly string ServerUrl = "wss://broadcastlv.chat.bilibili.com/sub"; Timer timer; WebSocket ws; + private DanmuInfo danmuInfo; + private string buvid; public BiliBiliDanmaku() { - ws = new WebSocket(ServerUrl); - ws.OnOpen += Ws_OnOpen; - ws.OnError += Ws_OnError; - ws.OnMessage += Ws_OnMessage; - ws.OnClose += Ws_OnClose; - timer = new Timer(HeartbeatTime); - timer.Elapsed += Timer_Elapsed; + } private async void Ws_OnOpen(object sender, EventArgs e) { @@ -47,7 +46,10 @@ await Task.Run(() => ws.Send(EncodeData(JsonConvert.SerializeObject(new { roomid = roomId, - uid = 0 + uid = 0, + protover = 3, + key = danmuInfo.token, + buvid, }), 7)); }); @@ -78,6 +80,23 @@ private void Ws_OnError(object sender, WebSocketSharp.ErrorEventArgs e) public async Task Start(object args) { roomId = args.ToInt32(); + var _buvid = await GetBuvid(); + buvid = _buvid; + var info = await GetDanmuInfo(roomId); + if (info == null) + { + SendSystemMessage("获取弹幕信息失败"); + return; + } + danmuInfo = info; + var host=info.host_list.First(); + ws = new WebSocket($"wss://{host.host}/sub"); + ws.OnOpen += Ws_OnOpen; + ws.OnError += Ws_OnError; + ws.OnMessage += Ws_OnMessage; + ws.OnClose += Ws_OnClose; + timer = new Timer(HeartbeatTime); + timer.Elapsed += Timer_Elapsed; await Task.Run(() => { ws.Connect(); @@ -107,10 +126,18 @@ await Task.Run(() => private void ParseData(byte[] data) { - //协议版本。0为JSON,可以直接解析;1为房间人气值,Body为4位Int32;2为压缩过Buffer,需要解压再处理 + //协议版本。 + //0为JSON,可以直接解析; + //1为房间人气值,Body为Int32; + //2为zlib压缩过Buffer,需要解压再处理 + //3为brotli压缩过Buffer,需要解压再处理 int protocolVersion = BitConverter.ToInt32(new byte[4] { data[7], data[6], 0, 0 }, 0); - //操作类型。3=心跳回应,内容为房间人气值;5=通知,弹幕、广播等全部信息;8=进房回应,空 + //操作类型。 + //3=心跳回应,内容为房间人气值; + //5=通知,弹幕、广播等全部信息; + //8=进房回应,空 int operation = BitConverter.ToInt32(data.Skip(8).Take(4).Reverse().ToArray(), 0); + //内容 var body = data.Skip(16).ToArray(); if (operation == 3) @@ -125,10 +152,9 @@ private void ParseData(byte[] data) else if (operation == 5) { - if (protocolVersion == 2) + if (protocolVersion == 2 || protocolVersion == 3) { - body = DecompressData(body); - + body = DecompressData(body, protocolVersion); } var text = Encoding.UTF8.GetString(body); //可能有多条数据,做个分割 @@ -218,8 +244,12 @@ private byte[] EncodeData(string msg, int action) /// /// /// - private byte[] DecompressData(byte[] data) + private byte[] DecompressData(byte[] data,int protocolVersion) { + if (protocolVersion == 3) + { + return DecompressDataWithBrotli(data); + } using (MemoryStream outBuffer = new MemoryStream()) using (System.IO.Compression.DeflateStream compressedzipStream = new System.IO.Compression.DeflateStream(new MemoryStream(data, 2, data.Length - 2), System.IO.Compression.CompressionMode.Decompress)) { @@ -239,5 +269,91 @@ private byte[] DecompressData(byte[] data) } + /// + /// 解压数据 (使用Brotli) + /// + /// + /// + private byte[] DecompressDataWithBrotli(byte[] data) + { + using (var decompressedStream = new BrotliStream(new MemoryStream(data), CompressionMode.Decompress)) + { + using (var outBuffer = new MemoryStream()) + { + var block = new byte[1024]; + while (true) + { + var bytesRead = decompressedStream.Read(block, 0, block.Length); + if (bytesRead <= 0) + break; + outBuffer.Write(block, 0, bytesRead); + } + return outBuffer.ToArray(); + } + } + + + } + private async Task GetBuvid() + { + try + { + var result = await HttpUtil.GetString($"https://api.bilibili.com/x/frontend/finger/spi"); + var obj = JObject.Parse(result); + + return obj["data"]["b_3"].ToString(); + } + catch (Exception) + { + return ""; + } + } + + private async Task GetDanmuInfo(int roomId) + { + try + { + var result = await HttpUtil.GetString($"https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id={roomId}"); + var obj = JObject.Parse(result); + var info = obj["data"].ToObject(); + return info; + } + catch (Exception ex) + { + SendSystemMessage(ex.Message); + } + return null; + } + + private void SendSystemMessage(string msg) + { + NewMessage(this, new LiveMessage() + { + Type = LiveMessageType.Chat, + UserName = "系统", + Message = msg + }); + } + } + + + + class DanmuInfo + { + public string group { get; set; } + public int business_id { get; set; } + public double refresh_row_factor { get; set; } + public int refresh_rate { get; set; } + public int max_delay { get; set; } + public string token { get; set; } + public List host_list { get; set; } + } + + class DanmuInfoHostList + { + public string host { get; set; } + public int port { get; set; } + public int wss_port { get; set; } + public int ws_port { get; set; } } } diff --git a/AllLive.UWP/Package.appxmanifest b/AllLive.UWP/Package.appxmanifest index 0b640e9..048a46f 100644 --- a/AllLive.UWP/Package.appxmanifest +++ b/AllLive.UWP/Package.appxmanifest @@ -10,7 +10,7 @@ + Version="1.2.8.0" />