public NicoLiveVideo( string liveId, MediaPlayer mediaPlayer, NiconicoSession niconicoSession, NicoLiveProvider nicoLiveProvider, LoginUserLiveReservationProvider loginUserLiveReservationProvider, PlayerSettings playerSettings, IScheduler scheduler, string communityId = null ) { LiveId = liveId; _CommunityId = communityId; MediaPlayer = mediaPlayer; NiconicoSession = niconicoSession; NicoLiveProvider = nicoLiveProvider; LoginUserLiveReservationProvider = loginUserLiveReservationProvider; PlayerSettings = playerSettings; _UIScheduler = scheduler; _LiveComments = new ObservableCollection <LiveChatData>(); LiveComments = new ReadOnlyObservableCollection <LiveChatData>(_LiveComments); LiveComments.ObserveAddChanged() .Where(x => x.IsOperater && x.HasOperatorCommand) .SubscribeOn(_UIScheduler) .Subscribe(chat => { OperationCommandRecieved?.Invoke(this, new OperationCommandRecievedEventArgs() { Chat = chat }); }); }
public HohoemaNotificationService( PageManager pageManager, QueuePlaylist queuePlaylist, HohoemaPlaylistPlayer hohoemaPlaylistPlayer, NiconicoSession niconicoSession, NotificationService notificationService, NicoVideoProvider nicoVideoProvider, MylistProvider mylistProvider, NicoLiveProvider nicoLiveProvider, CommunityProvider communityProvider, UserProvider userProvider, IMessenger messenger ) { PageManager = pageManager; _queuePlaylist = queuePlaylist; _niconicoSession = niconicoSession; NotificationService = notificationService; NicoVideoProvider = nicoVideoProvider; MylistProvider = mylistProvider; NicoLiveProvider = nicoLiveProvider; CommunityProvider = communityProvider; UserProvider = userProvider; _messenger = messenger; }
public async Task UpdateLiveStatus() { LiveInfo = await NicoLiveProvider.GetLiveInfoAsync(LiveId); LiveStatus = LiveInfo?.VideoInfo.Video.CurrentStatus ?? StatusType.Invalid; if (LiveInfo == null) { throw new Exception("Invalid LiveId. (can not get Detail infomation from niconico)"); } await RefreshTimeshiftProgram(); if (LiveStatus != StatusType.OnAir || LiveStatus != StatusType.ComingSoon) { await ExitLiveViewing(); } if (LiveInfo?.IsOK ?? false) { // Official だと info.Communityはnullになる var info = LiveInfo.VideoInfo; _CommunityId = info.Community?.GlobalId; LiveTitle = info.Video.Title; BroadcasterId = info.Video.UserId.ToString(); //BroadcasterName = info.Video.; BroadcasterCommunityType = info.Video.ProviderType; BroadcasterCommunityImageUri = info.Community != null ? new Uri(info.Community.Thumbnail) : null; BroadcasterCommunityId = info.Community?.GlobalId; } }
public VideoPlayRequestBridgeToPlayer( IMessenger messenger, AppearanceSettings appearanceSettings, Lazy <AppWindowSecondaryViewPlayerManager> secondaryPlayerViewManager, Lazy <PrimaryViewPlayerManager> primaryViewPlayerManager, LocalObjectStorageHelper localObjectStorageHelper, QueuePlaylist queuePlaylist, NicoVideoProvider nicoVideoProvider, NicoLiveProvider nicoLiveProvider, PlaylistItemsSourceResolver playlistItemsSourceResolver ) { _messenger = messenger; _appearanceSettings = appearanceSettings; __secondaryPlayerManager = secondaryPlayerViewManager; __primaryViewPlayerManager = primaryViewPlayerManager; _localObjectStorage = localObjectStorageHelper; _queuePlaylist = queuePlaylist; _nicoVideoProvider = nicoVideoProvider; _nicoLiveProvider = nicoLiveProvider; _playlistItemsSourceResolver = playlistItemsSourceResolver; _messenger.Register <VideoPlayRequestMessage>(this); _messenger.Register <PlayerPlayLiveRequestMessage>(this); _messenger.Register <ChangePlayerDisplayViewRequestMessage>(this); }
private async Task <InAppNotificationPayload> SubmitLiveContentSuggestion(LiveId liveId) { var liveDesc = await NicoLiveProvider.GetLiveInfoAsync(liveId); if (liveDesc == null) { return(null); } var liveTitle = liveDesc.Data.Title; var payload = new InAppNotificationPayload() { Content = "InAppNotification_ContentDetectedFromClipboard".Translate(liveTitle), ShowDuration = DefaultNotificationShowDuration, IsShowDismissButton = true, Commands = { new InAppNotificationCommand() { Label = "WatchLiveStreaming".Translate(), Command = new RelayCommand(() => { _messenger.Send(new PlayerPlayLiveRequestMessage(new() { LiveId = liveId })); NotificationService.DismissInAppNotification(); }) },
private async Task <InAppNotificationPayload> SubmitLiveContentSuggestion(string liveId) { var liveDesc = await NicoLiveProvider.GetLiveInfoAsync(liveId); if (liveDesc == null) { return(null); } var liveTitle = liveDesc.VideoInfo.Video.Title; var payload = new InAppNotificationPayload() { Content = $"{liveTitle} をお探しですか?", ShowDuration = DefaultNotificationShowDuration, SymbolIcon = Symbol.Video, IsShowDismissButton = true, Commands = { new InAppNotificationCommand() { Label = "視聴する", Command = new DelegateCommand(() => { Playlist.PlayLiveVideo(liveId, liveTitle); NotificationService.DismissInAppNotification(); }) }, new InAppNotificationCommand() { Label = "放送情報を確認", Command = new DelegateCommand(() => { PageManager.OpenPageWithId(HohoemaPageType.LiveInfomation, liveId); NotificationService.DismissInAppNotification(); }) }, } }; if (liveDesc.VideoInfo.Community != null) { payload.Commands.Add(new InAppNotificationCommand() { Label = "コミュニティを開く", Command = new DelegateCommand(() => { PageManager.OpenPageWithId(HohoemaPageType.Community, liveDesc.VideoInfo.Community.GlobalId); NotificationService.DismissInAppNotification(); }) }); } return(payload); }
public async Task <LiveStatusType> GetLiveViewingFailedReason() { LiveStatusType type = LiveStatusType.Unknown; try { var playerStatus = await NicoLiveProvider.GetPlayerStatusAsync(LiveId); if (playerStatus.Program.IsLive) { type = Live.LiveStatusType.OnAir; } } catch (Exception ex) { if (ex.HResult == NiconicoHResult.ELiveNotFound) { type = Live.LiveStatusType.NotFound; } else if (ex.HResult == NiconicoHResult.ELiveClosed) { type = Live.LiveStatusType.Closed; } else if (ex.HResult == NiconicoHResult.ELiveComingSoon) { type = Live.LiveStatusType.ComingSoon; } else if (ex.HResult == NiconicoHResult.EMaintenance) { type = Live.LiveStatusType.Maintenance; } else if (ex.HResult == NiconicoHResult.ELiveCommunityMemberOnly) { type = Live.LiveStatusType.CommunityMemberOnly; } else if (ex.HResult == NiconicoHResult.ELiveFull) { type = Live.LiveStatusType.Full; } else if (ex.HResult == NiconicoHResult.ELivePremiumOnly) { type = Live.LiveStatusType.PremiumOnly; } else if (ex.HResult == NiconicoHResult.ENotSigningIn) { type = Live.LiveStatusType.NotLogin; } else { type = LiveStatusType.Unknown; } } return(type); }
public TimeshiftPageViewModel( LoginUserLiveReservationProvider loginUserLiveReservationProvider, NicoLiveProvider nicoLiveProvider, Services.HohoemaPlaylist hohoemaPlaylist, Services.PageManager pageManager, Services.DialogService dialogService ) : base(pageManager, useDefaultPageTitle: true) { LoginUserLiveReservationProvider = loginUserLiveReservationProvider; NicoLiveProvider = nicoLiveProvider; HohoemaPlaylist = hohoemaPlaylist; DialogService = dialogService; }
public TimeshiftPageViewModel( ApplicationLayoutManager applicationLayoutManager, LoginUserLiveReservationProvider loginUserLiveReservationProvider, NicoLiveProvider nicoLiveProvider, HohoemaPlaylist hohoemaPlaylist, NoUIProcessScreenContext noUIProcessScreenContext, Services.DialogService dialogService ) { ApplicationLayoutManager = applicationLayoutManager; LoginUserLiveReservationProvider = loginUserLiveReservationProvider; NicoLiveProvider = nicoLiveProvider; HohoemaPlaylist = hohoemaPlaylist; _noUIProcessScreenContext = noUIProcessScreenContext; DialogService = dialogService; }
/// <summary> /// ニコ生からの離脱処理<br /> /// HeartbeatAPIへの定期アクセスの停止、及びLeaveAPIへのアクセス /// </summary> /// <returns></returns> private async Task ExitLiveViewing() { using (var releaser = await _LiveSubscribeLock.LockAsync()) { // Display表示の維持リクエストを停止 Services.Helpers.DisplayRequestHelper.StopKeepDisplay(); // HeartbeatAPIへのアクセスを停止 EndCommentClientConnection(); // 放送からの離脱APIを叩く await NicoLiveProvider.LeaveAsync(LiveId); await StopLiveElapsedTimer(); } }
public TimeshiftPageViewModel( ILoggerFactory loggerFactory, ApplicationLayoutManager applicationLayoutManager, LoginUserLiveReservationProvider loginUserLiveReservationProvider, NicoLiveProvider nicoLiveProvider, NoUIProcessScreenContext noUIProcessScreenContext, Services.DialogService dialogService, OpenLiveContentCommand openLiveContentCommand ) : base(loggerFactory.CreateLogger <TimeshiftPageViewModel>()) { ApplicationLayoutManager = applicationLayoutManager; LoginUserLiveReservationProvider = loginUserLiveReservationProvider; NicoLiveProvider = nicoLiveProvider; _noUIProcessScreenContext = noUIProcessScreenContext; DialogService = dialogService; OpenLiveContentCommand = openLiveContentCommand; }
private async void Live2WebSocket_RecieveCurrentRoom(Live2CurrentRoomEventArgs e) { RoomName = e.RoomName; if (e.MessageServerType == "niwavided") { if (IsWatchWithTimeshift) { string waybackKey = await NicoLiveProvider.GetWaybackKeyAsync(e.ThreadId); _NicoLiveCommentClient = new Niwavided.NiwavidedNicoTimeshiftCommentClient( e.MessageServerUrl, e.ThreadId, NiconicoSession.UserIdString, waybackKey, LiveInfo.VideoInfo.Video.OpenTime.Value ); } else { _NicoLiveCommentClient = new Niwavided.NiwavidedNicoLiveCommentClient( e.MessageServerUrl, e.ThreadId, NiconicoSession.UserIdString, NiconicoSession.Context.HttpClient ); } _NicoLiveCommentClient.Connected += _NicoLiveCommentClient_Connected; _NicoLiveCommentClient.Disconnected += _NicoLiveCommentClient_Disconnected; _NicoLiveCommentClient.CommentRecieved += _NicoLiveCommentClient_CommentRecieved; _NicoLiveCommentClient.CommentPosted += _NicoLiveCommentClient_CommentPosted; // コメントの受信処理と映像のオープンが被ると // 自動再生が失敗する?ので回避のため数秒遅らせる // タイムシフトコメントはStartTimeへのシーク後に取得されることを想定して if (!(_NicoLiveCommentClient is Niwavided.NiwavidedNicoTimeshiftCommentClient)) { _NicoLiveCommentClient.Open(); await Task.Delay(Services.Helpers.DeviceTypeHelper.IsMobile? 3000 : 500); } } }
/// <summary> /// ニコ生へのコメント送信の有効性を保つために /// LiveAPIのハートビートへ定期的にアクセスする<br /> /// </summary> /// <returns></returns> /// <remarks>https://www59.atwiki.jp/nicoapi/pages/19.html</remarks> private async Task TryHeartbeat() { using (var releaser = await _HeartbeatTimerLock.LockAsync()) { if (LiveId == null) { return; } try { var res = await NicoLiveProvider.HeartbeatAsync(LiveId); Debug.WriteLine("heartbeat to " + LiveId); // 視聴者数やコメント数の更新 CommentCount = res.CommentCount; WatchCount = res.WatchCount; Heartbeat?.Invoke(res.CommentCount, res.WatchCount); } catch (Exception ex) when(ex.Message.Contains("NOTFOUND_SLOT")) { // await Stop(); //EndConnect?.Invoke(NicoLiveDisconnectReason.NotFoundSlot); } catch (Exception ex) { Close(); Debug.WriteLine(ex.ToString()); // ハートビートに失敗した場合は、放送終了か追い出された EndConnect?.Invoke(NicoLiveDisconnectReason.Close); } } }
public TimeshiftIncrementalCollectionSource(LoginUserLiveReservationProvider liveReservationProvider, NicoLiveProvider nicoLiveProvider) { LiveReservationProvider = liveReservationProvider; NicoLiveProvider = nicoLiveProvider; }
// TODO: 視聴開始(会場後のみ、チャンネル会員限定やチケット必要な場合あり) // TODO: タイムシフト予約(tsがある場合のみ、会場前のみ、プレミアムの場合は会場後でも可) // TODO: 後からタイムシフト予約(プレミアムの場合のみ) // TODO: 配信説明 // TODO: タグ // TODO: 配信者(チャンネルやコミュニティ)の概要説明 // TODO: 配信者(チャンネルやコミュニティ)のフォロー // TODO: オススメ生放送(放送中、放送予定を明示) // TODO: ニコニコ市場 // TODO: SNS共有 // gateとwatchをどちらも扱った上でその差を意識させないように表現する // LiveInfo.Video.CurrentStatusは開演前、放送中は時間の経過によって変化する可能性がある public LiveInfomationPageViewModel( ApplicationLayoutManager applicationLayoutManager, AppearanceSettings appearanceSettings, PageManager pageManager, NiconicoSession niconicoSession, NicoLiveProvider nicoLiveProvider, DialogService dialogService, OpenLiveContentCommand openLiveContentCommand, OpenLinkCommand openLinkCommand, CopyToClipboardCommand copyToClipboardCommand, CopyToClipboardWithShareTextCommand copyToClipboardWithShareTextCommand ) { ApplicationLayoutManager = applicationLayoutManager; _appearanceSettings = appearanceSettings; PageManager = pageManager; NiconicoSession = niconicoSession; NicoLiveProvider = nicoLiveProvider; HohoemaDialogService = dialogService; OpenLiveContentCommand = openLiveContentCommand; OpenLinkCommand = openLinkCommand; CopyToClipboardCommand = copyToClipboardCommand; CopyToClipboardWithShareTextCommand = copyToClipboardWithShareTextCommand; IsLoadFailed = new ReactiveProperty <bool>(false) .AddTo(_CompositeDisposable); LoadFailedMessage = new ReactiveProperty <string>() .AddTo(_CompositeDisposable); IsLiveIdAvairable = this.ObserveProperty(x => x.LiveId) .Select(x => x != default(LiveId)) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsLoggedIn = NiconicoSession.ObserveProperty(x => x.IsLoggedIn) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsPremiumAccount = NiconicoSession.ObserveProperty(x => x.IsPremiumAccount) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); _IsTsPreserved = new ReactiveProperty <bool>(false) .AddTo(_CompositeDisposable); LiveTags = new ReadOnlyObservableCollection <LiveTagViewModel>(_LiveTags); IchibaItems = new ReadOnlyObservableCollection <IchibaItem>(_IchibaItems); /* * ReccomendItems = _ReccomendItems.ToReadOnlyReactiveCollection(x => * { * var liveId = x.ProgramId; * var liveInfoVM = new LiveInfoListItemViewModel(liveId); * liveInfoVM.Setup(x); * * var reserve = _Reservations?.ReservedProgram.FirstOrDefault(reservation => liveId == reservation.Id); * if (reserve != null) * { * liveInfoVM.SetReservation(reserve); * } * * return liveInfoVM; * }) * .AddTo(_CompositeDisposable); */ IsShowOpenLiveContentButton = new[] { this.ObserveProperty(x => LiveProgram).ToUnit(), NiconicoSession.ObserveProperty(x => x.IsLoggedIn).ToUnit(), _IsTsPreserved.ToUnit() } .Merge() .Select(x => { if (LiveProgram == null) { return(false); } if (NiconicoSession.IsPremiumAccount) { if (LiveProgram.OnAirTime.BeginAt > DateTime.Now) { return(false); } return(LiveProgram.Timeshift.Enabled); } else { // 一般アカウントは放送中のみ if (LiveProgram.OnAirTime.BeginAt > DateTime.Now) { return(false); } if (_IsTsPreserved.Value) { return(true); } if (LiveProgram.OnAirTime.EndAt < DateTime.Now) { return(false); } return(true); } }) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsShowAddTimeshiftButton = new [] { this.ObserveProperty(x => LiveProgram).ToUnit(), NiconicoSession.ObserveProperty(x => x.IsLoggedIn).ToUnit(), _IsTsPreserved.ToUnit() } .Merge() .Select(x => { if (LiveProgram == null) { return(false); } if (!LiveProgram.Timeshift.Enabled) { return(false); } if (!NiconicoSession.IsLoggedIn) { return(false); } if (!NiconicoSession.IsPremiumAccount) { // 一般アカウントは放送開始の30分前からタイムシフトの登録はできなくなる if ((LiveProgram.ShowTime.BeginAt - TimeSpan.FromMinutes(30)) < DateTime.Now) { return(false); } } // 放送前、及び放送中はタイムシフトボタンを非表示…? // プレ垢なら常に表示しておいていいんじゃないの? //if (LiveProgram.ShowTime.EndAt > DateTime.Now) { return false; } // タイムシフト予約済み if (_IsTsPreserved.Value) { return(false); } return(true); }) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsShowDeleteTimeshiftButton = _IsTsPreserved; }
private async Task <InAppNotificationPayload> SubmitLiveContentSuggestion(string liveId) { var liveDesc = await NicoLiveProvider.GetLiveInfoAsync(liveId); if (liveDesc == null) { return(null); } var liveTitle = liveDesc.VideoInfo.Video.Title; var payload = new InAppNotificationPayload() { Content = "InAppNotification_ContentDetectedFromClipboard".Translate(liveTitle), ShowDuration = DefaultNotificationShowDuration, SymbolIcon = Symbol.Video, IsShowDismissButton = true, Commands = { new InAppNotificationCommand() { Label = "WatchLiveStreaming".Translate(), Command = new DelegateCommand(() => { _eventAggregator.GetEvent <Services.Player.PlayerPlayLiveRequest>() .Publish(new Services.Player.PlayerPlayLiveRequestEventArgs() { LiveId = liveId }); NotificationService.DismissInAppNotification(); }) }, new InAppNotificationCommand() { Label = HohoemaPageType.LiveInfomation.Translate(), Command = new DelegateCommand(() => { PageManager.OpenPageWithId(HohoemaPageType.LiveInfomation, liveId); NotificationService.DismissInAppNotification(); }) }, } }; if (liveDesc.VideoInfo.Community != null) { payload.Commands.Add(new InAppNotificationCommand() { Label = HohoemaPageType.Community.Translate(), Command = new DelegateCommand(() => { PageManager.OpenPageWithId(HohoemaPageType.Community, liveDesc.VideoInfo.Community.GlobalId); NotificationService.DismissInAppNotification(); }) }); } return(payload); }
// TODO: 視聴開始(会場後のみ、チャンネル会員限定やチケット必要な場合あり) // TODO: タイムシフト予約(tsがある場合のみ、会場前のみ、プレミアムの場合は会場後でも可) // TODO: 後からタイムシフト予約(プレミアムの場合のみ) // TODO: 配信説明 // TODO: タグ // TODO: 配信者(チャンネルやコミュニティ)の概要説明 // TODO: 配信者(チャンネルやコミュニティ)のフォロー // TODO: オススメ生放送(放送中、放送予定を明示) // TODO: ニコニコ市場 // TODO: SNS共有 // gateとwatchをどちらも扱った上でその差を意識させないように表現する // LiveInfo.Video.CurrentStatusは開演前、放送中は時間の経過によって変化する可能性がある public LiveInfomationPageViewModel( PageManager pageManager, Models.NiconicoSession niconicoSession, NicoLiveProvider nicoLiveProvider, DialogService dialogService, Services.HohoemaPlaylist hohoemaPlaylist, ExternalAccessService externalAccessService ) : base(pageManager) { NiconicoSession = niconicoSession; NicoLiveProvider = nicoLiveProvider; HohoemaDialogService = dialogService; HohoemaPlaylist = hohoemaPlaylist; ExternalAccessService = externalAccessService; IsLoadFailed = new ReactiveProperty <bool>(false) .AddTo(_CompositeDisposable); LoadFailedMessage = new ReactiveProperty <string>() .AddTo(_CompositeDisposable); IsLiveIdAvairable = this.ObserveProperty(x => x.LiveId) .Select(x => x != null ? NiconicoRegex.IsLiveId(x) : false) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsLoggedIn = NiconicoSession.ObserveProperty(x => x.IsLoggedIn) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsPremiumAccount = NiconicoSession.ObserveProperty(x => x.IsPremiumAccount) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); _IsTsPreserved = new ReactiveProperty <bool>(false) .AddTo(_CompositeDisposable); LiveTags = new ReadOnlyObservableCollection <LiveTagViewModel>(_LiveTags); IchibaItems = new ReadOnlyObservableCollection <IchibaItem>(_IchibaItems); ReccomendItems = _ReccomendItems.ToReadOnlyReactiveCollection(x => { var liveId = "lv" + x.ProgramId; var liveInfoVM = new LiveInfoListItemViewModel(liveId); liveInfoVM.Setup(x); var reserve = _Reservations?.ReservedProgram.FirstOrDefault(reservation => liveId == reservation.Id); if (reserve != null) { liveInfoVM.SetReservation(reserve); } return(liveInfoVM); }) .AddTo(_CompositeDisposable); IsShowOpenLiveContentButton = this.ObserveProperty(x => LiveInfo) .Select(x => { if (LiveInfo == null) { return(false); } if (NiconicoSession.IsPremiumAccount) { if (LiveInfo.Video.OpenTime > DateTime.Now) { return(false); } return(LiveInfo.Video.TimeshiftEnabled); } else { // 一般アカウントは放送中のみ if (LiveInfo.Video.OpenTime > DateTime.Now) { return(false); } if (_IsTsPreserved.Value) { return(true); } if (LiveInfo.Video.EndTime < DateTime.Now) { return(false); } return(true); } }) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsShowAddTimeshiftButton = this.ObserveProperty(x => LiveInfo) .Select(x => { if (LiveInfo == null) { return(false); } if (!LiveInfo.Video.TimeshiftEnabled) { return(false); } if (!NiconicoSession.IsLoggedIn) { return(false); } if (!niconicoSession.IsPremiumAccount) { // 一般アカウントは放送開始の30分前からタイムシフトの登録はできなくなる if ((LiveInfo.Video.StartTime - TimeSpan.FromMinutes(30)) < DateTime.Now) { return(false); } } if (LiveInfo.Video.TsArchiveEndTime != null && LiveInfo.Video.TsArchiveEndTime > DateTime.Now) { return(false); } if (_IsTsPreserved.Value) { return(false); } return(true); }) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsShowDeleteTimeshiftButton = _IsTsPreserved; }
public async Task StartLiveWatchingSessionAsync() { if (LiveInfo != null) { LiveInfo = null; await ExitLiveViewing(); await Task.Delay(TimeSpan.FromSeconds(1)); } try { await UpdateLiveStatus(); } catch { } TimeshiftPosition = LiveInfo.VideoInfo.Video.StartTime - LiveInfo.VideoInfo.Video.OpenTime; if (IsWatchWithTimeshift) { _StartTimeOffset = (DateTimeOffset.Now.ToOffset(JapanTimeZoneOffset) - LiveInfo.VideoInfo.Video.OpenTime) ?? TimeSpan.Zero; } else { _StartTimeOffset = TimeSpan.Zero; } // タイムシフトでの視聴かつタイムシフトの視聴予約済みかつ視聴権が未取得の場合は // 視聴権の使用を確認する if (_TimeshiftProgram?.GetReservationStatus() == Mntone.Nico2.Live.ReservationsInDetail.ReservationStatus.FIRST_WATCH) { var dialog = App.Current.Container.Resolve <Services.DialogService>(); // 視聴権に関する詳細な情報提示 // 視聴権の利用期限は 24H+放送時間 まで // ただし公開期限がそれより先に来る場合には公開期限が視聴期限となる var outdatedTime = DateTimeOffset.Now.ToOffset(JapanTimeZoneOffset) + (LiveInfo.VideoInfo.Video.EndTime - LiveInfo.VideoInfo.Video.StartTime) + TimeSpan.FromHours(24); string desc = string.Empty; if (outdatedTime > _TimeshiftProgram.ExpiredAt) { outdatedTime = _TimeshiftProgram.ExpiredAt.LocalDateTime; desc = $"この放送のタイムシフト視聴を開始しますか?\r公開期限内に限って繰り返し視聴できます。\r\r公開期限:{_TimeshiftProgram.ExpiredAt.ToString("g")}"; } else { desc = $"この放送のタイムシフト視聴を開始しますか?\r視聴開始を起点に視聴期限が設定されます。視聴期限内に限って繰り返し視聴できます。\r\r推定視聴期限:{outdatedTime.Value.ToString("g")}"; } var result = await dialog.ShowMessageDialog( desc , _TimeshiftProgram.Title, "視聴する", "キャンセル" ); if (result) { var token = await LoginUserLiveReservationProvider.GetReservationTokenAsync(); await Task.Delay(500); await LoginUserLiveReservationProvider.UseReservationAsync(_TimeshiftProgram.Id, token); await Task.Delay(3000); // タイムシフト予約一覧を更新 // 視聴権利用を開始したアイテムがFIRST_WATCH以外の視聴可能を示すステータスになっているはず await RefreshTimeshiftProgram(); Debug.WriteLine("use reservation after status: " + _TimeshiftProgram.Status); } } try { _PlayerProps = await NicoLiveProvider.GetLeoPlayerPropsAsync(LiveId); } catch (Exception ex) { FailedOpenLive?.Invoke(this, new FailedOpenLiveEventArgs() { Exception = ex, Message = "サービスからの応答がありません" }); LiveStatus = StatusType.Invalid; } if (_PlayerProps != null) { Debug.WriteLine(_PlayerProps.Program.BroadcastId); LivePlayerType = Live.LivePlayerType.Leo; if (Live2WebSocket == null) { Live2WebSocket = new Live2WebSocket(_PlayerProps); Live2WebSocket.RecieveCurrentStream += Live2WebSocket_RecieveCurrentStream; Live2WebSocket.RecieveStatistics += Live2WebSocket_RecieveStatistics; Live2WebSocket.RecieveDisconnect += Live2WebSocket_RecieveDisconnect; Live2WebSocket.RecieveCurrentRoom += Live2WebSocket_RecieveCurrentRoom; var quality = PlayerSettings.DefaultLiveQuality; _IsLowLatency = PlayerSettings.LiveWatchWithLowLatency; await Live2WebSocket.StartAsync(quality, _IsLowLatency); } await StartLiveViewing(); } else { throw new NotSupportedException("RTMP による放送は対応していません。"); } }