diff --git a/FoxTube/Controls/VideoPlayer.xaml.cs b/FoxTube/Controls/VideoPlayer.xaml.cs index 0c163ce..90f49de 100644 --- a/FoxTube/Controls/VideoPlayer.xaml.cs +++ b/FoxTube/Controls/VideoPlayer.xaml.cs @@ -53,6 +53,7 @@ namespace FoxTube public event ObjectEventHandler SetFullSize; public event ObjectEventHandler NextClicked; + public Button Next => next; bool isMuxed = false; bool audioReady = false; diff --git a/FoxTube/Package.appxmanifest b/FoxTube/Package.appxmanifest index 3a8f43c..af79362 100644 --- a/FoxTube/Package.appxmanifest +++ b/FoxTube/Package.appxmanifest @@ -1,6 +1,6 @@  - + FoxTube diff --git a/FoxTube/Pages/MainPage.xaml.cs b/FoxTube/Pages/MainPage.xaml.cs index cff7741..5fdad95 100644 --- a/FoxTube/Pages/MainPage.xaml.cs +++ b/FoxTube/Pages/MainPage.xaml.cs @@ -392,6 +392,13 @@ namespace FoxTube nav.IsBackEnabled = true; else nav.IsBackEnabled = false; + + if (content.SourcePageType == typeof(Home) || content.SourcePageType == typeof(Settings) || content.SourcePageType == typeof(Subscriptions)) + { + nav.ExpandedModeThresholdWidth = 1008; + if (nav.DisplayMode == NavigationViewDisplayMode.Expanded) + nav.IsPaneOpen = true; + } } public void MaximizeVideo() @@ -403,6 +410,9 @@ namespace FoxTube videoPlaceholder.Margin = new Thickness(0); nav.IsBackEnabled = true; + + nav.ExpandedModeThresholdWidth = short.MaxValue; + nav.IsPaneOpen = false; } public void Fullscreen(bool on) @@ -441,7 +451,6 @@ namespace FoxTube (videoPlaceholder.Content as VideoPage).player.pointerCaptured = false; videoPlaceholder.Content = null; Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Arrow, 0); - MaximizeVideo(); if (content.CanGoBack) nav.IsBackEnabled = true; @@ -665,7 +674,7 @@ namespace FoxTube nav.IsPaneOpen = true; } else - nav.ExpandedModeThresholdWidth = int.MaxValue; + nav.ExpandedModeThresholdWidth = short.MaxValue; if (videoPlaceholder.Content != null && videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) MinimizeAsInitializer(); diff --git a/FoxTube/Pages/VideoPage.xaml b/FoxTube/Pages/VideoPage.xaml index 3e4c9b9..444f60d 100644 --- a/FoxTube/Pages/VideoPage.xaml +++ b/FoxTube/Pages/VideoPage.xaml @@ -82,26 +82,7 @@ - - - - - - - - - - - - - - - - - - - - + diff --git a/FoxTube/Pages/VideoPage.xaml.cs b/FoxTube/Pages/VideoPage.xaml.cs index 6d41da4..9e086c4 100644 --- a/FoxTube/Pages/VideoPage.xaml.cs +++ b/FoxTube/Pages/VideoPage.xaml.cs @@ -20,7 +20,7 @@ using FoxTube.Controls; using YoutubeExplode.Models.MediaStreams; using YoutubeExplode; -// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 +//TODO: Refactor page sizing algorythm; Cleanup code namespace FoxTube.Pages { @@ -61,6 +61,8 @@ namespace FoxTube.Pages public CommentsPage comments; public LoadingPage loading; + DispatcherTimer liveTimer; + public VideoPage() { this.InitializeComponent(); @@ -90,7 +92,10 @@ namespace FoxTube.Pages private void Player_NextClicked(object sender, params object[] e) { - (relatedVideos.Children[0] as VideoCard).Button_Click(this, null); + if(playlistId != null) + playlistList.SelectedIndex++; + else + (relatedVideos.Children[0] as VideoCard).Button_Click(this, null); } protected override void OnNavigatedTo(NavigationEventArgs e) @@ -111,123 +116,20 @@ namespace FoxTube.Pages videoId = ids[0]; if (ids[1] != null) - { - playlistId = ids[1]; - List items = new List(); - VideoPlaylistItem selection = null; - - PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails"); - playlistRequest.Id = ids[1]; - Playlist playlistItem = (await playlistRequest.ExecuteAsync()).Items[0]; - - playlistName.Text = playlistItem.Snippet.Title; - playlistChannel.Text = playlistItem.Snippet.ChannelTitle; - - PlaylistItemsResource.ListRequest listRequest = SecretsVault.Service.PlaylistItems.List("snippet"); - listRequest.MaxResults = 50; - listRequest.PlaylistId = ids[1]; - PlaylistItemListResponse listResponse = await listRequest.ExecuteAsync(); - - foreach (PlaylistItem i in listResponse.Items) - { - items.Add(new VideoPlaylistItem(i.Snippet.Thumbnails.Medium.Url, i.Snippet.Title, i.Snippet.ResourceId.VideoId)); - if (items.Last().Id == videoId) - selection = items.Last(); - } - - string token = listResponse.NextPageToken; - while(!string.IsNullOrWhiteSpace(token)) - { - listRequest.PageToken = token; - listResponse = await listRequest.ExecuteAsync(); - - foreach (PlaylistItem i in listResponse.Items) - { - items.Add(new VideoPlaylistItem(i.Snippet.Thumbnails.Medium.Url, i.Snippet.Title, i.Snippet.ResourceId.VideoId)); - if (items.Last().Id == videoId) - selection = items.Last(); - } - - token = listResponse.NextPageToken; - } - - for (int k = 0; k < items.Count; k++) - items[k].Number = k + 1; - - playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{playlistItem.ContentDetails.ItemCount}"; - - playlistList.ItemsSource = items; - playlistList.SelectedItem = selection; - pivot.SelectedItem = playlist; - } + LoadPlaylist(ids[1]); else pivot.Items.Remove(playlist); - VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,statistics,status,contentDetails"); + VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,statistics,status,contentDetails,liveStreamingDetails"); request.Id = ids[0]; item = (await request.ExecuteAsync()).Items[0]; - title.Text = item.Snippet.Title; - Methods.FormatText(ref description, item.Snippet.Description); - - publishedAt.Text = item.Snippet.PublishedAt.ToString(); - if (item.Status.License == "youtube") - license.Text = "Standard YouTube License"; - else license.Text = "Creative Commons Attribution license (reuse allowed)"; - - VideoCategoriesResource.ListRequest categoryRequest = SecretsVault.NoAuthService.VideoCategories.List("snippet"); - categoryRequest.Id = item.Snippet.CategoryId; - category.Text = (await categoryRequest.ExecuteAsync()).Items[0].Snippet.Title; - - views.Text = $"{item.Statistics.ViewCount:0,0} views"; - dislikes.Text = $"{item.Statistics.DislikeCount:0,0}"; - likes.Text = $"{item.Statistics.LikeCount:0,0}"; - rating.Value = (double)item.Statistics.DislikeCount / (double)(item.Statistics.DislikeCount + item.Statistics.LikeCount) * 100; - - if (SecretsVault.IsAuthorized) - { - VideoGetRatingResponse ratingResponse = await SecretsVault.Service.Videos.GetRating(ids[0]).ExecuteAsync(); - if (ratingResponse.Items[0].Rating == "like") - { - userRating = Rating.Like; - like.Foreground = new SolidColorBrush(Colors.Green); - } - else if (ratingResponse.Items[0].Rating == "dislike") - { - userRating = Rating.Dislike; - dislike.Foreground = new SolidColorBrush(Colors.Red); - } - - foreach (Subscription s in SecretsVault.Subscriptions) - { - if (s.Snippet.ResourceId.ChannelId == item.Snippet.ChannelId) - { - subscribe.Background = new SolidColorBrush(Colors.Transparent); - subscribe.Foreground = new SolidColorBrush(Colors.Gray); - subscribe.Content = "Subscribed"; - } - } - subscribe.Visibility = Visibility.Visible; - } + if (item.Snippet.LiveBroadcastContent == "none") + LoadStats(); else - { - download.Visibility = Visibility.Collapsed; - addTo.Visibility = Visibility.Collapsed; - subscribe.Visibility = Visibility.Collapsed; - } + LoadStream(); - ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics"); - channelRequest.Id = item.Snippet.ChannelId; - var item1 = (await channelRequest.ExecuteAsync()).Items[0]; - - channelAvatar.ProfilePicture = new BitmapImage(new Uri(item1.Snippet.Thumbnails.Medium.Url)); - channelName.Text = item.Snippet.ChannelTitle; - subscribers.Text = $"{item1.Statistics.SubscriberCount:0,0} subscribers"; - - comments.Initialize(item); - player.Initialize(item, item1.Snippet.Thumbnails.Medium.Url); - LoadRelatedVideos(); - LoadDownloads(); + LoadInfo(); loading.Close(); } @@ -241,6 +143,155 @@ namespace FoxTube.Pages } } + async void LoadPlaylist(string id) + { + playlistId = id; + List items = new List(); + VideoPlaylistItem selection = null; + + //Retrieving data + PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails"); + playlistRequest.Id = id; + Playlist playlistItem = (await playlistRequest.ExecuteAsync()).Items[0]; + + PlaylistItemsResource.ListRequest listRequest = SecretsVault.Service.PlaylistItems.List("snippet"); + listRequest.MaxResults = 50; + listRequest.PlaylistId = id; + PlaylistItemListResponse listResponse = await listRequest.ExecuteAsync(); + + foreach (PlaylistItem i in listResponse.Items) + { + items.Add(new VideoPlaylistItem(i.Snippet.Thumbnails.Medium.Url, i.Snippet.Title, i.Snippet.ResourceId.VideoId)); + if (items.Last().Id == videoId) + selection = items.Last(); + } + + string token = listResponse.NextPageToken; + while (!string.IsNullOrWhiteSpace(token)) + { + listRequest.PageToken = token; + listResponse = await listRequest.ExecuteAsync(); + + foreach (PlaylistItem i in listResponse.Items) + { + items.Add(new VideoPlaylistItem(i.Snippet.Thumbnails.Medium.Url, i.Snippet.Title, i.Snippet.ResourceId.VideoId)); + if (items.Last().Id == videoId) + selection = items.Last(); + } + + token = listResponse.NextPageToken; + } + + for (int k = 0; k < items.Count; k++) + items[k].Number = k + 1; + + //Setting data + playlistName.Text = playlistItem.Snippet.Title; + playlistChannel.Text = playlistItem.Snippet.ChannelTitle; + + playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{playlistItem.ContentDetails.ItemCount}"; + + playlistList.ItemsSource = items; + playlistList.SelectedItem = selection; + pivot.SelectedItem = playlist; + + if (playlistList.SelectedIndex == playlistList.Items.Count - 1) + player.Next.Visibility = Visibility.Collapsed; + } + + async void LoadInfo() + { + //Setting meta + title.Text = item.Snippet.Title; + Methods.FormatText(ref description, item.Snippet.Description); + + //Setting channel button + ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics"); + channelRequest.Id = item.Snippet.ChannelId; + var item1 = (await channelRequest.ExecuteAsync()).Items[0]; + + channelAvatar.ProfilePicture = new BitmapImage(new Uri(item1.Snippet.Thumbnails.Medium.Url)); + channelName.Text = item.Snippet.ChannelTitle; + subscribers.Text = $"{item1.Statistics.SubscriberCount:0,0} subscribers"; + + //Setting ratings + dislikes.Text = $"{item.Statistics.DislikeCount:0,0}"; + likes.Text = $"{item.Statistics.LikeCount:0,0}"; + rating.Value = (double)item.Statistics.DislikeCount / (double)(item.Statistics.DislikeCount + item.Statistics.LikeCount) * 100; + + //Setting category + VideoCategoriesResource.ListRequest categoryRequest = SecretsVault.NoAuthService.VideoCategories.List("snippet"); + categoryRequest.Id = item.Snippet.CategoryId; + category.Text = (await categoryRequest.ExecuteAsync()).Items[0].Snippet.Title; + + //Setting User's rate + if (SecretsVault.IsAuthorized) + { + VideoGetRatingResponse ratingResponse = await SecretsVault.Service.Videos.GetRating(videoId).ExecuteAsync(); + if (ratingResponse.Items[0].Rating == "like") + { + userRating = Rating.Like; + like.Foreground = new SolidColorBrush(Colors.Green); + } + else if (ratingResponse.Items[0].Rating == "dislike") + { + userRating = Rating.Dislike; + dislike.Foreground = new SolidColorBrush(Colors.Red); + } + + foreach (Subscription s in SecretsVault.Subscriptions) + { + if (s.Snippet.ResourceId.ChannelId == item.Snippet.ChannelId) + { + subscribe.Background = new SolidColorBrush(Colors.Transparent); + subscribe.Foreground = new SolidColorBrush(Colors.Gray); + subscribe.Content = "Subscribed"; + } + } + subscribe.Visibility = Visibility.Visible; + } + else + { + download.Visibility = Visibility.Collapsed; + addTo.Visibility = Visibility.Collapsed; + subscribe.Visibility = Visibility.Collapsed; + } + + //Initializing player + player.Initialize(item, item1.Snippet.Thumbnails.Medium.Url); + + LoadRelatedVideos(); + } + + void LoadStream() + { + liveTimer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(10) }; + liveTimer.Tick += LiveStatsUpdate; + liveTimer.Start(); + LiveStatsUpdate(); + + commentsPlaceholder.Header = "Chat"; + //TODO: Initialize chat + download.Visibility = Visibility.Collapsed; + } + + private async void LiveStatsUpdate(object sender = null, object e = null) + { + VideosResource.ListRequest request = SecretsVault.Service.Videos.List("liveStreamingDetails"); + request.Id = videoId; + Video video = (await request.ExecuteAsync()).Items[0]; + + views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers} viewers"; + } + + void LoadStats() + { + views.Text = $"{item.Statistics.ViewCount:0,0} views"; + + comments.Initialize(item); + LoadDownloads(); + } + async void LoadDownloads() { try @@ -251,9 +302,10 @@ namespace FoxTube.Pages MenuFlyoutItem menuItem = new MenuFlyoutItem() { Text = i.VideoQualityLabel, - Tag = new object[] { i, i.VideoQualityLabel } + Tag = new { i, i.VideoQualityLabel } }; - menuItem.Click += downloadItemSelected; + menuItem.Click += (sender, e) => + DownloadAgent.Add(((sender as MenuFlyoutItem).Tag as object[])[0] as MediaStreamInfo, item, ((sender as MenuFlyoutItem).Tag as object[])[1] as string); downloadSelector.Items.Add(menuItem); } @@ -262,20 +314,17 @@ namespace FoxTube.Pages Text = "Audio track", Tag = new object[] { infoSet.Audio[0], "Audio only" } }; - audioItem.Click += downloadItemSelected; + audioItem.Click += (sender, e) => + DownloadAgent.Add(((sender as MenuFlyoutItem).Tag as object[])[0] as MediaStreamInfo, item, ((sender as MenuFlyoutItem).Tag as object[])[1] as string); downloadSelector.Items.Add(audioItem); } catch (Exception e) { - loading.Error(e.GetType().ToString(), e.Message); + Debug.WriteLine($"{e.GetType()}: '{e.Message}'"); + download.Visibility = Visibility.Collapsed; } } - private void downloadItemSelected(object sender, RoutedEventArgs e) - { - DownloadAgent.Add(((sender as MenuFlyoutItem).Tag as object[])[0] as MediaStreamInfo, item, ((sender as MenuFlyoutItem).Tag as object[])[1] as string); - } - async void LoadRelatedVideos() { SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet"); @@ -332,8 +381,7 @@ namespace FoxTube.Pages public void refresh_Click(object sender, RoutedEventArgs e) { - player = new VideoPlayer(); - Initialize(new string[2] { videoId, playlistId }); + Methods.MainPage.GoToVideo(videoId, playlistId); } private void grid_SizeChanged(object sender, SizeChangedEventArgs e) @@ -488,12 +536,8 @@ namespace FoxTube.Pages private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { - try - { - if ((e.AddedItems[0] as VideoPlaylistItem).Id != videoId) - Methods.MainPage.GoToVideo((e.AddedItems[0] as VideoPlaylistItem).Id, playlistId); - } - catch { } + if ((e.AddedItems[0] as VideoPlaylistItem).Id != videoId) + Methods.MainPage.GoToVideo((e.AddedItems[0] as VideoPlaylistItem).Id, playlistId); } private async void subscribe_Click(object sender, RoutedEventArgs e)