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

799 lines
28 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Timers;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Microsoft.Toolkit.Uwp.UI.Animations;
using Google.Apis.YouTube.v3.Data;
using Google.Apis.YouTube.v3;
using Windows.UI.Xaml.Media.Imaging;
using MyToolkit.Multimedia;
using Windows.Networking.Connectivity;
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.Graphics.Display;
using Windows.Media.Casting;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace FoxTube
{
public sealed partial class VideoPlayer : UserControl
{
public string videoId;
private bool miniView = false;
private bool fullScreen = false;
private bool pointerCaptured = false;
public event ObjectEventHandler SetFullSize;
public event ObjectEventHandler NextClicked;
CoreCursor cursorBackup = Window.Current.CoreWindow.PointerCursor;
public TimeSpan elapsed;
TimeSpan remaining;
TimeSpan total;
Video item;
string avatar;
double timecodeBackup;
SystemMediaTransportControls systemControls = SystemMediaTransportControls.GetForCurrentView();
List<YouTubeUri> uris = new List<YouTubeUri>();
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
Timer t = new Timer()
{
Interval = 5000,
Enabled = false
};
Timer seekTimer = new Timer()
{
Interval = 1000,
Enabled = true
};
public VideoPlayer()
{
this.InitializeComponent();
Visibility = Visibility.Collapsed;
if (!ApplicationView.GetForCurrentView().IsViewModeSupported(ApplicationViewMode.CompactOverlay))
miniViewBtn.Visibility = Visibility.Collapsed;;
volume.Value = Convert.ToDouble(settings.Values["volume"]);
videoSource.AutoPlay = (bool)settings.Values["videoAutoplay"];
t.Elapsed += T_Elapsed;
seekTimer.Elapsed += SeekTimer_Elapsed;
}
public async void Initialize(Video meta, string channelAvatar)
{
item = meta;
avatar = channelAvatar;
videoId = item.Id;
#region Checking qualities availability
uris = new List<YouTubeUri>(await YouTube.GetUrisAsync(videoId));
foreach (YouTubeUri i in uris.ToList())
if (!i.HasAudio || !i.HasVideo)
uris.Remove(i);
foreach (YouTubeUri u in uris)
{
Debug.WriteLine("-----------------");
Debug.WriteLine("URI: " + u.Uri);
Debug.WriteLine("Has video: " + u.HasVideo);
Debug.WriteLine("Has audio: " + u.HasAudio);
Debug.WriteLine("Type: " + u.Type);
Debug.WriteLine("Video quality: " + u.VideoQuality);
Debug.WriteLine("Audio quality: " + u.AudioQuality);
Debug.WriteLine("-----------------");
}
foreach(YouTubeUri i in uris)
switch(i.VideoQuality)
{
case YouTubeQuality.Quality2160P:
(quality.Items[0] as ComboBoxItem).Visibility = Visibility.Visible;
break;
case YouTubeQuality.Quality1080P:
(quality.Items[1] as ComboBoxItem).Visibility = Visibility.Visible;
break;
case YouTubeQuality.Quality720P:
(quality.Items[2] as ComboBoxItem).Visibility = Visibility.Visible;
break;
case YouTubeQuality.Quality480P:
(quality.Items[3] as ComboBoxItem).Visibility = Visibility.Visible;
break;
case YouTubeQuality.Quality360P:
(quality.Items[4] as ComboBoxItem).Visibility = Visibility.Visible;
break;
case YouTubeQuality.Quality240P:
(quality.Items[5] as ComboBoxItem).Visibility = Visibility.Visible;
break;
case YouTubeQuality.Quality144P:
(quality.Items[6] as ComboBoxItem).Visibility = Visibility.Visible;
break;
}
int k = (int)settings.Values["quality"];
switch(k)
{
case 0:
foreach(YouTubeUri i in uris)
if(i.VideoQuality == YouTubeQuality.Quality2160P)
{
quality.SelectedIndex = 0;
break;
}
SetFirstQuality();
break;
case 1:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality1080P)
{
quality.SelectedIndex = 1;
break;
}
SetFirstQuality();
break;
case 2:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality720P)
{
quality.SelectedIndex = 2;
break;
}
SetFirstQuality();
break;
case 3:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality480P)
{
quality.SelectedIndex = 3;
break;
}
SetFirstQuality();
break;
case 4:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality360P)
{
quality.SelectedIndex = 4;
break;
}
SetFirstQuality();
break;
case 5:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality240P)
{
quality.SelectedIndex = 5;
break;
}
SetFirstQuality();
break;
case 6:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality144P)
{
quality.SelectedIndex = 6;
break;
}
SetFirstQuality();
break;
}
#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;
t.Start();
Visibility = Visibility.Visible;
}
void SetFirstQuality()
{
switch (uris[0].VideoQuality)
{
case YouTubeQuality.Quality2160P:
quality.SelectedIndex = 0;
break;
case YouTubeQuality.Quality1080P:
quality.SelectedIndex = 1;
break;
case YouTubeQuality.Quality720P:
quality.SelectedIndex = 2;
break;
case YouTubeQuality.Quality480P:
quality.SelectedIndex = 3;
break;
case YouTubeQuality.Quality360P:
quality.SelectedIndex = 4;
break;
case YouTubeQuality.Quality240P:
quality.SelectedIndex = 5;
break;
case YouTubeQuality.Quality144P:
quality.SelectedIndex = 6;
break;
}
}
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;
}
});
}
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;
}
void Elapsed()
{
if(!volumePane.IsOpen && !qualityPane.IsOpen && !subsPane.IsOpen)
{
controls.Visibility = Visibility.Collapsed;
if(!miniView)
touchCentral.Visibility = Visibility.Collapsed;
if (pointerCaptured)
Window.Current.CoreWindow.PointerCursor = null;
seekIndicator.Visibility = Visibility.Collapsed;
t.Stop();
}
}
public void UpdateSize()
{
if(miniView)
{
Height = Window.Current.Bounds.Height;
Debug.WriteLine("Video player aspect ratio has been corrected.");
}
}
private void openVolume_Click(object sender, RoutedEventArgs e)
{
volumePane.IsOpen = true;
}
private void volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
double v = volume.Value;
if (v == 0)
muteBtn.Content = openVolume.Content = "";
else if (v <= 25 && v > 0)
muteBtn.Content = openVolume.Content = "";
else if (v <= 50 && v > 25)
muteBtn.Content = openVolume.Content = "";
else if (v <= 75 && v > 50)
muteBtn.Content = openVolume.Content = "";
else if (v > 75)
muteBtn.Content = openVolume.Content = "";
settings.Values["volume"] = volume.Value;
videoSource.Volume = volume.Value * 0.01;
}
private void openSets_Click(object sender, RoutedEventArgs e)
{
qualityPane.IsOpen = true;
}
private void openSubs_Click(object sender, RoutedEventArgs e)
{
subsPane.IsOpen = true;
subsSwitch.IsOn = !subsSwitch.IsOn;
}
private void muteBtn_Click(object sender, RoutedEventArgs e)
{
if(volume.Value != 0)
{
double v = (double)settings.Values["volume"];
volume.Value = 0;
settings.Values["volume"] = v;
}
else volume.Value = (double)settings.Values["volume"];
}
private void UserControl_Tapped(object sender, TappedRoutedEventArgs e)
{
if (e.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse)
{
touchCentral.Visibility = Visibility.Visible;
if (t.Enabled)
Elapsed();
else
ShowControls();
}
//else play_Click(this, null);
}
private void UserControl_PointerMoved(object sender, PointerRoutedEventArgs e)
{
ShowControls();
}
void ShowControls()
{
controls.Visibility = Visibility.Visible;
if (miniView)
seekIndicator.Visibility = Visibility.Visible;
if (pointerCaptured)
Window.Current.CoreWindow.PointerCursor = cursorBackup;
t.Stop();
t.Start();
}
private void quality_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(uris.Count > 0)
{
videoSource.Pause();
timecodeBackup = videoSource.Position.TotalSeconds;
switch(quality.SelectedIndex)
{
case 0:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality2160P)
{
videoSource.Source = i.Uri;
break;
}
break;
case 1:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality1080P)
{
videoSource.Source = i.Uri;
break;
}
break;
case 2:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality720P)
{
videoSource.Source = i.Uri;
break;
}
break;
case 3:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality480P)
{
videoSource.Source = i.Uri;
break;
}
break;
case 4:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality360P)
{
videoSource.Source = i.Uri;
break;
}
break;
case 5:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality240P)
{
videoSource.Source = i.Uri;
break;
}
break;
case 6:
foreach (YouTubeUri i in uris)
if (i.VideoQuality == YouTubeQuality.Quality144P)
{
videoSource.Source = i.Uri;
break;
}
break;
}
videoSource.Play();
Timer timer = new Timer(1000);
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
}
private async void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
(sender as Timer).Stop();
videoSource.Position = TimeSpan.FromSeconds(timecodeBackup);
});
}
private void subsSwitch_Toggled(object sender, RoutedEventArgs e)
{
}
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_CurrentStateChanged(object sender, RoutedEventArgs e)
{
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;
play.Content = "\xE103";
touchPlay.Content = "\xE103";
systemControls.PlaybackStatus = MediaPlaybackStatus.Playing;
break;
default:
bufferingBar.Visibility = Visibility.Collapsed;
systemControls.PlaybackStatus = MediaPlaybackStatus.Closed;
break;
}
}
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;
CoreApplicationViewTitleBar coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.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);
Methods.MainPage.SetTitleBar();
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.Hours}:00:" : "" + $"{elapsed:mm\\:ss}";
remainingTime.Text = remaining.Hours > 0 ? $"{remaining.Hours}:00:" : "" + $"{remaining:mm\\:ss}";
}
private void seek_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
{
videoSource.Position = elapsed;
}
private void fwd30_Click(object sender, RoutedEventArgs e)
{
videoSource.Position = elapsed.Add(TimeSpan.FromSeconds(30));
}
private void back10_Click(object sender, RoutedEventArgs e)
{
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);
}
private void matureDismiss_Click(object sender, RoutedEventArgs e)
{
if ((bool)matureDisable.IsChecked)
settings.Values.Add("showMature", false);
matureBlock.Visibility = Visibility.Collapsed;
Initialize(item, avatar);
}
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;
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 UserControl_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);
}
}
}