1.0-dev17 (Subscription page created)
This commit is contained in:
15
VDownload.Core/Enums/SubscriptionStatus.cs
Normal file
15
VDownload.Core/Enums/SubscriptionStatus.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Core.Enums
|
||||
{
|
||||
public enum SubscriptionStatus
|
||||
{
|
||||
Added,
|
||||
Loaded,
|
||||
Ready
|
||||
}
|
||||
}
|
||||
15
VDownload.Core/Exceptions/SubscriptionExistsException.cs
Normal file
15
VDownload.Core/Exceptions/SubscriptionExistsException.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Core.Exceptions
|
||||
{
|
||||
public class SubscriptionExistsException : Exception
|
||||
{
|
||||
public SubscriptionExistsException() { }
|
||||
public SubscriptionExistsException(string message) : base(message) { }
|
||||
public SubscriptionExistsException(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
}
|
||||
34
VDownload.Core/Interfaces/IPlaylist.cs
Normal file
34
VDownload.Core/Interfaces/IPlaylist.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.Core.Enums;
|
||||
|
||||
namespace VDownload.Core.Interfaces
|
||||
{
|
||||
public interface IPlaylist
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
// PLAYLIST PROPERTIES
|
||||
string ID { get; }
|
||||
PlaylistSource Source { get; }
|
||||
Uri Url { get; }
|
||||
string Name { get; }
|
||||
IVideo[] Videos { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region METHODS
|
||||
|
||||
// GET PLAYLIST METADATA
|
||||
Task GetMetadataAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
// GET VIDEOS FROM PLAYLIST
|
||||
Task GetVideosAsync(CancellationToken cancellationToken = default);
|
||||
Task GetVideosAsync(int numberOfVideos, CancellationToken cancellationToken = default);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
48
VDownload.Core/Interfaces/IVideo.cs
Normal file
48
VDownload.Core/Interfaces/IVideo.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.Core.Enums;
|
||||
using VDownload.Core.Structs;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace VDownload.Core.Interfaces
|
||||
{
|
||||
public interface IVideo
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
// VIDEO PROPERTIES
|
||||
VideoSource Source { get; }
|
||||
string ID { get; }
|
||||
Uri Url { get; }
|
||||
Metadata Metadata { get; }
|
||||
BaseStream[] BaseStreams { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region METHODS
|
||||
|
||||
// GET VIDEO METADATA
|
||||
Task GetMetadataAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
// GET VIDEO STREAMS
|
||||
Task GetStreamsAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
// DOWNLOAD VIDEO
|
||||
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, BaseStream baseStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region EVENT HANDLERS
|
||||
|
||||
event EventHandler<EventArgs.ProgressChangedEventArgs> DownloadingProgressChanged;
|
||||
event EventHandler<EventArgs.ProgressChangedEventArgs> ProcessingProgressChanged;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
86
VDownload.Core/Services/Sources/Source.cs
Normal file
86
VDownload.Core/Services/Sources/Source.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using VDownload.Core.Enums;
|
||||
using VDownload.Core.Interfaces;
|
||||
|
||||
namespace VDownload.Core.Services.Sources
|
||||
{
|
||||
public static class Source
|
||||
{
|
||||
#region CONSTANTS
|
||||
|
||||
// VIDEO SOURCES REGULAR EXPRESSIONS
|
||||
private static readonly (Regex Regex, VideoSource Type)[] VideoSources = new (Regex Regex, VideoSource Type)[]
|
||||
{
|
||||
(new Regex(@"^https://www.twitch.tv/videos/(?<id>\d+)"), VideoSource.TwitchVod),
|
||||
(new Regex(@"^https://www.twitch.tv/\S+/clip/(?<id>[^?]+)"), VideoSource.TwitchClip),
|
||||
(new Regex(@"^https://clips.twitch.tv/(?<id>[^?]+)"), VideoSource.TwitchClip),
|
||||
};
|
||||
|
||||
// PLAYLIST SOURCES REGULAR EXPRESSIONS
|
||||
private static readonly (Regex Regex, PlaylistSource Type)[] PlaylistSources = new (Regex Regex, PlaylistSource Type)[]
|
||||
{
|
||||
(new Regex(@"^https://www.twitch.tv/(?<id>[^?/]+)"), PlaylistSource.TwitchChannel),
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region METHODS
|
||||
|
||||
// GET VIDEO SOURCE
|
||||
public static IVideo GetVideo(string url)
|
||||
{
|
||||
VideoSource source = VideoSource.Null;
|
||||
string id = string.Empty;
|
||||
foreach ((Regex Regex, VideoSource Type) Source in VideoSources)
|
||||
{
|
||||
Match sourceMatch = Source.Regex.Match(url);
|
||||
if (sourceMatch.Success)
|
||||
{
|
||||
source = Source.Type;
|
||||
id = sourceMatch.Groups["id"].Value;
|
||||
}
|
||||
}
|
||||
return GetVideo(source, id);
|
||||
}
|
||||
public static IVideo GetVideo(VideoSource source, string id)
|
||||
{
|
||||
IVideo videoService = null;
|
||||
switch (source)
|
||||
{
|
||||
case VideoSource.TwitchVod: videoService = new Twitch.Vod(id); break;
|
||||
case VideoSource.TwitchClip: videoService = new Twitch.Clip(id); break;
|
||||
}
|
||||
return videoService;
|
||||
}
|
||||
|
||||
// GET PLAYLIST SOURCE
|
||||
public static IPlaylist GetPlaylist(string url)
|
||||
{
|
||||
PlaylistSource source = PlaylistSource.Null;
|
||||
string id = string.Empty;
|
||||
foreach ((Regex Regex, PlaylistSource Type) Source in PlaylistSources)
|
||||
{
|
||||
Match sourceMatch = Source.Regex.Match(url);
|
||||
if (sourceMatch.Success)
|
||||
{
|
||||
source = Source.Type;
|
||||
id = sourceMatch.Groups["id"].Value;
|
||||
}
|
||||
}
|
||||
return GetPlaylist(source, id);
|
||||
}
|
||||
public static IPlaylist GetPlaylist(PlaylistSource source, string id)
|
||||
{
|
||||
IPlaylist playlistService = null;
|
||||
switch (source)
|
||||
{
|
||||
case PlaylistSource.TwitchChannel: playlistService = new Twitch.Channel(id); break;
|
||||
}
|
||||
return playlistService;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
67
VDownload.Core/Services/Subscription.cs
Normal file
67
VDownload.Core/Services/Subscription.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.Core.Interfaces;
|
||||
|
||||
namespace VDownload.Core.Services
|
||||
{
|
||||
[Serializable]
|
||||
public class Subscription
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public Subscription(IPlaylist playlist)
|
||||
{
|
||||
Playlist = playlist;
|
||||
SavedVideos = Playlist.Videos;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
public IPlaylist Playlist { get; private set; }
|
||||
public IVideo[] SavedVideos { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PUBLIC METHODS
|
||||
|
||||
public async Task<IVideo[]> GetNewVideosAsync()
|
||||
{
|
||||
await Playlist.GetVideosAsync();
|
||||
return GetUnsavedVideos();
|
||||
}
|
||||
|
||||
public async Task<IVideo[]> GetNewVideosAndUpdateAsync()
|
||||
{
|
||||
await Playlist.GetVideosAsync();
|
||||
IVideo[] newVideos = GetUnsavedVideos();
|
||||
SavedVideos = Playlist.Videos;
|
||||
return newVideos;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
private IVideo[] GetUnsavedVideos()
|
||||
{
|
||||
List<IVideo> newVideos = Playlist.Videos.ToList();
|
||||
foreach (IVideo savedVideo in SavedVideos)
|
||||
{
|
||||
newVideos.RemoveAll((v) => v.Source == savedVideo.Source && v.ID == savedVideo.ID);
|
||||
}
|
||||
return newVideos.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
79
VDownload.Core/Services/SubscriptionsCollectionManagement.cs
Normal file
79
VDownload.Core/Services/SubscriptionsCollectionManagement.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.Core.Exceptions;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace VDownload.Core.Services
|
||||
{
|
||||
public static class SubscriptionsCollectionManagement
|
||||
{
|
||||
#region CONSTANTS
|
||||
|
||||
private static readonly StorageFolder SubscriptionFolderLocation = ApplicationData.Current.LocalFolder;
|
||||
private static readonly string SubscriptionsFolderName = "Subscriptions";
|
||||
private static readonly string SubscriptionFileExtension = "vsub";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PUBLIC METHODS
|
||||
|
||||
public static async Task<(Subscription Subscription, StorageFile SubscriptionFile)[]> GetSubscriptionsAsync()
|
||||
{
|
||||
List<(Subscription Subscription, StorageFile SubscriptionFile)> subscriptions = new List<(Subscription Subscription,StorageFile SubscriptionFile)> ();
|
||||
StorageFolder subscriptionsFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(SubscriptionsFolderName, CreationCollisionOption.OpenIfExists);
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
foreach (StorageFile file in await subscriptionsFolder.GetFilesAsync())
|
||||
{
|
||||
if (file.Name.EndsWith(SubscriptionFileExtension))
|
||||
{
|
||||
Stream fileStream = await file.OpenStreamForReadAsync();
|
||||
Subscription subscription = (Subscription)formatter.Deserialize(fileStream);
|
||||
subscriptions.Add((subscription, file));
|
||||
}
|
||||
}
|
||||
return subscriptions.ToArray();
|
||||
}
|
||||
|
||||
public static async Task<StorageFile> CreateSubscriptionFileAsync(Subscription subscription)
|
||||
{
|
||||
StorageFolder subscriptionsFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(SubscriptionsFolderName, CreationCollisionOption.OpenIfExists);
|
||||
try
|
||||
{
|
||||
StorageFile subscriptionFile = await subscriptionsFolder.CreateFileAsync($"{(int)subscription.Playlist.Source}-{subscription.Playlist.ID}.{SubscriptionFileExtension}", CreationCollisionOption.FailIfExists);
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
Stream subscriptionFileStream = await subscriptionFile.OpenStreamForWriteAsync();
|
||||
formatter.Serialize(subscriptionFileStream, subscription);
|
||||
return subscriptionFile;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if ((uint)ex.HResult == 0x800700B7)
|
||||
{
|
||||
throw new SubscriptionExistsException($"Subscription with id \"{(int)subscription.Playlist.Source}-{subscription.Playlist.ID}\" already exists");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task UpdateSubscriptionFileAsync(Subscription subscription, StorageFile subscriptionFile)
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
Stream subscriptionFileStream = await subscriptionFile.OpenStreamForWriteAsync();
|
||||
formatter.Serialize(subscriptionFileStream, subscription);
|
||||
}
|
||||
|
||||
public static async Task DeleteSubscriptionFileAsync(StorageFile subscriptionFile) => await subscriptionFile.DeleteAsync(StorageDeleteOption.PermanentDelete);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
141
VDownload/Strings/en-US/DialogResources.resw
Normal file
141
VDownload/Strings/en-US/DialogResources.resw
Normal file
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Base_CloseButtonText" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="Subscription_Adding_Base_Title" xml:space="preserve">
|
||||
<value>Playlist adding error</value>
|
||||
</data>
|
||||
<data name="Subscription_Adding_InternetNotAvailable_Content" xml:space="preserve">
|
||||
<value>Unable to connect to servers. Check your internet connection.</value>
|
||||
</data>
|
||||
<data name="Subscription_Adding_PlaylistNotFound_Content" xml:space="preserve">
|
||||
<value>Playlist not found. Check the URL.</value>
|
||||
</data>
|
||||
<data name="Subscription_Adding_SubscriptionExists_Content" xml:space="preserve">
|
||||
<value>This playlist has been already subscribed</value>
|
||||
</data>
|
||||
<data name="Subscription_Adding_TwitchAccessTokenNotFound_Content" xml:space="preserve">
|
||||
<value>To be able to subscribe Twitch playlists (Channels), you have to link your Twitch account with VDownload. Go to Sources page to sign in.</value>
|
||||
</data>
|
||||
<data name="Subscription_Adding_TwitchAccessTokenNotValid_Content" xml:space="preserve">
|
||||
<value>There is a problem with linked Twitch account. Check Twitch login status in Sources page.</value>
|
||||
</data>
|
||||
</root>
|
||||
34
VDownload/Views/Sources/MainPage.xaml
Normal file
34
VDownload/Views/Sources/MainPage.xaml
Normal file
@@ -0,0 +1,34 @@
|
||||
<Page
|
||||
x:Class="VDownload.Views.Sources.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:VDownload.Views.Sources"
|
||||
xmlns:cc="using:VDownload.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
|
||||
<Page.Resources>
|
||||
<ResourceDictionary Source="ms-appx:///Resources/Icons.xaml"/>
|
||||
</Page.Resources>
|
||||
|
||||
|
||||
<Grid Padding="20" RowSpacing="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock x:Uid="Sources_HeaderTextBlock" Grid.Row="0" FontSize="28" FontWeight="SemiBold"/>
|
||||
|
||||
<StackPanel Grid.Row="1" Spacing="10">
|
||||
<cc:SettingControl x:Name="TwitchSettingControl" x:Uid="Sources_TwitchSettingControl" Grid.Row="0" Icon="{StaticResource TwitchIcon}" Title="Twitch">
|
||||
<cc:SettingControl.SettingContent>
|
||||
<Button x:Name="TwitchSettingControlLoginButton" x:Uid="Sources_TwitchSettingControl_LoginButton" IsEnabled="False" Click="TwitchSettingControlLoginButton_Click"/>
|
||||
</cc:SettingControl.SettingContent>
|
||||
</cc:SettingControl>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
212
VDownload/Views/Sources/MainPage.xaml.cs
Normal file
212
VDownload/Views/Sources/MainPage.xaml.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
using Microsoft.Toolkit.Uwp.Connectivity;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.UI.WindowManagement;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Hosting;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace VDownload.Views.Sources
|
||||
{
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region EVENT HANDLERS
|
||||
|
||||
protected override async void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
Task[] checkingTasks = new Task[1];
|
||||
|
||||
checkingTasks[0] = CheckTwitch();
|
||||
|
||||
await Task.WhenAll(checkingTasks);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
private async Task CheckTwitch()
|
||||
{
|
||||
try
|
||||
{
|
||||
string twitchAccessToken = await Core.Services.Sources.Twitch.Helpers.Auth.ReadAccessTokenAsync();
|
||||
#pragma warning disable IDE0042 // Deconstruct variable declaration
|
||||
(bool IsValid, string Login, DateTime? ExpirationDate) twitchAccessTokenValidation = await Core.Services.Sources.Twitch.Helpers.Auth.ValidateAccessTokenAsync(twitchAccessToken);
|
||||
#pragma warning restore IDE0042 // Deconstruct variable declaration
|
||||
if (twitchAccessTokenValidation.IsValid)
|
||||
{
|
||||
TwitchSettingControl.Description = $"{ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_Description_LoggedIn")} {twitchAccessTokenValidation.Login}";
|
||||
TwitchSettingControlLoginButton.Content = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_LoginButton_Content_LoggedIn");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (twitchAccessToken != null)
|
||||
{
|
||||
TwitchSettingControl.Description = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_Description_AccessTokenExpired");
|
||||
}
|
||||
else if (twitchAccessTokenValidation.ExpirationDate < DateTime.Now)
|
||||
{
|
||||
TwitchSettingControl.Description = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_Description_NotLoggedIn");
|
||||
}
|
||||
Debug.WriteLine(twitchAccessTokenValidation.ExpirationDate.Value.ToString("dd.MM.yyyy"));
|
||||
TwitchSettingControlLoginButton.Content = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_LoginButton_Content_NotLoggedIn");
|
||||
}
|
||||
TwitchSettingControlLoginButton.IsEnabled = true;
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
if (!NetworkHelper.Instance.ConnectionInformation.IsInternetAvailable)
|
||||
{
|
||||
TwitchSettingControl.Description = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_Description_InternetNotAvailable");
|
||||
TwitchSettingControlLoginButton.Content = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_LoginButton_Content_NotLoggedIn");
|
||||
TwitchSettingControlLoginButton.IsEnabled = false;
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region TWITCH
|
||||
|
||||
|
||||
|
||||
// TWITCH LOGIN BUTTON CLICKED
|
||||
private async void TwitchSettingControlLoginButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
string accessToken = await Core.Services.Sources.Twitch.Helpers.Auth.ReadAccessTokenAsync();
|
||||
var accessTokenValidation = await Core.Services.Sources.Twitch.Helpers.Auth.ValidateAccessTokenAsync(accessToken);
|
||||
if (accessTokenValidation.IsValid)
|
||||
{
|
||||
// Revoke access token
|
||||
await Core.Services.Sources.Twitch.Helpers.Auth.RevokeAccessTokenAsync(accessToken);
|
||||
|
||||
// Delete access token
|
||||
await Core.Services.Sources.Twitch.Helpers.Auth.DeleteAccessTokenAsync();
|
||||
|
||||
// Update Twitch SettingControl
|
||||
TwitchSettingControl.Description = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_Description_NotLoggedIn");
|
||||
TwitchSettingControlLoginButton.Content = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_LoginButton_Content_NotLoggedIn");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open new window
|
||||
AppWindow TwitchAuthWindow = await AppWindow.TryCreateAsync();
|
||||
TwitchAuthWindow.Title = "Twitch Authentication";
|
||||
|
||||
#pragma warning disable CS8305 // Type is for evaluation purposes only and is subject to change or removal in future updates.
|
||||
WebView2 TwitchAuthWebView = new WebView2();
|
||||
await TwitchAuthWebView.EnsureCoreWebView2Async();
|
||||
TwitchAuthWebView.Source = Core.Services.Sources.Twitch.Helpers.Auth.AuthorizationUrl;
|
||||
ElementCompositionPreview.SetAppWindowContent(TwitchAuthWindow, TwitchAuthWebView);
|
||||
|
||||
// NavigationStarting event (only when redirected)
|
||||
TwitchAuthWebView.NavigationStarting += async (s, a) =>
|
||||
{
|
||||
if (new Uri(a.Uri).Host == Core.Services.Sources.Twitch.Helpers.Auth.RedirectUrl.Host)
|
||||
{
|
||||
// Close window
|
||||
await TwitchAuthWindow.CloseAsync();
|
||||
|
||||
// Get response
|
||||
string response = a.Uri.Replace(Core.Services.Sources.Twitch.Helpers.Auth.RedirectUrl.OriginalString, "");
|
||||
|
||||
if (response[1] == '#')
|
||||
{
|
||||
// Get access token
|
||||
accessToken = response.Split('&')[0].Replace("/#access_token=", "");
|
||||
|
||||
// Check token
|
||||
accessTokenValidation = await Core.Services.Sources.Twitch.Helpers.Auth.ValidateAccessTokenAsync(accessToken);
|
||||
|
||||
// Save token
|
||||
await Core.Services.Sources.Twitch.Helpers.Auth.SaveAccessTokenAsync(accessToken);
|
||||
|
||||
// Update Twitch SettingControl
|
||||
TwitchSettingControl.Description = $"{ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_Description_LoggedIn")} {accessTokenValidation.Login}";
|
||||
TwitchSettingControlLoginButton.Content = ResourceLoader.GetForCurrentView().GetString("Sources_TwitchSettingControl_LoginButton_Content_LoggedIn");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignored errors
|
||||
string[] ignoredErrors = new[]
|
||||
{
|
||||
"The user denied you access",
|
||||
};
|
||||
|
||||
// Errors translation
|
||||
Dictionary<string, string> errorsTranslation = new Dictionary<string, string>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Get error info
|
||||
string errorInfo = (response.Split('&')[1].Replace("error_description=", "")).Replace('+', ' ');
|
||||
if (!ignoredErrors.Contains(errorInfo))
|
||||
{
|
||||
// Error
|
||||
ContentDialog loginErrorDialog = new ContentDialog
|
||||
{
|
||||
Title = ResourceLoader.GetForCurrentView().GetString("SourcesTwitchLoginErrorDialogTitle"),
|
||||
Content = errorsTranslation.Keys.Contains(errorInfo) ? errorsTranslation[errorInfo] : $"{ResourceLoader.GetForCurrentView().GetString("SourcesTwitchLoginErrorDialogDescriptionUnknown")} ({errorInfo})",
|
||||
CloseButtonText = ResourceLoader.GetForCurrentView().GetString("CloseErrorDialogButtonText"),
|
||||
};
|
||||
await loginErrorDialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
#pragma warning restore CS8305 // Type is for evaluation purposes only and is subject to change or removal in future updates.
|
||||
|
||||
await TwitchAuthWindow.TryShowAsync();
|
||||
|
||||
// Clear cache
|
||||
TwitchAuthWebView.CoreWebView2.CookieManager.DeleteAllCookies();
|
||||
}
|
||||
}
|
||||
catch (WebException wex)
|
||||
{
|
||||
if (!NetworkHelper.Instance.ConnectionInformation.IsInternetAvailable)
|
||||
{
|
||||
TwitchSettingControl.Description = ResourceLoader.GetForCurrentView().GetString("SourcesTwitchSettingControlDescriptionInternetConnectionError");
|
||||
TwitchSettingControlLoginButton.Content = ResourceLoader.GetForCurrentView().GetString("SourcesTwitchLoginButtonTextNotLoggedIn");
|
||||
TwitchSettingControlLoginButton.IsEnabled = false;
|
||||
ContentDialog internetAccessErrorDialog = new ContentDialog
|
||||
{
|
||||
Title = ResourceLoader.GetForCurrentView().GetString("SourcesTwitchLoginErrorDialogTitle"),
|
||||
Content = ResourceLoader.GetForCurrentView().GetString("SourcesTwitchLoginErrorDialogDescriptionInternetConnectionError"),
|
||||
CloseButtonText = ResourceLoader.GetForCurrentView().GetString("CloseErrorDialogButtonText"),
|
||||
};
|
||||
await internetAccessErrorDialog.ShowAsync();
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<UserControl
|
||||
x:Class="VDownload.Views.Subscriptions.Controls.SubscriptionPanel"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:VDownload.Views.Subscriptions.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
CornerRadius="{ThemeResource ControlCornerRadius}">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="ms-appx:///Resources/Colors.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Background="{ThemeResource SubscriptionsSubscriptionPanelBackgroundColor}" Padding="5" ColumnSpacing="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="TitleTextBlock" Grid.Column="1" FontSize="16" FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||
<TextBlock x:Name="CountTextBlock" x:Uid="Subscriptions_SubscriptionPanel_CountTextBlock" Grid.Column="2" FontSize="12" VerticalAlignment="Center"/>
|
||||
<AppBarButton x:Name="UpdateButton" Grid.Column="3" Width="40" Height="48" Margin="0,-4,0,-4" Icon="Sync" Click="UpdateButton_Click"/>
|
||||
<AppBarButton x:Name="RemoveButton" Grid.Column="4" Width="40" Height="48" Margin="0,-4,0,-4" Icon="Delete" Click="RemoveButton_Click"/>
|
||||
<AppBarButton x:Name="SourceButton" Grid.Column="5" Width="40" Height="48" Margin="0,-4,0,-4" Icon="Link" Click="SourceButton_Click"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.Core.Services;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Storage;
|
||||
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;
|
||||
|
||||
namespace VDownload.Views.Subscriptions.Controls
|
||||
{
|
||||
public sealed partial class SubscriptionPanel : UserControl
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public SubscriptionPanel(Subscription subscription, StorageFile subscriptionFile)
|
||||
{
|
||||
InitializeComponent();
|
||||
Subscription = subscription;
|
||||
SubscriptionFile = subscriptionFile;
|
||||
|
||||
TitleTextBlock.Text = Subscription.Playlist.Name;
|
||||
SourceButton.Icon = new BitmapIcon { UriSource = new Uri($"ms-appx:///Assets/Sources/{Subscription.Playlist.GetType().Namespace.Split(".").Last()}.png"), ShowAsMonochrome = false };
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
private Subscription Subscription { get; set; }
|
||||
private StorageFile SubscriptionFile { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PUBLIC METHODS
|
||||
|
||||
public async Task UpdateNewVideosCounterAsync()
|
||||
{
|
||||
CountTextBlock.Text = (await Subscription.GetNewVideosAsync()).Length.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region EVENT HANDLERS
|
||||
|
||||
private async void RemoveButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await SubscriptionsCollectionManagement.DeleteSubscriptionFileAsync(SubscriptionFile);
|
||||
((StackPanel)Parent).Children.Remove(this);
|
||||
}
|
||||
|
||||
private async void UpdateButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CountTextBlock.Text = ResourceLoader.GetForCurrentView().GetString("Subscriptions_SubscriptionPanel_CountTextBlock_SyncText");
|
||||
await Subscription.GetNewVideosAndUpdateAsync();
|
||||
await SubscriptionsCollectionManagement.UpdateSubscriptionFileAsync(Subscription, SubscriptionFile);
|
||||
CountTextBlock.Text = "0";
|
||||
}
|
||||
|
||||
private async void SourceButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await Windows.System.Launcher.LaunchUriAsync(Subscription.Playlist.Url);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
44
VDownload/Views/Subscriptions/MainPage.xaml
Normal file
44
VDownload/Views/Subscriptions/MainPage.xaml
Normal file
@@ -0,0 +1,44 @@
|
||||
<Page
|
||||
x:Class="VDownload.Views.Subscriptions.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:VDownload.Views.Subscriptions"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Page.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="ms-appx:///Resources/Colors.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid Padding="20" RowSpacing="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock x:Uid="Subscriptions_HeaderTextBlock" Grid.Row="0" FontSize="28" FontWeight="SemiBold"/>
|
||||
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<StackPanel x:Name="SubscriptionsListStackPanel" VerticalAlignment="Stretch" Spacing="10"/>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid Grid.Row="2" VerticalAlignment="Center" Padding="8" CornerRadius="{ThemeResource ControlCornerRadius}" ColumnSpacing="10" Background="{ThemeResource SubscriptionsAddingPanelBackgroundColor}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="AddingTextBox" x:Uid="Subscriptions_AddingTextBox" Grid.Column="0" VerticalAlignment="Center"/>
|
||||
<Button x:Name="AddingButton" x:Uid="Subscriptions_AddingButton" Grid.Column="1" Click="AddingButton_Click"/>
|
||||
<muxc:ProgressRing x:Name="AddingProgressRing" Grid.Column="2" Visibility="Collapsed" Width="15" Height="15" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
148
VDownload/Views/Subscriptions/MainPage.xaml.cs
Normal file
148
VDownload/Views/Subscriptions/MainPage.xaml.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using Microsoft.Toolkit.Uwp.Connectivity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.Core.Exceptions;
|
||||
using VDownload.Core.Interfaces;
|
||||
using VDownload.Core.Services;
|
||||
using VDownload.Core.Services.Sources;
|
||||
using VDownload.Views.Subscriptions.Controls;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Storage;
|
||||
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;
|
||||
|
||||
namespace VDownload.Views.Subscriptions
|
||||
{
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region EVENT HANDLERS
|
||||
|
||||
protected override async void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
(Subscription Subscription, StorageFile SubscriptionFile)[] subscriptions = await SubscriptionsCollectionManagement.GetSubscriptionsAsync();
|
||||
foreach((Subscription Subscription, StorageFile SubscriptionFile) subscription in subscriptions)
|
||||
{
|
||||
AddSubscriptionToList(subscription.Subscription, subscription.SubscriptionFile);
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddingButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
async Task ShowDialog(string localErrorKey)
|
||||
{
|
||||
ContentDialog errorDialog = new ContentDialog
|
||||
{
|
||||
Title = ResourceLoader.GetForCurrentView("DialogResources").GetString("Subscription_Adding_Base_Title"),
|
||||
Content = ResourceLoader.GetForCurrentView("DialogResources").GetString($"Subscription_Adding_{localErrorKey}_Content"),
|
||||
CloseButtonText = ResourceLoader.GetForCurrentView("DialogResources").GetString("Base_CloseButtonText"),
|
||||
};
|
||||
await errorDialog.ShowAsync();
|
||||
AddingProgressRing.Visibility = Visibility.Collapsed;
|
||||
AddingButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
AddingProgressRing.Visibility = Visibility.Visible;
|
||||
AddingButton.IsEnabled = false;
|
||||
|
||||
IPlaylist playlist = Source.GetPlaylist(AddingTextBox.Text); // TODO: Change name of class (method returns Playlist object, not source of playlist)
|
||||
|
||||
if (playlist is null)
|
||||
{
|
||||
await ShowDialog("PlaylistNotFound");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
await playlist.GetMetadataAsync();
|
||||
await playlist.GetVideosAsync();
|
||||
}
|
||||
catch (MediaNotFoundException)
|
||||
{
|
||||
await ShowDialog("PlaylistNotFound");
|
||||
return;
|
||||
}
|
||||
catch (TwitchAccessTokenNotFoundException)
|
||||
{
|
||||
await ShowDialog("TwitchAccessTokenNotFound");
|
||||
return;
|
||||
}
|
||||
catch (TwitchAccessTokenNotValidException)
|
||||
{
|
||||
await ShowDialog("TwitchAccessTokenNotValid");
|
||||
return;
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
if (!NetworkHelper.Instance.ConnectionInformation.IsInternetAvailable)
|
||||
{
|
||||
await ShowDialog("InternetNotAvailable");
|
||||
return;
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
|
||||
Subscription subscription = new Subscription(playlist);
|
||||
|
||||
StorageFile subscriptionFile = null;
|
||||
try
|
||||
{
|
||||
subscriptionFile = await SubscriptionsCollectionManagement.CreateSubscriptionFileAsync(subscription);
|
||||
}
|
||||
catch (SubscriptionExistsException)
|
||||
{
|
||||
await ShowDialog("SubscriptionExists");
|
||||
return;
|
||||
}
|
||||
|
||||
AddSubscriptionToList(subscription, subscriptionFile);
|
||||
|
||||
AddingProgressRing.Visibility = Visibility.Collapsed;
|
||||
AddingButton.IsEnabled = true;
|
||||
AddingTextBox.Text = string.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
private void AddSubscriptionToList(Subscription subscription, StorageFile subscriptionFile)
|
||||
{
|
||||
SubscriptionPanel subscriptionPanel = new SubscriptionPanel(subscription, subscriptionFile);
|
||||
SubscriptionsListStackPanel.Children.Add(subscriptionPanel);
|
||||
subscriptionPanel.UpdateNewVideosCounterAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user