Archived
1
0
This commit is contained in:
Michael Gordeev
2018-12-12 21:15:38 +03:00
parent aa3214cc60
commit 1105460cae
11 changed files with 179 additions and 88 deletions
+11 -7
View File
@@ -12,6 +12,7 @@ using Windows.ApplicationModel.Background;
using Windows.ApplicationModel.Core; using Windows.ApplicationModel.Core;
using Windows.Globalization; using Windows.Globalization;
using Windows.Storage; using Windows.Storage;
using Windows.System;
using Windows.System.Power; using Windows.System.Power;
using Windows.UI.Notifications; using Windows.UI.Notifications;
using Windows.UI.Popups; using Windows.UI.Popups;
@@ -161,11 +162,6 @@ namespace FoxTube
switch(arguments[0]) switch(arguments[0])
{ {
case "dcancel":
Debug.WriteLine("Cancel has been required");
try { Methods.MainPage.Agent.Remove(arguments[1]); }
catch { }
break;
case "later": case "later":
try try
{ {
@@ -194,6 +190,9 @@ namespace FoxTube
Debug.WriteLine(e.Message); Debug.WriteLine(e.Message);
} }
break; break;
case "download":
await Launcher.LaunchFileAsync(await StorageFile.GetFileFromPathAsync(arguments[1]));
break;
} }
} }
} }
@@ -237,6 +236,12 @@ namespace FoxTube
case "channel": case "channel":
Methods.MainPage.GoToChannel(args[1]); Methods.MainPage.GoToChannel(args[1]);
break; break;
case "download":
Methods.MainPage.GoToDownloads();
break;
case "dcancel":
DownloadAgent.Remove(args[1]);
break;
} }
} }
@@ -273,8 +278,7 @@ namespace FoxTube
await ApplicationData.Current.RoamingFolder.CreateFileAsync("watchlater.json", CreationCollisionOption.ReplaceExisting), await ApplicationData.Current.RoamingFolder.CreateFileAsync("watchlater.json", CreationCollisionOption.ReplaceExisting),
JsonConvert.SerializeObject(SecretsVault.WatchLater));*/ JsonConvert.SerializeObject(SecretsVault.WatchLater));*/
//Saving downloads //Saving downloads
Methods.MainPage.Agent.QuitPrompt(); DownloadAgent.QuitPrompt();
ToastNotificationManager.CreateToastNotifier().Show(Background.Notification.GetInternalToast(null, "All data saved", "", null, null));
deferral.Complete(); deferral.Complete();
} }
} }
+38 -32
View File
@@ -1,70 +1,76 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using Windows.Storage; using Windows.Storage;
using FoxTube.Classes; using FoxTube.Classes;
using Newtonsoft.Json; using Newtonsoft.Json;
using Windows.UI.Popups;
using YoutubeExplode.Models.MediaStreams; using YoutubeExplode.Models.MediaStreams;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using Windows.Foundation; using System.Diagnostics;
using FoxTube.Controls;
namespace FoxTube.Controls namespace FoxTube
{ {
public class DownloadAgent public static class DownloadAgent
{ {
public List<DownloadItem> items = new List<DownloadItem>(); public static List<DownloadItem> items = new List<DownloadItem>();
StorageFolder roaming = ApplicationData.Current.RoamingFolder; private static ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
public IAsyncOperation<IUICommand> prompt; public static StorageFolder Downloads { get; set; }
public DownloadAgent() public static async void Initialize()
{
Initialize();
Windows.UI.Core.Preview.SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += (s, a) => QuitPrompt();
}
public async void Initialize()
{ {
Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists);
try try
{ {
List<DownloadItemContainer> containers = JsonConvert.DeserializeObject<List<DownloadItemContainer>>(await FileIO.ReadTextAsync(await roaming.GetFileAsync("downloads.json"))); List<DownloadItemContainer> containers = JsonConvert.DeserializeObject<List<DownloadItemContainer>>((string)settings.Values["downloads"]);
containers.ForEach(i => items.Add(new DownloadItem(i)));
foreach (DownloadItemContainer i in containers)
try { items.Add(new DownloadItem(i)); }
catch (FileNotFoundException) { }
} }
catch { } catch { }
} }
public void Add(MediaStreamInfo info, Video meta, string qualty) public static void Add(MediaStreamInfo info, Video meta, string qualty)
{ {
items.Add(new DownloadItem(info, meta, qualty)); items.Insert(0, new DownloadItem(info, meta, qualty));
} }
public void Remove(string id) public static void CancelItem(string id)
{
DownloadItem item = items.Find(x => x.Container.Id == id);
if (item == null || !item.InProgress)
return;
item.CancelPrompt();
}
public static void Remove(string id)
{ {
DownloadItem item = items.Find(x => x.Container.Id == id); DownloadItem item = items.Find(x => x.Container.Id == id);
if (item == null) if (item == null)
return; return;
if (item.InProgress) if (item.InProgress)
item.cancel_Click(this, null); item.Cancel();
else else
items.Remove(item); items.Remove(item);
} }
public async void QuitPrompt() public static void QuitPrompt()
{ {
foreach (DownloadItem i in items.FindAll(x => x.InProgress)) foreach (DownloadItem i in items.FindAll(i => i.InProgress))
i.Cancel(); i.Cancel();
items.RemoveAll(x => x.InProgress);
List<DownloadItemContainer> containers = new List<DownloadItemContainer>(); List<DownloadItemContainer> containers = new List<DownloadItemContainer>();
foreach (DownloadItem i in items) items.ForEach(i => containers.Add(i.Container));
containers.Add(i.Container);
await FileIO.WriteTextAsync( string data = JsonConvert.SerializeObject(containers);
await roaming.CreateFileAsync("downloads.json", CreationCollisionOption.ReplaceExisting),
JsonConvert.SerializeObject(containers)); try
{
settings.Values["downloads"] = data;
}
catch
{
settings.Values.Add("downloads", data);
}
} }
} }
} }
+2 -2
View File
@@ -8,10 +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 => File.Path.ToUri(); public string Name { get; set; }
public string Extension { get; set; }
public Uri Thumbnail { get; set; } public Uri Thumbnail { get; set; }
public string Quality { get; set; } public string Quality { get; set; }
public TimeSpan Duration { get; set; } public TimeSpan Duration { get; set; }
public StorageFile File { get; set; }
} }
} }
+2 -2
View File
@@ -20,7 +20,7 @@
</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="2"/> <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"/> <TextBlock Margin="5" Name="path" Grid.Column="1" VerticalAlignment="Bottom" Text="C://Users/Michael Gordeev/Downloads/[Title].mp4" Foreground="LightGray" MaxLines="1" TextWrapping="WrapWholeWords"/>
<StackPanel Grid.Column="2" Margin="5"> <StackPanel Grid.Column="2" Margin="5">
<TextBlock Text="Extension:" Foreground="Gray" Name="ext"/> <TextBlock Text="Extension:" Foreground="Gray" Name="ext"/>
@@ -47,7 +47,7 @@
<TextBlock Name="status" Text="Initializing..." HorizontalAlignment="Left"/> <TextBlock Name="status" Text="Initializing..." HorizontalAlignment="Left"/>
<ProgressBar Name="progressBar" Width="200" Maximum="1" IsIndeterminate="True" Foreground="Red"/> <ProgressBar Name="progressBar" Width="200" Maximum="1" IsIndeterminate="True" Foreground="Red"/>
<TextBlock Name="perc" Text="--%"/> <TextBlock Name="perc" Text="--%"/>
<Button Content="Cancel" Name="cancel" Click="cancel_Click" HorizontalAlignment="Right"/> <Button Content="Cancel" Name="cancel" Click="CancelPrompt" HorizontalAlignment="Right"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>
+41 -27
View File
@@ -15,19 +15,17 @@ using Windows.UI.Popups;
using Windows.Storage.Pickers; using Windows.Storage.Pickers;
using Windows.UI.Notifications; using Windows.UI.Notifications;
using Microsoft.Toolkit.Uwp.Notifications; using Microsoft.Toolkit.Uwp.Notifications;
using Windows.Foundation; using System.Diagnostics;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
public sealed partial class DownloadItem : UserControl public sealed partial class DownloadItem : UserControl
{ {
public DownloadItemContainer Container { get; private set; } public DownloadItemContainer Container { get; private set; }
public StorageFile file;
public bool InProgress { get; set; } = false; public bool InProgress { get; set; } = false;
YoutubeClient client = new YoutubeClient(); YoutubeClient client = new YoutubeClient();
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
CancellationTokenSource cts = new CancellationTokenSource(); CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token; CancellationToken token;
@@ -45,17 +43,28 @@ namespace FoxTube.Controls
this.InitializeComponent(); this.InitializeComponent();
Container = container; Container = container;
if (!File.Exists(container.Path.AbsolutePath)) Initialize();
}
public async void Initialize()
{
try
{ {
Methods.MainPage.Agent.Remove(Container.Id); file = await DownloadAgent.Downloads.GetFileAsync(Container.Name);
}
catch
{
DownloadAgent.Remove(Container.Id);
return; return;
} }
title.Text = Container.Title; title.Text = Container.Title;
path.Text = file.Name;
thumbnail.Source = new BitmapImage(Container.Thumbnail); thumbnail.Source = new BitmapImage(Container.Thumbnail);
quality.Text = $"Quality: {Container.Quality}"; 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}";
ext.Text = $"Extension: {Container.Extension}";
progressPanel.Visibility = Visibility.Collapsed; progressPanel.Visibility = Visibility.Collapsed;
donePanel.Visibility = Visibility.Visible; donePanel.Visibility = Visibility.Visible;
@@ -66,20 +75,11 @@ namespace FoxTube.Controls
InProgress = true; InProgress = true;
Container = new DownloadItemContainer(); Container = new DownloadItemContainer();
token = new CancellationTokenSource().Token; token = cts.Token;
progress.ProgressChanged += UpdateInfo; progress.ProgressChanged += UpdateInfo;
FolderPicker picker = new FolderPicker() file = await DownloadAgent.Downloads.CreateFileAsync($"{meta.Snippet.Title.ReplaceInvalidChars('_')}.{info.Container.GetFileExtension()}", CreationCollisionOption.GenerateUniqueName);
{ Container.Name = file.Name;
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);
ToastContent toastContent = new ToastContent() ToastContent toastContent = new ToastContent()
{ {
@@ -123,6 +123,7 @@ namespace FoxTube.Controls
Container.Quality = q; Container.Quality = q;
Container.Thumbnail = meta.Snippet.Thumbnails.Medium.Url.ToUri(); Container.Thumbnail = meta.Snippet.Thumbnails.Medium.Url.ToUri();
Container.Title = meta.Snippet.Title; Container.Title = meta.Snippet.Title;
Container.Extension = info.Container.GetFileExtension();
thumbnail.Source = new BitmapImage(new Uri(meta.Snippet.Thumbnails.Medium.Url)); thumbnail.Source = new BitmapImage(new Uri(meta.Snippet.Thumbnails.Medium.Url));
title.Text = meta.Snippet.Title; title.Text = meta.Snippet.Title;
@@ -130,19 +131,20 @@ namespace FoxTube.Controls
quality.Text = $"Quality: {q}"; quality.Text = $"Quality: {q}";
duration.Text = $"Duration: {XmlConvert.ToTimeSpan(meta.ContentDetails.Duration)}"; duration.Text = $"Duration: {XmlConvert.ToTimeSpan(meta.ContentDetails.Duration)}";
channel.Text = $"Author: {meta.Snippet.ChannelTitle}"; channel.Text = $"Author: {meta.Snippet.ChannelTitle}";
path.Text = Container.File.Path; path.Text = file.Name;
progressPanel.Visibility = Visibility.Visible; progressPanel.Visibility = Visibility.Visible;
donePanel.Visibility = Visibility.Collapsed; donePanel.Visibility = Visibility.Collapsed;
await client.DownloadMediaStreamAsync(info, await Container.File.OpenStreamForWriteAsync(), progress, token); await client.DownloadMediaStreamAsync(info, await file.OpenStreamForWriteAsync(), progress, token);
DownloadCompleted();
progressPanel.Visibility = Visibility.Collapsed; progressPanel.Visibility = Visibility.Collapsed;
donePanel.Visibility = Visibility.Visible; donePanel.Visibility = Visibility.Visible;
InProgress = false; InProgress = false;
if(!cts.IsCancellationRequested)
DownloadCompleted();
} }
private void UpdateInfo(object sender, double e) private void UpdateInfo(object sender, double e)
@@ -158,7 +160,7 @@ namespace FoxTube.Controls
private void DownloadCompleted() private void DownloadCompleted()
{ {
Windows.Data.Xml.Dom.XmlDocument template = new Windows.Data.Xml.Dom.XmlDocument(); Windows.Data.Xml.Dom.XmlDocument template = new Windows.Data.Xml.Dom.XmlDocument();
template.LoadXml($@"<toast activationType='background' launch='download|{Container.Id}'> template.LoadXml($@"<toast activationType='background' launch='download|{file.Path}'>
<visual> <visual>
<binding template='ToastGeneric'> <binding template='ToastGeneric'>
<text>Download complete</text> <text>Download complete</text>
@@ -177,7 +179,7 @@ namespace FoxTube.Controls
private async void open_Click(object sender, RoutedEventArgs e) private async void open_Click(object sender, RoutedEventArgs e)
{ {
await Launcher.LaunchFileAsync(Container.File); await Launcher.LaunchFileAsync(file);
} }
private void gotoOriginal_Click(object sender, RoutedEventArgs e) private void gotoOriginal_Click(object sender, RoutedEventArgs e)
@@ -193,13 +195,25 @@ namespace FoxTube.Controls
cts.Cancel(); cts.Cancel();
try try
{ {
await Container.File.DeleteAsync(); await file.DeleteAsync();
} }
catch { } catch { }
Methods.MainPage.Agent.Remove(Container.Id);
Windows.Data.Xml.Dom.XmlDocument template = new Windows.Data.Xml.Dom.XmlDocument();
template.LoadXml($@"<toast activationType='foreground' launch='download'>
<visual>
<binding template='ToastGeneric'>
<text>Download canceled</text>
<text>{Container.Title}</text>
</binding>
</visual>
</toast>");
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(template) { Tag = $"download|{Container.Id}" });
DownloadAgent.Remove(Container.Id);
} }
public async void cancel_Click(object sender, RoutedEventArgs e) public async void CancelPrompt(object sender = null, RoutedEventArgs e = null)
{ {
if(InProgress) if(InProgress)
{ {
+11
View File
@@ -51,4 +51,15 @@
</Grid> </Grid>
</Grid> </Grid>
</Button> </Button>
<UserControl.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Icon="Play" Text="Play"/>
<MenuFlyoutItem Icon="Contact" Text="View channel"/>
<MenuFlyoutSeparator/>
<MenuFlyoutItem Icon="Link" Text="Copy link"/>
<MenuFlyoutItem Icon="Share" Text="Share"/>
<MenuFlyoutSeparator/>
<MenuFlyoutItem Icon="Download" Text="Download"/>
</MenuFlyout>
</UserControl.ContextFlyout>
</UserControl> </UserControl>
+3 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp"> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap mp uap3">
<Identity Name="foxtube-5d1cba1f-d7d5-472b-acb7-beb360bab268" Publisher="CN=XFox" Version="1.0.0.0" /> <Identity Name="foxtube-5d1cba1f-d7d5-472b-acb7-beb360bab268" Publisher="CN=XFox" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="5d1cba1f-d7d5-472b-acb7-beb360bab268" PhonePublisherId="00000000-0000-0000-0000-000000000000" /> <mp:PhoneIdentity PhoneProductId="5d1cba1f-d7d5-472b-acb7-beb360bab268" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties> <Properties>
@@ -41,5 +41,7 @@
</Applications> </Applications>
<Capabilities> <Capabilities>
<Capability Name="internetClient" /> <Capability Name="internetClient" />
<uap3:Capability Name="backgroundMediaPlayback" />
<uap:Capability Name="videosLibrary" />
</Capabilities> </Capabilities>
</Package> </Package>
+25 -5
View File
@@ -9,9 +9,29 @@
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer> <Grid>
<StackPanel> <Grid.RowDefinitions>
<ItemsControl Name="stack"/> <RowDefinition Height="auto"/>
</StackPanel> <RowDefinition/>
</ScrollViewer> <RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBlock Name="path" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/>
<Button Grid.Column="1" Content="Open folder" Name="open" Click="Open_Click" VerticalAlignment="Center"/>
</Grid>
<ScrollViewer Grid.Row="1">
<StackPanel Name="stack"/>
</ScrollViewer>
<TextBlock Grid.Row="1" Name="empty" HorizontalAlignment="Center" VerticalAlignment="Top" FontSize="28" Text="You haven't downloaded anything yet" Margin="10" TextWrapping="WrapWholeWords" Foreground="Gray" FontWeight="SemiBold"/>
<CommandBar DefaultLabelPosition="Right" Grid.Row="2">
<AppBarButton Label="Refresh" Icon="Refresh" Click="Refresh"/>
</CommandBar>
</Grid>
</Page> </Page>
+35 -7
View File
@@ -25,18 +25,46 @@ namespace FoxTube.Pages
public Downloads() public Downloads()
{ {
this.InitializeComponent(); this.InitializeComponent();
try SetPath();
{
stack.ItemsSource = Methods.MainPage.Agent.items;
}
catch { }
} }
protected override void OnNavigatedFrom(NavigationEventArgs e) protected override void OnNavigatedFrom(NavigationEventArgs e)
{ {
base.OnNavigatedFrom(e); base.OnNavigatedFrom(e);
stack.ItemsSource = null; stack.Children.Clear();
stack.Items.Clear(); }
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
DownloadAgent.items.ForEach(i =>
{
stack.Children.Add(i);
i.Initialize();
});
empty.Visibility = stack.Children.Count > 0 ? Visibility.Collapsed : Visibility.Visible;
}
void SetPath()
{
path.Text = DownloadAgent.Downloads.Path;
}
void Refresh(object sender, RoutedEventArgs e)
{
stack.Children.Clear();
DownloadAgent.items.ForEach(i =>
{
stack.Children.Add(i);
i.Initialize();
});
empty.Visibility = stack.Children.Count > 0 ? Visibility.Collapsed : Visibility.Visible;
}
private async void Open_Click(object sender, RoutedEventArgs e)
{
await Launcher.LaunchFolderAsync(DownloadAgent.Downloads);
} }
/*private async void changePath_Click(object sender, RoutedEventArgs e) /*private async void changePath_Click(object sender, RoutedEventArgs e)
+8 -2
View File
@@ -39,8 +39,6 @@ namespace FoxTube
public sealed partial class MainPage : Page public sealed partial class MainPage : Page
{ {
public DownloadAgent Agent = new DownloadAgent();
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
Sender s = Sender.None; Sender s = Sender.None;
@@ -96,6 +94,9 @@ namespace FoxTube
SecretsVault.NotPurchased += () => removeAds.Visibility = Visibility.Visible; SecretsVault.NotPurchased += () => removeAds.Visibility = Visibility.Visible;
SecretsVault.CheckAuthorization(); SecretsVault.CheckAuthorization();
SecretsVault.CheckAddons(); SecretsVault.CheckAddons();
DownloadAgent.Initialize();
SetTitleBar(); SetTitleBar();
Initialize(); Initialize();
} }
@@ -362,6 +363,11 @@ namespace FoxTube
content.Navigate(typeof(PlaylistPage), id); content.Navigate(typeof(PlaylistPage), id);
} }
public void GoToDownloads()
{
content.Navigate(typeof(Downloads));
}
private void Page_SizeChanged(object sender, SizeChangedEventArgs e) private void Page_SizeChanged(object sender, SizeChangedEventArgs e)
{ {
if (videoPlaceholder.Content != null) if (videoPlaceholder.Content != null)
+1 -1
View File
@@ -266,7 +266,7 @@ namespace FoxTube.Pages
private void downloadItemSelected(object sender, RoutedEventArgs e) private void downloadItemSelected(object sender, RoutedEventArgs e)
{ {
Methods.MainPage.Agent.Add(((sender as MenuFlyoutItem).Tag as object[])[0] as MediaStreamInfo, item, ((sender as MenuFlyoutItem).Tag as object[])[1] as string); DownloadAgent.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()