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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user