1.0-dev17 (Subscription page created)
This commit is contained in:
@@ -4,6 +4,6 @@ namespace VDownload.Core.EventArgs
|
||||
{
|
||||
public class PlaylistSearchSuccessedEventArgs : System.EventArgs
|
||||
{
|
||||
public IPlaylistService PlaylistService { get; set; }
|
||||
public IPlaylist PlaylistService { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@ namespace VDownload.Core.EventArgs
|
||||
{
|
||||
public class VideoSearchSuccessedEventArgs : System.EventArgs
|
||||
{
|
||||
public IVideoService VideoService { get; set; }
|
||||
public IVideo Video { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Core.Exceptions
|
||||
{
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Core.Interfaces
|
||||
{
|
||||
public interface IPlaylistService
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
// PLAYLIST PROPERTIES
|
||||
string ID { get; }
|
||||
Uri PlaylistUrl { get; }
|
||||
string Name { get; }
|
||||
IVideoService[] Videos { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region METHODS
|
||||
|
||||
// GET PLAYLIST METADATA
|
||||
Task GetMetadataAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
// GET VIDEOS FROM PLAYLIST
|
||||
Task GetVideosAsync(int numberOfVideos, CancellationToken cancellationToken = default);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
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 IVideoService
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
// VIDEO PROPERTIES
|
||||
string ID { get; }
|
||||
Uri VideoUrl { 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
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using Windows.Storage;
|
||||
|
||||
namespace VDownload.Core.Services
|
||||
{
|
||||
public class Config
|
||||
public static class Config
|
||||
{
|
||||
#region CONSTANTS
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using VDownload.Core.Enums;
|
||||
|
||||
namespace VDownload.Core.Services
|
||||
{
|
||||
public 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 (VideoSource Type, string ID) GetVideoSource(string url)
|
||||
{
|
||||
foreach ((Regex Regex, VideoSource Type) Source in VideoSources)
|
||||
{
|
||||
Match sourceMatch = Source.Regex.Match(url);
|
||||
if (sourceMatch.Success) return (Source.Type, sourceMatch.Groups["id"].Value);
|
||||
}
|
||||
return (VideoSource.Null, null);
|
||||
}
|
||||
|
||||
// GET PLAYLIST SOURCE
|
||||
public static (PlaylistSource Type, string ID) GetPlaylistSource(string url)
|
||||
{
|
||||
foreach ((Regex Regex, PlaylistSource Type) Source in PlaylistSources)
|
||||
{
|
||||
Match sourceMatch = Source.Regex.Match(url);
|
||||
if (sourceMatch.Success) return (Source.Type, sourceMatch.Groups["id"].Value);
|
||||
}
|
||||
return (PlaylistSource.Null, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -7,19 +7,22 @@ using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.Core.Enums;
|
||||
using VDownload.Core.Exceptions;
|
||||
using VDownload.Core.Interfaces;
|
||||
using VDownload.Core.Services.Sources.Twitch.Helpers;
|
||||
|
||||
namespace VDownload.Core.Services.Sources.Twitch
|
||||
{
|
||||
public class Channel : IPlaylistService
|
||||
[Serializable]
|
||||
public class Channel : IPlaylist
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public Channel(string id)
|
||||
{
|
||||
ID = id;
|
||||
Source = PlaylistSource.TwitchChannel;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -29,9 +32,11 @@ namespace VDownload.Core.Services.Sources.Twitch
|
||||
#region PROPERTIES
|
||||
|
||||
public string ID { get; private set; }
|
||||
public Uri PlaylistUrl { get; private set; }
|
||||
public PlaylistSource Source { get; private set; }
|
||||
public Uri Url { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public IVideoService[] Videos { get; private set; }
|
||||
public IVideo[] Videos { get; private set; }
|
||||
private string UniqueUserID { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -55,14 +60,15 @@ namespace VDownload.Core.Services.Sources.Twitch
|
||||
}
|
||||
|
||||
// Create unified playlist url
|
||||
PlaylistUrl = new Uri($"https://twitch.tv/{ID}");
|
||||
Url = new Uri($"https://twitch.tv/{ID}");
|
||||
|
||||
// Set parameters
|
||||
if (!ID.All(char.IsDigit)) ID = (string)response["id"];
|
||||
UniqueUserID = (string)response["id"];
|
||||
Name = (string)response["display_name"];
|
||||
}
|
||||
|
||||
// GET CHANNEL VIDEOS
|
||||
public async Task GetVideosAsync(CancellationToken cancellationToken = default) => await GetVideosAsync(0, cancellationToken);
|
||||
public async Task GetVideosAsync(int numberOfVideos, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@@ -89,7 +95,7 @@ namespace VDownload.Core.Services.Sources.Twitch
|
||||
JToken response = null;
|
||||
using (WebClient client = await Client.Helix())
|
||||
{
|
||||
client.QueryString.Add("user_id", ID);
|
||||
client.QueryString.Add("user_id", UniqueUserID);
|
||||
client.QueryString.Add("first", count.ToString());
|
||||
client.QueryString.Add("after", pagination);
|
||||
response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/videos"));
|
||||
|
||||
@@ -18,13 +18,15 @@ using Windows.Storage;
|
||||
|
||||
namespace VDownload.Core.Services.Sources.Twitch
|
||||
{
|
||||
public class Clip : IVideoService
|
||||
[Serializable]
|
||||
public class Clip : IVideo
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public Clip(string id)
|
||||
{
|
||||
ID = id;
|
||||
Source = VideoSource.TwitchClip;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -33,8 +35,9 @@ namespace VDownload.Core.Services.Sources.Twitch
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
public VideoSource Source { get; private set; }
|
||||
public string ID { get; private set; }
|
||||
public Uri VideoUrl { get; private set; }
|
||||
public Uri Url { get; private set; }
|
||||
public Metadata Metadata { get; private set; }
|
||||
public BaseStream[] BaseStreams { get; private set; }
|
||||
|
||||
@@ -60,7 +63,7 @@ namespace VDownload.Core.Services.Sources.Twitch
|
||||
}
|
||||
|
||||
// Create unified video url
|
||||
VideoUrl = new Uri($"https://clips.twitch.tv/{ID}");
|
||||
Url = new Uri($"https://clips.twitch.tv/{ID}");
|
||||
|
||||
// Set metadata
|
||||
Metadata = new Metadata()
|
||||
|
||||
@@ -8,17 +8,12 @@ using Windows.Storage;
|
||||
|
||||
namespace VDownload.Core.Services.Sources.Twitch.Helpers
|
||||
{
|
||||
public class Auth
|
||||
public static class Auth
|
||||
{
|
||||
#region CONSTANTS
|
||||
|
||||
// CLIENT ID
|
||||
public readonly static string ClientID = "yukkqkwp61wsv3u1pya17crpyaa98y";
|
||||
|
||||
// GQL API CLIENT ID
|
||||
public readonly static string GQLApiClientID = "kimne78kx3ncx6brgo4mv6wki5h1ko";
|
||||
|
||||
// REDIRECT URL
|
||||
public readonly static Uri RedirectUrl = new Uri("https://www.vd.com");
|
||||
|
||||
// AUTHORIZATION URL
|
||||
@@ -35,16 +30,13 @@ namespace VDownload.Core.Services.Sources.Twitch.Helpers
|
||||
|
||||
#region METHODS
|
||||
|
||||
// READ ACCESS TOKEN
|
||||
public static async Task<string> ReadAccessTokenAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get file
|
||||
StorageFolder authDataFolder = await ApplicationData.Current.LocalCacheFolder.GetFolderAsync("AuthData");
|
||||
StorageFile authDataFile = await authDataFolder.GetFileAsync("Twitch.auth");
|
||||
|
||||
// Return data
|
||||
return await FileIO.ReadTextAsync(authDataFile);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
@@ -53,42 +45,33 @@ namespace VDownload.Core.Services.Sources.Twitch.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
// SAVE ACCESS TOKEN
|
||||
public static async Task SaveAccessTokenAsync(string accessToken)
|
||||
{
|
||||
// Get file
|
||||
StorageFolder authDataFolder = await ApplicationData.Current.LocalCacheFolder.CreateFolderAsync("AuthData", CreationCollisionOption.OpenIfExists);
|
||||
StorageFile authDataFile = await authDataFolder.CreateFileAsync("Twitch.auth", CreationCollisionOption.ReplaceExisting);
|
||||
|
||||
// Save data
|
||||
await FileIO.WriteTextAsync(authDataFile, accessToken);
|
||||
}
|
||||
|
||||
// DELETE ACCESS TOKEN
|
||||
public static async Task DeleteAccessTokenAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get file
|
||||
StorageFolder authDataFolder = await ApplicationData.Current.LocalCacheFolder.GetFolderAsync("AuthData");
|
||||
StorageFile authDataFile = await authDataFolder.GetFileAsync("Twitch.auth");
|
||||
|
||||
// Delete file
|
||||
await authDataFile.DeleteAsync();
|
||||
}
|
||||
catch (FileNotFoundException) { }
|
||||
}
|
||||
|
||||
// VALIDATE ACCESS TOKEN
|
||||
public static async Task<(bool IsValid, string Login, DateTime? ExpirationDate)> ValidateAccessTokenAsync(string accessToken)
|
||||
{
|
||||
// Create client
|
||||
WebClient client = new WebClient { Encoding = Encoding.UTF8 };
|
||||
client.Headers.Add("Authorization", $"Bearer {accessToken}");
|
||||
|
||||
try
|
||||
{
|
||||
// Check access token
|
||||
JObject response = JObject.Parse(await client.DownloadStringTaskAsync("https://id.twitch.tv/oauth2/validate"));
|
||||
|
||||
string login = response["login"].ToString();
|
||||
@@ -108,13 +91,10 @@ namespace VDownload.Core.Services.Sources.Twitch.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
// REVOKE ACCESS TOKEN
|
||||
public static async Task RevokeAccessTokenAsync(string accessToken)
|
||||
{
|
||||
// Create client
|
||||
WebClient client = new WebClient { Encoding = Encoding.UTF8 };
|
||||
|
||||
// Revoke access token
|
||||
await client.UploadStringTaskAsync(new Uri("https://id.twitch.tv/oauth2/revoke"), $"client_id={ClientID}&token={accessToken}");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,34 +4,28 @@ using VDownload.Core.Exceptions;
|
||||
|
||||
namespace VDownload.Core.Services.Sources.Twitch.Helpers
|
||||
{
|
||||
internal class Client
|
||||
internal static class Client
|
||||
{
|
||||
internal static async Task<WebClient> Helix()
|
||||
{
|
||||
// Get access token
|
||||
string accessToken = await Auth.ReadAccessTokenAsync();
|
||||
if (accessToken == null) throw new TwitchAccessTokenNotFoundException();
|
||||
|
||||
// Check access token
|
||||
var twitchAccessTokenValidation = await Auth.ValidateAccessTokenAsync(accessToken);
|
||||
if (!twitchAccessTokenValidation.IsValid) throw new TwitchAccessTokenNotValidException();
|
||||
|
||||
// Create client
|
||||
WebClient client = new WebClient();
|
||||
client.Headers.Add("Authorization", $"Bearer {accessToken}");
|
||||
client.Headers.Add("Client-Id", Auth.ClientID);
|
||||
|
||||
// Return client
|
||||
return client;
|
||||
}
|
||||
|
||||
internal static WebClient GQL()
|
||||
{
|
||||
// Create client
|
||||
WebClient client = new WebClient();
|
||||
client.Headers.Add("Client-Id", Auth.GQLApiClientID);
|
||||
|
||||
// Return client
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,15 @@ using Windows.Storage;
|
||||
|
||||
namespace VDownload.Core.Services.Sources.Twitch
|
||||
{
|
||||
public class Vod : IVideoService
|
||||
[Serializable]
|
||||
public class Vod : IVideo
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public Vod(string id)
|
||||
{
|
||||
ID = id;
|
||||
Source = VideoSource.TwitchVod;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -32,8 +34,9 @@ namespace VDownload.Core.Services.Sources.Twitch
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
public VideoSource Source { get; private set; }
|
||||
public string ID { get; private set; }
|
||||
public Uri VideoUrl { get; private set; }
|
||||
public Uri Url { get; private set; }
|
||||
public Metadata Metadata { get; private set; }
|
||||
public BaseStream[] BaseStreams { get; private set; }
|
||||
|
||||
@@ -72,7 +75,7 @@ namespace VDownload.Core.Services.Sources.Twitch
|
||||
internal void GetMetadataAsync(JToken response)
|
||||
{
|
||||
// Create unified video url
|
||||
VideoUrl = new Uri($"https://www.twitch.tv/videos/{ID}");
|
||||
Url = new Uri($"https://www.twitch.tv/videos/{ID}");
|
||||
|
||||
// Set metadata
|
||||
Metadata = new Metadata()
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace VDownload.Core.Services
|
||||
{
|
||||
public class TaskId
|
||||
public static class TaskId
|
||||
{
|
||||
#region CONSTANTS
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
|
||||
namespace VDownload.Core.Services
|
||||
{
|
||||
public class TimeSpanCustomFormat
|
||||
public static class TimeSpanCustomFormat
|
||||
{
|
||||
// (TH:)MM:SS
|
||||
public static string ToOptTHBaseMMSS(TimeSpan timeSpan, params TimeSpan[] formatBase)
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Core.Structs
|
||||
{
|
||||
[Serializable]
|
||||
public struct BaseStream
|
||||
{
|
||||
public Uri Url { get; set; }
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Core.Structs
|
||||
{
|
||||
[Serializable]
|
||||
public struct Metadata
|
||||
{
|
||||
public string Title { get; set; }
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace VDownload.Core.Structs
|
||||
{
|
||||
public struct TaskData
|
||||
{
|
||||
public IVideoService VideoService { get; set; }
|
||||
public IVideo VideoService { get; set; }
|
||||
public TaskOptions TaskOptions { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
<Compile Include="Enums\MediaFileExtension.cs" />
|
||||
<Compile Include="Enums\MediaType.cs" />
|
||||
<Compile Include="Enums\PlaylistSource.cs" />
|
||||
<Compile Include="Enums\SubscriptionStatus.cs" />
|
||||
<Compile Include="Enums\TaskAddingRequestSource.cs" />
|
||||
<Compile Include="Enums\VideoFileExtension.cs" />
|
||||
<Compile Include="Enums\VideoSource.cs" />
|
||||
@@ -133,18 +134,21 @@
|
||||
<Compile Include="EventArgs\PlaylistSearchSuccessedEventArgs.cs" />
|
||||
<Compile Include="EventArgs\VideoSearchSuccessedEventArgs.cs" />
|
||||
<Compile Include="Exceptions\MediaNotFoundException.cs" />
|
||||
<Compile Include="Exceptions\SubscriptionExistsException.cs" />
|
||||
<Compile Include="Exceptions\TwitchAccessTokenNotFoundException.cs" />
|
||||
<Compile Include="Exceptions\TwitchAccessTokenNotValidException.cs" />
|
||||
<Compile Include="Interfaces\IPlaylistService.cs" />
|
||||
<Compile Include="Interfaces\IVideoService.cs" />
|
||||
<Compile Include="Interfaces\IPlaylist.cs" />
|
||||
<Compile Include="Interfaces\IVideo.cs" />
|
||||
<Compile Include="Services\Sources\Twitch\Helpers\Client.cs" />
|
||||
<Compile Include="Services\Subscription.cs" />
|
||||
<Compile Include="Services\SubscriptionsCollectionManagement.cs" />
|
||||
<Compile Include="Services\TimeSpanCustomFormat.cs" />
|
||||
<Compile Include="Structs\BaseStream.cs" />
|
||||
<Compile Include="Structs\Metadata.cs" />
|
||||
<Compile Include="Structs\TaskData.cs" />
|
||||
<Compile Include="Services\Config.cs" />
|
||||
<Compile Include="Services\MediaProcessor.cs" />
|
||||
<Compile Include="Services\Source.cs" />
|
||||
<Compile Include="Services\Sources\Source.cs" />
|
||||
<Compile Include="Services\Sources\Twitch\Helpers\Auth.cs" />
|
||||
<Compile Include="Services\Sources\Twitch\Channel.cs" />
|
||||
<Compile Include="Services\Sources\Twitch\Clip.cs" />
|
||||
|
||||
Reference in New Issue
Block a user