private void _disconnect(Exception e)
 {
     if (!_connected)
     {
         return;
     }
     InfoLogger.SendInfo(_roomid, "INFO", "连接断开");
     _connected = false;
     _client.Close();
     _netStream = null;
     OnDisconnected?.Invoke(this, new DisconnectEvtArgs {
         Error = e
     });
 }
Exemple #2
0
        public async void Start(string savepath)
        {
            try
            {
                if (IsRunning)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "已经是运行状态了。");
                    return;
                }
                //设置运行状态。
                IsRunning = true;

                //读取设置
                var config = Config.Instance;
                _downloadCommentOption = config.IsDownloadComment;
                _autoRetry             = config.IsAutoRetry;

                int.TryParse(config.Timeout ?? "2000", out _streamTimeout);

                //获取真实下载地址
                try
                {
                    _flvUrl = await PathFinder.GetTrueUrl(_roomid);
                }
                catch
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "未取得下载地址");
                    Stop();
                    return; //停止并退出
                }

                flvDownloader       = new FlvDownloader(_roomid, savepath, _downloadCommentOption, _commentProvider);
                flvDownloader.Info += _flvDownloader_Info;
                CheckStreaming();
                try
                {
                    flvDownloader.Start(_flvUrl);
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "下载视频流时出错:" + e.Message);
                    Stop();
                }
            }catch (Exception e)
            {
                InfoLogger.SendInfo(_roomid, "ERROR", "未知错误:" + e.Message);
                Stop();
            }
        }
Exemple #3
0
        static public Task <string> GetTrueUrl(string roomid)
        {
            return(Task.Run(() => {
                if (roomid == null)
                {
                    InfoLogger.SendInfo(roomid, "ERROR", "房间号获取错误。");
                    throw new Exception("No roomid");
                }
                var apiUrl = "https://api.live.bilibili.com/room/v1/Room/playUrl?cid=" + roomid + "&otype=json&qn=10000&platform=web";
                SendStat(roomid);

                //访问API获取结果
                var wc = new WebClient();
                wc.Headers.Add("Accept: */*");
                wc.Headers.Add("User-Agent: " + Ver.UA);
                wc.Headers.Add("Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4");

                string resultString;

                try
                {
                    resultString = wc.DownloadString(apiUrl);
                }
                catch (WebException e0)
                {
                    InfoLogger.SendInfo(roomid, "ERROR", "发送解析请求失败<net>:" + e0.Message);
                    throw;
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(roomid, "ERROR", "发送解析请求失败:" + e.Message);
                    throw;
                }

                //解析结果
                try
                {
                    var jsonResult = JObject.Parse(resultString);
                    var trueUrl = jsonResult["data"]["durl"][0]["url"].ToString();
                    InfoLogger.SendInfo(roomid, "INFO", "地址解析成功:" + trueUrl);
                    return trueUrl;
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(roomid, "ERROR", "视频流地址解析失败:" + e.Message);
                    throw;
                }
            }));
        }
 private async void HeartbeatLoop()
 {
     try
     {
         while (_connected)
         {
             SendHeartbeatAsync();
             await Task.Delay(30000);
         }
     }
     catch (Exception e)
     {
         InfoLogger.SendInfo(_roomid, "ERROR", e.Message);
         _disconnect(e);
     }
 }
        private Task <string> GetCmtServer()
        {
            return(Task.Run(() => {
                //获取真实弹幕服务器地址。
                InfoLogger.SendInfo(_roomid, "INFO", "开始解析弹幕服务器");

                var chatWc = new WebClient();
                chatWc.Headers.Add("Accept: */*");
                chatWc.Headers.Add("User-Agent: " + Ver.UA);
                chatWc.Headers.Add("Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4");

                var chatApi = "http://live.bilibili.com/api/player?id=cid:" + _roomid;
                string chatXmlString;
                try
                {
                    chatXmlString = chatWc.DownloadString(chatApi);
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "无法解析弹幕服务器:" + e.Message);
                    throw;
                }

                //解析弹幕信息Xml
                chatXmlString = "<root>" + chatXmlString + "</root>";
                var chatXml = new XmlDocument();
                try
                {
                    chatXml.LoadXml(chatXmlString);
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "解析XML失败:" + e.Message);
                    throw;
                }

                //取得弹幕服务器Url
                var serverNode = chatXml.DocumentElement?.SelectSingleNode("/root/dm_server");
                var cmtServerUrl = serverNode?.InnerText;

                InfoLogger.SendInfo(_roomid, "INFO", "解析弹幕服务器地址成功:" + cmtServerUrl);
                return cmtServerUrl;
            }));
        }
Exemple #6
0
 public void Stop()
 {
     if (IsRunning)
     {
         IsRunning     = false;
         _recordedSize = 0;
         if (flvDownloader != null)
         {
             flvDownloader.Stop();
             flvDownloader = null;
         }
         InfoLogger.SendInfo(_roomid, "INFO", "停止");
         OnStop?.Invoke(this);
     }
     else
     {
         InfoLogger.SendInfo(_roomid, "ERROR", "已经是停止状态了");
     }
 }
Exemple #7
0
        public async void Connect()
        {
            try
            {
                var cmtServer = await GetCmtServer();

                var cmtHost = cmtServer.Item1;
                var cmtPort = cmtServer.Item2;

                if (cmtHost == null)
                {
                    throw new Exception("无法获得弹幕服务器地址");
                }

                //连接弹幕服务器
                _client = new TcpClient();
                await _client.ConnectAsync(cmtHost, cmtPort);

                _netStream = _client.GetStream();

                int.TryParse(_roomid, out int roomIdNumber);
                if (SendJoinChannel(roomIdNumber))
                {
                    _connected = true;
                    HeartbeatLoop();
                    var thread = new Thread(ReceiveMessageLoop)
                    {
                        IsBackground = true
                    };
                    thread.Start();
                }
                else
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "加入频道失败");
                    throw new Exception("Could't add the channel");
                }
            }catch (Exception e)
            {
                InfoLogger.SendInfo(_roomid, "ERROR", e.Message);
                _disconnect(e);
            }
        }
Exemple #8
0
 public void Stop(bool isNetError = false)
 {
     if (IsRunning)
     {
         IsRunning     = false;
         _recordedSize = 0;
         if (flvDownloader != null)
         {
             flvDownloader.Stop();
             flvDownloader = null;
         }
         InfoLogger.SendInfo(_roomid, "INFO", "停止");
         OnStop?.Invoke(this, isNetError);
         _timer?.Dispose();
     }
     else
     {
         InfoLogger.SendInfo(_roomid, "ERROR", "已经是停止状态了");
     }
 }
Exemple #9
0
        private async void CheckStreaming()
        {
            await Task.Delay(_streamTimeout);

            try
            {
                if (flvDownloader == null)
                {
                    return;
                }
                if (_recordedSize <= 1)
                {
                    InfoLogger.SendInfo(_roomid, "INFO", "接收流超时。");
                    Stop();
                }
            }catch (Exception ex)
            {
                InfoLogger.SendInfo(_roomid, "ERROR", "在检查直播状态时发生未知错误:" + ex.Message);
                Stop();
            }
        }
Exemple #10
0
        /// <summary>
        /// 获取弹幕服务器地址和端口。
        /// </summary>
        /// <returns>Tuple&lt;string, int>(弹幕服务器地址, 端口)</returns>
        private Task <Tuple <string, int> > GetCmtServer()
        {
            return(Task.Run(() => {
                //获取真实弹幕服务器地址。
                InfoLogger.SendInfo(_roomid, "INFO", "开始解析弹幕服务器");

                var chatWc = new WebClient();
                chatWc.Headers.Add("Accept: */*");
                chatWc.Headers.Add("User-Agent: " + Ver.UA);
                chatWc.Headers.Add("Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4");

                var chatApi = "https://api.live.bilibili.com/room/v1/Danmu/getConf?room_id=" + _roomid;
                string chatConfString;
                try
                {
                    chatConfString = chatWc.DownloadString(chatApi);
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "无法解析弹幕服务器:" + e.Message);
                    throw;
                }

                //解析弹幕信息
                try
                {
                    var chatConf = JObject.Parse(chatConfString);
                    var cmtServerHost = chatConf["data"]["host"].ToString();
                    int.TryParse(chatConf["data"]["port"].ToString(), out int cmtServerPort);
                    InfoLogger.SendInfo(_roomid, "INFO", $"解析弹幕服务器地址成功:{cmtServerHost}:{cmtServerPort}");
                    return new Tuple <string, int>(cmtServerHost, cmtServerPort);
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "解析弹幕服务器失败:" + e.Message);
                    throw;
                }
            }));
        }
Exemple #11
0
        static public Task <RoomInfo> GetRoomInfo(string originalRoomId)
        {
            return(Task.Run(() => {
                //InfoLogger.SendInfo(originalRoomId, "DEBUG", "正在刷新信息");

                var roomWebPageUrl = "https://api.live.bilibili.com/room/v1/Room/get_info?id=" + originalRoomId;
                var wc = new WebClient();
                wc.Headers.Add("Accept: */*");
                wc.Headers.Add("User-Agent: " + Ver.UA);
                wc.Headers.Add("Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4");

                //发送HTTP请求
                byte[] roomHtml;

                try
                {
                    roomHtml = wc.DownloadData(roomWebPageUrl);
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(originalRoomId, "ERROR", "获取房间信息失败:" + e.Message);
                    return null;
                }

                //解析返回结果
                try
                {
                    var roomJson = Encoding.UTF8.GetString(roomHtml);
                    var result = JObject.Parse(roomJson);
                    var uid = result["data"]["uid"].ToString();

                    var userInfoUrl = "https://api.bilibili.com/x/web-interface/card?mid=" + uid;
                    var uwc = new WebClient();
                    uwc.Headers.Add("Accept: */*");
                    uwc.Headers.Add("User-Agent: " + Ver.UA);
                    uwc.Headers.Add("Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4");

                    byte[] userHtml;
                    try
                    {
                        userHtml = uwc.DownloadData(userInfoUrl);
                    }
                    catch (Exception e)
                    {
                        InfoLogger.SendInfo(originalRoomId, "ERROR", "获取用户信息失败:" + e.Message);
                        return null;
                    }

                    var userJson = Encoding.UTF8.GetString(userHtml);
                    var userResult = JObject.Parse(userJson);
                    var userName = userResult["data"]["card"]["name"].ToString();

                    var roominfo = new RoomInfo
                    {
                        realRoomid = result["data"]["room_id"].ToString(),
                        title = result["data"]["title"].ToString(),
                        liveStatus = result["data"]["live_status"].ToString() == "1" ? true : false,
                        username = userName
                    };
                    return roominfo;
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(originalRoomId, "ERROR", "房间信息解析失败:" + e.Message);
                    return null;
                }
            }));
        }
Exemple #12
0
        public CommentModel(string json, long time, int version = 1)
        {
            Time        = time;
            RawData     = json;
            JsonVersion = version;
            switch (version)
            {
            case 1:
            {
                var obj = JArray.Parse(json);

                CommentText = obj[1].ToString();
                CommentUser = obj[2][1].ToString();
                MsgType     = MsgTypeEnum.Comment;
                break;
            }

            case 2:
            {
                var obj = JObject.Parse(json);

                var cmd = obj["cmd"].ToString();
                if (cmd.StartsWith("LIVE"))
                {
                    MsgType = MsgTypeEnum.LiveStart;
                    RoomId  = obj["roomid"].ToString();
                }
                else if (cmd.StartsWith("PREPARING"))
                {
                    MsgType = MsgTypeEnum.LiveEnd;
                    RoomId  = obj["roomid"].ToString();
                }
                else if (cmd.StartsWith("DANMU_MSG"))
                {
                    CommentText   = obj["info"][1].ToString();
                    CommentUser   = obj["info"][2][1].ToString();
                    IsAdmin       = obj["info"][2][2].ToString() == "1";
                    IsVip         = obj["info"][2][3].ToString() == "1";
                    DmType        = Convert.ToInt32(obj["info"][0][1]);
                    Fontsize      = Convert.ToInt32(obj["info"][0][2]);
                    Color         = Convert.ToInt32(obj["info"][0][3]);
                    SendTimestamp = Convert.ToInt64(obj["info"][0][4]);
                    UserHash      = obj["info"][0][7].ToString();
                    MsgType       = MsgTypeEnum.Comment;
                }
                else if (cmd.StartsWith("SEND_GIFT"))
                {
                    MsgType   = MsgTypeEnum.GiftSend;
                    GiftName  = obj["data"]["giftName"].ToString();
                    GiftUser  = obj["data"]["uname"].ToString();
                    Giftrcost = obj["data"]["rcost"].ToString();
                    GiftNum   = obj["data"]["num"].ToString();
                }
                else if (cmd.StartsWith("GIFT_TOP"))
                {
                    MsgType = MsgTypeEnum.GiftTop;
                }
                else if (cmd.StartsWith("WELCOME"))
                {
                    MsgType     = MsgTypeEnum.Welcome;
                    CommentUser = obj["data"]["uname"].ToString();
                    IsVip       = true;
                    IsAdmin     = obj["data"]["isadmin"].ToString() == "1";
                }
                else if (cmd == "SUPER_CHAT_MESSAGE")
                {
                    MsgType = MsgTypeEnum.SuperChatMessage;
                    var price = obj["data"]["price"].ToString();
                    CommentText   = $"SC ¥{price} " + obj["data"]["message"].ToString();
                    CommentUser   = obj["data"]["user_info"]["uname"].ToString();
                    Fontsize      = 40;
                    SendTimestamp = Convert.ToInt64(obj["data"]["ts"]);
                    InfoLogger.SendInfo("debug", "superchat", CommentText);
                }
                else
                {
                    MsgType = MsgTypeEnum.Unknown;
                }
                break;
            }

            default:
                throw new Exception("无法解析的弹幕数据");
            }
        }
Exemple #13
0
        public async void Start(string savepath)
        {
            try
            {
                if (IsRunning)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "已经是运行状态了。");
                    return;
                }
                //设置运行状态。
                IsRunning = true;

                //读取设置
                var config = Config.Instance;
                _downloadCommentOption = config.IsDownloadComment;
                _autoRetry             = config.IsAutoRetry;

                int.TryParse(config.Timeout ?? "2000", out _streamTimeout);

                //获取真实下载地址
                try
                {
                    _flvUrl = await PathFinder.GetTrueUrl(_roomid);
                }
                catch (WebException)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "未取得下载地址<net>");
                    Stop(true);
                    return; //停止并退出
                }
                catch
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "未取得下载地址");
                    Stop();
                    return; //停止并退出
                }

                flvDownloader       = new FlvDownloader(_roomid, savepath, _downloadCommentOption, _commentProvider);
                flvDownloader.Info += _flvDownloader_Info;
                CheckStreaming();

                _larecordedSize = _recordedSize = 0;
                try
                {
                    flvDownloader.Start(_flvUrl);
                }
                catch (WebException e)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "下载视频流时出错<net>:" + e.Message);
                    Stop(true);
                    return; //停止并退出
                }
                catch (Exception e)
                {
                    InfoLogger.SendInfo(_roomid, "ERROR", "下载视频流时出错:" + e.Message);
                    Stop();
                }
                _timer = new Timer((e) => {
                    if (_larecordedSize == _recordedSize)
                    {
                        InfoLogger.SendInfo(_roomid, "INFO", "接收流超时,超时时间内文件大小未有变动。");
                        Stop(true);
                    }
                    else
                    {
                        _larecordedSize = _recordedSize;
                    }
                }, null, _streamTimeout, _streamTimeout);
            }
            catch (WebException e)
            {
                InfoLogger.SendInfo(_roomid, "ERROR", "未知错误<net>:" + e.Message);
                Stop(true);
                return; //停止并退出
            }
            catch (Exception e)
            {
                InfoLogger.SendInfo(_roomid, "ERROR", "未知错误:" + e.Message);
                Stop();
            }
        }