Archived
1
0

Now can download videos

This commit is contained in:
Michael Gordeev
2018-10-21 21:59:35 +03:00
parent 3bca3a30be
commit fb3b88a046
11 changed files with 142 additions and 116 deletions
+6 -4
View File
@@ -5,6 +5,8 @@ using Windows.Storage;
using FoxTube.Classes; using FoxTube.Classes;
using Newtonsoft.Json; using Newtonsoft.Json;
using Windows.UI.Popups; using Windows.UI.Popups;
using YoutubeExplode.Models.MediaStreams;
using Google.Apis.YouTube.v3.Data;
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
@@ -32,14 +34,14 @@ namespace FoxTube.Controls
catch { } catch { }
} }
public void Add(string url) public void Add(MediaStreamInfo info, Video meta, string qualty)
{ {
items.Add(new DownloadItem(url)); items.Add(new DownloadItem(info, meta, qualty));
} }
private void Item_DownloadCanceled(object sender, params object[] e) public void Remove(string id)
{ {
items.Remove(sender as DownloadItem); items.Remove(items.Find(x => x.Container.Id == id));
} }
public async void QuitPrompt() public async void QuitPrompt()
+4 -3
View File
@@ -1,5 +1,5 @@
using System; using System;
using YoutubeExplode.Models.MediaStreams; using Windows.Storage;
namespace FoxTube.Classes namespace FoxTube.Classes
{ {
@@ -8,9 +8,10 @@ namespace FoxTube.Classes
public string Title { get; set; } public string Title { get; set; }
public string Channel { get; set; } public string Channel { get; set; }
public string Id { get; set; } public string Id { get; set; }
public Uri Path { get; set; } public Uri Path => File.Path.ToUri();
public Uri Thumbnail { get; set; } public Uri Thumbnail { get; set; }
public VideoQuality Quality { get; set; } public string Quality { get; set; }
public TimeSpan Duration { get; set; } public TimeSpan Duration { get; set; }
public StorageFile File { get; set; }
} }
} }
+14
View File
@@ -1,6 +1,8 @@
using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3;
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Web; using System.Web;
using Windows.ApplicationModel.Core; using Windows.ApplicationModel.Core;
@@ -31,6 +33,18 @@ namespace FoxTube
return new Uri(url); return new Uri(url);
} }
public static string ReplaceInvalidChars(this string str, char newValue)
{
foreach (char i in Path.GetInvalidFileNameChars())
str = str.Replace(i, newValue);
return str;
}
public static string Last(this string[] arr)
{
return arr[arr.Length - 1];
}
public static string GetAgo(DateTime dateTime) public static string GetAgo(DateTime dateTime)
{ {
TimeSpan span = DateTime.Now - dateTime; TimeSpan span = DateTime.Now - dateTime;
+4 -3
View File
@@ -10,7 +10,7 @@
d:DesignWidth="1500"> d:DesignWidth="1500">
<!--<Button HorizontalAlignment="Stretch" Background="WhiteSmoke" Height="100" Padding="0" HorizontalContentAlignment="Stretch"/>--> <!--<Button HorizontalAlignment="Stretch" Background="WhiteSmoke" Height="100" Padding="0" HorizontalContentAlignment="Stretch"/>-->
<Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Height="100"> <Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Height="100" HorizontalAlignment="Stretch" Margin="5">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
<ColumnDefinition/> <ColumnDefinition/>
@@ -19,10 +19,11 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Image Name="thumbnail" Source="/Assets/videoThumbSample.png"/> <Image Name="thumbnail" Source="/Assets/videoThumbSample.png"/>
<TextBlock Name="title" Grid.Column="1" Margin="5" TextWrapping="WrapWholeWords" Text="[Title]" FontSize="20" MaxLines="3"/> <TextBlock Name="title" Grid.Column="1" Margin="5" TextWrapping="WrapWholeWords" Text="[Title]" FontSize="20" MaxLines="2"/>
<TextBlock Margin="5" Name="path" Grid.Column="1" VerticalAlignment="Bottom" Text="C://Users/Michael Gordeev/Downloads/[Title].mp4" Foreground="LightGray"/>
<StackPanel Grid.Column="2" Margin="5"> <StackPanel Grid.Column="2" Margin="5">
<TextBlock Text="Extension:" Foreground="Gray"/> <TextBlock Text="Extension:" Foreground="Gray" Name="ext"/>
<TextBlock Text="Quality:" Foreground="Gray" Name="quality"/> <TextBlock Text="Quality:" Foreground="Gray" Name="quality"/>
<TextBlock Text="Duration:" Foreground="Gray" Name="duration"/> <TextBlock Text="Duration:" Foreground="Gray" Name="duration"/>
<TextBlock Text="Author:" Foreground="Gray" Name="channel"/> <TextBlock Text="Author:" Foreground="Gray" Name="channel"/>
+86 -40
View File
@@ -7,6 +7,14 @@ using Windows.UI.Xaml.Media.Imaging;
using Windows.System; using Windows.System;
using FoxTube.Classes; using FoxTube.Classes;
using YoutubeExplode.Models.MediaStreams; using YoutubeExplode.Models.MediaStreams;
using YoutubeExplode;
using Windows.Storage;
using Google.Apis.YouTube.v3.Data;
using System.Threading;
using System.Xml;
using Windows.UI.Popups;
using Windows.Storage.Pickers;
using System.Diagnostics;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
@@ -16,11 +24,18 @@ namespace FoxTube.Controls
{ {
public DownloadItemContainer Container { get; private set; } public DownloadItemContainer Container { get; private set; }
public bool InProgress { get; set; } = false; public bool InProgress { get; set; } = false;
public DownloadItem(string url) YoutubeClient client = new YoutubeClient();
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token;
Progress<double> progress = new Progress<double>();
public DownloadItem(MediaStreamInfo info, Video meta, string q)
{ {
this.InitializeComponent(); this.InitializeComponent();
Download(url); Download(info, meta, q);
} }
public DownloadItem(DownloadItemContainer container) public DownloadItem(DownloadItemContainer container)
@@ -29,11 +44,14 @@ namespace FoxTube.Controls
Container = container; Container = container;
if (!File.Exists(container.Path.AbsolutePath)) if (!File.Exists(container.Path.AbsolutePath))
throw new FileNotFoundException(); {
Methods.MainPage.Agent.Remove(Container.Id);
return;
}
title.Text = Container.Title; title.Text = Container.Title;
thumbnail.Source = new BitmapImage(Container.Thumbnail); thumbnail.Source = new BitmapImage(Container.Thumbnail);
quality.Text = $"Quality: {Container.Quality.GetVideoQualityLabel()}"; quality.Text = $"Quality: {Container.Quality}";
duration.Text = $"Duration: {Container.Duration}"; duration.Text = $"Duration: {Container.Duration}";
channel.Text = $"Author: {Container.Channel}"; channel.Text = $"Author: {Container.Channel}";
@@ -41,41 +59,71 @@ namespace FoxTube.Controls
donePanel.Visibility = Visibility.Visible; donePanel.Visibility = Visibility.Visible;
} }
void Download(string url) async void Download(MediaStreamInfo info, Video meta, string q)
{ {
InProgress = true;
Container = new DownloadItemContainer();
token = new CancellationTokenSource().Token;
progress.ProgressChanged += UpdateInfo;
FolderPicker picker = new FolderPicker()
{
SuggestedStartLocation = PickerLocationId.Downloads,
ViewMode = PickerViewMode.Thumbnail
};
picker.FileTypeFilter.Add(".shit"); //Because overwise it trhows an exception
StorageFolder folder = await picker.PickSingleFolderAsync();
if (folder == null)
Cancel();
Container.File = await folder.CreateFileAsync($"{meta.Snippet.Title.ReplaceInvalidChars('_')}.{info.Container.GetFileExtension()}", CreationCollisionOption.GenerateUniqueName);
//TO-DO: Create toast
Container.Channel = meta.Snippet.ChannelTitle;
Container.Duration = XmlConvert.ToTimeSpan(meta.ContentDetails.Duration);
Container.Id = meta.Id;
Container.Quality = q;
Container.Thumbnail = meta.Snippet.Thumbnails.Medium.Url.ToUri();
Container.Title = meta.Snippet.Title;
thumbnail.Source = new BitmapImage(new Uri(meta.Snippet.Thumbnails.Medium.Url));
title.Text = meta.Snippet.Title;
ext.Text = $"Extension: {info.Container.GetFileExtension()}";
quality.Text = $"Quality: {q}";
duration.Text = $"Duration: {XmlConvert.ToTimeSpan(meta.ContentDetails.Duration)}";
channel.Text = $"Author: {meta.Snippet.ChannelTitle}";
path.Text = Container.File.Path;
progressPanel.Visibility = Visibility.Visible;
donePanel.Visibility = Visibility.Collapsed;
await client.DownloadMediaStreamAsync(info, await Container.File.OpenStreamForWriteAsync(), progress, token);
progressPanel.Visibility = Visibility.Collapsed;
donePanel.Visibility = Visibility.Visible;
InProgress = false;
} }
private void UpdateInfo(object sender, DownloadProgressChangedEventArgs e) private void UpdateInfo(object sender, double e)
{ {
progressBar.Value = e.ProgressPercentage; status.Text = "Downloading";
perc.Text = $"{e.ProgressPercentage}%"; progressBar.Value = e;
perc.Text = $"{(int)e}%";
//TO-DO: Update toast
} }
private void DownloadCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) private void DownloadCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{ {
/*progressPanel.Visibility = Visibility.Collapsed; //TO-DO: Update toast
donePanel.Visibility = Visibility.Visible;
string node = $@"<item>
<title{title.Text}></title>
<snippet>
<quality>{quality.Text.Split(' ')[1]}</quality>
<duration>{duration.Text.Split(' ')[1]}</duration>
<author>{channel.Text.Split(' ')[1]}</author>
</snippet>
<details>
<path>{uri}</path>
<id>{Id}</id>
</details>
</item>";
DownloadComplete.Invoke(this, node);*/
} }
private async void open_Click(object sender, RoutedEventArgs e) private async void open_Click(object sender, RoutedEventArgs e)
{ {
await Launcher.LaunchUriAsync(Container.Path); await Launcher.LaunchFileAsync(Container.File);
} }
private void gotoOriginal_Click(object sender, RoutedEventArgs e) private void gotoOriginal_Click(object sender, RoutedEventArgs e)
@@ -83,30 +131,28 @@ namespace FoxTube.Controls
Methods.MainPage.GoToVideo(Container.Id); Methods.MainPage.GoToVideo(Container.Id);
} }
public void Cancel() public async void Cancel()
{ {
status.Text = "Cancelling...";
progressBar.IsIndeterminate = true;
cancel.IsEnabled = false;
cts.Cancel();
await Container.File.DeleteAsync();
Methods.MainPage.Agent.Remove(Container.Id);
} }
private void cancel_Click(object sender, RoutedEventArgs e) private async void cancel_Click(object sender, RoutedEventArgs e)
{ {
/*if(client.IsBusy) if(InProgress)
{ {
MessageDialog dialog = new MessageDialog("Are you sure?", "Cancelling download"); MessageDialog dialog = new MessageDialog("Are you sure?", "Cancelling download");
dialog.Commands.Add(new UICommand("Yes", (command) => dialog.Commands.Add(new UICommand("Yes", (command) => Cancel()));
{
status.Text = "Cancelling...";
progressBar.IsIndeterminate = true;
cancel.IsEnabled = false;
client.CancelAsync();
DownloadCanceled.Invoke(this, null);
}));
dialog.Commands.Add(new UICommand("No")); dialog.Commands.Add(new UICommand("No"));
dialog.DefaultCommandIndex = 1; dialog.DefaultCommandIndex = 1;
await dialog.ShowAsync(); await dialog.ShowAsync();
}*/ }
} }
} }
} }
-3
View File
@@ -431,9 +431,6 @@
<PackageReference Include="runtime.win10-arm64.runtime.native.System.IO.Compression"> <PackageReference Include="runtime.win10-arm64.runtime.native.System.IO.Compression">
<Version>4.3.2</Version> <Version>4.3.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Syroot.Windows.IO.KnownFolders">
<Version>1.2.0</Version>
</PackageReference>
<PackageReference Include="YoutubeExplode"> <PackageReference Include="YoutubeExplode">
<Version>4.4.0</Version> <Version>4.4.0</Version>
</PackageReference> </PackageReference>
+3 -22
View File
@@ -9,28 +9,9 @@
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Padding="5"> <ScrollViewer>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel> <StackPanel>
<TextBlock FontSize="28" Text="Downloads"/> <ItemsControl Name="stack"/>
<Grid VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button Name="openFolder" Click="openFolder_Click" Content="Open folder" Margin="5"/>
<TextBlock Name="path" IsTextSelectionEnabled="True" Grid.Column="1" Text="C://Users/Admin/Downloads" VerticalAlignment="Center"/>
<Button Name="changePath" Click="changePath_Click" Grid.Column="2" Content="Change path" Margin="5"/>
</Grid>
</StackPanel> </StackPanel>
<ScrollViewer Grid.Row="1"> </ScrollViewer>
<StackPanel Margin="5" Name="stack">
<ListView ItemsSource="{Binding Path=Methods.MainPage.agent.items}" SelectionMode="None"/>
</StackPanel>
</ScrollViewer>
</Grid>
</Page> </Page>
+3 -9
View File
@@ -22,14 +22,13 @@ namespace FoxTube.Pages
/// </summary> /// </summary>
public sealed partial class Downloads : Page public sealed partial class Downloads : Page
{ {
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
public Downloads() public Downloads()
{ {
this.InitializeComponent(); this.InitializeComponent();
path.Text = settings.Values["defaultDownload"] as string; stack.ItemsSource = Methods.MainPage.Agent.items;
} }
private async void changePath_Click(object sender, RoutedEventArgs e) /*private async void changePath_Click(object sender, RoutedEventArgs e)
{ {
FolderPicker picker = new FolderPicker() FolderPicker picker = new FolderPicker()
{ {
@@ -42,11 +41,6 @@ namespace FoxTube.Pages
if (p != null) if (p != null)
settings.Values["defaultDownload"] = p.Path; settings.Values["defaultDownload"] = p.Path;
path.Text = settings.Values["defaultDownload"] as string; path.Text = settings.Values["defaultDownload"] as string;
} }*/
private async void openFolder_Click(object sender, RoutedEventArgs e)
{
await Launcher.LaunchFolderAsync( await StorageFolder.GetFolderFromPathAsync(settings.Values["defaultDownload"] as string));
}
} }
} }
-4
View File
@@ -24,7 +24,6 @@ using System.Net;
using Windows.UI.Popups; using Windows.UI.Popups;
using Windows.Networking.Connectivity; using Windows.Networking.Connectivity;
using Windows.UI.Core; using Windows.UI.Core;
using Syroot.Windows.IO;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
@@ -72,9 +71,6 @@ namespace FoxTube
if (settings.Values["safeSearch"] == null) if (settings.Values["safeSearch"] == null)
settings.Values.Add("safeSearch", 0); settings.Values.Add("safeSearch", 0);
if (settings.Values["defaultDownload"] == null)
settings.Values.Add("defaultDownload", Syroot.Windows.IO.KnownFolders.Downloads.Path + "\\DownloadedVideos");
if (settings.Values["notificationsHistory"] == null) if (settings.Values["notificationsHistory"] == null)
{ {
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
+1 -1
View File
@@ -33,7 +33,7 @@ namespace FoxTube.Pages.SettingsPages
this.InitializeComponent(); this.InitializeComponent();
language.SelectedIndex = (string)settings.Values["language"] == "en-US"? 0 : 1; language.SelectedIndex = (string)settings.Values["language"] == "en-US"? 0 : 1;
quality.SelectedIndex = (int)settings.Values["quality"]; quality.SelectedItem = quality.Items.ToList().Find(x => (x as ComboBoxItem).Tag as string == (string)settings.Values["quality"]);
newVideo.IsOn = (bool)settings.Values["newVideoNotification"]; newVideo.IsOn = (bool)settings.Values["newVideoNotification"];
+21 -27
View File
@@ -17,6 +17,8 @@ using Windows.ApplicationModel;
using Windows.Storage.Streams; using Windows.Storage.Streams;
using Windows.UI; using Windows.UI;
using FoxTube.Controls; using FoxTube.Controls;
using YoutubeExplode.Models.MediaStreams;
using YoutubeExplode;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
@@ -235,38 +237,30 @@ namespace FoxTube.Pages
async void LoadDownloads() async void LoadDownloads()
{ {
/*List<YouTubeUri> uris = (await YouTube.GetUrisAsync(item.Id)).ToList(); MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(videoId);
if (uris.Count > 0) foreach(MuxedStreamInfo i in infoSet.Muxed)
foreach (YouTubeUri u in uris) {
MenuFlyoutItem menuItem = new MenuFlyoutItem()
{ {
if (u.HasAudio && u.HasVideo) Text = i.VideoQualityLabel,
{ Tag = new object[] { i, i.VideoQualityLabel }
MenuFlyoutItem menuItem = new MenuFlyoutItem() };
{ menuItem.Click += downloadItemSelected;
Text = Methods.QualityToString(u.VideoQuality), downloadSelector.Items.Add(menuItem);
Tag = u.Uri.AbsoluteUri }
};
menuItem.Click += downloadItemSelected; MenuFlyoutItem audioItem = new MenuFlyoutItem()
downloadSelector.Items.Add(menuItem); {
} Text = "Audio track",
else if (u.HasAudio) Tag = new object[] { infoSet.Audio[0], "Audio only" }
{ };
MenuFlyoutItem menuItem = new MenuFlyoutItem() audioItem.Click += downloadItemSelected;
{ downloadSelector.Items.Add(audioItem);
Text = Methods.QualityToString(u.AudioQuality),
Tag = u.Uri.AbsoluteUri
};
menuItem.Click += downloadItemSelected;
downloadSelector.Items.Add(menuItem);
}
}
else
download.Visibility = Visibility.Collapsed;*/
} }
private void downloadItemSelected(object sender, RoutedEventArgs e) private void downloadItemSelected(object sender, RoutedEventArgs e)
{ {
Methods.MainPage.Agent.Add((sender as MenuFlyoutItem).Tag.ToString()); Methods.MainPage.Agent.Add(((sender as MenuFlyoutItem).Tag as object[])[0] as MediaStreamInfo, item, ((sender as MenuFlyoutItem).Tag as object[])[1] as string);
} }
async void LoadRelatedVideos() async void LoadRelatedVideos()