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; } }
/// <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); } }); } }
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); }
// コメント投稿の結果を受け取る 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); }
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); }
/// <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); }
public ShereLiveInfoContentViewModel(NicoLiveVideo liveVideo, Views.Service.TextInputDialogService textInputDialog) { NicoLiveVideo = liveVideo; TextInputDialog = textInputDialog; IsStillLoggedInTwitter = new ReactiveProperty <bool>(!TwitterHelper.IsLoggedIn); }
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*/); }
// 配信の次枠を自動で開く private async void NicoLiveVideo_NextLive(NicoLiveVideo sender, string liveId) { await Task.Delay(TimeSpan.FromSeconds(3)); HohoemaApp.Playlist.PlayLiveVideo(liveId, LiveTitle); }
public override async Task OnEnter() { DescriptionHtmlFileUri = await NicoLiveVideo.MakeLiveSummaryHtmlUri(); OnPropertyChanged(nameof(DescriptionHtmlFileUri)); }
public static void CopyToClipboard(NicoLiveVideo video) { CopyToClipboard(MakeShareText(video)); }
public static string MakeShareText(NicoLiveVideo live) { return(MakeLiveShareText(live.LiveTitle, live.LiveId)); }
public static void Share(NicoLiveVideo video) { Share(MakeShareText(video)); }
public static async Task ShareToTwitter(NicoLiveVideo video) { await ShareToTwitter(MakeShareText(video)); }
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); }
/// <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; }
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); }