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
+2
View File
@@ -10,6 +10,8 @@
<add key="listenAny" value="true" />
<!--系统代理端口-->
<add key="proxyPort" value="8827" />
<!--上游代理地址,例如开启了系统代理,但是需要将其他无关请求转发到VPN工具中,例如:127.0.0.1:11223,不要带http://-->
<add key="upstreamProxy" value=""/>
<!--在控制台输出弹幕-->
<add key="printBarrage" value="true" />
<!--要在控制台打印的弹幕类型,可以用','隔开 all[全部],1[普通弹幕],2[点赞消息],3[进入直播间],4[关注消息],5[礼物消息],6[统计消息],7[粉丝团消息]-->
+81
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -20,6 +21,11 @@ namespace BarrageGrab
/// </summary>
public static WsBarrageService WssService { get; private set; } = new WsBarrageService();
/// <summary>
/// 房间缓存信息
/// </summary>
public static RoomCacheManager RoomCaches { get; } = new RoomCacheManager();
/// <summary>
/// 程序进程信息
/// </summary>
@@ -30,5 +36,80 @@ namespace BarrageGrab
{
}
/// <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"]);
PrintBarrage = AppSettings["printBarrage"].ToLower() == "true";
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());
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();
UsedProxy = bool.Parse(AppSettings["usedProxy"].Trim());
ListenAny = bool.Parse(AppSettings["listenAny"].Trim());
UpstreamProxy = AppSettings["upstreamProxy"].Trim();
var printFilter = AppSettings["printFilter"].Trim().ToLower();
if (printFilter != "all")
@@ -92,5 +93,10 @@ namespace BarrageGrab
/// 域名白名单列表
/// </summary>
public string[] HostNameFilter { get; private set; } = new string[0];
/// <summary>
/// 上游代理地址
/// </summary>
public string UpstreamProxy { get; set; }
}
}
@@ -3,7 +3,7 @@
/// <summary>
/// 弹幕消息类型
/// </summary>
public enum BarrageMsgType
public enum PackMsgType
{
无 = 0,
弹幕消息 = 1,
@@ -50,7 +50,12 @@
/// <summary>
/// 消息类型
/// </summary>
public BarrageMsgType Type { get; set; }
public PackMsgType Type { get; set; }
/// <summary>
/// 进程名
/// </summary>
public string ProcessName { get; set; }
/// <summary>
/// 消息对象
@@ -62,10 +67,11 @@
}
public BarrageMsgPack(string data, BarrageMsgType type)
public BarrageMsgPack(string data, PackMsgType type,string processName)
{
Data = data;
Type = type;
ProcessName = processName;
}
}
@@ -93,6 +99,11 @@
/// 房间号
/// </summary>
public long RoomId { get; set; }
/// <summary>
/// web直播间ID
/// </summary>
public long WebRoomId { get; set; }
}
/// <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;
ExplicitProxyEndPoint explicitEndPoint = null;
ExternalProxy upStreamProxy = null;
const string SCRIPT_HOST = "lf-cdn-tos.bytescm.com";
const string LIVE_HOST = "live.douyin.com";
@@ -29,7 +30,6 @@ namespace BarrageGrab.Proxy
const string BARRAGE_POOL_PATH = "/webcast/im/fetch";
static ConsoleWriter console = new ConsoleWriter();
public TitaniumProxy()
{
//注册系统代理
@@ -48,6 +48,20 @@ namespace BarrageGrab.Proxy
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.BeforeResponse += ProxyServer_BeforeResponse;
//proxyServer.AfterResponse += ProxyServer_AfterResponse;
@@ -58,7 +72,6 @@ namespace BarrageGrab.Proxy
proxyServer.AddEndPoint(explicitEndPoint);
}
private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
{
string uri = e.HttpClient.Request.RequestUri.ToString();
@@ -131,7 +144,7 @@ namespace BarrageGrab.Proxy
var urlNoQuery = url.Split('?')[0];
var processid = e.HttpClient.ProcessId.Value;
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 ?? "";
//检测是否为dom页,用于脚本注入
@@ -145,8 +158,9 @@ namespace BarrageGrab.Proxy
}
//获取 content-type
if (isLiveRoom)
if (liveRoomMactch.Success)
{
string webrid = liveRoomMactch.Groups[1].Value;
//获取直播页注入js
string liveRoomInjectScript = GetInjectScript("livePage");
@@ -158,6 +172,16 @@ namespace BarrageGrab.Proxy
{
//利用 HtmlAgilityPack 在尾部注入script 标签
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
{
var doc = new HtmlAgilityPack.HtmlDocument();
@@ -219,7 +243,6 @@ namespace BarrageGrab.Proxy
}
}
private Task ProxyServer_ServerCertificateValidationCallback(object sender, CertificateValidationEventArgs e)
{
// set IsValid to true/false based on Certificate Errors
+203 -134
View File
@@ -122,58 +122,104 @@ namespace BarrageGrab
return user;
}
//粉丝团
private void Grab_OnFansclubMessage(object sender, FansclubMessage e)
static int count = 0;
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()
{
MsgId = e.Common.msgId,
Content = e.Content,
RoomId = e.Common.roomId,
Type = e.Type,
User = GetUser(e.User)
MsgId = msg.Common.msgId,
Content = msg.Content,
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
Type = msg.Type,
User = GetUser(msg.User)
};
enty.Level = enty.User.FansClub.Level;
Print(enty.User.GenderToString() + " " + enty.Content, ConsoleColor.Blue, BarrageMsgType.粉丝团消息);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.粉丝团消息);
var json = JsonConvert.SerializeObject(pack);
this.Broadcast(json);
var msgType = PackMsgType.粉丝团消息;
PrintMsg(enty, msgType);
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()
{
MsgId = e.Common.msgId,
OnlineUserCount = e.Total,
TotalUserCount = e.totalUser,
TotalUserCountStr = e.totalPvForAnchor,
OnlineUserCountStr = e.onlineUserForAnchor,
RoomId = e.Common.roomId,
Content = $"当前直播间人数 {e.onlineUserForAnchor},累计直播间人数 {e.totalPvForAnchor}",
MsgId = msg.Common.msgId,
OnlineUserCount = msg.Total,
TotalUserCount = msg.totalUser,
TotalUserCountStr = msg.totalPvForAnchor,
OnlineUserCountStr = msg.onlineUserForAnchor,
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
Content = $"当前直播间人数 {msg.onlineUserForAnchor},累计直播间人数 {msg.totalPvForAnchor}",
User = null
};
Print(enty.Content, ConsoleColor.Magenta, BarrageMsgType.直播间统计);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.直播间统计);
var json = JsonConvert.SerializeObject(pack);
this.Broadcast(json);
var msgType = PackMsgType.直播间统计;
PrintMsg(enty, msgType);
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
if (e.groupId > 0 && giftCountCache.ContainsKey(key))
if (msg.groupId > 0 && giftCountCache.ContainsKey(key))
{
lock (giftCountCache)
{
@@ -184,7 +230,7 @@ namespace BarrageGrab
}
int lastCount = 0;
int currCount = (int)e.repeatCount;
int currCount = (int)msg.repeatCount;
var backward = currCount <= lastCount;
if (currCount <= 0) currCount = 1;
@@ -202,7 +248,7 @@ namespace BarrageGrab
}
else
{
if (e.groupId > 0 && !backward)
if (msg.groupId > 0 && !backward)
{
lock (giftCountCache)
{
@@ -218,175 +264,190 @@ namespace BarrageGrab
var enty = new GiftMsg()
{
MsgId = e.Common.msgId,
RoomId = e.Common.roomId,
Content = $"{e.User.Nickname} 送出 {e.Gift.Name} x {currCount} 个,增量{count}个",
DiamondCount = e.Gift.diamondCount,
MsgId = msg.Common.msgId,
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
Content = $"{msg.User.Nickname} 送出 {msg.Gift.Name} x {currCount} 个,增量{count}个",
DiamondCount = msg.Gift.diamondCount,
RepeatCount = currCount,
GiftCount = count,
GroupId = e.groupId,
GiftId = e.giftId,
GiftName = e.Gift.Name,
User = GetUser(e.User)
GroupId = msg.groupId,
GiftId = msg.giftId,
GiftName = msg.Gift.Name,
User = GetUser(msg.User)
};
Print($"{enty.User.GenderToString()} {enty.Content}", ConsoleColor.Red, BarrageMsgType.礼物消息);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.礼物消息);
var json = JsonConvert.SerializeObject(pack);
this.Broadcast(json);
var msgType = PackMsgType.礼物消息;
PrintMsg(enty, msgType);
var pack = new BarrageMsgPack(enty.ToJson(), PackMsgType.礼物消息, e.Process);
Broadcast(pack);
}
//关注
private void Grab_OnSocialMessage(object sender, SocialMessage e)
private void Grab_OnSocialMessage(object sender, WssBarrageGrab.RoomMessageEventArgs<SocialMessage> e)
{
if (!CheckRoomId(e.Common.roomId)) return;
if (e.Action != 1) return;
var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
if (msg.Action != 1) return;
var enty = new Msg()
{
MsgId = e.Common.msgId,
Content = $"{e.User.Nickname} 关注了主播",
RoomId = e.Common.roomId,
User = GetUser(e.User)
MsgId = msg.Common.msgId,
Content = $"{msg.User.Nickname} 关注了主播",
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
User = GetUser(msg.User)
};
Print($"{enty.User.GenderToString()} {enty.Content}", ConsoleColor.Yellow, 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);
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;
if (e.Action != 3) return;
var msg = e.Message;
if (!CheckRoomId(msg.Common.roomId)) return;
if (msg.Action != 3) return;
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()
{
MsgId = e.Common.msgId,
Content = $"{e.User.Nickname} 分享了直播间到{type}",
RoomId = e.Common.roomId,
MsgId = msg.Common.msgId,
Content = $"{msg.User.Nickname} 分享了直播间到{type}",
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
ShareType = type,
User = GetUser(e.User)
User = GetUser(msg.User)
};
var msgType = PackMsgType.直播间分享;
PrintMsg(enty, msgType);
//shareTarget: (112:好友),(1微信)(2朋友圈)(3微博)(5:qq)(4:qq空间),shareType: 1
Print($"{enty.User.GenderToString()} {enty.Content}", ConsoleColor.DarkBlue, BarrageMsgType.直播间分享);
var pack = new BarrageMsgPack(JsonConvert.SerializeObject(enty), BarrageMsgType.直播间分享);
var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
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()
{
MsgId = e.Common.msgId,
Content = $"{e.User.Nickname} 来了 直播间人数:{e.memberCount}",
RoomId = e.Common.roomId,
CurrentCount = e.memberCount,
User = GetUser(e.User)
MsgId = msg.Common.msgId,
Content = $"{msg.User.Nickname} 来了 直播间人数:{msg.memberCount}",
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
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);
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()
{
MsgId = e.Common.msgId,
Count = e.Count,
Content = $"{e.User.Nickname} 为主播点了{e.Count}个赞,总点赞{e.Total}",
RoomId = e.Common.roomId,
Total = e.Total,
User = GetUser(e.User)
MsgId = msg.Common.msgId,
Count = msg.Count,
Content = $"{msg.User.Nickname} 为主播点了{msg.Count}个赞,总点赞{msg.Total}",
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
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 json = JsonConvert.SerializeObject(pack);
this.Broadcast(json);
var msgType = PackMsgType.点赞消息;
PrintMsg(enty, msgType);
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()
{
MsgId = e.Common.msgId,
Content = e.Content,
RoomId = e.Common.roomId,
User = GetUser(e.User)
MsgId = msg.Common.msgId,
Content = msg.Content,
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
User = GetUser(msg.User),
};
var msgType = PackMsgType.弹幕消息;
PrintMsg(enty, msgType);
Print($"{enty.User.GenderToString()} {enty.User.Nickname}: {enty.Content}", ConsoleColor.White, BarrageMsgType.弹幕消息);
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);
var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
Broadcast(pack);
}
//直播间状态变更
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;
//下播
if (e.Status == 3)
if (msg.Status == 3)
{
var enty = new Msg()
{
MsgId = e.Common.msgId,
MsgId = msg.Common.msgId,
Content = "直播已结束",
RoomId = e.Common.roomId,
RoomId = msg.Common.roomId,
WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(msg.Common.roomId.ToString()),
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)
{
var json = JsonConvert.SerializeObject(pack);
this.Broadcast(json);
Broadcast(pack);
}
}
static int count = 0;
private void Print(string msg, ConsoleColor color, BarrageMsgType bartype)
{
if (!Appsetting.PrintFilter.Any(a => a == bartype.GetHashCode())) return;
if (Appsetting.PrintBarrage)
{
if (++count > 1000)
{
Console.Clear();
Console.WriteLine("控制台已清理");
}
console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")} [{bartype.ToString()}] " + msg + "\n", color);
count = 0;
}
}
//static int count = 0;
//private void Print(string msg, ConsoleColor color, PackMsgType bartype)
//{
// if (!Appsetting.PrintFilter.Any(a => a == bartype.GetHashCode())) return;
// if (Appsetting.PrintBarrage)
// {
// if (++count > 1000)
// {
// Console.Clear();
// Console.WriteLine("控制台已清理");
// }
// console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")} [{bartype.ToString()}] " + msg + "\n", color);
// count = 0;
// }
//}
private void Dieout_Elapsed(object sender, ElapsedEventArgs e)
{
@@ -442,16 +503,24 @@ namespace BarrageGrab
/// 广播消息
/// </summary>
/// <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;
socket.Socket.Send(msg);
var state = item.Value;
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>
+45 -19
View File
@@ -28,42 +28,42 @@ namespace BarrageGrab
/// <summary>
/// 进入直播间
/// </summary>
public event EventHandler<MemberMessage> OnMemberMessage;
public event EventHandler<RoomMessageEventArgs<MemberMessage>> OnMemberMessage;
/// <summary>
/// 关注
/// </summary>
public event EventHandler<SocialMessage> OnSocialMessage;
public event EventHandler<RoomMessageEventArgs<SocialMessage>> OnSocialMessage;
/// <summary>
/// 聊天
/// </summary>
public event EventHandler<ChatMessage> OnChatMessage;
public event EventHandler<RoomMessageEventArgs<ChatMessage>> OnChatMessage;
/// <summary>
/// 点赞
/// </summary>
public event EventHandler<LikeMessage> OnLikeMessage;
public event EventHandler<RoomMessageEventArgs<LikeMessage>> OnLikeMessage;
/// <summary>
/// 礼物
/// </summary>
public event EventHandler<GiftMessage> OnGiftMessage;
public event EventHandler<RoomMessageEventArgs<GiftMessage>> OnGiftMessage;
/// <summary>
/// 直播间统计
/// </summary>
public event EventHandler<RoomUserSeqMessage> OnRoomUserSeqMessage;
public event EventHandler<RoomMessageEventArgs<RoomUserSeqMessage>> OnRoomUserSeqMessage;
/// <summary>
/// 直播间状态变更
/// </summary>
public event EventHandler<ControlMessage> OnControlMessage;
public event EventHandler<RoomMessageEventArgs<ControlMessage>> OnControlMessage;
/// <summary>
/// 粉丝团消息
/// </summary>
public event EventHandler<FansclubMessage> OnFansclubMessage;
public event EventHandler<RoomMessageEventArgs<FansclubMessage>> OnFansclubMessage;
public WssBarrageGrab()
{
@@ -128,7 +128,7 @@ namespace BarrageGrab
succPackHostNames.Add(e.HostName);
SaveHostNameCache();
}
response.Messages.ForEach(f => DoMessage(f));
response.Messages.ForEach(f => DoMessage(f,e.ProcessName));
}
catch (Exception) { }
}
@@ -146,7 +146,7 @@ namespace BarrageGrab
}
response.Messages.ForEach(f =>
{
DoMessage(f);
DoMessage(f,e.ProcessName);
});
}
@@ -154,7 +154,7 @@ namespace BarrageGrab
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;
if (msgDic.ContainsKey(msg.Method))
@@ -182,28 +182,28 @@ namespace BarrageGrab
case "WebcastMemberMessage":
{
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;
}
//关注
case "WebcastSocialMessage":
{
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;
}
//消息
case "WebcastChatMessage":
{
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;
}
//点赞
case "WebcastLikeMessage":
{
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;
}
//礼物
@@ -247,28 +247,28 @@ namespace BarrageGrab
}
}
this.OnGiftMessage?.Invoke(this, arg);
this.OnGiftMessage?.Invoke(this, new RoomMessageEventArgs<GiftMessage>(processName, arg));
break;
}
//直播间统计
case "WebcastRoomUserSeqMessage":
{
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;
}
//直播间状态变更
case "WebcastControlMessage":
{
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;
}
//粉丝团消息
case "WebcastFansclubMessage":
{
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;
}
default:
@@ -309,5 +309,31 @@ namespace BarrageGrab
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\ProtoEntity\Messages.cs" />
<Compile Include="Modles\ProtoEntity\Wss.cs" />
<Compile Include="Modles\RoomInfo.cs" />
<Compile Include="ObjectExtension.cs" />
<Compile Include="Proxy\EventArgs\HttpResponseEventArgs.cs" />
<Compile Include="Proxy\EventArgs\WsMessageEventArgs.cs" />
+20 -1
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
1. [重要更新] 支持浏览器/客户端 http 弹幕监听,这也会解决原先版本因网络波动使抖音客户端弹幕获取方式降级,而获取不到弹幕导致必须刷新页面重新连接的问题。
@@ -51,6 +57,7 @@
程序中有基本的配置可以过滤弹幕进程,弹幕数据通过Websocket服务推送,其他程序只需接入ws服务器就能接收到到弹幕数据消息
``` xml
<!--配置更改后重启才能生效-->
<appSettings>
<!--过滤Websocket数据源进程,可用','进行分隔,程序将会监听以下进程的弹幕信息-->
<add key="processFilter" value="直播伴侣,douyin,chrome,msedge,QQBrowser,360se,firefox,2345explorer,iexplore" />
@@ -60,6 +67,8 @@
<add key="listenAny" value="true" />
<!--系统代理端口-->
<add key="proxyPort" value="8827" />
<!--上游代理地址,例如需要将其他无关请求转发到本机另外的代理工具中,例如:127.0.0.1:11223,不要带http://-->
<add key="upstreamProxy" value=""/>
<!--在控制台输出弹幕-->
<add key="printBarrage" value="true" />
<!--要在控制台打印的弹幕类型,可以用','隔开 all[全部],1[普通弹幕],2[点赞消息],3[进入直播间],4[关注消息],5[礼物消息],6[统计消息],7[粉丝团消息]-->
@@ -70,7 +79,7 @@
<add key="filterHostName" value="true" />
<!--已知的弹幕域名列表 ','分隔 用作过滤规则中,凡是webcast开头的域名程序都会自动列入白名单-->
<add key="hostNameFilter" value="" />
<!--要进行过滤的房间ID(这里的房间ID每次开播会不一样),不填代表监听所有,多项使用','分隔,浏览器进入直播间 F12 控制台输入 'window.localStorage.playRoom' 即可快速看到房间ID(不是地址栏中的那个) -->
<!--要进行过滤的房间ID,不填代表监听所有,多项使用','分隔,浏览器进入直播间 F12 控制台输入 'window.localStorage.playRoom' 即可快速看到房间ID(不是地址栏中的那个) -->
<add key="roomIds" value="" />
</appSettings>
```
@@ -126,3 +135,13 @@
## ⚖️免责声明
+ 本程序仅供学习参考,不得用于商业用途,不得用于恶意搜集他人直播间用户信息!
## 🍻赞助支持
开源不易,如果该程序能够帮助到你,你的支持将会是我保持迭代的动力🍻!
<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>