Archived
1
0
This repository has been archived on 2026-04-22. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
FoxTube/FoxTube/Controls/VideoPlayer.xaml.cs
T
Michael Gordeev 7f76ef2d97 Context menu for cards done
Related Work Items: #226
2018-12-31 02:02:01 +03:00

810 lines
28 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Timers;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Media.Imaging;
using System.Diagnostics;
using Windows.Media;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using System.Xml;
using Windows.ApplicationModel.Core;
using Windows.UI;
using Windows.Media.Casting;
using YoutubeExplode.Models.MediaStreams;
using YoutubeExplode;
using YoutubeExplode.Models.ClosedCaptions;
using System.Globalization;
using FoxTube.Controls;
using Windows.System;
using Windows.Media.Core;
using Windows.Media.MediaProperties;
using Windows.Storage;
using Windows.Storage.FileProperties;
using Windows.Media.Editing;
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
{
get { return miniview; }
set
{
miniview = value;
if (value)
captions?.Hide();
else
captions?.Show();
}
}
private bool fullScreen = false;
public bool pointerCaptured = false;
public event ObjectEventHandler SetFullSize;
public event ObjectEventHandler NextClicked;
public Button Next => next;
CoreCursor cursorBackup = Window.Current.CoreWindow.PointerCursor;
Point cursorPositionBackup;
public TimeSpan elapsed;
TimeSpan remaining;
TimeSpan total;
string avatar;
double timecodeBackup = 0;
bool needUpdateTimecode = false;
SystemMediaTransportControls systemControls;
LiveCaptions captions;
IReadOnlyList<ClosedCaptionTrackInfo> ccInfo;
MediaStreamInfoSet streamInfo;
Timer t = new Timer()
{
Interval = 5000,
Enabled = false
};
Timer seekTimer = new Timer()
{
Interval = 1000,
Enabled = true
};
DispatcherTimer timer = new DispatcherTimer()
{
Interval = TimeSpan.FromSeconds(1)
};
DispatcherTimer ctrlsFadeTimer = null;
public VideoPlayer()
{
InitializeComponent();
}
public 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();
Visibility = Visibility.Visible;
}
catch (Exception e)
{
RaiseError(e);
}
}
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 ?? item.Snippet.Thumbnails.Medium).Url.ToUri());
title.Text = item.Snippet.Title;
channelName.Text = item.Snippet.ChannelTitle;
ctrlsFadeTimer = new DispatcherTimer();
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 async void LoadVideo()
{
InitializeContols();
captions = grid.Children[2] as LiveCaptions;
timer.Tick += UpdateSeek;
timer.Start();
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:hh\\:mm\\:ss}" : $"{elapsed:mm\\:ss}";
remainingTime.Text = remaining.Hours > 0 ? $"{remaining:hh\\:mm\\:ss}" : $"{remaining:mm\\:ss}";
#region Retrieving info for CC and Media streams
//Loading streams
streamInfo = await new YoutubeClient().GetVideoMediaStreamInfosAsync(videoId);
List<VideoQuality> q = streamInfo.GetAllVideoQualities().ToList();
q.Sort();
q.Reverse();
foreach (VideoQuality i in q)
quality.Items.Add(new ComboBoxItem() { Content = i.GetVideoQualityLabel() });
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
quality.SelectedItem = quality.Items.ToList().Exists(x => (x as ComboBoxItem).Content as string == s) ? quality.Items.Find(x => (x as ComboBoxItem).Content as string == s) : quality.Items.First();
//Loading captions
ccInfo = await new YoutubeClient().GetVideoClosedCaptionTrackInfosAsync(videoId);
foreach (ClosedCaptionTrackInfo cc in ccInfo)
{
subsLang.Items.Add(new ComboBoxItem()
{
Content = string.Format("{0}{1}", CultureInfo.GetCultureInfo(cc.Language.Code).DisplayName, cc.IsAutoGenerated ? " (Auto-generated)" : ""),
Tag = cc
});
}
if (ccInfo.Count > 0)
subsLang.SelectedIndex = 0;
else
captionsBtn.Visibility = Visibility.Collapsed;
#endregion
//quality_SelectionChanged(this, null);
}
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}";
((TextBlock)errorPlate.Children[2]).Text = $"Error type: {e.GetType()}";
((TextBlock)errorPlate.Children[3]).Text = $"Message: {e.Message}";
((Grid)errorPlate.Parent).Visibility = Visibility.Visible;
}
private async void SystemControls_Engaged(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
switch (args.Button)
{
case SystemMediaTransportControlsButton.Pause:
videoSource.Pause();
break;
case SystemMediaTransportControlsButton.Play:
videoSource.Play();
break;
case SystemMediaTransportControlsButton.Next:
NextClicked.Invoke(this, null);
break;
}
});
}
void Elapsed(object sender, object e)
{
controls.Visibility = Visibility.Collapsed;
if (!MiniView)
touchCentral.Visibility = Visibility.Collapsed;
if (pointerCaptured)
Window.Current.CoreWindow.PointerCursor = null;
seekIndicator.Visibility = Visibility.Collapsed;
ctrlsFadeTimer?.Stop();
}
public void UpdateSize()
{
if(MiniView)
Height = Window.Current.Bounds.Height;
}
private void volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
double v = volume.Value;
if (v == 0)
muteBtn.Content = openVolume.Content = "\xE74F";
else if (v <= 25 && v > 0)
muteBtn.Content = openVolume.Content = "\xE992";
else if (v <= 50 && v > 25)
muteBtn.Content = openVolume.Content = "\xE993";
else if (v <= 75 && v > 50)
muteBtn.Content = openVolume.Content = "\xE994";
else if (v > 75)
muteBtn.Content = openVolume.Content = "\xE995";
SettingsStorage.Volume = (int) volume.Value;
videoSource.Volume = volume.Value * 0.01;
}
private void muteBtn_Click(object sender, RoutedEventArgs e)
{
if (volume.Value != 0)
{
int v = SettingsStorage.Volume;
volume.Value = 0;
SettingsStorage.Volume = v;
}
else volume.Value = SettingsStorage.Volume;
}
private void UserControl_Tapped(object sender, TappedRoutedEventArgs e)
{
if (e.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch && ctrlsFadeTimer != null)
{
touchCentral.Visibility = Visibility.Visible;
if (ctrlsFadeTimer.IsEnabled)
Elapsed(this, null);
else
ShowControls();
}
}
private void UserControl_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (ctrlsFadeTimer == null)
return;
if (cursorPositionBackup == null)
cursorPositionBackup = Window.Current.CoreWindow.PointerPosition;
else if (cursorPositionBackup == Window.Current.CoreWindow.PointerPosition)
return;
ShowControls();
}
private void UserControl_PointerExited(object sender, PointerRoutedEventArgs e)
{
if (ctrlsFadeTimer.IsEnabled && 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()
{
if (ctrlsFadeTimer == null)
return;
controls.Visibility = Visibility.Visible;
if (MiniView)
seekIndicator.Visibility = Visibility.Visible;
Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Arrow, 0);
ctrlsFadeTimer?.Stop();
ctrlsFadeTimer?.Start();
}
private async void quality_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//try
{
SettingsStorage.RememberedQuality = ((ComboBoxItem)quality.SelectedItem).Content.ToString();
videoSource.Pause();
timecodeBackup = videoSource.Position.TotalSeconds;
if(streamInfo.Muxed.ToList().Exists(x => x.VideoQualityLabel == (quality.SelectedItem as ComboBoxItem).Content.ToString()))
videoSource.Source = streamInfo.Muxed.Find(x => x.VideoQualityLabel == (quality.SelectedItem as ComboBoxItem).Content as string).Url.ToUri();
else
{
VideoStreamInfo videoInfo = streamInfo.Video.Find(i => i.VideoQualityLabel == (quality.SelectedItem as ComboBoxItem).Content.ToString());
AudioStreamInfo audioInfo = streamInfo.Audio.First();
MediaComposition muxedStream = new MediaComposition();
BackgroundAudioTrack audioTrack = await BackgroundAudioTrack.CreateFromFileAsync(await StorageFile.GetFileFromPathAsync(audioInfo.Url));
MediaClip videoTrack = await MediaClip.CreateFromFileAsync(await StorageFile.GetFileFromApplicationUriAsync(videoInfo.Url.ToUri()));
muxedStream.BackgroundAudioTracks.Add(audioTrack);
muxedStream.Clips.Add(videoTrack);
videoSource.SetMediaStreamSource(muxedStream.GenerateMediaStreamSource());
}
needUpdateTimecode = true;
videoSource.Play();
}
//catch
{
}
}
private void subsSwitch_Toggled(object sender, RoutedEventArgs e)
{
if (subsSwitch.IsOn)
subsLang.Visibility = Visibility.Visible;
else
subsLang.Visibility = Visibility.Collapsed;
LoadTrack();
}
void LoadTrack()
{
if (subsSwitch.IsOn)
{
if (ccInfo[subsLang.SelectedIndex].IsAutoGenerated)
captions.Initialize(ccInfo[subsLang.SelectedIndex].Url.Replace("format=3", "format=0"), true);
else
captions.Initialize(ccInfo[subsLang.SelectedIndex].Url);
}
else
captions?.Close();
}
private void fullscreen_Click(object sender, RoutedEventArgs e)
{
fullScreen = !fullScreen;
SetFullSize.Invoke(this, fullScreen);
Methods.MainPage.Fullscreen(fullScreen);
if(fullScreen)
{
ApplicationView.GetForCurrentView().TryEnterFullScreenMode();
fullscreen.Content = "\xE1D8";
Height = Methods.MainPage.Height;
}
else
{
ApplicationView.GetForCurrentView().ExitFullScreenMode();
fullscreen.Content = "\xE1D9";
Height = double.NaN;
}
}
private void play_Click(object sender, RoutedEventArgs e)
{
if (videoSource.CurrentState == MediaElementState.Playing)
videoSource.Pause();
else if (videoSource.CurrentState == MediaElementState.Paused)
videoSource.Play();
}
private void videoSource_Opened(object sender, RoutedEventArgs arg)
{
if (SettingsStorage.Autoplay)
play_Click(this, null);
}
private void videoSource_CurrentStateChanged(object sender, RoutedEventArgs e)
{
if(videoSource.CurrentState == MediaElementState.Playing && needUpdateTimecode)
{
videoSource.Position = TimeSpan.FromSeconds(timecodeBackup);
needUpdateTimecode = false;
}
switch(videoSource.CurrentState)
{
case MediaElementState.Buffering:
bufferingBar.Visibility = Visibility.Visible;
seek.IsEnabled = false;
play.IsEnabled = false;
touchPlay.IsEnabled = false;
play.Content = "\xE102";
touchPlay.Content = "\xE102";
systemControls.PlaybackStatus = MediaPlaybackStatus.Paused;
break;
case MediaElementState.Paused:
bufferingBar.Visibility = Visibility.Collapsed;
seek.IsEnabled = true;
play.IsEnabled = true;
touchPlay.IsEnabled = true;
play.Content = "\xE102";
touchPlay.Content = "\xE102";
systemControls.PlaybackStatus = MediaPlaybackStatus.Paused;
break;
case MediaElementState.Playing:
bufferingBar.Visibility = Visibility.Collapsed;
seek.IsEnabled = true;
play.IsEnabled = true;
touchPlay.IsEnabled = true;
seekTimer.Start();
play.Content = "\xE103";
touchPlay.Content = "\xE103";
systemControls.PlaybackStatus = MediaPlaybackStatus.Playing;
break;
default:
bufferingBar.Visibility = Visibility.Collapsed;
systemControls.PlaybackStatus = MediaPlaybackStatus.Closed;
break;
}
//SecretsVault.HistoryAdd(videoId, elapsed, total);
}
private async void miniView_Click(object sender, RoutedEventArgs e)
{
ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
MiniView = !MiniView;
SetFullSize(this, MiniView);
if (MiniView)
{
if (fullScreen)
{
fullscreen.Content = "\xE740";
fullScreen = false;
}
await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.CompactOverlay);
pointerCaptured = false;
titleBar.ButtonBackgroundColor = Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
mainControls.Visibility = Visibility.Collapsed;
header.Visibility = Visibility.Collapsed;
touchCentral.Visibility = Visibility.Visible;
miniViewExit.Visibility = Visibility.Visible;
touchBack10.FontSize = touchFwd30.FontSize = 20;
touchPlay.FontSize = 50;
Methods.MainPage.Fullscreen(true);
}
else
{
await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.Default);
mainControls.Visibility = Visibility.Visible;
header.Visibility = Visibility.Visible;
touchCentral.Visibility = Visibility.Collapsed;
miniViewExit.Visibility = Visibility.Collapsed;
touchBack10.FontSize = touchFwd30.FontSize = 40;
touchPlay.FontSize = 100;
Methods.MainPage.Fullscreen(false);
Height = double.NaN;
}
}
private void seek_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
elapsed = TimeSpan.FromSeconds(seek.Value);
remaining = total.Subtract(elapsed);
elapsedTime.Text = elapsed.Hours > 0 ? $"{elapsed:hh\\:mm\\:ss}" : $"{elapsed:mm\\:ss}";
remainingTime.Text = remaining.Hours > 0 ? $"{remaining:hh\\:mm\\:ss}" : $"{remaining:mm\\:ss}";
}
private void seek_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
{
videoSource.Position = elapsed;
}
private void fwd30_Click(object sender, RoutedEventArgs e)
{
if(remaining.TotalSeconds >= 30)
videoSource.Position = elapsed.Add(TimeSpan.FromSeconds(30));
}
private void back10_Click(object sender, RoutedEventArgs e)
{
if (elapsed.TotalSeconds >= 10)
videoSource.Position = elapsed.Subtract(TimeSpan.FromSeconds(10));
}
private void next_Click(object sender, RoutedEventArgs e)
{
NextClicked.Invoke(this, null);
}
private void matureDismiss_Click(object sender, RoutedEventArgs e)
{
if ((bool)matureDisable.IsChecked)
SettingsStorage.Mature = MatureState.Allowed;
else
SettingsStorage.Mature = MatureState.AllowedOnce;
Methods.MainPage.GoToVideo(videoId, Methods.MainPage.GetPlaylist());
}
private void signin_Click(object sender, RoutedEventArgs e)
{
SecretsVault.Authorize();
}
public void Pause()
{
videoSource.Pause();
}
public void minimize_Click(object sender, RoutedEventArgs e)
{
if(fullScreen)
{
ApplicationView.GetForCurrentView().ExitFullScreenMode();
fullscreen.Content = "\xE740";
fullScreen = false;
Methods.MainPage.Fullscreen(false);
}
else
SetFullSize.Invoke(this, true);
Width = 432;
Height = 243;
MiniView = true;
Methods.MainPage.MinimizeVideo();
mainControls.Visibility = Visibility.Collapsed;
header.Visibility = Visibility.Collapsed;
touchCentral.Visibility = Visibility.Visible;
maximize.Visibility = Visibility.Visible;
close.Visibility = Visibility.Visible;
touchBack10.FontSize = touchFwd30.FontSize = 20;
touchPlay.FontSize = 50;
}
private void close_Click(object sender, RoutedEventArgs e)
{
systemControls.IsEnabled = false;
pointerCaptured = false;
Elapsed(this, null);
Methods.MainPage.CloseVideo();
}
private void maximize_Click(object sender, RoutedEventArgs e)
{
SetFullSize.Invoke(this, false);
Width = double.NaN;
Height = double.NaN;
MiniView = false;
Methods.MainPage.MaximizeVideo();
mainControls.Visibility = Visibility.Visible;
header.Visibility = Visibility.Visible;
touchCentral.Visibility = Visibility.Collapsed;
maximize.Visibility = Visibility.Collapsed;
close.Visibility = Visibility.Collapsed;
touchBack10.FontSize = touchFwd30.FontSize = 40;
touchPlay.FontSize = 100;
}
private void cast_Click(object sender, RoutedEventArgs e)
{
if(videoSource.Source != null)
{
if (videoSource.CurrentState != MediaElementState.Paused)
videoSource.Pause();
CastingDevicePicker picker = new CastingDevicePicker();
picker.Filter.SupportsVideo = true;
picker.CastingDeviceSelected += Picker_CastingDeviceSelected;
Point positinon = cast.TransformToVisual(Window.Current.Content).TransformPoint(new Point(0, 0));
picker.Show(new Rect(positinon.X, positinon.Y, cast.ActualWidth, cast.ActualHeight), Windows.UI.Popups.Placement.Below);
}
}
private async void Picker_CastingDeviceSelected(CastingDevicePicker sender, CastingDeviceSelectedEventArgs args)
{
CastingConnection connection = args.SelectedCastingDevice.CreateCastingConnection();
await connection.RequestStartCastingAsync(videoSource.GetAsCastingSource());
}
private void playPauseArea_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
if (MiniView && ApplicationView.GetForCurrentView().ViewMode == ApplicationViewMode.CompactOverlay)
miniView_Click(this, null);
else if (MiniView && ApplicationView.GetForCurrentView().ViewMode == ApplicationViewMode.Default)
maximize_Click(this, null);
else if (fullScreen)
fullscreen_Click(this, null);
else if (!MiniView && !fullScreen)
fullscreen_Click(this, null);
}
private void playPauseArea_Tapped(object sender, TappedRoutedEventArgs e)
{
if (e.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse && !MiniView)
play_Click(this, null);
}
public void KeyUpPressed(object sender, KeyRoutedEventArgs e)
{
switch(e.Key)
{
case VirtualKey.Escape:
case VirtualKey.F11:
if (fullScreen)
fullscreen_Click(this, null);
break;
case VirtualKey.Space:
play_Click(this, null);
break;
case VirtualKey.Left:
back10_Click(this, null);
break;
case VirtualKey.Right:
fwd30_Click(this, null);
break;
}
}
private void subsLang_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
LoadTrack();
}
private void videoSource_BufferingProgressChanged(object sender, RoutedEventArgs e)
{
bufferingLevel.Value = videoSource.BufferingProgress * 100;
}
private void GotoLive_Click(object sender, RoutedEventArgs e)
{
}
}
}