1.0-dev17 (Subscription page created)

This commit is contained in:
2022-05-05 15:14:26 +02:00
Unverified
parent e23258a638
commit 7a57fb65f3
14 changed files with 1043 additions and 0 deletions

View 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
}
}

View 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) { }
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}

View 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
}
}