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(); }
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(); }