diff --git a/FoxTube/Controls/VideoPlayer.xaml b/FoxTube/Controls/VideoPlayer.xaml index 7a15539..9dced1b 100644 --- a/FoxTube/Controls/VideoPlayer.xaml +++ b/FoxTube/Controls/VideoPlayer.xaml @@ -16,7 +16,8 @@ PointerEntered="UserControl_PointerEntered"> - + + diff --git a/FoxTube/Controls/VideoPlayer.xaml.cs b/FoxTube/Controls/VideoPlayer.xaml.cs index f003749..bd98229 100644 --- a/FoxTube/Controls/VideoPlayer.xaml.cs +++ b/FoxTube/Controls/VideoPlayer.xaml.cs @@ -37,14 +37,19 @@ using YoutubeExplode.Models.ClosedCaptions; using System.Globalization; using FoxTube.Controls; using Windows.System; +using Windows.Devices.Sensors; +using Windows.System.Profile; // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 namespace FoxTube { + public enum DeviceType { Other, Desktop, Mobile } + public sealed partial class VideoPlayer : UserControl { public string videoId; + private DeviceType deviceType = DeviceType.Other; private bool miniview = false; public bool MiniView @@ -80,9 +85,8 @@ namespace FoxTube SystemMediaTransportControls systemControls = SystemMediaTransportControls.GetForCurrentView(); LiveCaptions captions; - YoutubeClient client = new YoutubeClient(); IReadOnlyList ccInfo; - MediaStreamInfoSet streamInfo; + List streamInfo; ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; Timer t = new Timer() @@ -101,9 +105,24 @@ namespace FoxTube this.InitializeComponent(); Visibility = Visibility.Collapsed; if (!ApplicationView.GetForCurrentView().IsViewModeSupported(ApplicationViewMode.CompactOverlay)) - miniViewBtn.Visibility = Visibility.Collapsed;; + miniViewBtn.Visibility = Visibility.Collapsed; - captions = grid.Children[1] as LiveCaptions; + switch(AnalyticsInfo.VersionInfo.DeviceFamily) + { + case "Windows.Mobile": + deviceType = DeviceType.Mobile; + break; + + case "Windows.Desktop": + deviceType = DeviceType.Desktop; + break; + + default: + deviceType = DeviceType.Other; + break; + } + + captions = grid.Children[2] as LiveCaptions; volume.Value = Convert.ToDouble(settings.Values["volume"]); videoSource.AutoPlay = (bool)settings.Values["videoAutoplay"]; @@ -114,8 +133,21 @@ namespace FoxTube seekIndicator.Value = seekIndicator.Maximum; seekTimer.Stop(); }; + audioSource.CurrentStateChanged += AudioSource_CurrentStateChanged; t.Elapsed += T_Elapsed; seekTimer.Elapsed += SeekTimer_Elapsed; + + if(SimpleOrientationSensor.GetDefault() != null && deviceType == DeviceType.Mobile) + { + if (SimpleOrientationSensor.GetDefault().GetCurrentOrientation() == SimpleOrientation.Rotated270DegreesCounterclockwise || SimpleOrientationSensor.GetDefault().GetCurrentOrientation() == SimpleOrientation.Rotated90DegreesCounterclockwise) + fullscreen_Click(this, null); + SimpleOrientationSensor.GetDefault().OrientationChanged += (s, arg) => + { + if (((SimpleOrientationSensor.GetDefault().GetCurrentOrientation() == SimpleOrientation.NotRotated || SimpleOrientationSensor.GetDefault().GetCurrentOrientation() == SimpleOrientation.Rotated180DegreesCounterclockwise) && fullScreen) || + ((SimpleOrientationSensor.GetDefault().GetCurrentOrientation() == SimpleOrientation.Rotated270DegreesCounterclockwise || SimpleOrientationSensor.GetDefault().GetCurrentOrientation() == SimpleOrientation.Rotated90DegreesCounterclockwise) && !fullScreen)) + fullscreen_Click(this, null); + }; + } } public async void Initialize(Video meta, string channelAvatar) @@ -126,22 +158,23 @@ namespace FoxTube #region Retrieving info for CC and Media streams //Loading streams - streamInfo = await client.GetVideoMediaStreamInfosAsync(item.Id); - foreach(MuxedStreamInfo i in streamInfo.Muxed) + streamInfo = (await YouTube.GetUrisAsync(item.Id)).ToList(); + streamInfo.ForEach(x => Debug.WriteLine(x)); + foreach (YouTubeUri i in streamInfo) { - if (i.VideoQuality == VideoQuality.High2160) + if (i.VideoQuality == YouTubeQuality.Quality2160P) (quality.Items[0] as ComboBoxItem).Visibility = Visibility.Visible; - if (i.VideoQuality == VideoQuality.High1080) + if (i.VideoQuality == YouTubeQuality.Quality1080P) (quality.Items[1] as ComboBoxItem).Visibility = Visibility.Visible; - if (i.VideoQuality == VideoQuality.High720) + if (i.VideoQuality == YouTubeQuality.Quality720P) (quality.Items[2] as ComboBoxItem).Visibility = Visibility.Visible; - if (i.VideoQuality == VideoQuality.Medium480) + if (i.VideoQuality == YouTubeQuality.Quality480P) (quality.Items[3] as ComboBoxItem).Visibility = Visibility.Visible; - if (i.VideoQuality == VideoQuality.Medium360) + if (i.VideoQuality == YouTubeQuality.Quality360P) (quality.Items[4] as ComboBoxItem).Visibility = Visibility.Visible; - if (i.VideoQuality == VideoQuality.Low240) + if (i.VideoQuality == YouTubeQuality.Quality240P) (quality.Items[5] as ComboBoxItem).Visibility = Visibility.Visible; - if (i.VideoQuality == VideoQuality.Low144) + if (i.VideoQuality == YouTubeQuality.Quality144P) (quality.Items[6] as ComboBoxItem).Visibility = Visibility.Visible; } @@ -152,7 +185,7 @@ namespace FoxTube quality.SelectedItem = quality.Items.First(x => (x as ComboBoxItem).Visibility == Visibility.Visible); //Loading captions - ccInfo = await client.GetVideoClosedCaptionTrackInfosAsync(item.Id); + ccInfo = await new YoutubeClient().GetVideoClosedCaptionTrackInfosAsync(item.Id); foreach (ClosedCaptionTrackInfo cc in ccInfo) { subsLang.Items.Add(new ComboBoxItem() @@ -255,6 +288,11 @@ namespace FoxTube { seek.Value = videoSource.Position.TotalSeconds; seekIndicator.Value = seek.Value; + if (Math.Round(videoSource.Position.TotalSeconds, 1) != Math.Round(audioSource.Position.TotalSeconds, 1)) + { + Debug.WriteLine($"Correcting tracks synchronization (Video track position: {videoSource.Position}; Audio track position: {audioSource.Position})"); + audioSource.Position = videoSource.Position; + } } void Elapsed() @@ -296,7 +334,7 @@ namespace FoxTube settings.Values["volume"] = volume.Value; - videoSource.Volume = volume.Value * 0.01; + audioSource.Volume = volume.Value * 0.01; } private void muteBtn_Click(object sender, RoutedEventArgs e) @@ -344,7 +382,7 @@ namespace FoxTube private void quality_SelectionChanged(object sender, SelectionChangedEventArgs e) { - try + //try { videoSource.Pause(); timecodeBackup = videoSource.Position.TotalSeconds; @@ -352,32 +390,74 @@ namespace FoxTube switch((quality.SelectedItem as ComboBoxItem).Content) { case "2160p": - videoSource.Source = new Uri(streamInfo.Muxed.First(x => x.VideoQuality == VideoQuality.High2160).Url); + videoSource.Source = streamInfo.First(x => x.VideoQuality == YouTubeQuality.Quality2160P).Uri; + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityHigh).Uri; } + catch + { + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityMedium).Uri; } + catch { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityLow).Uri; } + } break; case "1080p": - videoSource.Source = new Uri(streamInfo.Muxed.First(x => x.VideoQuality == VideoQuality.High1080).Url); + videoSource.Source = streamInfo.First(x => x.VideoQuality == YouTubeQuality.Quality1080P).Uri; + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityHigh).Uri; } + catch + { + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityMedium).Uri; } + catch { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityLow).Uri; } + } break; case "720p": - videoSource.Source = new Uri(streamInfo.Muxed.First(x => x.VideoQuality == VideoQuality.High720).Url); + videoSource.Source = streamInfo.First(x => x.VideoQuality == YouTubeQuality.Quality720P).Uri; + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityHigh).Uri; } + catch + { + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityMedium).Uri; } + catch { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityLow).Uri; } + } break; case "480p": - videoSource.Source = new Uri(streamInfo.Muxed.First(x => x.VideoQuality == VideoQuality.Medium480).Url); + videoSource.Source = streamInfo.First(x => x.VideoQuality == YouTubeQuality.Quality480P).Uri; + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityMedium).Uri; } + catch + { + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityHigh).Uri; } + catch { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityLow).Uri; } + } break; case "360p": - videoSource.Source = new Uri(streamInfo.Muxed.First(x => x.VideoQuality == VideoQuality.Medium360).Url); + videoSource.Source = streamInfo.First(x => x.VideoQuality == YouTubeQuality.Quality360P).Uri; + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityMedium).Uri; } + catch + { + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityHigh).Uri; } + catch { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityLow).Uri; } + } break; case "240p": - videoSource.Source = new Uri(streamInfo.Muxed.First(x => x.VideoQuality == VideoQuality.Low240).Url); + videoSource.Source = streamInfo.First(x => x.VideoQuality == YouTubeQuality.Quality240P).Uri; + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityLow).Uri; } + catch + { + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityMedium).Uri; } + catch { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityHigh).Uri; } + } break; case "144p": - videoSource.Source = new Uri(streamInfo.Muxed.First(x => x.VideoQuality == VideoQuality.Low144).Url); + videoSource.Source = streamInfo.First(x => x.VideoQuality == YouTubeQuality.Quality144P).Uri; + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityLow).Uri; } + catch + { + try { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityMedium).Uri; } + catch { audioSource.Source = streamInfo.First(x => x.AudioQuality == YouTubeQuality.QualityHigh).Uri; } + } break; } needUpdateTimecode = true; videoSource.Play(); } - catch + //catch { } @@ -417,12 +497,18 @@ namespace FoxTube ApplicationView.GetForCurrentView().TryEnterFullScreenMode(); fullscreen.Content = "\xE1D8"; Height = Methods.MainPage.Height; + + if (deviceType == DeviceType.Mobile) + DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape; } else { ApplicationView.GetForCurrentView().ExitFullScreenMode(); fullscreen.Content = "\xE1D9"; Height = double.NaN; + + if (deviceType == DeviceType.Mobile) + DisplayInformation.AutoRotationPreferences = DisplayOrientations.Portrait; } } @@ -434,6 +520,21 @@ namespace FoxTube videoSource.Play(); } + private void AudioSource_CurrentStateChanged(object sender, RoutedEventArgs e) + { + switch (audioSource.CurrentState) + { + case MediaElementState.Buffering: + videoSource.Pause(); + break; + + case MediaElementState.Playing: + if(videoSource.CurrentState == MediaElementState.Paused) + videoSource.Play(); + break; + } + } + private void videoSource_CurrentStateChanged(object sender, RoutedEventArgs e) { if(videoSource.CurrentState == MediaElementState.Playing && needUpdateTimecode) @@ -445,6 +546,7 @@ namespace FoxTube switch(videoSource.CurrentState) { case MediaElementState.Buffering: + audioSource.Pause(); bufferingBar.Visibility = Visibility.Visible; seek.IsEnabled = false; @@ -458,6 +560,8 @@ namespace FoxTube break; case MediaElementState.Paused: + if(audioSource.CurrentState != MediaElementState.Buffering) + audioSource.Pause(); bufferingBar.Visibility = Visibility.Collapsed; seek.IsEnabled = true; @@ -471,6 +575,7 @@ namespace FoxTube break; case MediaElementState.Playing: + audioSource.Play(); bufferingBar.Visibility = Visibility.Collapsed; seek.IsEnabled = true; @@ -482,10 +587,17 @@ namespace FoxTube play.Content = "\xE103"; touchPlay.Content = "\xE103"; + if (Math.Round(videoSource.Position.TotalSeconds, 1) != Math.Round(audioSource.Position.TotalSeconds, 1)) + { + Debug.WriteLine($"Correcting tracks synchronization (Video track position: {videoSource.Position}; Audio track position: {audioSource.Position})"); + audioSource.Position = videoSource.Position; + } + systemControls.PlaybackStatus = MediaPlaybackStatus.Playing; break; default: + audioSource.Pause(); bufferingBar.Visibility = Visibility.Collapsed; systemControls.PlaybackStatus = MediaPlaybackStatus.Closed; break; diff --git a/FoxTube/Pages/MainPage.xaml b/FoxTube/Pages/MainPage.xaml index fdec779..8a69bb3 100644 --- a/FoxTube/Pages/MainPage.xaml +++ b/FoxTube/Pages/MainPage.xaml @@ -8,6 +8,7 @@ xmlns:ads="using:Microsoft.Advertising.WinRT.UI" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:pages="using:FoxTube.Pages" + xmlns:Windows10version1803="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 6)" mc:Ignorable="d" SizeChanged="Page_SizeChanged" PreviewKeyUp="Page_PreviewKeyUp"> @@ -26,7 +27,7 @@ - +