예제 #1
0
        public SummaryLiveInfoContentViewModel(string communityName, NicoLiveVideo liveVideo, PageManager pageManager)
        {
            NicoLiveVideo = liveVideo;
            PageManager   = pageManager;

            CommunityName = communityName;

            if (liveVideo.BroadcasterCommunityId != null)
            {
                IsCommunityLive = liveVideo.BroadcasterCommunityId.StartsWith("co");
            }

            var playerStatus = NicoLiveVideo.PlayerStatusResponse;

            if (playerStatus != null)
            {
                OpenAt  = playerStatus.Program.OpenedAt.DateTime;
                StartAt = playerStatus.Program.StartedAt.DateTime;
                EndAt   = playerStatus.Program.EndedAt.DateTime;

                BroadcasterName     = playerStatus.Program.BroadcasterName;
                BroadcasterImageUrl = playerStatus.Program.CommunityImageUrl.OriginalString;
                Description         = playerStatus.Program.Description;
            }
        }
예제 #2
0
        /// <summary>
        /// 放送開始からの経過時間を更新します
        /// </summary>
        /// <param name="state">Timerオブジェクトのコールバックとして登録できるようにするためのダミー</param>
        async void UpdateLiveElapsedTime(object state = null)
        {
            using (var releaser = await _LiveElapsedTimeUpdateTimerLock.LockAsync())
            {
                await HohoemaApp.UIDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async() =>
                {
                    // ローカルの現在時刻から放送開始のベース時間を引いて
                    // 放送経過時間の絶対値を求める
                    LiveElapsedTime = DateTime.Now - _StartAt;

                    // 終了時刻を過ぎたら生放送情報を更新する
                    if (!_IsEndMarked && DateTime.Now > _EndAt)
                    {
                        _IsEndMarked = true;

                        await Task.Delay(TimeSpan.FromSeconds(3));
                        if (await TryUpdateLiveStatus())
                        {
                            // 放送が延長されていた場合は継続
                            // _EndAtもTryUpdateLiveStatus内で更新されているはず
                            _IsEndMarked = false;
                        }
                    }

                    // 終了時刻の30秒前から
                    if (!_IsNextLiveSubscribeStarted && DateTime.Now > _EndAt - TimeSpan.FromSeconds(10))
                    {
                        _IsNextLiveSubscribeStarted = true;

                        await NicoLiveVideo.StartNextLiveSubscribe(NicoLiveVideo.DefaultNextLiveSubscribeDuration);
                    }
                });
            }
        }
예제 #3
0
        public SettingsLiveInfoContentViewModel(NicoLiveVideo liveVideo, HohoemaApp hohoemaApp)
        {
            _PlayerSettings = hohoemaApp.UserSettings.PlayerSettings;


            CommentRenderingFPS = _PlayerSettings.ToReactivePropertyAsSynchronized(x => x.CommentRenderingFPS)
                                  .AddTo(_CompositeDisposable);
            CommentDisplayDuration = _PlayerSettings.ToReactivePropertyAsSynchronized(x => x.CommentDisplayDuration, x => x.TotalSeconds, x => TimeSpan.FromSeconds(x))
                                     .AddTo(_CompositeDisposable);
            CommentFontScale = _PlayerSettings.ToReactivePropertyAsSynchronized(x => x.DefaultCommentFontScale)
                               .AddTo(_CompositeDisposable);
            CommentColor = _PlayerSettings.ToReactivePropertyAsSynchronized(x => x.CommentColor)
                           .AddTo(_CompositeDisposable);
            ScrollVolumeFrequency = _PlayerSettings.ToReactivePropertyAsSynchronized(x => x.ScrollVolumeFrequency)
                                    .AddTo(_CompositeDisposable);

            Observable.Merge(
                CommentRenderingFPS.ToUnit(),
                CommentDisplayDuration.ToUnit(),
                CommentFontScale.ToUnit(),
                CommentColor.ToUnit(),
                ScrollVolumeFrequency.ToUnit()
                )
            .SubscribeOnUIDispatcher()
            .Subscribe(_ => _PlayerSettings.Save().ConfigureAwait(false))
            .AddTo(_CompositeDisposable);
        }
예제 #4
0
        // コメント投稿の結果を受け取る
        private void NicoLiveVideo_PostCommentResult(NicoLiveVideo sender, bool postSuccess)
        {
            NowSubmittingComment.Value = false;

            if (postSuccess)
            {
                WritingComment.Value = "";
            }
        }
        public SettingsLiveInfoContentViewModel(NicoLiveVideo liveVideo, PlayerSettings playerSettings)
        {
            PlayerSettings = playerSettings;

            CommentRenderingFPS = PlayerSettings.ToReactivePropertyAsSynchronized(x => x.CommentRenderingFPS)
                                  .AddTo(_CompositeDisposable);
            CommentDisplayDuration = PlayerSettings.ToReactivePropertyAsSynchronized(x => x.CommentDisplayDuration, x => x.TotalSeconds, x => TimeSpan.FromSeconds(x))
                                     .AddTo(_CompositeDisposable);
            CommentFontScale = PlayerSettings.ToReactivePropertyAsSynchronized(x => x.DefaultCommentFontScale)
                               .AddTo(_CompositeDisposable);
            CommentColor = PlayerSettings.ToReactivePropertyAsSynchronized(x => x.CommentColor)
                           .AddTo(_CompositeDisposable);
            ScrollVolumeFrequency = PlayerSettings.ToReactivePropertyAsSynchronized(x => x.SoundVolumeChangeFrequency)
                                    .AddTo(_CompositeDisposable);
        }
예제 #6
0
        protected override void OnHohoemaNavigatingFrom(NavigatingFromEventArgs e, Dictionary <string, object> viewModelState, bool suspending)
        {
            if (!suspending)
            {
                NicoLiveVideo.Dispose();
                NicoLiveVideo = null;
            }

            MediaPlayer.PlaybackSession.PlaybackStateChanged -= PlaybackSession_PlaybackStateChanged;

            IsFullScreen.Value = false;
            StopLiveElapsedTimer().ConfigureAwait(false);

            base.OnHohoemaNavigatingFrom(e, viewModelState, suspending);
        }
예제 #7
0
        /// <summary>
        /// 生放送情報だけを更新し、配信ストリームの更新は行いません。
        /// </summary>
        /// <returns></returns>
        private async Task <bool> TryUpdateLiveStatus()
        {
            if (NicoLiveVideo == null)
            {
                return(false);
            }

            LiveStatusType?liveStatus = null;

            try
            {
                NowUpdating.Value = true;


                liveStatus = await NicoLiveVideo.UpdateLiveStatus();

                if (liveStatus == null)
                {
                    _StartAt = NicoLiveVideo.PlayerStatusResponse.Program.StartedAt;
                    _EndAt   = NicoLiveVideo.PlayerStatusResponse.Program.EndedAt;
                }
                else
                {
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
            finally
            {
                NowUpdating.Value = false;
            }

            ResetSuggestion(liveStatus);

            NowSubmittingComment.Value = false;

            return(liveStatus == null);
        }
예제 #8
0
 public ShereLiveInfoContentViewModel(NicoLiveVideo liveVideo, Views.Service.TextInputDialogService textInputDialog)
 {
     NicoLiveVideo          = liveVideo;
     TextInputDialog        = textInputDialog;
     IsStillLoggedInTwitter = new ReactiveProperty <bool>(!TwitterHelper.IsLoggedIn);
 }
예제 #9
0
        public CommentLiveInfoContentViewModel(NicoLiveVideo liveVideo, ReadOnlyObservableCollection <Comment> comments)
        {
            NicoLiveVideo = liveVideo;

            LiveComments = comments;
        }
 public ShereLiveInfoContentViewModel(NicoLiveVideo liveVideo, Services.DialogService dialogService)
 {
     NicoLiveVideo          = liveVideo;
     HohoemaDialogService   = dialogService;
     IsStillLoggedInTwitter = new ReactiveProperty <bool>(false /*!TwitterHelper.IsLoggedIn*/);
 }
예제 #11
0
        // 配信の次枠を自動で開く
        private async void NicoLiveVideo_NextLive(NicoLiveVideo sender, string liveId)
        {
            await Task.Delay(TimeSpan.FromSeconds(3));

            HohoemaApp.Playlist.PlayLiveVideo(liveId, LiveTitle);
        }
예제 #12
0
        public override async Task OnEnter()
        {
            DescriptionHtmlFileUri = await NicoLiveVideo.MakeLiveSummaryHtmlUri();

            OnPropertyChanged(nameof(DescriptionHtmlFileUri));
        }
예제 #13
0
 public static void CopyToClipboard(NicoLiveVideo video)
 {
     CopyToClipboard(MakeShareText(video));
 }
예제 #14
0
 public static string MakeShareText(NicoLiveVideo live)
 {
     return(MakeLiveShareText(live.LiveTitle, live.LiveId));
 }
예제 #15
0
 public static void Share(NicoLiveVideo video)
 {
     Share(MakeShareText(video));
 }
예제 #16
0
 public static async Task ShareToTwitter(NicoLiveVideo video)
 {
     await ShareToTwitter(MakeShareText(video));
 }
예제 #17
0
        public LiveVideoPlayerControlViewModel(
            HohoemaApp hohoemaApp,
            PageManager pageManager,
            TextInputDialogService textInputDialogService,
            ToastNotificationService toast
            )
            : base(hohoemaApp, pageManager, canActivateBackgroundUpdate: true)
        {
            _TextInputDialogService   = textInputDialogService;
            _ToastNotificationService = toast;

            MediaPlayer = HohoemaApp.MediaPlayer;

            // play
            CurrentState = new ReactiveProperty <MediaElementState>();
            NowPlaying   = CurrentState.Select(x => x == MediaElementState.Playing)
                           .ToReactiveProperty();


            NowUpdating    = new ReactiveProperty <bool>(false);
            LivePlayerType = new ReactiveProperty <Models.Live.LivePlayerType?>();

            CanChangeQuality = new ReactiveProperty <bool>(false);
            RequestQuality   = new ReactiveProperty <string>();
            CurrentQuality   = new ReactiveProperty <string>();

            IsAvailableSuperLowQuality = new ReactiveProperty <bool>(false);
            IsAvailableLowQuality      = new ReactiveProperty <bool>(false);
            IsAvailableNormalQuality   = new ReactiveProperty <bool>(false);
            IsAvailableHighQuality     = new ReactiveProperty <bool>(false);

            ChangeQualityCommand = new DelegateCommand <string>(
                (quality) =>
            {
                NicoLiveVideo.ChangeQualityRequest(quality).ConfigureAwait(false);
                HohoemaApp.UserSettings.PlayerSettings.DefaultLiveQuality = quality;
                HohoemaApp.UserSettings.PlayerSettings.Save().ConfigureAwait(false);
            },
                (quality) => NicoLiveVideo.Qualities.Any(x => x == quality)
                );

            IsVisibleComment = new ReactiveProperty <bool>(PlayerWindowUIDispatcherScheduler, true).AddTo(_CompositeDisposable);

            CommentCanvasHeight = new ReactiveProperty <double>(PlayerWindowUIDispatcherScheduler, 0.0).AddTo(_CompositeDisposable);
            CommentDefaultColor = new ReactiveProperty <Color>(PlayerWindowUIDispatcherScheduler, Colors.White).AddTo(_CompositeDisposable);

            CommentOpacity = HohoemaApp.UserSettings.PlayerSettings.ObserveProperty(x => x.CommentOpacity)
                             .Select(x => x.ToOpacity())
                             .ToReadOnlyReactiveProperty(eventScheduler: PlayerWindowUIDispatcherScheduler);


            // post comment
            WritingComment       = new ReactiveProperty <string>(PlayerWindowUIDispatcherScheduler, "").AddTo(_CompositeDisposable);
            NowCommentWriting    = new ReactiveProperty <bool>(PlayerWindowUIDispatcherScheduler).AddTo(_CompositeDisposable);
            NowSubmittingComment = new ReactiveProperty <bool>(PlayerWindowUIDispatcherScheduler).AddTo(_CompositeDisposable);

            // TODO: ニコ生での匿名コメント設定
            CommandString   = new ReactiveProperty <string>(PlayerWindowUIDispatcherScheduler, "").AddTo(_CompositeDisposable);
            CommandEditerVM = new CommentCommandEditerViewModel(true /* isDefaultAnnonymous */);
            CommandEditerVM.OnCommandChanged += CommandEditerVM_OnCommandChanged;
            CommandEditerVM.ChangeEnableAnonymity(true);
            CommandEditerVM.IsAnonymousComment.Value = true;

            CommandEditerVM_OnCommandChanged();


            CommentSubmitCommand = Observable.CombineLatest(
                WritingComment.Select(x => !string.IsNullOrEmpty(x)),
                NowSubmittingComment.Select(x => !x)
                )
                                   .Select(x => x.All(y => y))
                                   .ToReactiveCommand(PlayerWindowUIDispatcherScheduler)
                                   .AddTo(_CompositeDisposable);

            CommentSubmitCommand.Subscribe(async x =>
            {
                if (NicoLiveVideo != null)
                {
                    NowSubmittingComment.Value = true;
                    await NicoLiveVideo.PostComment(WritingComment.Value, CommandString.Value, LiveElapsedTime);
                }
            });


            // operation command
            PermanentDisplayText = new ReactiveProperty <string>(PlayerWindowUIDispatcherScheduler, "").AddTo(_CompositeDisposable);


            // sound
            IsFullScreen = new ReactiveProperty <bool>(PlayerWindowUIDispatcherScheduler, false).AddTo(_CompositeDisposable);
            IsFullScreen
            .Subscribe(isFullScreen =>
            {
                var appView = ApplicationView.GetForCurrentView();
                if (isFullScreen)
                {
                    if (!appView.TryEnterFullScreenMode())
                    {
                        IsFullScreen.Value = false;
                    }
                }
                else
                {
                    appView.ExitFullScreenMode();
                }
            })
            .AddTo(_CompositeDisposable);

            IsSmallWindowModeEnable = HohoemaApp.Playlist
                                      .ToReactivePropertyAsSynchronized(x => x.IsPlayerFloatingModeEnable);


            IsAutoHideEnable =
                Observable.CombineLatest(
                    NowPlaying
                    , NowCommentWriting.Select(x => !x)
                    )
                .Select(x => x.All(y => y))
                .ToReactiveProperty(PlayerWindowUIDispatcherScheduler)
                .AddTo(_CompositeDisposable);

            Suggestion    = new ReactiveProperty <LiveSuggestion>();
            HasSuggestion = Suggestion.Select(x => x != null)
                            .ToReactiveProperty();

            AutoHideDelayTime = HohoemaApp.UserSettings.PlayerSettings
                                .ToReactivePropertyAsSynchronized(x => x.AutoHidePlayerControlUIPreventTime, PlayerWindowUIDispatcherScheduler)
                                .AddTo(_CompositeDisposable);

            IsDisplayControlUI = HohoemaApp.Playlist.ToReactivePropertyAsSynchronized(x => x.IsDisplayPlayerControlUI);


            IsMuted = HohoemaApp.UserSettings.PlayerSettings
                      .ToReactivePropertyAsSynchronized(x => x.IsMute, PlayerWindowUIDispatcherScheduler)
                      .AddTo(_CompositeDisposable);
            IsMuted.Subscribe(isMuted =>
            {
                MediaPlayer.IsMuted = isMuted;
            })
            .AddTo(_CompositeDisposable);

            SoundVolume = HohoemaApp.UserSettings.PlayerSettings
                          .ToReactivePropertyAsSynchronized(x => x.SoundVolume, PlayerWindowUIDispatcherScheduler)
                          .AddTo(_CompositeDisposable);
            SoundVolume.Subscribe(volume =>
            {
                MediaPlayer.Volume = volume;
            })
            .AddTo(_CompositeDisposable);

            CommentUpdateInterval = HohoemaApp.UserSettings.PlayerSettings.ObserveProperty(x => x.CommentRenderingFPS)
                                    .Select(x => TimeSpan.FromSeconds(1.0 / x))
                                    .ToReactiveProperty()
                                    .AddTo(_CompositeDisposable);

            RequestCommentDisplayDuration = HohoemaApp.UserSettings.PlayerSettings
                                            .ObserveProperty(x => x.CommentDisplayDuration)
                                            .ToReactiveProperty(PlayerWindowUIDispatcherScheduler)
                                            .AddTo(_CompositeDisposable);

            CommentFontScale = HohoemaApp.UserSettings.PlayerSettings
                               .ObserveProperty(x => x.DefaultCommentFontScale)
                               .ToReactiveProperty(PlayerWindowUIDispatcherScheduler)
                               .AddTo(_CompositeDisposable);


            IsForceLandscape = new ReactiveProperty <bool>(PlayerWindowUIDispatcherScheduler, HohoemaApp.UserSettings.PlayerSettings.IsForceLandscape);



            IsStillLoggedInTwitter = new ReactiveProperty <bool>(!TwitterHelper.IsLoggedIn)
                                     .AddTo(_CompositeDisposable);
        }
예제 #18
0
        /// <summary>
        /// 生放送情報を取得してライブストリームの受信を開始します。<br />
        /// 配信受信処理のハードリセット動作として機能します。
        /// </summary>
        /// <returns></returns>
        private async Task TryStartViewing()
        {
            if (NicoLiveVideo == null)
            {
                return;
            }

            try
            {
                MediaPlayer.PlaybackSession.PlaybackStateChanged += PlaybackSession_PlaybackStateChanged;

                NowUpdating.Value = true;

                var liveStatus = await NicoLiveVideo.SetupLive();

                if (liveStatus == null)
                {
                    LivePlayerType.Value = NicoLiveVideo.LivePlayerType;

                    OnPropertyChanged(nameof(MediaPlayer));
                    _StartAt = NicoLiveVideo.PlayerStatusResponse.Program.StartedAt;
                    _EndAt   = NicoLiveVideo.PlayerStatusResponse.Program.EndedAt;

                    await StartLiveElapsedTimer();

                    LiveTitle   = NicoLiveVideo.LiveTitle;
                    Title       = LiveTitle;
                    CommunityId = NicoLiveVideo.BroadcasterCommunityId;

                    // seet
                    RoomName = NicoLiveVideo.PlayerStatusResponse.Room.Name;
                    SeetId   = NicoLiveVideo.PlayerStatusResponse.Room.SeatId;

                    OnPropertyChanged(nameof(NicoLiveVideo));

                    if (CommunityName == null)
                    {
                        if (CommunityId == null)
                        {
                            CommunityId = NicoLiveVideo.BroadcasterCommunityId;
                        }

                        try
                        {
                            var communityDetail = await HohoemaApp.ContentFinder.GetCommunityInfo(CommunityId);

                            if (communityDetail.IsStatusOK)
                            {
                                CommunityName = communityDetail.Community.Name;
                            }
                        }
                        catch { }
                    }

                    if (NicoLiveVideo.LivePlayerType == Models.Live.LivePlayerType.Leo)
                    {
                        CanChangeQuality.Value = true;

                        NicoLiveVideo.ObserveProperty(x => x.RequestQuality)
                        .Subscribe(q =>
                        {
                            RequestQuality.Value = q;
                        });

                        NicoLiveVideo.ObserveProperty(x => x.CurrentQuality)
                        .Subscribe(x =>
                        {
                            CurrentQuality.Value = x;
                        });

                        NicoLiveVideo.ObserveProperty(x => x.Qualities)
                        .Subscribe(types =>
                        {
                            IsAvailableSuperLowQuality.Value = types?.Any(x => x == "super_low") ?? false;
                            IsAvailableLowQuality.Value      = types?.Any(x => x == "low") ?? false;
                            IsAvailableNormalQuality.Value   = types?.Any(x => x == "normal") ?? false;
                            IsAvailableHighQuality.Value     = types?.Any(x => x == "high") ?? false;

                            ChangeQualityCommand.RaiseCanExecuteChanged();
                        });
                    }
                }
                else
                {
                    Debug.WriteLine("生放送情報の取得失敗しました " + LiveId);
                }

                ResetSuggestion(liveStatus);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
            finally
            {
                NowUpdating.Value = false;
            }

            // コメント送信中にコメントクライアント切断した場合に対応
            NowSubmittingComment.Value = false;
        }
예제 #19
0
        public override void OnNavigatedTo(NavigatedToEventArgs e, Dictionary <string, object> viewModelState)
        {
            if (e.Parameter is string)
            {
                var json    = e.Parameter as string;
                var payload = LiveVideoPagePayload.FromParameterString(json);

                LiveId        = payload.LiveId;
                LiveTitle     = payload.LiveTitle;
                CommunityId   = payload.CommunityId;
                CommunityName = payload.CommunityName;
            }

            if (LiveId != null)
            {
                NicoLiveVideo = new NicoLiveVideo(LiveId, HohoemaApp);

                NowConnecting = Observable.CombineLatest(
                    NicoLiveVideo.ObserveProperty(x => x.LiveStatusType).Select(x => x != null)
                    )
                                .Select(x => x.All(y => y))
                                .ToReactiveProperty(PlayerWindowUIDispatcherScheduler)
                                .AddTo(_NavigatingCompositeDisposable);
                OnPropertyChanged(nameof(NowConnecting));

                LiveComments = NicoLiveVideo.LiveComments.ToReadOnlyReactiveCollection(x =>
                {
                    var comment = new Views.Comment();

                    comment.CommentText    = x.Text;
                    comment.CommentId      = !string.IsNullOrEmpty(x.No) ? x.GetCommentNo() : 0;
                    comment.IsAnonimity    = !string.IsNullOrEmpty(x.Anonymity) ? x.GetAnonymity() : false;
                    comment.UserId         = x.User_id;
                    comment.IsOwnerComment = x.User_id == NicoLiveVideo?.BroadcasterId;

                    try
                    {
                        comment.IsLoginUserComment = !comment.IsAnonimity ? uint.Parse(x.User_id) == HohoemaApp.LoginUserId : false;
                    }
                    catch { }



                    //x.GetVposでサーバー上のコメント位置が取れるが、
                    // 受け取った順で表示したいのでローカルの放送時間からコメント位置を割り当てる
                    comment.VideoPosition = (uint)(MediaPlayer.PlaybackSession.Position.TotalMilliseconds * 0.1) + 50;

                    if (x.Vpos != null && x.GetVpos() < (comment.VideoPosition - 200))
                    {
                        Debug.WriteLine("古いコメントのため非表示 : " + comment.CommentText);
                        comment.IsVisible = false;
                    }

                    // EndPositionはコメントレンダラが再計算するが、仮置きしないと表示対象として処理されない
                    comment.EndPosition = comment.VideoPosition + 1000;

                    comment.ApplyCommands(x.GetCommandTypes());

                    return(comment);
                });

                OnPropertyChanged(nameof(LiveComments));

                CommentCount = NicoLiveVideo.ObserveProperty(x => x.CommentCount)
                               .ToReactiveProperty(PlayerWindowUIDispatcherScheduler)
                               .AddTo(_NavigatingCompositeDisposable);
                OnPropertyChanged(nameof(CommentCount));

                WatchCount = NicoLiveVideo.ObserveProperty(x => x.WatchCount)
                             .ToReactiveProperty(PlayerWindowUIDispatcherScheduler)
                             .AddTo(_NavigatingCompositeDisposable);
                OnPropertyChanged(nameof(WatchCount));

                CommunityId = NicoLiveVideo.BroadcasterCommunityId;


                // post comment
                NicoLiveVideo.PostCommentResult += NicoLiveVideo_PostCommentResult;

                // operation command
                PermanentDisplayText = NicoLiveVideo.ObserveProperty(x => x.PermanentDisplayText)
                                       .ToReactiveProperty(PlayerWindowUIDispatcherScheduler)
                                       .AddTo(_NavigatingCompositeDisposable);
                OnPropertyChanged(nameof(PermanentDisplayText));


                // next live
                NicoLiveVideo.NextLive += NicoLiveVideo_NextLive;
            }

            base.OnNavigatedTo(e, viewModelState);
        }