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
{
///
/// Web房间号
///
public string WebRoomId { get; set; }
///
/// 房间号
///
public string RoomId { get; set; }
///
/// 直播间名称
///
public string Title { get; set; }
///
/// 是否直播中
///
public bool IsLive { get; set; }
///
/// 实时在线人数
///
public long UserCount { get; set; }
///
/// 累计在线人数
///
public string TotalUserCount { get; set; }
///
/// 点赞数
///
public long LikeCount { get; set; }
///
/// 直播间二维码图像链接
///
public string QrcodeUrl { get; set; }
///
/// 直播间地址
///
public string LiveUrl { get; set; }
///
/// 封面链接
///
public string Cover { get; set; }
///
/// 直播间管理员用户id
///
public List AdminUserIds { get; set; } = new List();
///
/// 主播信息
///
public RoomAnchor Owner { get; set; }
///
/// 直播间的一些配置
///
public RoomAuth AuthInfo { get; set; }
///
/// 自身信息,Api方式没有
///
public OdinData Odin { get; set; }
///
/// Response请求头设置的 Ttwid,Api方式没有
///
public string Ttwid { get; set; }
public class RoomAnchor
{
///
/// 用户ID
///
public string UserId { get; set; }
///
/// SecUid
///
public string SecUid { get; set; }
///
/// 昵称
///
public string Nickname { get; set; }
///
/// 头像地址
///
public string HeadUrl { get; set; }
///
/// 关注状态 0未关注,1已关注,...
///
public int FollowStatus { get; set; }
}
public class RoomAuth
{
///
/// 是否允许聊天
///
public bool Chat { get; set; }
///
/// 是否允许弹幕
///
public bool Danmaku { get; set; }
///
/// 是否允许送礼物
///
public bool Gift { get; set; }
///
/// 是否允许发红包
///
public bool LuckMoney { get; set; }
///
/// 是否允许点赞
///
public bool Digg { get; set; }
///
/// 是否允许房间贡献者
///
public bool RoomContributor { get; set; }
///
/// 是否允许使用道具
///
public bool Props { get; set; }
///
/// 是否允许查看用户名片
///
public bool UserCard { get; set; }
///
/// 是否允许查看 POI
///
public bool POI { get; set; }
///
/// 更多主播?
///
public int MoreAnchor { get; set; }
///
/// banner?
///
public int Banner { get; set; }
///
/// 分享配置?
///
public int Share { get; set; }
///
/// 用户角标?
///
public int UserCorner { get; set; }
///
/// 横屏?
///
public int Landscape { get; set; }
///
/// 横屏聊天?
///
public int LandscapeChat { get; set; }
///
/// 公屏?
///
public int PublicScreen { get; set; }
///
/// 礼物主播魔法表情配置?
///
public int GiftAnchorMt { get; set; }
///
/// 录屏配置?
///
public int RecordScreen { get; set; }
///
/// 打赏贴纸配置?
///
public int DonationSticker { get; set; }
///
/// 小时榜配置?
///
public int HourRank { get; set; }
///
/// 商务名片配置?
///
public int CommerceCard { get; set; }
///
/// 语音聊天配置?
///
public int AudioChat { get; set; }
///
/// 弹幕默认开关
///
public int DanmakuDefault { get; set; }
///
/// KTV 点歌?
///
public int KtvOrderSong { get; set; }
///
/// 选集?
///
public int SelectionAlbum { get; set; }
///
/// 点赞?
///
public int Like { get; set; }
///
/// 倍速播放?
///
public int MultiplierPlayback { get; set; }
///
/// 下载视频?
///
public int DownloadVideo { get; set; }
///
/// 收藏?
///
public int Collect { get; set; }
///
/// 定时下播?
///
public int TimedShutdown { get; set; }
///
/// 快进?
///
public int Seek { get; set; }
///
/// 举报?
///
public int Denounce { get; set; }
///
/// 踩?
///
public int Dislike { get; set; }
///
/// 只看 TA?
///
public int OnlyTa { get; set; }
///
/// 投屏?
///
public int CastScreen { get; set; }
///
/// 评论墙?
///
public int CommentWall { get; set; }
///
/// 弹幕样式
///
public object BulletStyle { get; set; }
///
/// 显示游戏插件?
///
public int ShowGamePlugin { get; set; }
///
/// PK礼物?
///
public int VSGift { get; set; }
///
/// PK话题?
///
public int VSTopic { get; set; }
///
/// PK排行榜?
///
public int VSRank { get; set; }
///
/// 管理员评论墙?
///
public int AdminCommentWall { get; set; }
///
/// 商务组件?
///
public int CommerceComponent { get; set; }
///
/// 抖音会员?
///
public int DouPlus { get; set; }
///
/// 游戏积分玩法?
///
public int GamePointsPlaying { get; set; }
///
/// 海报?
///
public int Poster { get; set; }
///
/// 精彩时刻?
///
public int Highlights { get; set; }
///
/// 打字评论状态?
///
public int TypingCommentState { get; set; }
///
/// 上下滑动引导?
///
public int StrokeUpDownGuide { get; set; }
///
/// 右上角统计浮层?
///
public int UpRightStatsFloatingLayer { get; set; }
///
/// 投屏显式?
///
public int CastScreenExplicit { get; set; }
///
/// 选集?
///
public int Selection { get; set; }
///
/// 行业服务?
///
public int IndustryService { get; set; }
///
/// 竖屏排行榜?
///
public int VerticalRank { get; set; }
///
/// 进场特效?
///
public int EnterEffects { get; set; }
///
/// 粉丝团?
///
public int FansClub { get; set; }
///
/// 表情外显?
///
public int EmojiOutside { get; set; }
///
/// 售票?
///
public int CanSellTicket { get; set; }
///
/// 抖音会员人气宝石?
///
public int DouPlusPopularityGem { get; set; }
///
/// 任务中心?
///
public int MissionCenter { get; set; }
///
///扩展屏幕?
///
public int ExpandScreen { get; set; }
///
/// 粉丝群?
///
public int FansGroup { get; set; }
///
/// 话题?
///
public int Topic { get; set; }
///
/// 主播任务?
///
public int AnchorMission { get; set; }
///
/// 跑马灯?
///
public int Teleprompter { get; set; }
///
/// 长按?
///
public int LongTouch { get; set; }
///
/// 特殊样式
///
public SpecialStyle SpecialStyle { get; set; }
///
/// 固定聊天?
///
public int FixedChat { get; set; }
///
/// 竞猜?
///
public int QuizGamePointsPlaying { get; set; }
}
public class ChatStyle
{
///
/// 是否禁用样式
///
public int UnableStyle { get; set; }
///
/// 内容
///
public string Content { get; set; }
///
/// 关闭类型
///
public int OffType { get; set; }
}
public class SpecialStyle
{
///
/// 聊天样式
///
public ChatStyle Chat { get; set; }
///
/// 点赞样式
///
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; }
}
///
/// 将 直播间页面元素 转为房间信息对象
///
///
///
///
public static Tuple TryParseRoomPageHtml(string html, out RoomInfo result)
{
result = null;
if (html.IsNullOrWhiteSpace())
{
return Tuple.Create(-1, "无效的页面数据");
}
//var roomDataReg = new Regex(@"(?<=self\.__pace_f\.push\(\[1,""a:)\[.+?\](?=\\n?""\]\)[\s\n\r]*?<\/script>)");
//var roomDataReg = new Regex(@"(?<=self\.__pace_f\.push\(\[1,\s*""0:)\[.+?\](?=\\n""?\]\)[\s\n\r]*?<\/script>)");
//var roomDataReg = new Regex(@"(?<=self\.__pace_f\.push\(\[1,\s*""9:)\[.+?\](?=\\n""?\]\)[\s\n\r]*?<\/script>)");
var roomDataReg = new Regex(@"(?<=self\.__pace_f\.push\(\[\d,\s*""\w:.+)\{\\""state.+?\}(?=\]\\n""\]\)[\s\n\r]*?<\/script>)");
//字符串转义符号版本
var match = roomDataReg.Match(html);
if (!match.Success)
{
//Logger.LogError("在通过正则匹配直播页房间信息时失败,可能是官方做了升级");
return Tuple.Create(1, "未能匹配到房间信息");
}
var matchData = Regex.Unescape(match.Value);
JObject jsonObject = null;
try
{
jsonObject = JObject.Parse(matchData);
}
catch (Exception ex)
{
return Tuple.Create(2, "匹配到的房间数据格式有错误");
}
//var root = jsonObject["children"][3];
//var roomInfo = root["initialState"]["roomStore"]["roomInfo"];
//var odin = root["initialState"]["userStore"]["odin"];
//var room = roomInfo["room"];
//var roomOwner = roomInfo["anchor"];
var roomInfo = jsonObject["state"]["roomStore"]["roomInfo"];
var odin = jsonObject["state"]["userStore"]["odin"];
var room = roomInfo["room"];
var roomOwner = roomInfo["anchor"];
if (room == null)
{
return Tuple.Create(3, "房间信息为空,获取失败");
}
result = new RoomInfo();
result.Odin = odin?.ToObject();
result.WebRoomId = roomInfo["web_rid"]?.ToString() ?? "";
result.RoomId = roomInfo["roomId"]?.ToString() ?? "";
result.AdminUserIds = room["admin_user_ids_str"]?.Values()?.ToList() ?? new List();
result.IsLive = room["status"]?.Value() == 2;
result.Title = room["title"]?.ToString() ?? "";
result.UserCount = room["room_view_stats"]?["display_value"]?.Value() ?? 0;
result.TotalUserCount = room["stats"]?["total_user_str"]?.Value() ?? "0";
result.LikeCount = room["like_count"]?.Value() ?? 0;
result.QrcodeUrl = roomInfo["qrcode_url"]?.ToString() ?? "";
result.AuthInfo = room["room_auth"]?.ToObject();
result.Cover = room["cover"]?["url_list"]?.Values().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()?.FirstOrDefault() ?? "",
FollowStatus = roomOwner["follow_info"]["follow_status"].Value()
};
}
return Tuple.Create(0, "succ");
}
///
/// 从直播伴侣的直播创建回调中解析房间信息
///
///
///
/// 缓存
///
public static Tuple TryParseStreamPusherCreate(string json, out RoomInfo info)
{
info = null;
JObject res;
try
{
res = JsonConvert.DeserializeObject(json);
}
catch (Exception)
{
return Tuple.Create(4, "不是合法的json格式");
}
if (res == null)
{
return Tuple.Create(1, "正文为空");
}
var rootData = res["data"];
var ownerInfo = rootData["owner"];
var dto = new RoomInfo();
dto.RoomId = rootData["id_str"]?.ToString() ?? "";
dto.AdminUserIds = rootData["admin_user_ids_str"]?.Values().ToList() ?? new List();
dto.IsLive = rootData["status"]?.Value() == 2;
dto.Title = rootData["title"]?.ToString() ?? "";
dto.UserCount = long.Parse(rootData["room_view_stats"]?["display_value"]?.Value() ?? "0");
dto.TotalUserCount = rootData["room_view_stats"]?["total_user_str"]?.Value() ?? "0";
dto.LikeCount = rootData["like_count"]?.Value() ?? 0;
dto.QrcodeUrl = $"https://live.douyin.com/{ownerInfo?["display_id"] ?? ""}";
dto.AuthInfo = rootData["room_auth"]?.ToObject();
dto.Cover = rootData["cover"]?["url_list"]?.Values().FirstOrDefault() ?? "";//下播情况下没有cover字段
dto.WebRoomId = rootData["web_rid"]?.ToString() ?? ownerInfo?["display_id"]?.ToString() ?? "";
if (ownerInfo != null)
{
dto.Owner = new RoomAnchor()
{
UserId = ownerInfo["id_str"].ToString(),
Nickname = ownerInfo["nickname"].ToString(),
SecUid = ownerInfo["sec_uid"].ToString(),
HeadUrl = ownerInfo["avatar_thumb"]?["url_list"]?.Values()?.FirstOrDefault()?.ToString(),
FollowStatus = ownerInfo["follow_info"]?["follow_status"]?.Value() ?? 0
};
}
info = dto;
return Tuple.Create(0, "succ");
}
}
}