1. 添加了上游代理支持,现在可以将无关的请求转发到其他的代理地址!详见下方配置说明upstreamProxy

2. 内部添加了webRoomid 的缓存映射,只要打开直播间地址即可缓存WebRoomId和Roomid的映射关系,`WebRoomId`现已添加至ws弹幕流数据中!,需要注意直播伴侣端提取的弹幕当前不会有该字段,除非在开播后打开浏览器访问一次你的直播间
3. MsgPack 现在添加了进程名字段`ProcessName`
This commit is contained in:
小白猿
2023-09-24 12:47:55 +08:00
parent 00b929b83f
commit a39e2c4f96
10 changed files with 1008 additions and 194 deletions
+3 -1
View File
@@ -7,9 +7,11 @@
<!--Websocket监听端口--> <!--Websocket监听端口-->
<add key="wsListenPort" value="8888" /> <add key="wsListenPort" value="8888" />
<!--true:监听在0.0.0.0,接受任意Ip连接,false:监听在127.0.0.1,仅接受本机连接--> <!--true:监听在0.0.0.0,接受任意Ip连接,false:监听在127.0.0.1,仅接受本机连接-->
<add key="listenAny" value="true" /> <add key="listenAny" value="true" />
<!--系统代理端口--> <!--系统代理端口-->
<add key="proxyPort" value="8827" /> <add key="proxyPort" value="8827" />
<!--上游代理地址,例如开启了系统代理,但是需要将其他无关请求转发到VPN工具中,例如:127.0.0.1:11223,不要带http://-->
<add key="upstreamProxy" value=""/>
<!--在控制台输出弹幕--> <!--在控制台输出弹幕-->
<add key="printBarrage" value="true" /> <add key="printBarrage" value="true" />
<!--要在控制台打印的弹幕类型,可以用','隔开 all[全部],1[普通弹幕],2[点赞消息],3[进入直播间],4[关注消息],5[礼物消息],6[统计消息],7[粉丝团消息]--> <!--要在控制台打印的弹幕类型,可以用','隔开 all[全部],1[普通弹幕],2[点赞消息],3[进入直播间],4[关注消息],5[礼物消息],6[统计消息],7[粉丝团消息]-->
+82 -1
View File
@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@@ -20,6 +21,11 @@ namespace BarrageGrab
/// </summary> /// </summary>
public static WsBarrageService WssService { get; private set; } = new WsBarrageService(); public static WsBarrageService WssService { get; private set; } = new WsBarrageService();
/// <summary>
/// 房间缓存信息
/// </summary>
public static RoomCacheManager RoomCaches { get; } = new RoomCacheManager();
/// <summary> /// <summary>
/// 程序进程信息 /// 程序进程信息
/// </summary> /// </summary>
@@ -29,6 +35,81 @@ namespace BarrageGrab
static AppRuntime() static AppRuntime()
{ {
} }
/// <summary>
/// 房间缓存管理器
/// </summary>
public class RoomCacheManager
{
/// <summary>
/// 房间ID - 房间信息映射缓存
/// </summary>
public ConcurrentDictionary<string, RoomInfo> RoomInfoCache { get; } = new ConcurrentDictionary<string, RoomInfo>();
/// <summary>
/// 添加WebRoomid-房间ID 映射
/// </summary>
/// <param name="webrid"></param>
/// <param name="roomid"></param>
public void SetRoomCache(string roomid, string webrid)
{
if (RoomInfoCache.ContainsKey(roomid))
{
RoomInfoCache[roomid].WebRoomId = webrid;
}
else
{
RoomInfoCache.TryAdd(roomid, new RoomInfo()
{
RoomId = roomid,
WebRoomId = webrid,
Title = "房间" + webrid
});
}
}
/// <summary>
/// 添加房间缓存信息
/// </summary>
/// <param name="roomid"></param>
/// <param name="roomInfo"></param>
public void AddRoomInfoCache(RoomInfo roomInfo)
{
if (roomInfo == null) return;
var roomid = roomInfo.RoomId;
if (RoomInfoCache.ContainsKey(roomid))
{
RoomInfoCache[roomid] = roomInfo;
}
else
{
RoomInfoCache.TryAdd(roomid, roomInfo);
}
}
/// <summary>
/// 根据roomid从缓存获取webRoomid
/// </summary>
/// <param name="roomid"></param>
/// <returns></returns>
public long GetCachedWebRoomid(string roomid)
{
if (RoomInfoCache.TryGetValue(roomid, out var value)) return long.Parse(value.WebRoomId);
return -1;
}
/// <summary>
/// 根据roomid从缓存获取房间信息
/// </summary>
/// <param name="roomid"></param>
/// <returns></returns>
public RoomInfo GetCachedWebRoomInfo(string roomid)
{
if (RoomInfoCache.TryGetValue(roomid, out var value)) return value;
return null;
}
}
} }
} }
+7 -1
View File
@@ -22,12 +22,13 @@ namespace BarrageGrab
WsProt = int.Parse(AppSettings["wsListenPort"]); WsProt = int.Parse(AppSettings["wsListenPort"]);
PrintBarrage = AppSettings["printBarrage"].ToLower() == "true"; PrintBarrage = AppSettings["printBarrage"].ToLower() == "true";
ProxyPort = int.Parse(AppSettings["proxyPort"]); ProxyPort = int.Parse(AppSettings["proxyPort"]);
PrintFilter = Enum.GetValues(typeof(BarrageMsgType)).Cast<int>().ToArray(); PrintFilter = Enum.GetValues(typeof(PackMsgType)).Cast<int>().ToArray();
FilterHostName = bool.Parse(AppSettings["filterHostName"].Trim()); FilterHostName = bool.Parse(AppSettings["filterHostName"].Trim());
HostNameFilter = AppSettings["hostNameFilter"].Trim().Split(',').Where(w => !string.IsNullOrWhiteSpace(w)).ToArray(); HostNameFilter = AppSettings["hostNameFilter"].Trim().Split(',').Where(w => !string.IsNullOrWhiteSpace(w)).ToArray();
RoomIds = AppSettings["roomIds"].Trim().Split(',').Where(w => !string.IsNullOrWhiteSpace(w)).Select(s => long.Parse(s)).ToArray(); RoomIds = AppSettings["roomIds"].Trim().Split(',').Where(w => !string.IsNullOrWhiteSpace(w)).Select(s => long.Parse(s)).ToArray();
UsedProxy = bool.Parse(AppSettings["usedProxy"].Trim()); UsedProxy = bool.Parse(AppSettings["usedProxy"].Trim());
ListenAny = bool.Parse(AppSettings["listenAny"].Trim()); ListenAny = bool.Parse(AppSettings["listenAny"].Trim());
UpstreamProxy = AppSettings["upstreamProxy"].Trim();
var printFilter = AppSettings["printFilter"].Trim().ToLower(); var printFilter = AppSettings["printFilter"].Trim().ToLower();
if (printFilter != "all") if (printFilter != "all")
@@ -92,5 +93,10 @@ namespace BarrageGrab
/// 域名白名单列表 /// 域名白名单列表
/// </summary> /// </summary>
public string[] HostNameFilter { get; private set; } = new string[0]; public string[] HostNameFilter { get; private set; } = new string[0];
/// <summary>
/// 上游代理地址
/// </summary>
public string UpstreamProxy { get; set; }
} }
} }
@@ -3,7 +3,7 @@
/// <summary> /// <summary>
/// 弹幕消息类型 /// 弹幕消息类型
/// </summary> /// </summary>
public enum BarrageMsgType public enum PackMsgType
{ {
无 = 0, 无 = 0,
弹幕消息 = 1, 弹幕消息 = 1,
@@ -50,7 +50,12 @@
/// <summary> /// <summary>
/// 消息类型 /// 消息类型
/// </summary> /// </summary>
public BarrageMsgType Type { get; set; } public PackMsgType Type { get; set; }
/// <summary>
/// 进程名
/// </summary>
public string ProcessName { get; set; }
/// <summary> /// <summary>
/// 消息对象 /// 消息对象
@@ -62,10 +67,11 @@
} }
public BarrageMsgPack(string data, BarrageMsgType type) public BarrageMsgPack(string data, PackMsgType type,string processName)
{ {
Data = data; Data = data;
Type = type; Type = type;
ProcessName = processName;
} }
} }
@@ -93,6 +99,11 @@
/// 房间号 /// 房间号
/// </summary> /// </summary>
public long RoomId { get; set; } public long RoomId { get; set; }
/// <summary>
/// web直播间ID
/// </summary>
public long WebRoomId { get; set; }
} }
/// <summary> /// <summary>
+576
View File
@@ -0,0 +1,576 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
namespace BarrageGrab.Modles
{
[Serializable]
public class RoomInfo
{
/// <summary>
/// Web房间号
/// </summary>
public string WebRoomId { get; set; }
/// <summary>
/// 房间号
/// </summary>
public string RoomId { get; set; }
/// <summary>
/// 直播间名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 是否直播中
/// </summary>
public bool IsLive { get; set; }
/// <summary>
/// 实时在线人数
/// </summary>
public long UserCount { get; set; }
/// <summary>
/// 累计在线人数
/// </summary>
public string TotalUserCount { get; set; }
/// <summary>
/// 点赞数
/// </summary>
public long LikeCount { get; set; }
/// <summary>
/// 直播间二维码图像链接
/// </summary>
public string QrcodeUrl { get; set; }
/// <summary>
/// 直播间地址
/// </summary>
public string LiveUrl { get; set; }
/// <summary>
/// 封面链接
/// </summary>
public string Cover { get; set; }
/// <summary>
/// 直播间管理员用户id
/// </summary>
public List<string> AdminUserIds { get; set; } = new List<string>();
/// <summary>
/// 主播信息
/// </summary>
public RoomAnchor Owner { get; set; }
/// <summary>
/// 直播间的一些配置
/// </summary>
public RoomAuth AuthInfo { get; set; }
/// <summary>
/// 自身信息,Api方式没有
/// </summary>
public OdinData Odin { get; set; }
/// <summary>
/// Response请求头设置的 Ttwid,Api方式没有
/// </summary>
public string Ttwid { get; set; }
public class RoomAnchor
{
/// <summary>
/// 用户ID
/// </summary>
public string UserId { get; set; }
/// <summary>
/// SecUid
/// </summary>
public string SecUid { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string Nickname { get; set; }
/// <summary>
/// 头像地址
/// </summary>
public string HeadUrl { get; set; }
/// <summary>
/// 关注状态 0未关注,1已关注,...
/// </summary>
public int FollowStatus { get; set; }
}
public class RoomAuth
{
/// <summary>
/// 是否允许聊天
/// </summary>
public bool Chat { get; set; }
/// <summary>
/// 是否允许弹幕
/// </summary>
public bool Danmaku { get; set; }
/// <summary>
/// 是否允许送礼物
/// </summary>
public bool Gift { get; set; }
/// <summary>
/// 是否允许发红包
/// </summary>
public bool LuckMoney { get; set; }
/// <summary>
/// 是否允许点赞
/// </summary>
public bool Digg { get; set; }
/// <summary>
/// 是否允许房间贡献者
/// </summary>
public bool RoomContributor { get; set; }
/// <summary>
/// 是否允许使用道具
/// </summary>
public bool Props { get; set; }
/// <summary>
/// 是否允许查看用户名片
/// </summary>
public bool UserCard { get; set; }
/// <summary>
/// 是否允许查看 POI
/// </summary>
public bool POI { get; set; }
/// <summary>
/// 更多主播?
/// </summary>
public int MoreAnchor { get; set; }
/// <summary>
/// banner?
/// </summary>
public int Banner { get; set; }
/// <summary>
/// 分享配置?
/// </summary>
public int Share { get; set; }
/// <summary>
/// 用户角标?
/// </summary>
public int UserCorner { get; set; }
/// <summary>
/// 横屏?
/// </summary>
public int Landscape { get; set; }
/// <summary>
/// 横屏聊天?
/// </summary>
public int LandscapeChat { get; set; }
/// <summary>
/// 公屏?
/// </summary>
public int PublicScreen { get; set; }
/// <summary>
/// 礼物主播魔法表情配置?
/// </summary>
public int GiftAnchorMt { get; set; }
/// <summary>
/// 录屏配置?
/// </summary>
public int RecordScreen { get; set; }
/// <summary>
/// 打赏贴纸配置?
/// </summary>
public int DonationSticker { get; set; }
/// <summary>
/// 小时榜配置?
/// </summary>
public int HourRank { get; set; }
/// <summary>
/// 商务名片配置?
/// </summary>
public int CommerceCard { get; set; }
/// <summary>
/// 语音聊天配置?
/// </summary>
public int AudioChat { get; set; }
/// <summary>
/// 弹幕默认开关
/// </summary>
public int DanmakuDefault { get; set; }
/// <summary>
/// KTV 点歌?
/// </summary>
public int KtvOrderSong { get; set; }
/// <summary>
/// 选集?
/// </summary>
public int SelectionAlbum { get; set; }
/// <summary>
/// 点赞?
/// </summary>
public int Like { get; set; }
/// <summary>
/// 倍速播放?
/// </summary>
public int MultiplierPlayback { get; set; }
/// <summary>
/// 下载视频?
/// </summary>
public int DownloadVideo { get; set; }
/// <summary>
/// 收藏?
/// </summary>
public int Collect { get; set; }
/// <summary>
/// 定时下播?
/// </summary>
public int TimedShutdown { get; set; }
/// <summary>
/// 快进?
/// </summary>
public int Seek { get; set; }
/// <summary>
/// 举报?
/// </summary>
public int Denounce { get; set; }
/// <summary>
/// 踩?
/// </summary>
public int Dislike { get; set; }
/// <summary>
/// 只看 TA?
/// </summary>
public int OnlyTa { get; set; }
/// <summary>
/// 投屏?
/// </summary>
public int CastScreen { get; set; }
/// <summary>
/// 评论墙?
/// </summary>
public int CommentWall { get; set; }
/// <summary>
/// 弹幕样式
/// </summary>
public object BulletStyle { get; set; }
/// <summary>
/// 显示游戏插件?
/// </summary>
public int ShowGamePlugin { get; set; }
/// <summary>
/// PK礼物?
/// </summary>
public int VSGift { get; set; }
/// <summary>
/// PK话题?
/// </summary>
public int VSTopic { get; set; }
/// <summary>
/// PK排行榜?
/// </summary>
public int VSRank { get; set; }
/// <summary>
/// 管理员评论墙?
/// </summary>
public int AdminCommentWall { get; set; }
/// <summary>
/// 商务组件?
/// </summary>
public int CommerceComponent { get; set; }
/// <summary>
/// 抖音会员?
/// </summary>
public int DouPlus { get; set; }
/// <summary>
/// 游戏积分玩法?
/// </summary>
public int GamePointsPlaying { get; set; }
/// <summary>
/// 海报?
/// </summary>
public int Poster { get; set; }
/// <summary>
/// 精彩时刻?
/// </summary>
public int Highlights { get; set; }
/// <summary>
/// 打字评论状态?
/// </summary>
public int TypingCommentState { get; set; }
/// <summary>
/// 上下滑动引导?
/// </summary>
public int StrokeUpDownGuide { get; set; }
/// <summary>
/// 右上角统计浮层?
/// </summary>
public int UpRightStatsFloatingLayer { get; set; }
/// <summary>
/// 投屏显式?
/// </summary>
public int CastScreenExplicit { get; set; }
/// <summary>
/// 选集?
/// </summary>
public int Selection { get; set; }
/// <summary>
/// 行业服务?
/// </summary>
public int IndustryService { get; set; }
/// <summary>
/// 竖屏排行榜?
/// </summary>
public int VerticalRank { get; set; }
/// <summary>
/// 进场特效?
/// </summary>
public int EnterEffects { get; set; }
/// <summary>
/// 粉丝团?
/// </summary>
public int FansClub { get; set; }
/// <summary>
/// 表情外显?
/// </summary>
public int EmojiOutside { get; set; }
/// <summary>
/// 售票?
/// </summary>
public int CanSellTicket { get; set; }
/// <summary>
/// 抖音会员人气宝石?
/// </summary>
public int DouPlusPopularityGem { get; set; }
/// <summary>
/// 任务中心?
/// </summary>
public int MissionCenter { get; set; }
/// <summary>
///扩展屏幕?
/// </summary>
public int ExpandScreen { get; set; }
/// <summary>
/// 粉丝群?
/// </summary>
public int FansGroup { get; set; }
/// <summary>
/// 话题?
/// </summary>
public int Topic { get; set; }
/// <summary>
/// 主播任务?
/// </summary>
public int AnchorMission { get; set; }
/// <summary>
/// 跑马灯?
/// </summary>
public int Teleprompter { get; set; }
/// <summary>
/// 长按?
/// </summary>
public int LongTouch { get; set; }
/// <summary>
/// 特殊样式
/// </summary>
public SpecialStyle SpecialStyle { get; set; }
/// <summary>
/// 固定聊天?
/// </summary>
public int FixedChat { get; set; }
/// <summary>
/// 竞猜?
/// </summary>
public int QuizGamePointsPlaying { get; set; }
}
public class ChatStyle
{
/// <summary>
/// 是否禁用样式
/// </summary>
public int UnableStyle { get; set; }
/// <summary>
/// 内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 关闭类型
/// </summary>
public int OffType { get; set; }
}
public class SpecialStyle
{
/// <summary>
/// 聊天样式
/// </summary>
public ChatStyle Chat { get; set; }
/// <summary>
/// 点赞样式
/// </summary>
public ChatStyle Like { get; set; }
}
public class OdinData
{
public string user_id { get; set; }
public string user_type { get; set; }
public string user_is_auth { get; set; }
public string user_is_login { get; set; }
public string user_unique_id { get; set; }
}
/// <summary>
/// 将 直播间页面元素 转为房间信息对象
/// </summary>
/// <param name="html"></param>
/// <param name="result"></param>
/// <returns></returns>
public static (int, string) TryParseRoomPageHtml(string html, out RoomInfo result)
{
result = null;
if (html.IsNullOrWhiteSpace())
{
return (-1, "无效的页面数据");
}
var roomDataReg = new Regex(@"(?<=self\.__pace_f\.push\(\[1,""a:)\[.+?\](?=\\n?""\]\)[\s\n\r]*?<\/script>)");
var match = roomDataReg.Match(html);
if (!match.Success)
{
Logger.LogError("在通过正则匹配直播页房间信息时失败,可能是官方做了升级");
return (1, "未能匹配到房间信息");
}
var matchData = Regex.Unescape(match.Value);
JToken jsonObject = null;
try
{
jsonObject = JsonConvert.DeserializeObject<JArray>(matchData)[3];
}
catch (Exception ex)
{
return (2, "匹配到的房间数据格式有错误");
}
var roomInfo = jsonObject["state"]["roomStore"]["roomInfo"];
var odin = jsonObject["state"]["userStore"]["odin"];
var room = roomInfo["room"];
var roomOwner = roomInfo["anchor"];
if (room == null)
{
return (3, "房间信息为空,获取失败");
}
result = new RoomInfo();
result.Odin = odin?.ToObject<RoomInfo.OdinData>();
result.WebRoomId = roomInfo["web_rid"]?.ToString() ?? "";
result.RoomId = roomInfo["roomId"]?.ToString() ?? "";
result.AdminUserIds = room["admin_user_ids_str"]?.Values<string>()?.ToList() ?? new List<string>();
result.IsLive = room["status"]?.Value<int>() == 2;
result.Title = room["title"]?.ToString() ?? "";
result.UserCount = room["room_view_stats"]?["display_value"]?.Value<long>() ?? 0;
result.TotalUserCount = room["stats"]?["total_user_str"]?.Value<string>() ?? "0";
result.LikeCount = room["like_count"]?.Value<long>() ?? 0;
result.QrcodeUrl = roomInfo["qrcode_url"]?.ToString() ?? "";
result.AuthInfo = room["room_auth"]?.ToObject<RoomInfo.RoomAuth>();
result.Cover = room["cover"]?["url_list"]?.Values<string>().FirstOrDefault() ?? "";//下播情况下没有cover字段
if (roomOwner != null)
{
result.Owner = new RoomInfo.RoomAnchor()
{
UserId = roomOwner["id_str"].ToString(),
Nickname = roomOwner["nickname"].ToString(),
SecUid = roomOwner["sec_uid"].ToString(),
HeadUrl = roomOwner["avatar_thumb"]["url_list"].Values<string>()?.FirstOrDefault() ?? "",
FollowStatus = roomOwner["follow_info"]["follow_status"].Value<int>()
};
}
return (0, "succ");
}
}
}
+28 -5
View File
@@ -21,6 +21,7 @@ namespace BarrageGrab.Proxy
{ {
ProxyServer proxyServer = null; ProxyServer proxyServer = null;
ExplicitProxyEndPoint explicitEndPoint = null; ExplicitProxyEndPoint explicitEndPoint = null;
ExternalProxy upStreamProxy = null;
const string SCRIPT_HOST = "lf-cdn-tos.bytescm.com"; const string SCRIPT_HOST = "lf-cdn-tos.bytescm.com";
const string LIVE_HOST = "live.douyin.com"; const string LIVE_HOST = "live.douyin.com";
@@ -29,7 +30,6 @@ namespace BarrageGrab.Proxy
const string BARRAGE_POOL_PATH = "/webcast/im/fetch"; const string BARRAGE_POOL_PATH = "/webcast/im/fetch";
static ConsoleWriter console = new ConsoleWriter(); static ConsoleWriter console = new ConsoleWriter();
public TitaniumProxy() public TitaniumProxy()
{ {
//注册系统代理 //注册系统代理
@@ -48,6 +48,20 @@ namespace BarrageGrab.Proxy
proxyServer.CertificateManager.CreateRootCertificate(); proxyServer.CertificateManager.CreateRootCertificate();
} }
//设置上游代理地址
var upstreamProxyAddr = Appsetting.Current.UpstreamProxy;
if (!upstreamProxyAddr.IsNullOrWhiteSpace())
{
upStreamProxy = new ExternalProxy()
{
HostName = upstreamProxyAddr.Split(':')[0],
Port = int.Parse(upstreamProxyAddr.Split(':')[1]),
ProxyType = ExternalProxyType.Http
};
proxyServer.UpStreamHttpProxy = upStreamProxy;
proxyServer.UpStreamHttpsProxy = upStreamProxy;
}
proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback; proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback;
proxyServer.BeforeResponse += ProxyServer_BeforeResponse; proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
//proxyServer.AfterResponse += ProxyServer_AfterResponse; //proxyServer.AfterResponse += ProxyServer_AfterResponse;
@@ -58,7 +72,6 @@ namespace BarrageGrab.Proxy
proxyServer.AddEndPoint(explicitEndPoint); proxyServer.AddEndPoint(explicitEndPoint);
} }
private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e) private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
{ {
string uri = e.HttpClient.Request.RequestUri.ToString(); string uri = e.HttpClient.Request.RequestUri.ToString();
@@ -131,7 +144,7 @@ namespace BarrageGrab.Proxy
var urlNoQuery = url.Split('?')[0]; var urlNoQuery = url.Split('?')[0];
var processid = e.HttpClient.ProcessId.Value; var processid = e.HttpClient.ProcessId.Value;
var processName = base.GetProcessName(processid); var processName = base.GetProcessName(processid);
var isLiveRoom = Regex.IsMatch(uri.Trim(), @".*:\/\/live.douyin\.com\/\d+"); var liveRoomMactch = Regex.Match(uri.Trim(), @".*:\/\/live.douyin\.com\/(\d+)");
var contentType = e.HttpClient.Response.ContentType ?? ""; var contentType = e.HttpClient.Response.ContentType ?? "";
//检测是否为dom页,用于脚本注入 //检测是否为dom页,用于脚本注入
@@ -145,8 +158,9 @@ namespace BarrageGrab.Proxy
} }
//获取 content-type //获取 content-type
if (isLiveRoom) if (liveRoomMactch.Success)
{ {
string webrid = liveRoomMactch.Groups[1].Value;
//获取直播页注入js //获取直播页注入js
string liveRoomInjectScript = GetInjectScript("livePage"); string liveRoomInjectScript = GetInjectScript("livePage");
@@ -158,6 +172,16 @@ namespace BarrageGrab.Proxy
{ {
//利用 HtmlAgilityPack 在尾部注入script 标签 //利用 HtmlAgilityPack 在尾部注入script 标签
var html = await e.GetResponseBodyAsString(); var html = await e.GetResponseBodyAsString();
(int code, string msg) = RoomInfo.TryParseRoomPageHtml(html, out var roominfo);
if (code == 0)
{
Logger.LogInfo($"直播页{webrid}房间信息已采集到缓存");
roominfo.WebRoomId = webrid;
roominfo.LiveUrl = url;
AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
}
try try
{ {
var doc = new HtmlAgilityPack.HtmlDocument(); var doc = new HtmlAgilityPack.HtmlDocument();
@@ -218,7 +242,6 @@ namespace BarrageGrab.Proxy
} }
} }
} }
private Task ProxyServer_ServerCertificateValidationCallback(object sender, CertificateValidationEventArgs e) private Task ProxyServer_ServerCertificateValidationCallback(object sender, CertificateValidationEventArgs e)
{ {
+208 -139
View File
@@ -122,58 +122,104 @@ namespace BarrageGrab
return user; return user;
} }
//粉丝团 static int count = 0;
private void Grab_OnFansclubMessage(object sender, FansclubMessage e) private void PrintMsg(Msg msg, PackMsgType barType)
{ {
if (!CheckRoomId(e.Common.roomId)) return; if (!Appsetting.PrintBarrage) return;
var rinfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(msg.RoomId.ToString());
var roomName = (rinfo?.Owner?.Nickname ?? ("直播间" + (msg.WebRoomId == 0 ? msg.RoomId : msg.WebRoomId)));
var text = $"{DateTime.Now.ToString("HH:mm:ss")} [{roomName}] [{barType}]";
if (msg.User != null)
{
text += $" [{msg.User?.GenderToString()}] ";
}
ConsoleColor color = ConsoleColor.White;
var append = msg.Content;
switch (barType)
{
case PackMsgType.弹幕消息: color = ConsoleColor.White; append = $"{msg?.User?.Nickname}: {msg.Content}"; break;
case PackMsgType.点赞消息: color = ConsoleColor.Cyan; break;
case PackMsgType.进直播间: color = ConsoleColor.Green; break;
case PackMsgType.关注消息: color = ConsoleColor.Yellow; break;
case PackMsgType.礼物消息: color = ConsoleColor.Red; break;
case PackMsgType.直播间统计: color = ConsoleColor.Magenta; break;
case PackMsgType.粉丝团消息: color = ConsoleColor.Blue; break;
case PackMsgType.直播间分享: color = ConsoleColor.DarkBlue; break;
case PackMsgType.下播: color = ConsoleColor.DarkCyan; append = $"直播已结束"; break;
default: break;
}
text += append;
if (++count > 10000)
{
Console.Clear();
Console.WriteLine("控制台已清理");
count = 0;
}
console.WriteLine(text + "\n", color);
}
//粉丝团
private void Grab_OnFansclubMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<FansclubMessage> e)
{
var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
var enty = new FansclubMsg() var enty = new FansclubMsg()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
Content = e.Content, Content = msg.Content,
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
Type = e.Type, WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
User = GetUser(e.User) Type = msg.Type,
User = GetUser(msg.User)
}; };
enty.Level = enty.User.FansClub.Level; enty.Level = enty.User.FansClub.Level;
Print(enty.User.GenderToString() + " " + enty.Content, ConsoleColor.Blue, BarrageMsgType.粉丝团消息);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.粉丝团消息); var msgType = PackMsgType.粉丝团消息;
var json = JsonConvert.SerializeObject(pack); PrintMsg(enty, msgType);
this.Broadcast(json); Broadcast(new BarrageMsgPack(enty.ToJson(), msgType,e.Process));
} }
//统计消息 //统计消息
private void Grab_OnRoomUserSeqMessage(object sender, RoomUserSeqMessage e) private void Grab_OnRoomUserSeqMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<RoomUserSeqMessage> e)
{ {
if (!CheckRoomId(e.Common.roomId)) return; var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
var enty = new UserSeqMsg() var enty = new UserSeqMsg()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
OnlineUserCount = e.Total, OnlineUserCount = msg.Total,
TotalUserCount = e.totalUser, TotalUserCount = msg.totalUser,
TotalUserCountStr = e.totalPvForAnchor, TotalUserCountStr = msg.totalPvForAnchor,
OnlineUserCountStr = e.onlineUserForAnchor, OnlineUserCountStr = msg.onlineUserForAnchor,
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
Content = $"当前直播间人数 {e.onlineUserForAnchor},累计直播间人数 {e.totalPvForAnchor}", WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
Content = $"当前直播间人数 {msg.onlineUserForAnchor},累计直播间人数 {msg.totalPvForAnchor}",
User = null User = null
}; };
Print(enty.Content, ConsoleColor.Magenta, BarrageMsgType.直播间统计);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.直播间统计); var msgType = PackMsgType.直播间统计;
var json = JsonConvert.SerializeObject(pack); PrintMsg(enty, msgType);
this.Broadcast(json); var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
Broadcast(pack);
} }
//礼物 //礼物
private void Grab_OnGiftMessage(object sender, GiftMessage e) private void Grab_OnGiftMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<GiftMessage> e)
{ {
if (!CheckRoomId(e.Common.roomId)) return; var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
var key = e.giftId + "-" + e.groupId.ToString(); var key = msg.Common.roomId + "-" + msg.giftId + "-" + msg.groupId.ToString();
//判断礼物重复 //判断礼物重复
if (e.repeatEnd == 1) if (msg.repeatEnd == 1)
{ {
//清除缓存中的key //清除缓存中的key
if (e.groupId > 0 && giftCountCache.ContainsKey(key)) if (msg.groupId > 0 && giftCountCache.ContainsKey(key))
{ {
lock (giftCountCache) lock (giftCountCache)
{ {
@@ -184,7 +230,7 @@ namespace BarrageGrab
} }
int lastCount = 0; int lastCount = 0;
int currCount = (int)e.repeatCount; int currCount = (int)msg.repeatCount;
var backward = currCount <= lastCount; var backward = currCount <= lastCount;
if (currCount <= 0) currCount = 1; if (currCount <= 0) currCount = 1;
@@ -202,7 +248,7 @@ namespace BarrageGrab
} }
else else
{ {
if (e.groupId > 0 && !backward) if (msg.groupId > 0 && !backward)
{ {
lock (giftCountCache) lock (giftCountCache)
{ {
@@ -218,175 +264,190 @@ namespace BarrageGrab
var enty = new GiftMsg() var enty = new GiftMsg()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
Content = $"{e.User.Nickname} 送出 {e.Gift.Name} x {currCount} 个,增量{count}个", WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
DiamondCount = e.Gift.diamondCount, Content = $"{msg.User.Nickname} 送出 {msg.Gift.Name} x {currCount} 个,增量{count}个",
DiamondCount = msg.Gift.diamondCount,
RepeatCount = currCount, RepeatCount = currCount,
GiftCount = count, GiftCount = count,
GroupId = e.groupId, GroupId = msg.groupId,
GiftId = e.giftId, GiftId = msg.giftId,
GiftName = e.Gift.Name, GiftName = msg.Gift.Name,
User = GetUser(e.User) User = GetUser(msg.User)
}; };
var msgType = PackMsgType.礼物消息;
Print($"{enty.User.GenderToString()} {enty.Content}", ConsoleColor.Red, BarrageMsgType.礼物消息); PrintMsg(enty, msgType);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.礼物消息); var pack = new BarrageMsgPack(enty.ToJson(), PackMsgType.礼物消息, e.Process);
var json = JsonConvert.SerializeObject(pack); Broadcast(pack);
this.Broadcast(json);
} }
//关注 //关注
private void Grab_OnSocialMessage(object sender, SocialMessage e) private void Grab_OnSocialMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<SocialMessage> e)
{ {
if (!CheckRoomId(e.Common.roomId)) return; var msg = e.Message;
if (e.Action != 1) return; if (!CheckRoomId(msg.Common.roomId)) return;
if (msg.Action != 1) return;
var enty = new Msg() var enty = new Msg()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
Content = $"{e.User.Nickname} 关注了主播", Content = $"{msg.User.Nickname} 关注了主播",
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
User = GetUser(e.User) WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
User = GetUser(msg.User)
}; };
Print($"{enty.User.GenderToString()} {enty.Content}", ConsoleColor.Yellow, BarrageMsgType.关注消息); var msgType = PackMsgType.关注消息;
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.关注消息); PrintMsg(enty, msgType);
var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
var json = JsonConvert.SerializeObject(pack); var json = JsonConvert.SerializeObject(pack);
this.Broadcast(json); Broadcast(pack);
} }
//直播间分享 //直播间分享
private void Grab_OnShardMessage(object sender, SocialMessage e) private void Grab_OnShardMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<SocialMessage> e)
{ {
if (!CheckRoomId(e.Common.roomId)) return; var msg = e.Message;
if (e.Action != 3) return; if (!CheckRoomId(msg.Common.roomId)) return;
if (msg.Action != 3) return;
ShareType type = ShareType.未知; ShareType type = ShareType.未知;
if (Enum.IsDefined(type.GetType(), int.Parse(e.shareTarget))) if (Enum.IsDefined(type.GetType(), int.Parse(msg.shareTarget)))
{ {
type = (ShareType)int.Parse(e.shareTarget); type = (ShareType)int.Parse(msg.shareTarget);
} }
var enty = new ShareMessage() var enty = new ShareMessage()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
Content = $"{e.User.Nickname} 分享了直播间到{type}", Content = $"{msg.User.Nickname} 分享了直播间到{type}",
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
ShareType = type, ShareType = type,
User = GetUser(e.User) User = GetUser(msg.User)
}; };
//shareTarget: (112:好友),(1微信)(2朋友圈)(3微博)(5:qq)(4:qq空间),shareType: 1
Print($"{enty.User.GenderToString()} {enty.Content}", ConsoleColor.DarkBlue, BarrageMsgType.直播间分享); var msgType = PackMsgType.直播间分享;
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.直播间分享); PrintMsg(enty, msgType);
//shareTarget: (112:好友),(1微信)(2朋友圈)(3微博)(5:qq)(4:qq空间),shareType: 1
var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
var json = JsonConvert.SerializeObject(pack); var json = JsonConvert.SerializeObject(pack);
this.Broadcast(json); Broadcast(pack);
} }
//来了 //来了
private void Grab_OnMemberMessage(object sender, Modles.ProtoEntity.MemberMessage e) private void Grab_OnMemberMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<Modles.ProtoEntity.MemberMessage> e)
{ {
if (!CheckRoomId(e.Common.roomId)) return; var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
var enty = new Modles.JsonEntity.MemberMessage() var enty = new Modles.JsonEntity.MemberMessage()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
Content = $"{e.User.Nickname} 来了 直播间人数:{e.memberCount}", Content = $"{msg.User.Nickname} 来了 直播间人数:{msg.memberCount}",
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
CurrentCount = e.memberCount, WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
User = GetUser(e.User) CurrentCount = msg.memberCount,
User = GetUser(msg.User)
}; };
Print($"{enty.User.GenderToString()} {enty.Content}", ConsoleColor.Green, BarrageMsgType.进直播间);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.进直播间); var msgType = PackMsgType.进直播间;
PrintMsg(enty, msgType);
var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
var json = JsonConvert.SerializeObject(pack); var json = JsonConvert.SerializeObject(pack);
this.Broadcast(json); Broadcast(pack);
} }
//点赞 //点赞
private void Grab_OnLikeMessage(object sender, LikeMessage e) private void Grab_OnLikeMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<LikeMessage> e)
{ {
if (!CheckRoomId(e.Common.roomId)) return; var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
var enty = new LikeMsg() var enty = new LikeMsg()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
Count = e.Count, Count = msg.Count,
Content = $"{e.User.Nickname} 为主播点了{e.Count}个赞,总点赞{e.Total}", Content = $"{msg.User.Nickname} 为主播点了{msg.Count}个赞,总点赞{msg.Total}",
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
Total = e.Total, WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
User = GetUser(e.User) Total = msg.Total,
User = GetUser(msg.User)
}; };
Print($"{enty.User.GenderToString()} {enty.Content}", ConsoleColor.Cyan, BarrageMsgType.点赞消息);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.点赞消息); var msgType = PackMsgType.点赞消息;
var json = JsonConvert.SerializeObject(pack); PrintMsg(enty, msgType);
this.Broadcast(json); var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
Broadcast(pack);
} }
//弹幕 //弹幕
private void Grab_OnChatMessage(object sender, ChatMessage e) private void Grab_OnChatMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<ChatMessage> e)
{ {
if (!CheckRoomId(e.Common.roomId)) return; var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
var enty = new Msg() var enty = new Msg()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
Content = e.Content, Content = msg.Content,
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
User = GetUser(e.User) WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
User = GetUser(msg.User),
}; };
var msgType = PackMsgType.弹幕消息;
PrintMsg(enty, msgType);
var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
Print($"{enty.User.GenderToString()} {enty.User.Nickname}: {enty.Content}", ConsoleColor.White, BarrageMsgType.弹幕消息); Broadcast(pack);
if (e.User.followInfo.followStatus != 1 && e.User.followInfo.followStatus != 0 && e.User.followInfo.followStatus != 2)
{
Console.WriteLine(e.User.followInfo.followStatus);
}
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.弹幕消息);
var json = JsonConvert.SerializeObject(pack);
this.Broadcast(json);
} }
//直播间状态变更 //直播间状态变更
private void Grab_OnControlMessage(object sender, ControlMessage e) private void Grab_OnControlMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<ControlMessage> e)
{ {
if (!CheckRoomId(e.Common.roomId)) return; var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
BarrageMsgPack pack = null; BarrageMsgPack pack = null;
//下播 //下播
if (e.Status == 3) if (msg.Status == 3)
{ {
var enty = new Msg() var enty = new Msg()
{ {
MsgId = e.Common.msgId, MsgId = msg.Common.msgId,
Content = "直播已结束", Content = "直播已结束",
RoomId = e.Common.roomId, RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
User = null User = null
}; };
Print($"直播已结束", ConsoleColor.DarkCyan, BarrageMsgType.下播);
pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.下播); var msgType = PackMsgType.下播;
PrintMsg(enty, msgType);
pack = new BarrageMsgPack(enty.ToJson(), PackMsgType.下播, e.Process);
} }
if (pack != null) if (pack != null)
{ {
var json = JsonConvert.SerializeObject(pack); Broadcast(pack);
this.Broadcast(json);
} }
} }
static int count = 0; //static int count = 0;
private void Print(string msg, ConsoleColor color, BarrageMsgType bartype) //private void Print(string msg, ConsoleColor color, PackMsgType bartype)
{ //{
if (!Appsetting.PrintFilter.Any(a => a == bartype.GetHashCode())) return; // if (!Appsetting.PrintFilter.Any(a => a == bartype.GetHashCode())) return;
if (Appsetting.PrintBarrage) // if (Appsetting.PrintBarrage)
{ // {
if (++count > 1000) // if (++count > 1000)
{ // {
Console.Clear(); // Console.Clear();
Console.WriteLine("控制台已清理"); // Console.WriteLine("控制台已清理");
} // }
console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")} [{bartype.ToString()}] " + msg + "\n", color); // console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")} [{bartype.ToString()}] " + msg + "\n", color);
count = 0; // count = 0;
} // }
} //}
private void Dieout_Elapsed(object sender, ElapsedEventArgs e) private void Dieout_Elapsed(object sender, ElapsedEventArgs e)
{ {
@@ -442,16 +503,24 @@ namespace BarrageGrab
/// 广播消息 /// 广播消息
/// </summary> /// </summary>
/// <param name="msg"></param> /// <param name="msg"></param>
public void Broadcast(string msg) public void Broadcast(BarrageMsgPack pack)
{ {
foreach (var user in socketList) if (pack == null) return;
var offLines = new List<string>();
foreach (var item in socketList)
{ {
var socket = user.Value; var state = item.Value;
socket.Socket.Send(msg); if (item.Value.Socket.IsAvailable)
{
state.Socket.Send(pack.ToJson());
}
else
{
offLines.Add(item.Key);
}
} }
//删除掉线的套接字 //删除掉线的套接字
var offlines = socketList.Where(w => !w.Value.Socket.IsAvailable).Select(s => s.Key).ToList(); offLines.ForEach(key => socketList.Remove(key));
offlines.ForEach(key => socketList.Remove(key));
} }
/// <summary> /// <summary>
+49 -23
View File
@@ -28,48 +28,48 @@ namespace BarrageGrab
/// <summary> /// <summary>
/// 进入直播间 /// 进入直播间
/// </summary> /// </summary>
public event EventHandler<MemberMessage> OnMemberMessage; public event EventHandler<RoomMessageEventArgs<MemberMessage>> OnMemberMessage;
/// <summary> /// <summary>
/// 关注 /// 关注
/// </summary> /// </summary>
public event EventHandler<SocialMessage> OnSocialMessage; public event EventHandler<RoomMessageEventArgs<SocialMessage>> OnSocialMessage;
/// <summary> /// <summary>
/// 聊天 /// 聊天
/// </summary> /// </summary>
public event EventHandler<ChatMessage> OnChatMessage; public event EventHandler<RoomMessageEventArgs<ChatMessage>> OnChatMessage;
/// <summary> /// <summary>
/// 点赞 /// 点赞
/// </summary> /// </summary>
public event EventHandler<LikeMessage> OnLikeMessage; public event EventHandler<RoomMessageEventArgs<LikeMessage>> OnLikeMessage;
/// <summary> /// <summary>
/// 礼物 /// 礼物
/// </summary> /// </summary>
public event EventHandler<GiftMessage> OnGiftMessage; public event EventHandler<RoomMessageEventArgs<GiftMessage>> OnGiftMessage;
/// <summary> /// <summary>
/// 直播间统计 /// 直播间统计
/// </summary> /// </summary>
public event EventHandler<RoomUserSeqMessage> OnRoomUserSeqMessage; public event EventHandler<RoomMessageEventArgs<RoomUserSeqMessage>> OnRoomUserSeqMessage;
/// <summary> /// <summary>
/// 直播间状态变更 /// 直播间状态变更
/// </summary> /// </summary>
public event EventHandler<ControlMessage> OnControlMessage; public event EventHandler<RoomMessageEventArgs<ControlMessage>> OnControlMessage;
/// <summary> /// <summary>
/// 粉丝团消息 /// 粉丝团消息
/// </summary> /// </summary>
public event EventHandler<FansclubMessage> OnFansclubMessage; public event EventHandler<RoomMessageEventArgs<FansclubMessage>> OnFansclubMessage;
public WssBarrageGrab() public WssBarrageGrab()
{ {
proxy.OnWebSocketData += Proxy_OnWebSocketData; proxy.OnWebSocketData += Proxy_OnWebSocketData;
proxy.OnFetchResponse += Proxy_OnFetchResponse; proxy.OnFetchResponse += Proxy_OnFetchResponse;
} }
public void Start() public void Start()
{ {
@@ -128,7 +128,7 @@ namespace BarrageGrab
succPackHostNames.Add(e.HostName); succPackHostNames.Add(e.HostName);
SaveHostNameCache(); SaveHostNameCache();
} }
response.Messages.ForEach(f => DoMessage(f)); response.Messages.ForEach(f => DoMessage(f,e.ProcessName));
} }
catch (Exception) { } catch (Exception) { }
} }
@@ -143,18 +143,18 @@ namespace BarrageGrab
{ {
succPackHostNames.Add(e.HostName); succPackHostNames.Add(e.HostName);
SaveHostNameCache(); SaveHostNameCache();
} }
response.Messages.ForEach(f => response.Messages.ForEach(f =>
{ {
DoMessage(f); DoMessage(f,e.ProcessName);
}); });
} }
//用于缓存接收过的消息ID,判断是否重复接收 //用于缓存接收过的消息ID,判断是否重复接收
Dictionary<string, List<long>> msgDic = new Dictionary<string, List<long>>(); Dictionary<string, List<long>> msgDic = new Dictionary<string, List<long>>();
//发送事件 //发送事件
private void DoMessage(Message msg) private void DoMessage(Message msg,string processName)
{ {
List<long> msgIdList; List<long> msgIdList;
if (msgDic.ContainsKey(msg.Method)) if (msgDic.ContainsKey(msg.Method))
@@ -182,28 +182,28 @@ namespace BarrageGrab
case "WebcastMemberMessage": case "WebcastMemberMessage":
{ {
var arg = Serializer.Deserialize<MemberMessage>(new ReadOnlyMemory<byte>(msg.Payload)); var arg = Serializer.Deserialize<MemberMessage>(new ReadOnlyMemory<byte>(msg.Payload));
this.OnMemberMessage?.Invoke(this, arg); this.OnMemberMessage?.Invoke(this, new RoomMessageEventArgs<MemberMessage>(processName,arg));
break; break;
} }
//关注 //关注
case "WebcastSocialMessage": case "WebcastSocialMessage":
{ {
var arg = Serializer.Deserialize<SocialMessage>(new ReadOnlyMemory<byte>(msg.Payload)); var arg = Serializer.Deserialize<SocialMessage>(new ReadOnlyMemory<byte>(msg.Payload));
this.OnSocialMessage?.Invoke(this, arg); this.OnSocialMessage?.Invoke(this, new RoomMessageEventArgs<SocialMessage>(processName, arg));
break; break;
} }
//消息 //消息
case "WebcastChatMessage": case "WebcastChatMessage":
{ {
var arg = Serializer.Deserialize<ChatMessage>(new ReadOnlyMemory<byte>(msg.Payload)); var arg = Serializer.Deserialize<ChatMessage>(new ReadOnlyMemory<byte>(msg.Payload));
this.OnChatMessage?.Invoke(this, arg); this.OnChatMessage?.Invoke(this, new RoomMessageEventArgs<ChatMessage>(processName, arg));
break; break;
} }
//点赞 //点赞
case "WebcastLikeMessage": case "WebcastLikeMessage":
{ {
var arg = Serializer.Deserialize<LikeMessage>(new ReadOnlyMemory<byte>(msg.Payload)); var arg = Serializer.Deserialize<LikeMessage>(new ReadOnlyMemory<byte>(msg.Payload));
this.OnLikeMessage?.Invoke(this, arg); this.OnLikeMessage?.Invoke(this, new RoomMessageEventArgs<LikeMessage>(processName, arg));
break; break;
} }
//礼物 //礼物
@@ -247,28 +247,28 @@ namespace BarrageGrab
} }
} }
this.OnGiftMessage?.Invoke(this, arg); this.OnGiftMessage?.Invoke(this, new RoomMessageEventArgs<GiftMessage>(processName, arg));
break; break;
} }
//直播间统计 //直播间统计
case "WebcastRoomUserSeqMessage": case "WebcastRoomUserSeqMessage":
{ {
var arg = Serializer.Deserialize<RoomUserSeqMessage>(new ReadOnlyMemory<byte>(msg.Payload)); var arg = Serializer.Deserialize<RoomUserSeqMessage>(new ReadOnlyMemory<byte>(msg.Payload));
this.OnRoomUserSeqMessage?.Invoke(this, arg); this.OnRoomUserSeqMessage?.Invoke(this, new RoomMessageEventArgs<RoomUserSeqMessage>(processName, arg));
break; break;
} }
//直播间状态变更 //直播间状态变更
case "WebcastControlMessage": case "WebcastControlMessage":
{ {
var arg = Serializer.Deserialize<ControlMessage>(new ReadOnlyMemory<byte>(msg.Payload)); var arg = Serializer.Deserialize<ControlMessage>(new ReadOnlyMemory<byte>(msg.Payload));
this.OnControlMessage?.Invoke(this, arg); this.OnControlMessage?.Invoke(this, new RoomMessageEventArgs<ControlMessage>(processName, arg));
break; break;
} }
//粉丝团消息 //粉丝团消息
case "WebcastFansclubMessage": case "WebcastFansclubMessage":
{ {
var arg = Serializer.Deserialize<FansclubMessage>(new ReadOnlyMemory<byte>(msg.Payload)); var arg = Serializer.Deserialize<FansclubMessage>(new ReadOnlyMemory<byte>(msg.Payload));
this.OnFansclubMessage?.Invoke(this, arg); this.OnFansclubMessage?.Invoke(this, new RoomMessageEventArgs<FansclubMessage>(processName, arg));
break; break;
} }
default: default:
@@ -309,5 +309,31 @@ namespace BarrageGrab
Console.WriteLine("写入成功解包域名缓存失败:" + ex.Message, ConsoleColor.Red); Console.WriteLine("写入成功解包域名缓存失败:" + ex.Message, ConsoleColor.Red);
} }
} }
public class RoomMessageEventArgs<T> : EventArgs where T : class
{
/// <summary>
/// 进程名
/// </summary>
public string Process { get; set; }
/// <summary>
/// 消息
/// </summary>
public T Message { get; set; }
public RoomMessageEventArgs()
{
}
public RoomMessageEventArgs(string process, T data)
{
this.Process = process;
this.Message = data;
}
}
} }
} }
+1
View File
@@ -143,6 +143,7 @@
<Compile Include="Modles\JsonEntity\Command.cs" /> <Compile Include="Modles\JsonEntity\Command.cs" />
<Compile Include="Modles\ProtoEntity\Messages.cs" /> <Compile Include="Modles\ProtoEntity\Messages.cs" />
<Compile Include="Modles\ProtoEntity\Wss.cs" /> <Compile Include="Modles\ProtoEntity\Wss.cs" />
<Compile Include="Modles\RoomInfo.cs" />
<Compile Include="ObjectExtension.cs" /> <Compile Include="ObjectExtension.cs" />
<Compile Include="Proxy\EventArgs\HttpResponseEventArgs.cs" /> <Compile Include="Proxy\EventArgs\HttpResponseEventArgs.cs" />
<Compile Include="Proxy\EventArgs\WsMessageEventArgs.cs" /> <Compile Include="Proxy\EventArgs\WsMessageEventArgs.cs" />
+40 -21
View File
@@ -4,6 +4,12 @@
## ⛳近期更新 ## ⛳近期更新
2023-08-17 v2.6.8
1. 添加了上游代理支持,现在可以将无关的请求转发到其他的代理地址!详见下方配置说明`upstreamProxy`
2. 内部添加了webRoomid 的缓存映射,只要打开直播间地址即可缓存WebRoomId和Roomid的映射关系,`WebRoomId`现已添加至ws弹幕流数据中!,需要注意直播伴侣端提取的弹幕当前不会有该字段,除非在开播后打开浏览器访问一次你的直播间
3. MsgPack 现在添加了进程名字段`ProcessName`
2023-08-17 v2.6.7 2023-08-17 v2.6.7
1. [重要更新] 支持浏览器/客户端 http 弹幕监听,这也会解决原先版本因网络波动使抖音客户端弹幕获取方式降级,而获取不到弹幕导致必须刷新页面重新连接的问题。 1. [重要更新] 支持浏览器/客户端 http 弹幕监听,这也会解决原先版本因网络波动使抖音客户端弹幕获取方式降级,而获取不到弹幕导致必须刷新页面重新连接的问题。
@@ -51,27 +57,30 @@
程序中有基本的配置可以过滤弹幕进程,弹幕数据通过Websocket服务推送,其他程序只需接入ws服务器就能接收到到弹幕数据消息 程序中有基本的配置可以过滤弹幕进程,弹幕数据通过Websocket服务推送,其他程序只需接入ws服务器就能接收到到弹幕数据消息
``` xml ``` xml
<!--配置更改后重启才能生效-->
<appSettings> <appSettings>
<!--过滤Websocket数据源进程,可用','进行分隔,程序将会监听以下进程的弹幕信息--> <!--过滤Websocket数据源进程,可用','进行分隔,程序将会监听以下进程的弹幕信息-->
<add key="processFilter" value="直播伴侣,douyin,chrome,msedge,QQBrowser,360se,firefox,2345explorer,iexplore" /> <add key="processFilter" value="直播伴侣,douyin,chrome,msedge,QQBrowser,360se,firefox,2345explorer,iexplore" />
<!--Websocket监听端口--> <!--Websocket监听端口-->
<add key="wsListenPort" value="8888" /> <add key="wsListenPort" value="8888" />
<!--true:监听在0.0.0.0,接受任意Ip连接,false:监听在127.0.0.1,仅接受本机连接--> <!--true:监听在0.0.0.0,接受任意Ip连接,false:监听在127.0.0.1,仅接受本机连接-->
<add key="listenAny" value="true" /> <add key="listenAny" value="true" />
<!--系统代理端口--> <!--系统代理端口-->
<add key="proxyPort" value="8827" /> <add key="proxyPort" value="8827" />
<!--在控制台输出弹幕--> <!--上游代理地址,例如需要将其他无关请求转发到本机另外的代理工具中,例如:127.0.0.1:11223,不要带http://-->
<add key="printBarrage" value="true" /> <add key="upstreamProxy" value=""/>
<!--要在控制台打印的弹幕类型,可以用','隔开 all[全部],1[普通弹幕],2[点赞消息],3[进入直播间],4[关注消息],5[礼物消息],6[统计消息],7[粉丝团消息]--> <!--在控制台输出弹幕-->
<add key="printFilter" value="all" /> <add key="printBarrage" value="true" />
<!--是否启用系统代理,若设置为false 则需要在程序手动指定代理地址 --> <!--要在控制台打印的弹幕类型,可以用','隔开 all[全部],1[普通弹幕],2[点赞消息],3[进入直播间],4[关注消息],5[礼物消息],6[统计消息],7[粉丝团消息]-->
<add key="usedProxy" value="true" /> <add key="printFilter" value="all" />
<!--开启内置的域名过滤,设置为false会解包所有https请求,cpu占用很高,建议在无法获取弹幕数据时调整 --> <!--是否启用系统代理,若设置为false 则需要在程序手动指定代理地址 -->
<add key="filterHostName" value="true" /> <add key="usedProxy" value="true" />
<!--已知的弹幕域名列表 ','分隔 用作过滤规则中,凡是webcast开头的域名程序都会自动列入白名单--> <!--开启内置的域名过滤,设置为false会解包所有https请求,cpu占用很高,建议在无法获取弹幕数据时调整 -->
<add key="hostNameFilter" value="" /> <add key="filterHostName" value="true" />
<!--要进行过滤的房间ID(这里的房间ID每次开播会不一样),不填代表监听所有,多项使用','分隔,浏览器进入直播间 F12 控制台输入 'window.localStorage.playRoom' 即可快速看到房间ID(不是地址栏中的那个) --> <!--已知的弹幕域名列表 ','分隔 用作过滤规则中,凡是webcast开头的域名程序都会自动列入白名单-->
<add key="roomIds" value="" /> <add key="hostNameFilter" value="" />
<!--要进行过滤的房间ID,不填代表监听所有,多项使用','分隔,浏览器进入直播间 F12 控制台输入 'window.localStorage.playRoom' 即可快速看到房间ID(不是地址栏中的那个) -->
<add key="roomIds" value="" />
</appSettings> </appSettings>
``` ```
@@ -125,4 +134,14 @@
## ⚖️免责声明 ## ⚖️免责声明
+ 本程序仅供学习参考,不得用于商业用途,不得用于恶意搜集他人直播间用户信息! + 本程序仅供学习参考,不得用于商业用途,不得用于恶意搜集他人直播间用户信息!
## 🍻赞助支持
开源不易,如果该程序能够帮助到你,你的支持将会是我保持迭代的动力🍻!
<p>
<img src="https://z1.ax1x.com/2023/09/24/pPTfZ2d.png" alt="微信支付" style="width:300px;height:350px;border-radius: 5px;" />
<img src="https://z1.ax1x.com/2023/09/24/pPTfexA.jpg" alt="支付宝" style="width:300px;height:350px;border-radius: 5px;" />
</p>