Archived
1
0

Player refactoring

This commit is contained in:
Michael Gordeev
2018-12-28 11:09:09 +03:00
parent 3074c04bec
commit 4958b092a4
4 changed files with 233 additions and 173 deletions
+18
View File
@@ -7,6 +7,8 @@ using Windows.Storage;
namespace FoxTube
{
public enum MatureState { Blocked, Allowed, AllowedOnce }
public static class SettingsStorage
{
public static string VideoQuality
@@ -139,6 +141,22 @@ namespace FoxTube
storage.Values["version"] = value;
}
}
public static MatureState Mature
{
get
{
if (storage.Values["mature"] == null)
{
storage.Values["mature"] = MatureState.Blocked;
return MatureState.Blocked;
}
else return (MatureState)storage.Values["mature"];
}
set
{
storage.Values["mature"] = value;
}
}
//Settings storage
private static readonly ApplicationDataContainer storage = ApplicationData.Current.LocalSettings;
+24 -9
View File
@@ -14,7 +14,6 @@
PointerEntered="UserControl_PointerEntered">
<Grid Background="White" Name="grid" Tapped="UserControl_Tapped">
<MediaElement Width="0" Height="0" VerticalAlignment="Top" HorizontalAlignment="Right" Name="audioSource" MediaOpened="videoSource_Opened" BufferingProgressChanged="videoSource_BufferingProgressChanged"/>
<MediaElement IsDoubleTapEnabled="False" CurrentStateChanged="videoSource_CurrentStateChanged" AutoPlay="False" MediaOpened="videoSource_Opened" BufferingProgressChanged="videoSource_BufferingProgressChanged" Volume="0" Name="videoSource" AreTransportControlsEnabled="False" PosterSource="ms-appx:///Assets/videoThumbSample.png"/>
<controls1:LiveCaptions Player="{x:Bind videoSource}" Visibility="Collapsed"/>
@@ -63,12 +62,18 @@
<ProgressBar VerticalAlignment="Bottom" Foreground="Red" Name="seekIndicator" Visibility="Collapsed"/>
</Grid>
<Button Name="skipAd" Visibility="Collapsed" Margin="0,0,0,25" Grid.Row="1" HorizontalAlignment="Right" Foreground="White" VerticalAlignment="Bottom" Padding="10" BorderBrush="Black" BorderThickness="2" Background="#7E000000">
<StackPanel Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="30" Margin="0,0,10,0" Text="&#xE101;" VerticalAlignment="Center"/>
<TextBlock Text="Skip ad" FontSize="30" TextWrapping="WrapWholeWords" MaxWidth="250"/>
<StackPanel Name="schedulePanel" Visibility="Collapsed" VerticalAlignment="Bottom" HorizontalAlignment="Right" Grid.Row="1" BorderBrush="Black" BorderThickness="2" Background="#7E000000" Padding="10" Margin="0,25" Orientation="Horizontal">
<FontIcon Glyph="&#xE704;" FontSize="30" Margin="0,0,10,0" VerticalAlignment="Top"/>
<StackPanel>
<TextBlock FontWeight="Bold" Text="Stream hasn't started yet"/>
<TextBlock Name="scheduleHeader" Visibility="Collapsed" Text="Stream schedule:"/>
<TextBlock Name="scheduleStart" Visibility="Collapsed" Text="Start time: "/>
<TextBlock Name="scheduleEnd" Visibility="Collapsed" Text="End time:"/>
<TextBlock Name="countdownHeader" Visibility="Collapsed" FontWeight="Bold" Text="Stream will be started in:" Margin="0,10,0,0"/>
<TextBlock Name="countdown" Visibility="Collapsed" FontWeight="SemiBold" FontSize="20" Text="1:00:00:00"/>
</StackPanel>
</Button>
</StackPanel>
<Grid Grid.Row="2" Height="50" Name="mainControls" Background="#7F000000">
<ProgressBar Name="bufferingBar" VerticalAlignment="Top" Margin="0,-4,0,0" IsIndeterminate="True" Visibility="Visible"/>
@@ -91,9 +96,15 @@
</Flyout>
</Button.Flyout>
</Button>
<Button Name="gotoLive" Visibility="Collapsed" Click="GotoLive_Click" Background="Transparent" Foreground="White" Height="50" FontSize="25" ToolTipService.ToolTip="Go to live broadcast">
<StackPanel Orientation="Horizontal">
<FontIcon Glyph="&#xE91F;" Foreground="Red"/>
<TextBlock Text="Live" Margin="5,0,0,5"/>
</StackPanel>
</Button>
</StackPanel>
<Grid Grid.Column="1">
<Grid Grid.Column="1" Name="seekPanel">
<TextBlock Name="elapsedTime" Foreground="White" Text="[Elapsed]" VerticalAlignment="Bottom" HorizontalAlignment="Left" ToolTipService.ToolTip="Time elapsed"/>
<TextBlock Name="remainingTime" Foreground="White" Text="[Remaining]" VerticalAlignment="Bottom" HorizontalAlignment="Right" ToolTipService.ToolTip="Time remaining"/>
<Grid VerticalAlignment="Top" Margin="0,15,0,0" Height="2">
@@ -103,8 +114,11 @@
</Grid>
<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button Click="back10_Click" Name="back10" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xED3C;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Skip back for 10 seconds"/>
<Button Click="fwd30_Click" Name="fwd30" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xED3D;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Skip forward for 30 seconds"/>
<TextBlock Text="1:12:32" Name="liveElapsed" Visibility="Collapsed" FontSize="20" VerticalAlignment="Center" ToolTipService.ToolTip="Elapsed time since stream start"/>
<StackPanel Orientation="Horizontal" Name="rewindPanel">
<Button Click="back10_Click" Name="back10" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xED3C;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Skip back for 10 seconds"/>
<Button Click="fwd30_Click" Name="fwd30" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xED3D;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Skip forward for 30 seconds"/>
</StackPanel>
<Line Stroke="White" StrokeThickness="2" Y1="5" Y2="45"/>
@@ -166,6 +180,7 @@
<Button Name="signin" Click="signin_Click" Content="Sign in now" Foreground="White" Background="Gray" HorizontalAlignment="Right" Grid.Column="1" Margin="0,0,10,0"/>
</Grid>
</Grid>
<Grid Background="#E5000000" Visibility="Collapsed">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Name="errorPlate">
<TextBlock Text="Something went wrong..." HorizontalAlignment="Center" FontSize="20"/>
+190 -164
View File
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Timers;
using Windows.Foundation;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@@ -29,9 +28,12 @@ using Windows.System;
namespace FoxTube
{
public enum PlayerLayout { Normal, Fullscreen, Minimized }
public sealed partial class VideoPlayer : UserControl
{
public string videoId;
Video item;
private bool miniview = false;
public bool MiniView
@@ -64,18 +66,16 @@ namespace FoxTube
TimeSpan remaining;
TimeSpan total;
Video item;
string avatar;
double timecodeBackup = 0;
bool needUpdateTimecode = false;
SystemMediaTransportControls systemControls = SystemMediaTransportControls.GetForCurrentView();
SystemMediaTransportControls systemControls;
LiveCaptions captions;
IReadOnlyList<ClosedCaptionTrackInfo> ccInfo;
MediaStreamInfoSet streamInfo;
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
Timer t = new Timer()
{
Interval = 5000,
@@ -87,37 +87,57 @@ namespace FoxTube
Enabled = true
};
DispatcherTimer timer = new DispatcherTimer()
{
Interval = TimeSpan.FromSeconds(1)
};
DispatcherTimer ctrlsFadeTimer;
public VideoPlayer()
{
this.InitializeComponent();
Visibility = Visibility.Collapsed;
if (!ApplicationView.GetForCurrentView().IsViewModeSupported(ApplicationViewMode.CompactOverlay))
miniViewBtn.Visibility = Visibility.Collapsed;
captions = grid.Children[2] as LiveCaptions;
volume.Value = Convert.ToDouble(settings.Values["volume"]);
videoSource.AutoPlay = (bool)settings.Values["videoAutoplay"];
videoSource.MediaEnded += (s, arg) =>
{
seek.Value = seek.Maximum;
seekIndicator.Value = seekIndicator.Maximum;
seekTimer.Stop();
};
audioSource.CurrentStateChanged += AudioSource_CurrentStateChanged;
t.Elapsed += T_Elapsed;
seekTimer.Elapsed += SeekTimer_Elapsed;
InitializeComponent();
}
public async void Initialize(Video meta, string channelAvatar)
{
try
{
Visibility = Visibility.Collapsed;
item = meta;
avatar = channelAvatar;
videoId = item.Id;
if (item.ContentDetails.ContentRating != null)
{
if(SecretsVault.IsAuthorized)
{
if (SettingsStorage.Mature == MatureState.AllowedOnce)
SettingsStorage.Mature = MatureState.Blocked;
else if(SettingsStorage.Mature == MatureState.Blocked)
{
Visibility = Visibility.Visible;
proceedMature.Visibility = Visibility.Visible;
matureBlock.Visibility = Visibility.Visible;
return;
}
}
else
{
Visibility = Visibility.Visible;
signReq.Visibility = Visibility.Visible;
matureBlock.Visibility = Visibility.Visible;
return;
}
}
if (item.Snippet.LiveBroadcastContent == "none")
LoadVideo();
else if (item.Snippet.LiveBroadcastContent == "live")
LoadStream();
else
LoadUpcoming();
#region Retrieving info for CC and Media streams
//Loading streams
streamInfo = await new YoutubeClient().GetVideoMediaStreamInfosAsync(videoId);
@@ -155,59 +175,9 @@ namespace FoxTube
else
captionsBtn.Visibility = Visibility.Collapsed;
#endregion
if (item.ContentDetails.ContentRating != null)
{
if (SecretsVault.IsAuthorized && settings.Values["showMature"] != null)
{
Visibility = Visibility.Visible;
proceedMature.Visibility = Visibility.Visible;
matureBlock.Visibility = Visibility.Visible;
return;
}
else if (!SecretsVault.IsAuthorized)
{
Visibility = Visibility.Visible;
signReq.Visibility = Visibility.Visible;
matureBlock.Visibility = Visibility.Visible;
return;
}
}
try { videoSource.PosterSource = new BitmapImage(new Uri(item.Snippet.Thumbnails.Maxres.Url)); }
catch { }
title.Text = item.Snippet.Title;
channelName.Text = item.Snippet.ChannelTitle;
quality_SelectionChanged(this, null);
total = XmlConvert.ToTimeSpan(item.ContentDetails.Duration);
seek.Maximum = total.TotalSeconds;
seekIndicator.Maximum = total.TotalSeconds;
elapsed = TimeSpan.FromSeconds(seek.Value);
remaining = total.Subtract(elapsed);
elapsedTime.Text = elapsed.Hours > 0 ? $"{elapsed.Hours}:00:" : "" + $"{elapsed:mm\\:ss}";
remainingTime.Text = remaining.Hours > 0 ? $"{remaining.Hours}:00:" : "" + $"{remaining:mm\\:ss}";
systemControls.IsNextEnabled = true;
systemControls.IsPauseEnabled = true;
systemControls.IsPlayEnabled = true;
systemControls.DisplayUpdater.Type = MediaPlaybackType.Video;
systemControls.DisplayUpdater.VideoProperties.Title = item.Snippet.Title;
systemControls.DisplayUpdater.VideoProperties.Subtitle = item.Snippet.ChannelTitle;
systemControls.DisplayUpdater.Thumbnail = RandomAccessStreamReference.CreateFromUri(new Uri(channelAvatar));
systemControls.DisplayUpdater.Update();
systemControls.ButtonPressed += SystemControls_Engaged;
systemControls.IsEnabled = true;
//SecretsVault.HistoryAdd(videoId, elapsed, total);
t.Start();
Visibility = Visibility.Visible;
}
catch (Exception e)
@@ -216,6 +186,116 @@ namespace FoxTube
}
}
public void InitializeContols()
{
volume.Value = SettingsStorage.Volume;
videoSource.AutoPlay = SettingsStorage.Autoplay;
if (!ApplicationView.GetForCurrentView().IsViewModeSupported(ApplicationViewMode.CompactOverlay))
miniViewBtn.Visibility = Visibility.Collapsed;
videoSource.MediaEnded += (s, arg) =>
{
seek.Value = seek.Maximum;
seekIndicator.Value = seekIndicator.Maximum;
timer.Stop();
};
#region System Media Transport Controls
systemControls = SystemMediaTransportControls.GetForCurrentView();
systemControls.IsNextEnabled = true;
systemControls.IsPauseEnabled = true;
systemControls.IsPlayEnabled = true;
systemControls.DisplayUpdater.Type = MediaPlaybackType.Video;
systemControls.DisplayUpdater.VideoProperties.Title = item.Snippet.Title;
systemControls.DisplayUpdater.VideoProperties.Subtitle = item.Snippet.ChannelTitle;
systemControls.DisplayUpdater.Thumbnail = RandomAccessStreamReference.CreateFromUri(avatar.ToUri());
systemControls.DisplayUpdater.Update();
systemControls.ButtonPressed += SystemControls_Engaged;
systemControls.IsEnabled = true;
#endregion
videoSource.PosterSource = new BitmapImage(item.Snippet.Thumbnails.Maxres.Url.ToUri());
title.Text = item.Snippet.Title;
channelName.Text = item.Snippet.ChannelTitle;
ctrlsFadeTimer.Interval = TimeSpan.FromSeconds(5);
ctrlsFadeTimer.Tick += Elapsed;
}
public void LoadUpcoming()
{
schedulePanel.Visibility = Visibility.Visible;
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue)
{
scheduleHeader.Visibility = Visibility.Visible;
scheduleStart.Visibility = Visibility.Visible;
countdownHeader.Visibility = Visibility.Visible;
countdown.Visibility = Visibility.Visible;
scheduleStart.Text = $"Start time: {item.LiveStreamingDetails.ScheduledStartTime.Value}";
timer.Tick += UpdateCountdown;
timer.Start();
}
if (item.LiveStreamingDetails.ScheduledEndTime.HasValue)
{
scheduleHeader.Visibility = Visibility.Visible;
scheduleEnd.Visibility = Visibility.Visible;
scheduleEnd.Text = $"End time: {item.LiveStreamingDetails.ScheduledEndTime.Value}";
}
}
public void LoadStream()
{
InitializeContols();
seekPanel.Visibility = Visibility.Collapsed;
rewindPanel.Visibility = Visibility.Collapsed;
captions.Visibility = Visibility.Collapsed;
gotoLive.Visibility = Visibility.Visible;
liveElapsed.Visibility = Visibility.Visible;
timer.Tick += UpdateLive;
//TODO: Set up a stream
}
public void LoadVideo()
{
InitializeContols();
captions = grid.Children[2] as LiveCaptions;
timer.Tick += UpdateSeek;
total = XmlConvert.ToTimeSpan(item.ContentDetails.Duration);
seek.Maximum = total.TotalSeconds;
seekIndicator.Maximum = total.TotalSeconds;
elapsed = TimeSpan.FromSeconds(seek.Value);
remaining = total.Subtract(elapsed);
elapsedTime.Text = elapsed.Hours > 0 ? $"{elapsed.Hours}:00:" : "" + $"{elapsed:mm\\:ss}";
remainingTime.Text = remaining.Hours > 0 ? $"{remaining.Hours}:00:" : "" + $"{remaining:mm\\:ss}";
}
public void UpdateCountdown(object sender, object e)
{
countdown.Text = $"{item.LiveStreamingDetails.ScheduledStartTime.Value - DateTime.Now:hh\\:mm\\:ss}";
}
public void UpdateLive(object sender, object e)
{
}
public void UpdateSeek(object sender, object e)
{
seek.Value = videoSource.Position.TotalSeconds;
seekIndicator.Value = seek.Value;
}
public void RaiseError(Exception e)
{
((TextBlock)errorPlate.Children[1]).Text = $"Video ID: {videoId}";
@@ -245,48 +325,21 @@ namespace FoxTube
});
}
private async void SeekTimer_Elapsed(object sender, ElapsedEventArgs e)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, SeekElapsed);
}
private async void T_Elapsed(object sender, ElapsedEventArgs e)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Elapsed);
}
void SeekElapsed()
{
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()
void Elapsed(object sender, object e)
{
controls.Visibility = Visibility.Collapsed;
if (!MiniView)
touchCentral.Visibility = Visibility.Collapsed;
if (pointerCaptured)
{
cursorPositionBackup = Window.Current.CoreWindow.PointerPosition;
Window.Current.CoreWindow.PointerCursor = null;
}
seekIndicator.Visibility = Visibility.Collapsed;
t.Stop();
ctrlsFadeTimer.Stop();
}
public void UpdateSize()
{
if(MiniView)
{
Height = Window.Current.Bounds.Height;
Debug.WriteLine("Video player aspect ratio has been corrected.");
}
}
private void volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
@@ -303,20 +356,20 @@ namespace FoxTube
else if (v > 75)
muteBtn.Content = openVolume.Content = "\xE995";
settings.Values["volume"] = volume.Value;
SettingsStorage.Volume = (int) volume.Value;
audioSource.Volume = videoSource.Volume = volume.Value * 0.01;
videoSource.Volume = volume.Value * 0.01;
}
private void muteBtn_Click(object sender, RoutedEventArgs e)
{
if(volume.Value != 0)
if (volume.Value != 0)
{
double v = (double)settings.Values["volume"];
int v = SettingsStorage.Volume;
volume.Value = 0;
settings.Values["volume"] = v;
SettingsStorage.Volume = v;
}
else volume.Value = (double)settings.Values["volume"];
else volume.Value = SettingsStorage.Volume;
}
private void UserControl_Tapped(object sender, TappedRoutedEventArgs e)
@@ -324,8 +377,8 @@ namespace FoxTube
if (e.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
{
touchCentral.Visibility = Visibility.Visible;
if (t.Enabled)
Elapsed();
if (ctrlsFadeTimer.IsEnabled)
Elapsed(this, null);
else
ShowControls();
}
@@ -340,15 +393,29 @@ namespace FoxTube
ShowControls();
}
private void UserControl_PointerExited(object sender, PointerRoutedEventArgs e)
{
if (t.Enabled && e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
{
pointerCaptured = false;
Elapsed(this, null);
}
}
private void UserControl_PointerEntered(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
pointerCaptured = true;
}
void ShowControls()
{
controls.Visibility = Visibility.Visible;
if (MiniView)
seekIndicator.Visibility = Visibility.Visible;
if (pointerCaptured)
Window.Current.CoreWindow.PointerCursor = cursorBackup;
t.Stop();
t.Start();
Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Arrow, 0);
ctrlsFadeTimer.Stop();
ctrlsFadeTimer.Start();
}
private void quality_SelectionChanged(object sender, SelectionChangedEventArgs e)
@@ -529,41 +596,10 @@ namespace FoxTube
videoSource.Play();
}
private void AudioSource_CurrentStateChanged(object sender, RoutedEventArgs e)
{
switch (audioSource.CurrentState)
{
case MediaElementState.Buffering:
if(videoSource.CurrentState != MediaElementState.Buffering)
videoSource.Pause();
break;
case MediaElementState.Playing:
if (videoSource.CurrentState == MediaElementState.Paused)
videoSource.Play();
else if (videoSource.CurrentState == MediaElementState.Buffering)
audioSource.Pause();
break;
}
}
private void videoSource_Opened(object sender, RoutedEventArgs arg)
{
if(!isMuxed)
{
if(sender == videoSource)
{
videoReady = true;
if (audioReady && ((timecodeBackup == 0 && (bool)settings.Values["videoAutoplay"]) || timecodeBackup > 0))
play_Click(this, null);
}
else if(sender == audioSource)
{
audioReady = true;
if (videoReady && ((timecodeBackup == 0 && (bool)settings.Values["videoAutoplay"]) || timecodeBackup > 0))
play_Click(this, null);
}
}
if (SettingsStorage.Autoplay)
play_Click(this, null);
}
private void videoSource_CurrentStateChanged(object sender, RoutedEventArgs e)
@@ -708,21 +744,6 @@ namespace FoxTube
videoSource.Position = elapsed.Subtract(TimeSpan.FromSeconds(10));
}
private void UserControl_PointerExited(object sender, PointerRoutedEventArgs e)
{
if (t.Enabled && e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
{
pointerCaptured = false;
Elapsed();
}
}
private void UserControl_PointerEntered(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
pointerCaptured = true;
}
private void next_Click(object sender, RoutedEventArgs e)
{
NextClicked.Invoke(this, null);
@@ -874,5 +895,10 @@ namespace FoxTube
{
bufferingLevel.Value = (audioSource.Source != null && videoSource.BufferingProgress > audioSource.BufferingProgress ? audioSource.BufferingProgress : videoSource.BufferingProgress) * 100;
}
private void GotoLive_Click(object sender, RoutedEventArgs e)
{
}
}
}
+1
View File
@@ -269,6 +269,7 @@ namespace FoxTube.Pages
commentsPlaceholder.Header = "Chat";
//TODO: Initialize chat
//TODO: Initialize player
download.Visibility = Visibility.Collapsed;
}