1. 添加了上游代理支持,现在可以将无关的请求转发到其他的代理地址!详见下方配置说明upstreamProxy
2. 内部添加了webRoomid 的缓存映射,只要打开直播间地址即可缓存WebRoomId和Roomid的映射关系,`WebRoomId`现已添加至ws弹幕流数据中!,需要注意直播伴侣端提取的弹幕当前不会有该字段,除非在开播后打开浏览器访问一次你的直播间 3. MsgPack 现在添加了进程名字段`ProcessName`
This commit is contained in:
@@ -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[粉丝团消息]-->
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user