private void MetadataProvider_MetadataUpdated(object sender, LiveData e)
 {
     _lastUpdatedAt = e.UpdatedAt;
     RaiseMetadataUpdated(e);
 }
        public virtual async Task ConnectAsync(string input, IBrowserProfile browserProfile)
        {
            //lastUpdatedAt==0でLiveDataを取る
            //配信中だったらそこに入っているInitialCommentsを送る
            //配信してなかったら始まるまでループ
            //websocketでコメントを取り始める

            BeforeConnect();
            LiveData initialLiveData = null;

            try
            {
                _cc = CreateCookieContainer(browserProfile);
                var itemDict = await GetPlayItemsAsync();

                MessageParser.Resolver = new ItemNameResolver(itemDict);

                _me = await Api.GetMeAsync(_server, _cc);

                long live_id    = -1;
                var  liveIdTest = Tools.ExtractLiveIdFromInput(input);
                if (liveIdTest.HasValue)
                {
                    //inputにLiveIdが含まれていた
                    live_id = liveIdTest.Value;
                }
                else
                {
                    //inputにuserPathが含まれているか調べる
                    var userPath = Tools.ExtractUserPathFromInput(input);
                    if (string.IsNullOrEmpty(userPath))
                    {
                        //LiveIdもuserPathも含まれていなかった
                        throw new InvalidInputException(input);
                    }
                    else
                    {
                        //userPathからLiveIdを取得する
                        live_id = await GetLiveIdFromUserPath(userPath, _cc, _cts.Token);
                    }
                }
                System.Diagnostics.Debug.Assert(live_id != -1);
                _live_id = live_id;

                _lastUpdatedAt  = 0;
                initialLiveData = await Api.GetLiveDataAsync(_server, live_id, _lastUpdatedAt, _cc);

                if (initialLiveData.Live.LiveStatus != PUBLISHING)
                {
                    SendSystemInfo("LiveStatus: " + initialLiveData.Live.LiveStatus, InfoType.Debug);
                    SendSystemInfo("配信が終了しました", InfoType.Notice);
                    AfterDisconnected();
                    return;
                }
                RaiseMetadataUpdated(initialLiveData);
                _startedAt     = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(initialLiveData.Live.StartedAt);
                _lastUpdatedAt = initialLiveData.UpdatedAt;
                foreach (var initialComment in Enumerable.Reverse(initialLiveData.Comments))
                {
                    Debug.WriteLine(initialComment.Message);

                    var message = MessageParser.ParseMessage(initialComment, "");
                    var context = CreateMessageContext(message, true);
                    if (context != null)
                    {
                        MessageReceived?.Invoke(this, context);
                    }
                }
            }
            catch (OperationCanceledException)//TaskCancelledもここに来る
            {
                AfterDisconnected();
                return;
            }
            catch (Exception ex)
            {
                _logger.LogException(ex);
                SendSystemInfo(ex.Message, InfoType.Error);
                AfterDisconnected();
                return;
            }

            var internalCommentProvider = new InternalCommentProvider(_logger);

            _internalCommentProvider = internalCommentProvider;
            internalCommentProvider.MessageReceived += InternalCommentProvider_MessageReceived;
            //var d = internal

            var retryCount = 0;

Retry:
            var commentProviderTask = internalCommentProvider.ReceiveAsync(_live_id, initialLiveData.Jwt);


            var metadataProvider = new MetadataProvider(_server, _siteOptions);

            metadataProvider.MetadataUpdated += MetadataProvider_MetadataUpdated;
            var metaProviderTask = metadataProvider.ReceiveAsync(_live_id, initialLiveData.UpdatedAt, _cc);

            var tasks = new List <Task>();

            tasks.Add(commentProviderTask);
            tasks.Add(metaProviderTask);

            while (tasks.Count > 0)
            {
                var t = await Task.WhenAny(tasks);

                if (t == commentProviderTask)
                {
                    metadataProvider.Disconnect();
                    try
                    {
                        await metaProviderTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                    tasks.Remove(metaProviderTask);
                    try
                    {
                        await commentProviderTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                    tasks.Remove(commentProviderTask);
                }
                else if (t == metaProviderTask)
                {
                    try
                    {
                        await metaProviderTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                    tasks.Remove(metaProviderTask);
                }
            }
            AfterDisconnected();
        }