Ejemplo n.º 1
0
        public async Task ReceiveInternalAsync(YtInitialData ytInitialData, YtCfg ytCfg, CookieContainer cc, ILoginState loginInfo)
        {
            var    dataToPost = new DataToPost(ytCfg);
            string initialContinuation;

            if (_siteOptions.IsAllChat)
            {
                initialContinuation = ytInitialData.ChatContinuation().AllChatContinuation;
            }
            else
            {
                initialContinuation = ytInitialData.ChatContinuation().JouiChatContinuation;
            }
            dataToPost.SetContinuation(initialContinuation);

            while (!_cts.IsCancellationRequested)
            {
                //例外はここではcatchしない。
                var s = await Tools.GetGetLiveChat(dataToPost, ytCfg.InnerTubeApiKey, cc, loginInfo);

                var actions      = s.GetActions();
                var continuation = s.GetContinuation();
                if (continuation is ReloadContinuation reload)
                {
                    throw new ReloadException();
                }
                else if (continuation is UnknownContinuation unknown)
                {
                    throw new SpecChangedException(unknown.Raw);
                }
                dataToPost.SetContinuation(continuation.Continuation);
                var count     = actions.Count;
                var timeoutMs = Math.Max(continuation.TimeoutMs, 1000);
                var waitTime  = count > 0 ? timeoutMs / count : 1000;
                foreach (var action in actions)
                {
                    ProcessAction(action);
                    try
                    {
                        await Task.Delay(waitTime, _cts.Token);
                    }
                    catch (TaskCanceledException)
                    {
                        return;
                    }
                }
            }
        }
 /// <summary>
 ///
 /// </summary>
 /// <param name="vid"></param>
 /// <param name="ytCfg"></param>
 /// <param name="cc"></param>
 /// <param name="loginInfo"></param>
 /// <returns></returns>
 /// <exception cref="ReloadException"></exception>
 /// <exception cref="SpecChangedException"></exception>
 public async Task ReceiveAsync(string vid, YtInitialData ytInitialData1, YtCfg ytCfg, CookieContainer cc, ILoginState loginInfo)
 {
     if (_cts != null)
     {
         throw new InvalidOperationException("receiving");
     }
     _cts = new CancellationTokenSource();
     try
     {
         await ReceiveInternalAsync(ytInitialData1, ytCfg, cc, loginInfo);
     }
     finally
     {
         _cts = null;
     }
 }
Ejemplo n.º 3
0
        public DataToPost(YtCfg ytCfg)
        {
            dynamic d = JsonConvert.DeserializeObject("{\"context\":{}}", new JsonSerializerSettings {
                Formatting = Formatting.None
            });
            dynamic context = JsonConvert.DeserializeObject(ytCfg.InnerTubeContext, new JsonSerializerSettings {
                Formatting = Formatting.None
            });

            d.context = context;
            //2021/01/16
            //userが最初から設定されている場合があった
            //ただ、その要素は
            //user
            //+gaiaId
            //+userId
            //+lockedSafetyMode
            //onBehalfOfUserは含まれていなかった。上記の要素だけで十分なのかは不明。
            if (!d.ContainsKey("user"))
            {
                if (ytCfg.DelegatedSessionId != null)//未ログインの場合は設定されない
                {
                    dynamic user = JsonConvert.DeserializeObject("{\"onBehalfOfUser\":" + "\"" + ytCfg.DelegatedSessionId + "\"" + "}", new JsonSerializerSettings {
                        Formatting = Formatting.None
                    });
                    d.context.user = user;
                }
                else
                {
                    dynamic user = JsonConvert.DeserializeObject("{}", new JsonSerializerSettings {
                        Formatting = Formatting.None
                    });
                    d.context.user = user;
                }
            }
            _d = d;
        }
        public async Task ReceiveInternalAsync(YtInitialData ytInitialData1, YtCfg ytCfg, CookieContainer cc, ILoginState loginInfo)
        {
            var    dataToPost = new DataToPost(ytCfg);
            string initialContinuation;

            if (_siteOptions.IsAllChat)
            {
                initialContinuation = ytInitialData1.AllChatContinuation;// ytInitialData.ChatContinuation().AllChatContinuation;
            }
            else
            {
                initialContinuation = ytInitialData1.JouiChatContinuation;// ytInitialData.ChatContinuation().JouiChatContinuation;
            }
            dataToPost.SetContinuation(initialContinuation);

            while (!_cts.IsCancellationRequested)
            {
                //例外はここではcatchしない。
                var getLiveChat = await Tools.GetGetLiveChat(dataToPost, ytCfg.InnertubeApiKey, cc, loginInfo, _logger);

                var actions      = getLiveChat.Actions;
                var continuation = getLiveChat.Continuation;// s.GetContinuation();
                if (continuation is null)
                {
                    throw new ContinuationNotExistsException();
                }
                if (continuation is ReloadContinuationData reload)
                {
                    throw new ReloadException();
                }
                else if (continuation is TimedContinuationData timed)
                {
                    dataToPost.SetContinuation(timed.Continaution);
                    await ProcessAction(actions, timed.TimeoutMs);
                }
                else if (continuation is InvalidationContinuationData invalid)
                {
                    dataToPost.SetContinuation(invalid.Continaution);
                    await ProcessAction(actions, invalid.TimeoutMs);
                }
                else if (continuation is UnknownContinuationData unknown)
                {
                    throw new SpecChangedException(unknown.Raw);
                }
                else
                {
                    //ここには来ない予定
                    throw new SpecChangedException("");
                }
                //if (continuation is ReloadContinuation reload)
                //{
                //    throw new ReloadException();
                //}
                //else if (continuation is UnknownContinuation unknown)
                //{
                //    throw new SpecChangedException(unknown.Raw);
                //}
                //dataToPost.SetContinuation(continuation.Continuation);
                //var timeoutMs = Math.Max(continuation.TimeoutMs, 1000);
                //if (actions.Count > 0)
                //{
                //    var waitTime = timeoutMs / actions.Count;
                //    foreach (var action in actions)
                //    {
                //        ProcessAction(action);
                //        try
                //        {
                //            await Task.Delay(waitTime, _cts.Token);
                //        }
                //        catch (TaskCanceledException)
                //        {
                //            return;
                //        }
                //    }
                //}
                //else
                //{
                //    var waitTime = timeoutMs;
                //    try
                //    {
                //        await Task.Delay(waitTime, _cts.Token);
                //    }
                //    catch (TaskCanceledException)
                //    {
                //        return;
                //    }
                //}
            }
        }
Ejemplo n.º 5
0
        private async Task ConnectInternalAsync(string input, IBrowserProfile browserProfile)
        {
            var resolver  = new VidResolver();
            var vidResult = await resolver.GetVid(_server, input);

            string vid;

            switch (vidResult)
            {
            case VidResult single:
                vid = single.Vid;
                break;

            case MultiVidsResult multi:
                SendSystemInfo("このチャンネルでは複数のライブが配信中です。", InfoType.Notice);
                foreach (var v in multi.Vids)
                {
                    SendSystemInfo(v, InfoType.Notice);    //titleも欲しい
                }
                return;

            case NoVidResult no:
                SendSystemInfo("このチャンネルでは生放送をしていないようです", InfoType.Error);
                return;

            default:
                throw new NotImplementedException();
            }
            _cc = CreateCookieContainer(browserProfile);
            await InitElapsedTimer(vid);

            _chatProvider = new ChatProvider2(_siteOptions);
            _chatProvider.MessageReceived      += ChatProvider_MessageReceived;
            _chatProvider.LoggedInStateChanged += _chatProvider_LoggedInStateChanged;
            _chatProvider.InfoReceived         += ChatProvider_InfoReceived;

            var metaProvider = new MetaDataYoutubeiProvider(_server, _logger);

            metaProvider.InfoReceived     += MetaProvider_InfoReceived;
            metaProvider.MetadataReceived += MetaProvider_MetadataReceived;

reload:

            var liveChatHtml = await GetLiveChat(vid, _cc);

            var ytCfgStr      = Tools.ExtractYtCfg(liveChatHtml);
            var ytCfg         = new YtCfg(ytCfgStr);
            var ytInitialData = Tools.ExtractYtInitialData(liveChatHtml);

            if (!ytInitialData.CanChat)
            {
                SendSystemInfo("このライブストリームではチャットは無効です。", InfoType.Notice);
                return;
            }
            var loginInfo = Tools.CreateLoginInfo(ytInitialData.IsLoggedIn);

            SetLoggedInState(ytInitialData.IsLoggedIn);
            _postCommentCoodinator = new DataCreator(ytInitialData, ytCfg.InnerTubeApiKey, _cc);
            var initialActions = ytInitialData.GetActions();

            foreach (var action in initialActions)
            {
                OnMessageReceived(action, true);
            }

            var chatTask = _chatProvider.ReceiveAsync(vid, ytInitialData, ytCfg, _cc, loginInfo);
            var metaTask = metaProvider.ReceiveAsync(ytCfg, vid, _cc);

            var tasks = new List <Task>
            {
                chatTask,
                metaTask
            };

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

                if (t == chatTask)
                {
                    metaProvider.Disconnect();
                    try
                    {
                        await metaTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                    tasks.Remove(metaTask);
                    try
                    {
                        await chatTask;
                    }
                    catch (ChatUnavailableException)
                    {
                        _isDisconnectedExpected = true;
                        SendSystemInfo("配信が終了したか、チャットが無効です。", InfoType.Notice);
                    }
                    catch (ReloadException)
                    {
                    }
                    catch (SpecChangedException ex)
                    {
                        SendSystemInfo("YouTubeの仕様変更に未対応のためコメント取得を継続できません", InfoType.Error);
                        _logger.LogException(ex);
                        _isDisconnectedExpected = true;
                    }
                    catch (Exception ex)
                    {
                        SendSystemInfo(ex.Message, InfoType.Error);
                        //意図しない切断
                        //ただし、サーバーからReloadメッセージが来た場合と違って、単純にリロードすれば済む問題ではない。
                        _logger.LogException(ex);
                        await Task.Delay(1000);
                    }
                    tasks.Remove(chatTask);

                    if (_isDisconnectedExpected == false)
                    {
                        //何らかの原因で意図しない切断が発生した。
                        SendSystemInfo("エラーが発生したためサーバーとの接続が切断されましたが、自動的に再接続します", InfoType.Notice);
                        goto reload;
                    }
                }
                else
                {
                    try
                    {
                        await metaTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                    }
                    tasks.Remove(metaTask);
                }
            }

            _chatProvider.MessageReceived      -= ChatProvider_MessageReceived;
            _chatProvider.LoggedInStateChanged -= _chatProvider_LoggedInStateChanged;
            _chatProvider.InfoReceived         -= ChatProvider_InfoReceived;
            metaProvider.InfoReceived          -= MetaProvider_InfoReceived;
            metaProvider.MetadataReceived      -= MetaProvider_MetadataReceived;
        }