Example #1
0
 private void WebSocket_Received(object sender, IPacket e)
 {
     try
     {
         if (e is PacketMessageEventMessageChat chat)
         {
             var comment        = Tools.Parse(chat.Comment);
             var commentData    = Tools.CreateCommentData(comment, _startAt, _siteOptions);
             var messageContext = CreateMessageContext(comment, commentData, false);
             if (messageContext != null)
             {
                 MessageReceived?.Invoke(this, messageContext);
             }
         }
         else if (e is PacketMessageEventMessageAudienceCount audienceCount)
         {
             var ac = audienceCount.AudienceCount;
             MetadataUpdated?.Invoke(this, new Metadata
             {
                 CurrentViewers = ac.live_viewers.ToString(),
                 TotalViewers   = ac.viewers.ToString(),
             });
         }
         else if (e is PacketMessageEventMessageLiveEnd liveEnd)
         {
             Disconnect();
         }
     }
     catch (Exception ex)
     {
         _logger.LogException(ex);
     }
 }
        public async Task ReceiveAsync()
        {
            _isDisconnectRequested = false;
            _cts = new CancellationTokenSource();

            while (true)
            {
                if (_isDisconnectRequested)
                {
                    break;
                }
                var liveInfo = await API.GetStreamAsync(_server, _channelName);

                if (liveInfo != null)
                {
                    MetadataUpdated?.Invoke(this, liveInfo);
                }
                try
                {
                    await Task.Delay(_pollingIntervalSec * 1000, _cts.Token);
                }
                catch (TaskCanceledException)
                {
                    break;
                }
            }
        }
        public async Task ReceiveAsync(long live_id, long lastUpdatedAt, CookieContainer cc)
        {
            long lua = lastUpdatedAt;

            _isDisconnectRequested = false;
            _cts = new CancellationTokenSource();

            while (true)
            {
                if (_isDisconnectRequested)
                {
                    break;
                }
                var liveData = await Api.GetLiveDataAsync(_server, live_id, lua, cc);

                lua = liveData.UpdatedAt;
                MetadataUpdated?.Invoke(this, liveData);
                try
                {
                    await Task.Delay(_pollingIntervalSec * 1000, _cts.Token);
                }
                catch (TaskCanceledException)
                {
                    break;
                }
            }
        }
Example #4
0
        private void OnMessageReceived(string data)
        {
            var message = MessageParser.ParseMessage(data, SendInfo);

            if (message is UnknownMessage)
            {
                _logger.LogException(new ParseException(data));
                return;
            }
            if (message != null)
            {
                if (message is IMirrativDisconnected disconnected)
                {
                    this.Stop();
                }
                MessageReceived?.Invoke(this, message);
            }
            if (message is IMirrativJoinRoom join)
            {
                MetadataUpdated?.Invoke(this, new Metadata
                {
                    CurrentViewers = join.OnlineViewerNum.ToString(),
                });
            }
        }
Example #5
0
 private void PromptyStatsProvider_Received(object sender, IPromptyStats e)
 {
     MetadataUpdated?.Invoke(this, new Metadata
     {
         IsLive       = e.LiveStatus == "LIVE",
         TotalViewers = e.ViewerCount.ToString(),
     });
 }
 private void RaiseMetadataUpdated(LiveData liveData)
 {
     MetadataUpdated?.Invoke(this, new Metadata
     {
         Title          = liveData.Live.Title,
         CurrentViewers = liveData.Live.ViewCount.ToString(),
         TotalViewers   = liveData.Live.TotalViewCount.ToString(),
     });
 }
Example #7
0
        private void _500msTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            var elapsed = DateTime.Now - _startAt;

            MetadataUpdated?.Invoke(this, new Metadata
            {
                Elapsed = Tools.ElapsedToString(elapsed),
            });
        }
Example #8
0
 public void HandleData(GlobalUpdate eventData)
 {
     GlobalUpdated?.Invoke(this, new NestGlobalEventArgs(eventData));
     DeviceUpdated?.Invoke(this, new NestDeviceEventArgs(eventData.Devices));
     StructureUpdated?.Invoke(this, new NestStructureEventArgs(eventData.Structures));
     ThermostatUpdated?.Invoke(this, new NestThermostatEventArgs(eventData.Thermostats));
     CameraUpdated?.Invoke(this, new NestCameraEventArgs(eventData.Cameras));
     SmokeCOAlarmUpdated?.Invoke(this, new NestSmokeCOAlarmEventArgs(eventData.SmokeCOAlarms));
     MetadataUpdated?.Invoke(this, new NestMetadataEventArgs(eventData.Metadata));
 }
        public async Task ConnectAsync(string input, IBrowserProfile browserProfile)
        {
            var cc = GetCookieContainer(browserProfile);

            var list = GetCommentProviderInternals(_options, _siteOptions, _userStoreManager, _dataSource, _logger, this, SiteContextGuid);
            var cu   = await GetCurrentUserInfo(browserProfile);

            if (cu.IsLoggedIn)
            {
                foreach (var f in list)
                {
                    var isValid = f.IsValidInput(input);
                    if (isValid)
                    {
                        _internal = f;
                        break;
                    }
                }
            }
            else
            {
                //未ログインでもWebSocket経由なら取れる。
                var f = new NewLiveInternalProvider(_options, _siteOptions, _userStoreManager, _logger, _dataSource)
                {
                    SiteContextGuid = SiteContextGuid,
                };
                var isValid = f.IsValidInput(input);
                if (isValid)
                {
                    _internal = f;
                }
            }
            if (_internal == null)
            {
                //非対応のInput
                //AfterDisconnected();
                return;
            }
            BeforeConnect();
            _internal.MetadataUpdated += (s, e) => MetadataUpdated?.Invoke(s, e);
            _internal.MessageReceived += (s, e) => MessageReceived?.Invoke(s, e);
            try
            {
                await _internal.ConnectAsync(input, cc);
            }
            catch (Exception ex)
            {
                throw new NicoException("", $"input={input},browser={browserProfile.Type}({browserProfile.ProfileName})", ex);
            }
            finally
            {
                AfterDisconnected();
            }
        }
 private void ElapsedTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
 {
     if (_startedAt.HasValue)
     {
         var elapsed = (GetCurrentDateTime().ToUniversalTime() - _startedAt.Value);
         MetadataUpdated?.Invoke(this, new Metadata
         {
             Elapsed = Tools.ElapsedToString(elapsed),
         });
     }
 }
        private void ElapsedTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (!_startedAt.HasValue)
            {
                return;
            }

            var elapsed  = GetCurrentDateTime() - _startedAt.Value;
            var metadata = new Metadata
            {
                Elapsed = SitePluginCommon.Utils.ElapsedToString(elapsed),
            };

            MetadataUpdated?.Invoke(this, metadata);
        }
Example #12
0
        private void OnMessageReceived(string data)
        {
            var message = ParseMessage(data, SendInfo);

            if (message != null)
            {
                MessageReceived?.Invoke(this, message);
            }
            if (message is IMirrativJoinRoom join)
            {
                MetadataUpdated?.Invoke(this, new Metadata
                {
                    CurrentViewers = join.OnlineViewerNum.ToString(),
                });
            }
        }
        private void MetaProvider_MetadataUpdated(object sender, Stream e)
        {
            var stream = e;

            Debug.Assert(stream != null);
            if (!_startedAt.HasValue)
            {
                _startedAt            = stream.StartedAt;
                _elapsedTimer.Enabled = true;
            }
            var metadata = new Metadata
            {
                Title          = stream.Title,
                CurrentViewers = stream.ViewerCount.ToString(),
            };

            MetadataUpdated?.Invoke(this, metadata);
        }
 private void WebSocket_Received(object sender, Packet p)
 {
     try
     {
         if (p.IsStatus())
         {
             MetadataUpdated?.Invoke(this, new Metadata
             {
                 Title   = p.Title,
                 Elapsed = Tools.ElapsedToString(p.Elapsed),
                 Others  = p.DisplayPointString(),
             });
             LiveStatus = p.Status;
         }
         else if ((MixchMessageType)p.Kind == MixchMessageType.PoiPoi)
         {
             lock (_poipoiStockDict)
             {
                 if (_poipoiStockDict.ContainsKey(p.PoiPoiKey()))
                 {
                     var _p = _poipoiStockDict[p.PoiPoiKey()];
                     _p.Count += p.Count;
                 }
                 else
                 {
                     _poipoiStockDict[p.PoiPoiKey()] = p;
                 }
             }
         }
         else if (p.HasMessage())
         {
             var messageContext = CreateMessageContext(p, false);
             if (messageContext != null)
             {
                 MessageReceived?.Invoke(this, messageContext);
             }
         }
     }
     catch (Exception ex)
     {
         _logger.LogException(ex);
     }
     _lastReceiveTime = DateTime.Now;
 }
        private async Task ReceiveAsync()
        {
            FinishReason           = ProviderFinishReason.Unknown;
            _isDisconnectRequested = false;
            _cts = new CancellationTokenSource();

            while (true)
            {
                if (_isDisconnectRequested)
                {
                    FinishReason = ProviderFinishReason.ByStopMethod;
                    break;
                }
                var liveInfo = await GetLiveInfoAsync();

                MetadataUpdated?.Invoke(this, liveInfo);
                await Wait();
            }
        }
        protected virtual Task CreateMetadataReceivingTask(ref IMetadataProvider metaProvider, BrowserType browserType, string vid, string liveChatHtml)
        {
            Task  metaTask = null;
            YtCfg ytCfg    = null;

            try
            {
                var ytCfgStr = Tools.ExtractYtcfg(liveChatHtml);
                ytCfg = new YtCfg(ytCfgStr);
            }
            catch (ParseException ex)
            {
                _logger.LogException(ex, "live_chatからのytcfgの抜き出しに失敗", liveChatHtml);
            }
            if (ytCfg != null)
            {
                //"service_ajax?name=updatedMetadataEndpoint"はIEには対応していないらしく、400が返って来てしまう。
                //そこで、IEの場合のみ旧版の"youtubei"を使うようにした。
                if (browserType == BrowserType.IE)
                {
                    metaProvider = new MetaDataYoutubeiProvider(_server, _logger);
                }
                else
                {
                    metaProvider = new MetadataProvider(_server, _logger);
                }
                metaProvider.MetadataReceived += (s, e) =>
                {
                    MetadataUpdated?.Invoke(this, e);
                };
                metaProvider.InfoReceived += (s, e) =>
                {
                    SendInfo(e.Comment, e.Type);
                };
                metaTask = metaProvider.ReceiveAsync(ytCfg: ytCfg, vid: vid, cc: _cc);
            }

            return(metaTask);
        }
Example #17
0
        public async Task ReceiveAsync()
        {
            _isDisconnectRequested = false;
            _cts = new CancellationTokenSource();

            while (true)
            {
                if (_isDisconnectRequested)
                {
                    break;
                }
                var liveInfo = await Api.PollLiveAsync(_server, _liveId);

                MetadataUpdated?.Invoke(this, liveInfo);
                try
                {
                    await Task.Delay(_siteOptions.PollingIntervalSec * 60 * 1000, _cts.Token);
                }
                catch (TaskCanceledException)
                {
                    break;
                }
            }
        }
Example #18
0
        private void _rpc_OnMetadataUpdated(RPCController sender, long peerId, MetadataVariable value)
        {
            if (_disposing)
            {
                return;
            }

            if (!Devices.ContainsKey(peerId))
            {
                ReloadRequired?.Invoke(this, ReloadType.Full);
                return;
            }
            Device device = Devices[peerId];

            if (!device.Metadata.ContainsKey(value.Name))
            {
                DeviceReloadRequired?.Invoke(this, device, null, DeviceReloadType.Metadata);
                return;
            }
            MetadataVariable variable = device.Metadata[value.Name];

            variable.SetValue(value);
            MetadataUpdated?.Invoke(this, device, variable);
        }
Example #19
0
        public async Task ConnectAsync(string input, IBrowserProfile browserProfile)
        {
            BeforeConnect();
            var autoReconnectMode = false;
            var cc = GetCookieContainer(browserProfile);

            await InitLoveIconUrlDict();

            string channelId;
            string liveId;

            try
            {
                (channelId, liveId) = GetLiveIdFromInput(input);
            }
            catch (InvalidUrlException)
            {
                SendSystemInfo("入力されたURLが正しくないようです", InfoType.Error);
                AfterDisconnected();
                return;
            }
            if (string.IsNullOrEmpty(liveId))
            {
                autoReconnectMode = true;
            }
            while (true)
            {
                if (autoReconnectMode)
                {
                    MetadataUpdated?.Invoke(this, new Metadata
                    {
                        Title = "(放送が始まるまで待機しています)",
                    });
                    try
                    {
                        liveId = await GetLiveIdFromChannelId(_server, channelId);
                    }
                    catch (LiveNotFoundException)
                    {
                        try
                        {
                            SendSystemInfo((LiveCheckIntervalMs / 1000) + "秒待ってから放送しているか確認します", InfoType.Debug);
                            await Task.Delay(LiveCheckIntervalMs, _cts.Token);
                        }
                        catch (TaskCanceledException) { break; }
                        continue;
                    }
                }
                var(liveInfo, raw) = await GetLiveInfo(channelId, liveId);

                if (liveInfo.LiveStatus == "FINISHED")
                {
                    SendSystemInfo("配信が終了しました", InfoType.Notice);
                    if (autoReconnectMode)
                    {
                        continue;
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    SendSystemInfo("LiveStatus=" + liveInfo.LiveStatus, InfoType.Debug);
                }
                MetadataUpdated?.Invoke(this, new Metadata
                {
                    Title = liveInfo.Title,
                });

                var url = liveInfo.ChatUrl;
                _provider           = CreateMessageProvider();
                _provider.Opened   += Provider_Opened;
                _provider.Received += Provider_Received;

                var messageProviderTask = _provider.ReceiveAsync(url);

                var tasks = new List <Task>();
                tasks.Add(messageProviderTask);
                var promptyStatsProvider = CreatePromptyStatsProvider();
                promptyStatsProvider.Received += PromptyStatsProvider_Received;
                var promptyStatsTask = promptyStatsProvider.ReceiveAsync(channelId, liveId);
                tasks.Add(promptyStatsTask);
                var blacklistProvider = CreateBlackListProvider();
                blacklistProvider.Received += BlacklistProvider_Received;
                var blackListTask = blacklistProvider.ReceiveAsync(Tools.ExtractCookies(cc));
                tasks.Add(blackListTask);


                while (true)
                {
                    var t = await Task.WhenAny(tasks);

                    if (t == messageProviderTask)
                    {
                        //messageProviderTaskが何かしらの理由で終了したから色々終了させる。
                        promptyStatsProvider.Disconnect();
                        blacklistProvider.Disconnect();
                        await RemoveTaskFromList(messageProviderTask, tasks);
                        await RemoveTaskFromList(promptyStatsTask, tasks);
                        await RemoveTaskFromList(blackListTask, tasks);

                        break;
                    }
                    else if (t == promptyStatsTask)
                    {
                        await RemoveTaskFromList(promptyStatsTask, tasks);
                    }
                    else if (t == blackListTask)
                    {
                        await RemoveTaskFromList(blackListTask, tasks);
                    }
                }
                SendSystemInfo("websocketが切断", InfoType.Debug);
                if (_isUserDisconnected)
                {
                    break;
                }
                else
                {
                    SendSystemInfo("websocketの切断がユーザによるものではないため放送ステータスを確認", InfoType.Debug);
                }
                try
                {
                    await AfterMessageProviderDisconnected();
                }
                catch (Exception) { break; }
            }
            if (autoReconnectMode)
            {
                //タイトルが(放送が始まるまで待機しています)となっている可能性を考慮して消す
                MetadataUpdated?.Invoke(this, new Metadata
                {
                    Title = "",
                });
            }
            AfterDisconnected();
        }
 private void MessageProvider_MetaReceived(object sender, IMetadata e)
 {
     MetadataUpdated?.Invoke(this, e);
 }
Example #21
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();
        }
        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();
        }
Example #23
0
        public async Task ConnectAsync(string input, IBrowserProfile browserProfile)
        {
            CanConnect    = false;
            CanDisconnect = true;

            _disconnectReason = DisconnectReason.Unknown;
            InputType inputType;

            try
            {
                while (true)
                {
                    _first.Reset();
                    string liveId;
                    if (Tools.IsValidUserId(input))
                    {
                        inputType = InputType.UserId;
                        var userId = Tools.ExtractUserId(input);
                        liveId = await GetLiveIdAsync(userId);//TODO:

                        //GetLiveIdAsync()を実行中にユーザがDisconnect()するとliveIdがnullになる
                        if (string.IsNullOrEmpty(liveId))
                        {
                            break;
                        }
                    }
                    else if (Tools.IsValidLiveId(input))
                    {
                        inputType = InputType.LiveId;
                        liveId    = Tools.ExtractLiveId(input);
                    }
                    else
                    {
                        inputType = InputType.Unknown;
                        //
                        break;
                    }

                    var liveInfo = await Api.GetLiveInfo(_server, liveId);

                    MetadataUpdated?.Invoke(this, LiveInfo2Meta(liveInfo));
                    Connected?.Invoke(this, new ConnectedEventArgs
                    {
                        IsInputStoringNeeded = false,
                        UrlToRestore         = null,
                    });
                    var initialComments = await Api.GetLiveComments(_server, liveId);

                    foreach (var c in initialComments)
                    {
                        var userId         = c.UserId;
                        var isFirstComment = _first.IsFirstComment(userId);
                        var user           = GetUser(userId);

                        var context = CreateMessageContext(c, true, "");
                        MessageReceived?.Invoke(this, context);
                    }
                    _provider = CreateMessageProvider(liveInfo.Broadcastkey);
                    _provider.MessageReceived += Provider_MessageReceived;
                    _provider.MetadataUpdated += Provider_MetadataUpdated;

                    var commentTask  = _provider.ReceiveAsync();
                    var metaProvider = new MetadataProvider(_server, _siteOptions, liveId);
                    metaProvider.MetadataUpdated += MetaProvider_MetadataUpdated;
                    var metaTask = metaProvider.ReceiveAsync();
                    var tasks    = new List <Task>();
                    tasks.Add(commentTask);
                    tasks.Add(metaTask);

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

                        if (t == commentTask)
                        {
                            try
                            {
                                await commentTask;
                            }
                            catch (Exception ex)
                            {
                                _logger.LogException(ex, "", $"input={input}");
                            }
                            tasks.Remove(commentTask);
                            metaProvider.Disconnect();
                            try
                            {
                                await metaTask;
                            }
                            catch (Exception ex)
                            {
                                _logger.LogException(ex, "", $"input={input}");
                            }
                            tasks.Remove(metaTask);
                        }
                        else if (t == metaTask)
                        {
                            try
                            {
                                await metaTask;
                            }
                            catch (Exception ex)
                            {
                                _logger.LogException(ex, "", $"input={input}");
                            }
                            tasks.Remove(metaTask);
                            //MetadataProviderの内部でcatchしないような例外が投げられた。メタデータの取得は諦めたほうが良い。多分。
                        }
                    }
                    //inputTypeがUserIdの場合は
                    if (inputType != InputType.UserId)
                    {
                        break;
                    }
                    if (_disconnectReason == DisconnectReason.User)
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogException(ex);
            }
            finally
            {
                CanConnect    = true;
                CanDisconnect = false;
            }
        }
 private void ActiveCounter_Updated(object sender, int e)
 {
     MetadataUpdated?.Invoke(this, new Metadata {
         Active = e.ToString()
     });
 }
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public async Task <DisconnectReason> ReceiveAsync(string vid, BrowserType browserType)
        {
            _disconnectReason = DisconnectReason.Unknown;
            string liveChatHtml = await GetLiveChatHtml(vid);

            string ytInitialData;

            try
            {
                ytInitialData = Tools.ExtractYtInitialDataFromLiveChatHtml(liveChatHtml);
            }
            catch (ParseException ex)
            {
                _logger.LogException(ex, "live_chatからのytInitialDataの抜き出しに失敗", liveChatHtml);
                return(DisconnectReason.YtInitialDataNotFound);
            }
            IContinuation      initialContinuation;
            List <CommentData> initialCommentData;

            try
            {
                (initialContinuation, initialCommentData) = Tools.ParseYtInitialData(ytInitialData);
            }
            catch (YouTubeLiveServerErrorException ex)
            {
                _logger.LogException(ex, "サーバエラー", $"ytInitialData={ytInitialData},vid={vid}");
                return(DisconnectReason.ServerError);
            }
            catch (ContinuationNotExistsException)
            {
                //放送終了
                return(DisconnectReason.Finished);
            }
            catch (ChatUnavailableException)
            {
                //SendInfo("この配信ではチャットが無効になっているようです", InfoType.Error);
                return(DisconnectReason.ChatUnavailable);
            }
            catch (Exception ex)
            {
                _logger.LogException(ex, "未知の例外", $"ytInitialData={ytInitialData},vid={vid}");
                return(DisconnectReason.Unknown);
            }

            Connected?.Invoke(this, EventArgs.Empty);

            //直近の過去コメントを送る。
            foreach (var data in initialCommentData)
            {
                if (_receivedCommentIds.Contains(data.Id))
                {
                    continue;
                }
                else
                {
                    _receivedCommentIds.Add(data.Id);
                }
                var messageContext = CreateMessageContext(data, true);
                MessageReceived?.Invoke(this, messageContext);
            }
            //コメント投稿に必要なものの準備
            PrepareForPostingComments(liveChatHtml, ytInitialData);

            var  tasks             = new List <Task>();
            Task activeCounterTask = null;
            IActiveCounter <string> activeCounter = null;

            if (_options.IsActiveCountEnabled)
            {
                activeCounter = new ActiveCounter <string>()
                {
                    CountIntervalSec = _options.ActiveCountIntervalSec,
                    MeasureSpanMin   = _options.ActiveMeasureSpanMin,
                };
                activeCounter.Updated += (s, e) =>
                {
                    MetadataUpdated?.Invoke(this, new Metadata {
                        Active = e.ToString()
                    });
                };
                activeCounterTask = activeCounter.Start();
                tasks.Add(activeCounterTask);
            }

            IMetadataProvider metaProvider = null;
            var metaTask = CreateMetadataReceivingTask(ref metaProvider, browserType, vid, liveChatHtml);

            if (metaTask != null)
            {
                tasks.Add(metaTask);
            }

            _chatProvider = new ChatProvider(_server, _logger);
            _chatProvider.ActionsReceived += (s, e) =>
            {
                foreach (var action in e)
                {
                    if (_receivedCommentIds.Contains(action.Id))
                    {
                        continue;
                    }
                    else
                    {
                        activeCounter?.Add(action.Id);
                        _receivedCommentIds.Add(action.Id);
                    }

                    var messageContext = CreateMessageContext(action, false);
                    MessageReceived?.Invoke(this, messageContext);
                }
            };
            _chatProvider.InfoReceived += (s, e) =>
            {
                SendInfo(e.Comment, e.Type);
            };
            var chatTask = _chatProvider.ReceiveAsync(vid, initialContinuation, _cc);

            tasks.Add(chatTask);

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

                if (t == metaTask)
                {
                    try
                    {
                        await metaTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex, "metaTaskが終了した原因");
                    }
                    //metaTask内でParseExceptionもしくはDisconnect()
                    //metaTaskは終わっても良い。
                    tasks.Remove(metaTask);
                    metaProvider = null;
                }
                else if (t == activeCounterTask)
                {
                    try
                    {
                        await activeCounterTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex, "activeCounterTaskが終了した原因");
                    }
                    tasks.Remove(activeCounterTask);
                    activeCounter = null;
                }
                else //chatTask
                {
                    tasks.Remove(chatTask);
                    try
                    {
                        await chatTask;
                    }
                    catch (ReloadException ex)
                    {
                        _logger.LogException(ex, "", $"vid={vid}");
                        _disconnectReason = DisconnectReason.Reload;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                        _disconnectReason = DisconnectReason.Unknown;
                    }
                    _chatProvider = null;

                    //chatTaskが終わったらmetaTaskも終了させる
                    metaProvider?.Disconnect();
                    if (metaTask != null)
                    {
                        try
                        {
                            await metaTask;
                        }
                        catch (Exception ex)
                        {
                            _logger.LogException(ex, "metaTaskが終了した原因");
                        }
                        tasks.Remove(metaTask);
                    }
                    metaProvider = null;

                    activeCounter?.Stop();
                    if (activeCounterTask != null)
                    {
                        try
                        {
                            await activeCounterTask;
                        }
                        catch (Exception ex)
                        {
                            _logger.LogException(ex, "activeCounterTaskが終了した原因");
                        }
                        tasks.Remove(activeCounterTask);
                    }
                    activeCounter = null;
                }
            }
            return(_disconnectReason);
        }
Example #26
0
        private void _rpc_InitCompleted(RPCController sender)
        {
            if (_disposing)
            {
                return;
            }

            if (Devices.Count == 0)
            {
                Reload();
            }
            else
            {
                bool            devicesDeleted   = false;
                bool            newDevices       = false;
                List <Variable> updatedVariables = Devices.UpdateVariables(_rpc.GetAllValues(), out devicesDeleted, out newDevices);
                foreach (Variable variable in updatedVariables)
                {
                    if (!Devices.ContainsKey(variable.PeerID))
                    {
                        continue;
                    }

                    Device device = Devices[variable.PeerID];
                    if (!device.Channels.ContainsKey(variable.Channel))
                    {
                        continue;
                    }

                    DeviceVariableUpdated?.Invoke(this, device, device.Channels[variable.Channel], variable, "HomegearLib.NET");
                }
                bool systemVariablesAdded   = false;
                bool systemVariablesDeleted = false;
                List <SystemVariable> updatedSystemVariables = SystemVariables.Update(out systemVariablesDeleted, out systemVariablesAdded);
                foreach (SystemVariable variable in updatedSystemVariables)
                {
                    SystemVariableUpdated?.Invoke(this, variable);
                }
                if ((devicesDeleted || newDevices) && ReloadRequired != null)
                {
                    ReloadRequired(this, ReloadType.Full);
                }
                else
                {
                    if ((systemVariablesAdded || systemVariablesDeleted) && ReloadRequired != null)
                    {
                        System.Diagnostics.Debug.Write("Position 3");
                        ReloadRequired(this, ReloadType.SystemVariables);
                    }
                    foreach (KeyValuePair <long, Device> devicePair in Devices)
                    {
                        if (devicePair.Value.MetadataRequested)
                        {
                            bool variablesAdded   = false;
                            bool variablesDeleted = false;
                            List <MetadataVariable> updatedMetadata = devicePair.Value.Metadata.Update(out variablesDeleted, out variablesAdded);
                            foreach (MetadataVariable variable in updatedMetadata)
                            {
                                MetadataUpdated?.Invoke(this, devicePair.Value, variable);
                            }
                            if (variablesAdded || variablesDeleted)
                            {
                                DeviceReloadRequired?.Invoke(this, devicePair.Value, null, DeviceReloadType.Metadata);
                            }
                        }
                    }
                }
            }
        }
Example #27
0
        public async Task ConnectAsync(string input, IBrowserProfile browserProfile)
        {
            _blocker.Reset();
            var cc = GetCookieContainer(browserProfile);

            var list = GetCommentProviderInternals(_options, _siteOptions, _userStoreManager, _dataSource, _logger, this, SiteContextGuid);
            var cu   = await GetCurrentUserInfo(browserProfile);

            if (cu.IsLoggedIn)
            {
                foreach (var f in list)
                {
                    var isValid = f.IsValidInput(input);
                    if (isValid)
                    {
                        _internal = f;
                        break;
                    }
                }
            }
            else
            {
                //未ログインでもWebSocket経由なら取れる。
                var f = new NewLiveInternalProvider(_options, _siteOptions, _userStoreManager, _logger, _dataSource)
                {
                    SiteContextGuid = SiteContextGuid,
                };
                var isValid = f.IsValidInput(input);
                if (isValid)
                {
                    _internal = f;
                }
            }
            if (_internal == null)
            {
                //非対応のInput
                //AfterDisconnected();
                return;
            }
            BeforeConnect();
            _internal.MetadataUpdated += (s, e) => MetadataUpdated?.Invoke(s, e);
            _internal.MessageReceived += (s, e) =>
            {
                if (e.Message is INicoComment nicoComment)
                {
                    var userId     = nicoComment.UserId;
                    var comment    = nicoComment.Text;
                    var postedDate = nicoComment.PostedAt;
                    if (!_blocker.IsUniqueComment(userId, comment, postedDate))
                    {
                        Debug.WriteLine("ニコ生で二重コメントを発見したため無視します");
                        return;
                    }
                }
                MessageReceived?.Invoke(s, e);
            };
            try
            {
                await _internal.ConnectAsync(input, cc);
            }
            catch (Exception ex)
            {
                throw new NicoException("", $"input={input},browser={browserProfile.Type}({browserProfile.ProfileName})", ex);
            }
            finally
            {
                _internal.MetadataUpdated -= (s, e) => MetadataUpdated?.Invoke(s, e);
                _internal.MessageReceived -= (s, e) => MessageReceived?.Invoke(s, e);
                AfterDisconnected();
            }
        }
Example #28
0
 private void Provider_MetadataUpdated(object sender, IMetadata e)
 {
     MetadataUpdated?.Invoke(this, e);
 }
 protected void RaiseMetadataUpdated(IMetadata metadata)
 {
     MetadataUpdated?.Invoke(this, metadata);
 }
Example #30
0
        //protected virtual Extract()
        private async Task ConnectInternalAsync(string input, IBrowserProfile browserProfile)
        {
            if (_ws != null)
            {
                throw new InvalidOperationException("");
            }
            var cookies = GetCookies(browserProfile);

            _cc      = CreateCookieContainer(cookies);
            _context = Tools.GetContext(cookies);
            string liveId;

            try
            {
                liveId = await GetLiveId(input);

                _liveId = liveId;
            }
            catch (InvalidInputException ex)
            {
                _logger.LogException(ex, "無効な入力値", $"input={input}");
                SendSystemInfo("無効な入力値です", InfoType.Error);
                AfterDisconnected();
                return;
            }

            var movieContext2 = await GetMovieInfo(liveId);

            var movieId = movieContext2.MovieId;

            if (movieId == 0)
            {
                SendSystemInfo("存在しないURLまたはIDです", InfoType.Error);
                AfterDisconnected();
                return;
            }
            if (movieContext2.OnairStatus == 2)
            {
                SendSystemInfo("この放送は終了しています", InfoType.Error);
                AfterDisconnected();
                return;
            }
            MetadataUpdated?.Invoke(this, new Metadata {
                Title = movieContext2.Title
            });

            _startAt            = movieContext2.StartedAt.DateTime;
            _500msTimer.Enabled = true;

            var(chats, raw) = await GetChats(movieContext2);

            try
            {
                foreach (var item in chats)
                {
                    var comment        = Tools.Parse(item);
                    var commentData    = Tools.CreateCommentData(comment, _startAt, _siteOptions);
                    var messageContext = CreateMessageContext(comment, commentData, true);
                    if (messageContext != null)
                    {
                        MessageReceived?.Invoke(this, messageContext);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogException(ex, "", "raw=" + raw);
            }
            foreach (var user in _userStoreManager.GetAllUsers(SiteType.Openrec))
            {
                if (!(user is IUser2 user2))
                {
                    continue;
                }
                _userDict.AddOrUpdate(user2.UserId, user2, (id, u) => u);
            }
Reconnect:
            _ws           = CreateOpenrecWebsocket();
            _ws.Received += WebSocket_Received;

            var userAgent         = GetUserAgent(browserProfile.Type);
            var wsTask            = _ws.ReceiveAsync(movieId.ToString(), userAgent, cookies);
            var blackListProvider = CreateBlacklistProvider();

            blackListProvider.Received += BlackListProvider_Received;
            var blackTask = blackListProvider.ReceiveAsync(movieId.ToString(), _context);

            var tasks = new List <Task>
            {
                wsTask,
                blackTask
            };

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

                if (t == blackTask)
                {
                    try
                    {
                        await blackTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                    tasks.Remove(blackTask);
                }
                else
                {
                    blackListProvider.Disconnect();
                    try
                    {
                        await blackTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                    tasks.Remove(blackTask);
                    SendSystemInfo("ブラックリストタスク終了", InfoType.Debug);
                    try
                    {
                        await wsTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                    tasks.Remove(wsTask);
                    SendSystemInfo("wsタスク終了", InfoType.Debug);
                }
            }
            _ws.Received -= WebSocket_Received;
            blackListProvider.Received -= BlackListProvider_Received;

            //意図的な切断では無い場合、配信がまだ続いているか確認して、配信中だったら再接続する。
            //2019/03/12 heartbeatを送っているのにも関わらずwebsocketが切断されてしまう場合を確認。ブラウザでも配信中に切断されて再接続するのを確認済み。
            if (!_isExpectedDisconnect)
            {
                var movieInfo = await GetMovieInfo(liveId);

                if (movieInfo.OnairStatus == 1)
                {
                    goto Reconnect;
                }
            }
        }