public async Task ConnectAsync(string input, IBrowserProfile browserProfile)
        {
            if (string.IsNullOrEmpty(input))
            {
                return;
            }
            BeforeConnect();
            MetadataUpdated?.Invoke(this, new Metadata
            {
                Active         = "-",
                CurrentViewers = "-",
                Elapsed        = "-",
                Title          = "-",
                TotalViewers   = "-",
            });
            string vid = null;
            bool   isInputStoringNeeded = false;
            var    resolver             = new VidResolver();

            try
            {
                var result = await resolver.GetVid(_server, input);

                if (result is MultiVidsResult multi)
                {
                    SendInfo("このチャンネルでは複数のライブが配信中です。", InfoType.Notice);
                    foreach (var v in multi.Vids)
                    {
                        SendInfo(v, InfoType.Notice);//titleも欲しい
                    }
                }
                else if (result is VidResult vidResult)
                {
                    vid = vidResult.Vid;
                }
                else if (result is NoVidResult no)
                {
                    SendInfo("このチャンネルでは生放送をしていないようです", InfoType.Error);
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
            catch (HttpRequestException ex)
            {
                SendInfo("Http error", InfoType.Error);
                _logger.LogException(ex, "Http error", "input=" + input);
                AfterConnect();
                return;
            }
            catch (YtInitialDataNotFoundException ex)
            {
                SendInfo("ytInitialDataが存在しません", InfoType.Error);
                _logger.LogException(ex);
                AfterConnect();
                return;
            }
            catch (Exception ex)
            {
                SendInfo("入力されたURLは存在しないか無効な値です", InfoType.Error);
                _logger.LogException(ex, "Invalid input", "input=" + input);
                AfterConnect();
                return;
            }
            if (string.IsNullOrEmpty(vid))
            {
                AfterConnect();
                return;
            }
            if (resolver.IsChannel(input) || resolver.IsCustomChannel(input) || resolver.IsUser(input))
            {
                isInputStoringNeeded = true;
            }

            _cc = CreateCookieContainer(browserProfile);
            var userCommentCountDict = CreateUserCommentCountDict();

            _connection            = CreateConnection(_logger, _cc, _options, _server, _siteOptions, userCommentCountDict, _receivedCommentIds, this, _userStoreManager, SiteContextGuid);
            _connection.Connected += (s, e) =>
            {
                Connected?.Invoke(this, new ConnectedEventArgs {
                    IsInputStoringNeeded = isInputStoringNeeded
                });
            };
            _connection.MessageReceived      += (s, e) => MessageReceived?.Invoke(s, e);
            _connection.MetadataUpdated      += (s, e) => MetadataUpdated?.Invoke(s, e);
            _connection.LoggedInStateChanged += (s, e) => LoggedInStateChanged?.Invoke(s, e);
            var reloadManager = new ReloadManager()
            {
                CountLimit             = 5,
                CountCheckTimeRangeMin = 1,
            };

reload:
            if (_disconnectedByUser)
            {
                AfterConnect();
                return;
            }
            if (!reloadManager.CanReload())
            {
                SendInfo($"{reloadManager.CountCheckTimeRangeMin}分以内に{reloadManager.CountLimit}回再接続を試みました。サーバーに余計な負荷を掛けるのを防ぐため自動再接続を中断します", InfoType.Error);
                AfterConnect();
                return;
            }
            reloadManager.SetTime();

            try
            {
                var disconnectReason = await _connection.ReceiveAsync(vid, browserProfile.Type);

                switch (disconnectReason)
                {
                case DisconnectReason.Reload:
                    SendInfo("エラーが発生したためサーバーとの接続が切断されましたが、自動的に再接続します", InfoType.Error);
                    goto reload;

                case DisconnectReason.ByUser:
                case DisconnectReason.Finished:
                    //TODO:SendInfo()
                    break;

                case DisconnectReason.ChatUnavailable:
                    SendInfo("この配信ではチャットが無効になっているようです", InfoType.Error);
                    break;

                case DisconnectReason.YtInitialDataNotFound:
                    SendInfo("ytInitialDataの取得に失敗しました", InfoType.Error);
                    break;

                case DisconnectReason.ServerError:
                    SendInfo("サーバでエラーが発生したため接続できませんでした", InfoType.Error);
                    break;
                }
            }
            catch (Exception ex)
            {
                _logger.LogException(ex, "", $"input={input}");
                SendInfo("回復不能なエラーが発生しました", InfoType.Error);
            }
            AfterConnect();
        }
Esempio n. 2
0
        public async Task ConnectAsync(string input, IBrowserProfile browserProfile)
        {
            if (string.IsNullOrEmpty(input))
            {
                return;
            }
            BeforeConnect();
            MetadataUpdated?.Invoke(this, new Metadata
            {
                Active         = "-",
                CurrentViewers = "-",
                Elapsed        = "-",
                Title          = "-",
                TotalViewers   = "-",
            });
            string vid = null;
            bool   isInputStoringNeeded = false;
            var    resolver             = new VidResolver();

            try
            {
                var result = await resolver.GetVid(_server, input);

                if (result is MultiVidsResult multi)
                {
                    SendInfo("このチャンネルでは複数のライブが配信中です。", InfoType.Notice);
                    foreach (var v in multi.Vids)
                    {
                        SendInfo(v, InfoType.Notice);//titleも欲しい
                    }
                }
                else if (result is VidResult vidResult)
                {
                    vid = vidResult.Vid;
                }
                else if (result is NoVidResult no)
                {
                    SendInfo("このチャンネルでは生放送をしていないようです", InfoType.Error);
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
            catch (HttpRequestException ex)
            {
                SendInfo("Http error", InfoType.Error);
                _logger.LogException(ex, "Http error", "input=" + input);
                AfterConnect();
                return;
            }
            catch (YtInitialDataNotFoundException ex)
            {
                SendInfo("ytInitialDataが存在しません", InfoType.Error);
                _logger.LogException(ex);
                AfterConnect();
                return;
            }
            catch (Exception ex)
            {
                SendInfo("入力されたURLは存在しないか無効な値です", InfoType.Error);
                _logger.LogException(ex, "Invalid input", "input=" + input);
                AfterConnect();
                return;
            }
            if (string.IsNullOrEmpty(vid))
            {
                AfterConnect();
                return;
            }
            if (resolver.IsChannel(input) || resolver.IsCustomChannel(input) || resolver.IsUser(input))
            {
                isInputStoringNeeded = true;
            }
            var html = await _server.GetAsync($"https://www.youtube.com/watch?v={vid}");

            var liveBroadcastDetails = Tools.ExtractLiveBroadcastDetailsFromLivePage(html);

            if (liveBroadcastDetails != null)
            {
                dynamic d = Newtonsoft.Json.JsonConvert.DeserializeObject(liveBroadcastDetails);
                if (d.ContainsKey("startTimestamp"))
                {
                    var startedStr = (string)d.startTimestamp;
                    _startedAt             = DateTime.Parse(startedStr);
                    _elapsedTimer.Interval = 500;
                    _elapsedTimer.Elapsed += (s, e) =>
                    {
                        if (!_startedAt.HasValue)
                        {
                            return;
                        }
                        var elapsed = DateTime.Now - _startedAt.Value;
                        MetadataUpdated?.Invoke(this, new Metadata
                        {
                            Elapsed = Tools.ToElapsedString(elapsed),
                        });
                    };
                    _elapsedTimer.Enabled = true;
                }
            }
            _cc = CreateCookieContainer(browserProfile);
            var userCommentCountDict = CreateUserCommentCountDict();

            _connection            = CreateConnection(_logger, _cc, _options, _server, _siteOptions, userCommentCountDict, _receivedCommentIds, this, _userStoreManager, SiteContextGuid);
            _connection.Connected += (s, e) =>
            {
                Connected?.Invoke(this, new ConnectedEventArgs {
                    IsInputStoringNeeded = isInputStoringNeeded
                });
            };
            _connection.MessageReceived      += (s, e) => MessageReceived?.Invoke(s, e);
            _connection.MetadataUpdated      += (s, e) => MetadataUpdated?.Invoke(s, e);
            _connection.LoggedInStateChanged += (s, e) => LoggedInStateChanged?.Invoke(s, e);
            var reloadManager = new ReloadManager()
            {
                CountLimit             = 5,
                CountCheckTimeRangeMin = 1,
            };

reload:
            if (_disconnectedByUser)
            {
                AfterConnect();
                return;
            }
            if (!reloadManager.CanReload())
            {
                SendInfo($"{reloadManager.CountCheckTimeRangeMin}分以内に{reloadManager.CountLimit}回再接続を試みました。サーバーに余計な負荷を掛けるのを防ぐため自動再接続を中断します", InfoType.Error);
                AfterConnect();
                return;
            }
            reloadManager.SetTime();

            try
            {
                var disconnectReason = await _connection.ReceiveAsync(vid, browserProfile.Type);

                switch (disconnectReason)
                {
                case DisconnectReason.Reload:
                    SendInfo("エラーが発生したためサーバーとの接続が切断されましたが、自動的に再接続します", InfoType.Error);
                    goto reload;

                case DisconnectReason.ByUser:
                    SendInfo("ユーザーが切断ボタンを押したため切断しました", InfoType.Debug);
                    break;

                case DisconnectReason.Finished:
                    SendInfo("配信が終了しました", InfoType.Notice);
                    break;

                case DisconnectReason.ChatUnavailable:
                    SendInfo("この配信ではチャットが無効になっているようです", InfoType.Error);
                    break;

                case DisconnectReason.YtInitialDataNotFound:
                    SendInfo("ytInitialDataの取得に失敗しました", InfoType.Error);
                    break;

                case DisconnectReason.ServerError:
                    SendInfo("サーバでエラーが発生したため接続できませんでした", InfoType.Error);
                    break;

                case DisconnectReason.Unknown:
                    SendInfo("原因不明のエラーが発生したため切断されましたが、自動的に再接続します", InfoType.Error);
                    goto reload;
                }
            }
            catch (Exception ex)
            {
                _logger.LogException(ex, "", $"input={input}");
                SendInfo("回復不能なエラーが発生しました", InfoType.Error);
            }
            AfterConnect();
        }