diff --git a/VDownload.Core/Enums/VideoStatus.cs b/VDownload.Core/Enums/TaskStatus.cs similarity index 78% rename from VDownload.Core/Enums/VideoStatus.cs rename to VDownload.Core/Enums/TaskStatus.cs index 8672007..f908ef6 100644 --- a/VDownload.Core/Enums/VideoStatus.cs +++ b/VDownload.Core/Enums/TaskStatus.cs @@ -1,6 +1,6 @@ namespace VDownload.Core.Enums { - public enum VideoStatus + public enum TaskStatus { Idle, Waiting, diff --git a/VDownload.Core/EventArgs/PlaylistSearchEventArgs.cs b/VDownload.Core/EventArgs/PlaylistSearchEventArgs.cs new file mode 100644 index 0000000..d0b9036 --- /dev/null +++ b/VDownload.Core/EventArgs/PlaylistSearchEventArgs.cs @@ -0,0 +1,8 @@ +namespace VDownload.Core.EventArgs +{ + public class PlaylistSearchEventArgs : System.EventArgs + { + public string Phrase { get; set; } + public int Count { get; set; } + } +} diff --git a/VDownload.Core/EventArgsObjects/VideoAddEventArgs.cs b/VDownload.Core/EventArgs/VideoAddEventArgs.cs similarity index 78% rename from VDownload.Core/EventArgsObjects/VideoAddEventArgs.cs rename to VDownload.Core/EventArgs/VideoAddEventArgs.cs index 0477e99..3e34a83 100644 --- a/VDownload.Core/EventArgsObjects/VideoAddEventArgs.cs +++ b/VDownload.Core/EventArgs/VideoAddEventArgs.cs @@ -4,13 +4,13 @@ using VDownload.Core.Interfaces; using VDownload.Core.Objects; using Windows.Storage; -namespace VDownload.Core.EventArgsObjects +namespace VDownload.Core.EventArgs { - public class VideoAddEventArgs : EventArgs + public class VideoAddEventArgs : System.EventArgs { public IVideoService VideoService { get; set; } public MediaType MediaType { get; set; } - public Stream Stream { get; set; } + public IBaseStream Stream { get; set; } public TimeSpan TrimStart { get; set; } public TimeSpan TrimEnd { get; set; } public string Filename { get; set; } diff --git a/VDownload.Core/EventArgs/VideoSearchEventArgs.cs b/VDownload.Core/EventArgs/VideoSearchEventArgs.cs new file mode 100644 index 0000000..720fd91 --- /dev/null +++ b/VDownload.Core/EventArgs/VideoSearchEventArgs.cs @@ -0,0 +1,7 @@ +namespace VDownload.Core.EventArgs +{ + public class VideoSearchEventArgs : System.EventArgs + { + public string Phrase { get; set; } + } +} diff --git a/VDownload.Core/EventArgsObjects/PlaylistSearchEventArgs.cs b/VDownload.Core/EventArgsObjects/PlaylistSearchEventArgs.cs deleted file mode 100644 index 9a2e598..0000000 --- a/VDownload.Core/EventArgsObjects/PlaylistSearchEventArgs.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace VDownload.Core.EventArgsObjects -{ - public class PlaylistSearchEventArgs : EventArgs - { - public string Phrase { get; set; } - public int Count { get; set; } - } -} diff --git a/VDownload.Core/EventArgsObjects/VideoSearchEventArgs.cs b/VDownload.Core/EventArgsObjects/VideoSearchEventArgs.cs deleted file mode 100644 index c0d47e4..0000000 --- a/VDownload.Core/EventArgsObjects/VideoSearchEventArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace VDownload.Core.EventArgsObjects -{ - public class VideoSearchEventArgs : EventArgs - { - public string Phrase { get; set; } - } -} diff --git a/VDownload.Core/Interfaces/IAStream.cs b/VDownload.Core/Interfaces/IAStream.cs deleted file mode 100644 index fc8a86f..0000000 --- a/VDownload.Core/Interfaces/IAStream.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using VDownload.Core.Enums; - -namespace VDownload.Core.Interfaces -{ - public interface IAStream - { - #region PROPERTIES - - Uri Url { get; } - bool IsChunked { get; } - StreamType StreamType { get; } - int AudioBitrate { get; } - string AudioCodec { get; } - - #endregion - } -} diff --git a/VDownload.Core/Interfaces/IVStream.cs b/VDownload.Core/Interfaces/IBaseStream.cs similarity index 69% rename from VDownload.Core/Interfaces/IVStream.cs rename to VDownload.Core/Interfaces/IBaseStream.cs index d35b57b..5810605 100644 --- a/VDownload.Core/Interfaces/IVStream.cs +++ b/VDownload.Core/Interfaces/IBaseStream.cs @@ -1,19 +1,21 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; using VDownload.Core.Enums; namespace VDownload.Core.Interfaces { - public interface IVStream + public interface IBaseStream { #region PROPERTIES Uri Url { get; } bool IsChunked { get; } StreamType StreamType { get; } - int Width { get; } int Height { get; } int FrameRate { get; } - string VideoCodec { get; } #endregion } diff --git a/VDownload.Core/Interfaces/IPlaylistService.cs b/VDownload.Core/Interfaces/IPlaylistService.cs index 458bf53..57bfe7b 100644 --- a/VDownload.Core/Interfaces/IPlaylistService.cs +++ b/VDownload.Core/Interfaces/IPlaylistService.cs @@ -7,6 +7,7 @@ namespace VDownload.Core.Interfaces { #region PROPERTIES + // PLAYLIST PROPERTIES string ID { get; } string Name { get; } @@ -16,8 +17,10 @@ namespace VDownload.Core.Interfaces #region METHODS + // GET PLAYLIST METADATA Task GetMetadataAsync(CancellationToken cancellationToken = default); + // GET VIDEOS FROM PLAYLIST Task GetVideosAsync(int numberOfVideos, CancellationToken cancellationToken = default); #endregion diff --git a/VDownload.Core/Interfaces/IVideoService.cs b/VDownload.Core/Interfaces/IVideoService.cs index 35a6d11..3834641 100644 --- a/VDownload.Core/Interfaces/IVideoService.cs +++ b/VDownload.Core/Interfaces/IVideoService.cs @@ -3,7 +3,6 @@ using System.ComponentModel; using System.Threading; using System.Threading.Tasks; using VDownload.Core.Enums; -using VDownload.Core.Objects; using Windows.Storage; namespace VDownload.Core.Interfaces @@ -21,7 +20,7 @@ namespace VDownload.Core.Interfaces TimeSpan Duration { get; } long Views { get; } Uri Thumbnail { get; } - Stream[] Streams { get; } + IBaseStream[] BaseStreams { get; } #endregion @@ -36,14 +35,7 @@ namespace VDownload.Core.Interfaces Task GetStreamsAsync(CancellationToken cancellationToken = default); // DOWNLOAD VIDEO - Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default); - Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, CancellationToken cancellationToken = default); - Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, IVStream videoStream, VideoFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default); - Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default); - Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default); - Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, CancellationToken cancellationToken = default); - Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default); - Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default); + Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IBaseStream baseStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default); #endregion diff --git a/VDownload.Core/Objects/Stream.cs b/VDownload.Core/Objects/Stream.cs index 3bb97d0..30d3449 100644 --- a/VDownload.Core/Objects/Stream.cs +++ b/VDownload.Core/Objects/Stream.cs @@ -4,7 +4,7 @@ using VDownload.Core.Interfaces; namespace VDownload.Core.Objects { - public class Stream : IVStream, IAStream + public class Stream : IBaseStream { #region CONSTRUCTORS diff --git a/VDownload.Core/Services/Config.cs b/VDownload.Core/Services/Config.cs index 3667dce..126a032 100644 --- a/VDownload.Core/Services/Config.cs +++ b/VDownload.Core/Services/Config.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using VDownload.Core.Enums; using Windows.Media.Editing; using Windows.Storage; diff --git a/VDownload.Core/Services/MediaProcessor.cs b/VDownload.Core/Services/MediaProcessor.cs index fb26bbd..1f59839 100644 --- a/VDownload.Core/Services/MediaProcessor.cs +++ b/VDownload.Core/Services/MediaProcessor.cs @@ -15,7 +15,7 @@ namespace VDownload.Core.Services { public class MediaProcessor { - #region CONSTRUCTOR + #region CONSTRUCTORS public MediaProcessor(StorageFile outputFile, TimeSpan trimStart, TimeSpan trimEnd) { @@ -40,10 +40,11 @@ namespace VDownload.Core.Services #region STANDARD METHODS + // SINGLE AUDIO & VIDEO FILE PROCESSING public async Task Run(StorageFile audioVideoInputFile, MediaFileExtension extension, MediaType mediaType, CancellationToken cancellationToken = default) { // Invoke ProcessingStarted event - ProcessingStarted?.Invoke(this, EventArgs.Empty); + ProcessingStarted?.Invoke(this, System.EventArgs.Empty); // Init transcoder MediaTranscoder mediaTranscoder = new MediaTranscoder @@ -55,31 +56,31 @@ namespace VDownload.Core.Services }; // Start transcoding operation + cancellationToken.ThrowIfCancellationRequested(); using (IRandomAccessStream outputFileOpened = await OutputFile.OpenAsync(FileAccessMode.ReadWrite)) { PrepareTranscodeResult transcodingPreparated = await mediaTranscoder.PrepareStreamTranscodeAsync(await audioVideoInputFile.OpenAsync(FileAccessMode.Read), outputFileOpened, await GetMediaEncodingProfile(audioVideoInputFile, extension, mediaType)); IAsyncActionWithProgress transcodingTask = transcodingPreparated.TranscodeAsync(); - try - { - await transcodingTask.AsTask(cancellationToken, new Progress((percent) => { ProcessingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(percent), null)); })); - await outputFileOpened.FlushAsync(); - } - catch (TaskCanceledException) { } + await transcodingTask.AsTask(cancellationToken, new Progress((percent) => { ProcessingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(percent), null)); })); + await outputFileOpened.FlushAsync(); transcodingTask.Close(); } // Invoke ProcessingCompleted event - ProcessingCompleted?.Invoke(this, EventArgs.Empty); + ProcessingCompleted?.Invoke(this, System.EventArgs.Empty); } + + // SEPARATE AUDIO & VIDEO FILES PROCESSING public async Task Run(StorageFile audioFile, StorageFile videoFile, VideoFileExtension extension, CancellationToken cancellationToken = default) { // Invoke ProcessingStarted event - ProcessingStarted?.Invoke(this, EventArgs.Empty); + ProcessingStarted?.Invoke(this, System.EventArgs.Empty); // Init editor MediaComposition mediaEditor = new MediaComposition(); // Add media files + cancellationToken.ThrowIfCancellationRequested(); Task getVideoFileTask = MediaClip.CreateFromFileAsync(videoFile).AsTask(); Task getAudioFileTask = BackgroundAudioTrack.CreateFromFileAsync(audioFile).AsTask(); await Task.WhenAll(getVideoFileTask, getAudioFileTask); @@ -97,11 +98,14 @@ namespace VDownload.Core.Services // Start rendering operation var renderOperation = mediaEditor.RenderToFileAsync(OutputFile, (MediaTrimmingPreference)Config.GetValue("media_editing_algorithm"), await GetMediaEncodingProfile(videoFile, audioFile, (MediaFileExtension)extension, MediaType.AudioVideo)); renderOperation.Progress += (info, progress) => { ProcessingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(progress), null)); }; + cancellationToken.ThrowIfCancellationRequested(); await renderOperation.AsTask(cancellationToken); // Invoke ProcessingCompleted event - ProcessingCompleted?.Invoke(this, EventArgs.Empty); + ProcessingCompleted?.Invoke(this, System.EventArgs.Empty); } + + // SINGLE AUDIO OR VIDEO FILES PROCESSING public async Task Run(StorageFile audioFile, AudioFileExtension extension, CancellationToken cancellationToken = default) { await Run(audioFile, (MediaFileExtension)extension, MediaType.OnlyAudio, cancellationToken); } public async Task Run(StorageFile videoFile, VideoFileExtension extension, CancellationToken cancellationToken = default) { await Run(videoFile, (MediaFileExtension)extension, MediaType.OnlyVideo, cancellationToken); } diff --git a/VDownload.Core/Services/Source.cs b/VDownload.Core/Services/Source.cs index 1286a8f..55e44e3 100644 --- a/VDownload.Core/Services/Source.cs +++ b/VDownload.Core/Services/Source.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; +using System.Text.RegularExpressions; using VDownload.Core.Enums; namespace VDownload.Core.Services @@ -12,6 +7,7 @@ namespace VDownload.Core.Services { #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/(?\d+)"), VideoSource.TwitchVod), @@ -19,6 +15,7 @@ namespace VDownload.Core.Services (new Regex(@"^https://clips.twitch.tv/(?[^?]+)"), 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/(?[^?]+)"), PlaylistSource.TwitchChannel), @@ -30,6 +27,7 @@ namespace VDownload.Core.Services #region METHODS + // GET VIDEO SOURCE public static (VideoSource Type, string ID) GetVideoSource(string url) { foreach ((Regex Regex, VideoSource Type) Source in VideoSources) @@ -40,6 +38,7 @@ namespace VDownload.Core.Services return (VideoSource.Null, null); } + // GET PLAYLIST SOURCE public static (PlaylistSource Type, string ID) GetPlaylistSource(string url) { foreach ((Regex Regex, PlaylistSource Type) Source in PlaylistSources) diff --git a/VDownload.Core/Services/Sources/Twitch/Auth.cs b/VDownload.Core/Services/Sources/Twitch/Auth.cs index 7498dfd..8c13420 100644 --- a/VDownload.Core/Services/Sources/Twitch/Auth.cs +++ b/VDownload.Core/Services/Sources/Twitch/Auth.cs @@ -65,7 +65,7 @@ namespace VDownload.Core.Services.Sources.Twitch StorageFile authDataFile = await authDataFolder.CreateFileAsync("Twitch.auth", CreationCollisionOption.ReplaceExisting); // Save data - FileIO.WriteTextAsync(authDataFile, accessToken); + await FileIO.WriteTextAsync(authDataFile, accessToken); } // DELETE ACCESS TOKEN diff --git a/VDownload.Core/Services/Sources/Twitch/Channel.cs b/VDownload.Core/Services/Sources/Twitch/Channel.cs index dbc756f..0c85327 100644 --- a/VDownload.Core/Services/Sources/Twitch/Channel.cs +++ b/VDownload.Core/Services/Sources/Twitch/Channel.cs @@ -40,14 +40,13 @@ namespace VDownload.Core.Services.Sources.Twitch // GET CHANNEL METADATA public async Task GetMetadataAsync(CancellationToken cancellationToken = default) { - // Set cancellation token - cancellationToken.ThrowIfCancellationRequested(); - // Get access token + cancellationToken.ThrowIfCancellationRequested(); string accessToken = await Auth.ReadAccessTokenAsync(); if (accessToken == null) throw new TwitchAccessTokenNotFoundException(); // Check access token + cancellationToken.ThrowIfCancellationRequested(); var twitchAccessTokenValidation = await Auth.ValidateAccessTokenAsync(accessToken); if (!twitchAccessTokenValidation.IsValid) throw new TwitchAccessTokenNotValidException(); @@ -58,6 +57,7 @@ namespace VDownload.Core.Services.Sources.Twitch // Get response client.QueryString.Add("login", ID); + cancellationToken.ThrowIfCancellationRequested(); JToken response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/users"))["data"][0]; // Set parameters @@ -68,10 +68,8 @@ namespace VDownload.Core.Services.Sources.Twitch // GET CHANNEL VIDEOS public async Task GetVideosAsync(int numberOfVideos, CancellationToken cancellationToken = default) { - // Set cancellation token - cancellationToken.ThrowIfCancellationRequested(); - // Get access token + cancellationToken.ThrowIfCancellationRequested(); string accessToken = await Auth.ReadAccessTokenAsync(); if (accessToken == null) throw new TwitchAccessTokenNotFoundException(); @@ -88,6 +86,7 @@ namespace VDownload.Core.Services.Sources.Twitch do { // Check access token + cancellationToken.ThrowIfCancellationRequested(); var twitchAccessTokenValidation = await Auth.ValidateAccessTokenAsync(accessToken); if (!twitchAccessTokenValidation.IsValid) throw new TwitchAccessTokenNotValidException(); @@ -104,6 +103,7 @@ namespace VDownload.Core.Services.Sources.Twitch client.QueryString.Add("first", count.ToString()); client.QueryString.Add("after", pagination); + cancellationToken.ThrowIfCancellationRequested(); JToken response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/videos")); pagination = (string)response["pagination"]["cursor"]; diff --git a/VDownload.Core/Services/Sources/Twitch/Clip.cs b/VDownload.Core/Services/Sources/Twitch/Clip.cs index 9e86fcc..48499b4 100644 --- a/VDownload.Core/Services/Sources/Twitch/Clip.cs +++ b/VDownload.Core/Services/Sources/Twitch/Clip.cs @@ -48,7 +48,7 @@ namespace VDownload.Core.Services.Sources.Twitch public TimeSpan Duration { get; private set; } public long Views { get; private set; } public Uri Thumbnail { get; private set; } - public Stream[] Streams { get; private set; } + public IBaseStream[] BaseStreams { get; private set; } #endregion @@ -59,14 +59,13 @@ namespace VDownload.Core.Services.Sources.Twitch // GET CLIP METADATA public async Task GetMetadataAsync(CancellationToken cancellationToken = default) { - // Set cancellation token - cancellationToken.ThrowIfCancellationRequested(); - // Get access token + cancellationToken.ThrowIfCancellationRequested(); string accessToken = await Auth.ReadAccessTokenAsync(); if (accessToken == null) throw new TwitchAccessTokenNotFoundException(); // Check access token + cancellationToken.ThrowIfCancellationRequested(); var twitchAccessTokenValidation = await Auth.ValidateAccessTokenAsync(accessToken); if (!twitchAccessTokenValidation.IsValid) throw new TwitchAccessTokenNotValidException(); @@ -93,14 +92,12 @@ namespace VDownload.Core.Services.Sources.Twitch public async Task GetStreamsAsync(CancellationToken cancellationToken = default) { - // Set cancellation token - cancellationToken.ThrowIfCancellationRequested(); - // Create client WebClient client = new WebClient { Encoding = Encoding.UTF8 }; client.Headers.Add("Client-ID", Auth.GQLApiClientID); // Get video streams + cancellationToken.ThrowIfCancellationRequested(); JToken[] response = JArray.Parse(await client.UploadStringTaskAsync("https://gql.twitch.tv/gql", "[{\"operationName\":\"VideoAccessToken_Clip\",\"variables\":{\"slug\":\"" + ID + "\"},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"36b89d2507fce29e5ca551df756d27c1cfe079e2609642b4390aa4c35796eb11\"}}}]"))[0]["data"]["clip"]["videoQualities"].ToArray(); // Init streams list @@ -126,60 +123,55 @@ namespace VDownload.Core.Services.Sources.Twitch } // Set Streams parameter - Streams = streams.ToArray(); + BaseStreams = streams.ToArray(); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) + public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IBaseStream baseStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) { - // Set cancellation token - cancellationToken.ThrowIfCancellationRequested(); - // Invoke DownloadingStarted event - DownloadingStarted?.Invoke(this, EventArgs.Empty); + DownloadingStarted?.Invoke(this, System.EventArgs.Empty); // Create client WebClient client = new WebClient(); client.Headers.Add("Client-Id", Auth.GQLApiClientID); // Get video GQL access token + cancellationToken.ThrowIfCancellationRequested(); JToken videoAccessToken = JArray.Parse(await client.UploadStringTaskAsync("https://gql.twitch.tv/gql", "[{\"operationName\":\"VideoAccessToken_Clip\",\"variables\":{\"slug\":\"" + ID + "\"},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"36b89d2507fce29e5ca551df756d27c1cfe079e2609642b4390aa4c35796eb11\"}}}]"))[0]["data"]["clip"]["playbackAccessToken"]; - + // Download + cancellationToken.ThrowIfCancellationRequested(); StorageFile rawFile = await downloadingFolder.CreateFileAsync("raw.mp4"); using (client = new WebClient()) { client.DownloadProgressChanged += (s, a) => { DownloadingProgressChanged(this, new ProgressChangedEventArgs(a.ProgressPercentage, null)); }; client.QueryString.Add("sig", (string)videoAccessToken["signature"]); client.QueryString.Add("token", HttpUtility.UrlEncode((string)videoAccessToken["value"])); + cancellationToken.ThrowIfCancellationRequested(); using (cancellationToken.Register(client.CancelAsync)) { - await client.DownloadFileTaskAsync(audioVideoStream.Url, rawFile.Path); + await client.DownloadFileTaskAsync(baseStream.Url, rawFile.Path); } } - DownloadingCompleted?.Invoke(this, EventArgs.Empty); + DownloadingCompleted?.Invoke(this, System.EventArgs.Empty); // Processing StorageFile outputFile = rawFile; if (extension != MediaFileExtension.MP4 || mediaType != MediaType.AudioVideo || trimStart > new TimeSpan(0) || trimEnd < Duration) { + cancellationToken.ThrowIfCancellationRequested(); outputFile = await downloadingFolder.CreateFileAsync($"transcoded.{extension.ToString().ToLower()}"); MediaProcessor mediaProcessor = new MediaProcessor(outputFile, trimStart, trimEnd); mediaProcessor.ProcessingStarted += ProcessingStarted; mediaProcessor.ProcessingProgressChanged += ProcessingProgressChanged; mediaProcessor.ProcessingCompleted += ProcessingCompleted; + cancellationToken.ThrowIfCancellationRequested(); await mediaProcessor.Run(rawFile, extension, mediaType, cancellationToken); } // Return output file return outputFile; } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, audioVideoStream, extension, mediaType, new TimeSpan(0), Duration, cancellationToken); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, IVStream videoStream, VideoFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) { throw new NotImplementedException("Twitch Clip download service doesn't support separate video and audio streams"); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, audioStream, videoStream, extension, new TimeSpan(0), Duration, cancellationToken); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) { throw new NotImplementedException("Twitch Clip download service doesn't support separate video and audio streams"); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, audioStream, extension, new TimeSpan(0), Duration, cancellationToken); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) { throw new NotImplementedException("Twitch Clip download service doesn't support separate video and audio streams"); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, videoStream, extension, new TimeSpan(0), Duration, cancellationToken); } #endregion diff --git a/VDownload.Core/Services/Sources/Twitch/Vod.cs b/VDownload.Core/Services/Sources/Twitch/Vod.cs index a9ffcaf..83e0841 100644 --- a/VDownload.Core/Services/Sources/Twitch/Vod.cs +++ b/VDownload.Core/Services/Sources/Twitch/Vod.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; using System.Linq; using System.Net; using System.Text.RegularExpressions; @@ -51,7 +50,7 @@ namespace VDownload.Core.Services.Sources.Twitch public TimeSpan Duration { get; private set; } public long Views { get; private set; } public Uri Thumbnail { get; private set; } - public Stream[] Streams { get; private set; } + public IBaseStream[] BaseStreams { get; private set; } #endregion @@ -62,14 +61,13 @@ namespace VDownload.Core.Services.Sources.Twitch // GET VOD METADATA public async Task GetMetadataAsync(CancellationToken cancellationToken = default) { - // Set cancellation token - cancellationToken.ThrowIfCancellationRequested(); - // Get access token + cancellationToken.ThrowIfCancellationRequested(); string accessToken = await Auth.ReadAccessTokenAsync(); if (accessToken == null) throw new TwitchAccessTokenNotFoundException(); // Check access token + cancellationToken.ThrowIfCancellationRequested(); var twitchAccessTokenValidation = await Auth.ValidateAccessTokenAsync(accessToken); if (!twitchAccessTokenValidation.IsValid) throw new TwitchAccessTokenNotValidException(); @@ -80,6 +78,7 @@ namespace VDownload.Core.Services.Sources.Twitch // Get response client.QueryString.Add("id", ID); + cancellationToken.ThrowIfCancellationRequested(); JToken response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/videos")).GetValue("data")[0]; // Set parameters @@ -102,17 +101,16 @@ namespace VDownload.Core.Services.Sources.Twitch // GET VOD STREAMS public async Task GetStreamsAsync(CancellationToken cancellationToken = default) { - // Set cancellation token - cancellationToken.ThrowIfCancellationRequested(); - // Create client WebClient client = new WebClient(); client.Headers.Add("Client-Id", Auth.GQLApiClientID); // Get video GQL access token + cancellationToken.ThrowIfCancellationRequested(); JToken videoAccessToken = JObject.Parse(await client.UploadStringTaskAsync("https://gql.twitch.tv/gql", "{\"operationName\":\"PlaybackAccessToken_Template\",\"query\":\"query PlaybackAccessToken_Template($login: String!, $isLive: Boolean!, $vodID: ID!, $isVod: Boolean!, $playerType: String!) { streamPlaybackAccessToken(channelName: $login, params: {platform: \\\"web\\\", playerBackend: \\\"mediaplayer\\\", playerType: $playerType}) @include(if: $isLive) { value signature __typename } videoPlaybackAccessToken(id: $vodID, params: {platform: \\\"web\\\", playerBackend: \\\"mediaplayer\\\", playerType: $playerType}) @include(if: $isVod) { value signature __typename }}\",\"variables\":{\"isLive\":false,\"login\":\"\",\"isVod\":true,\"vodID\":\"" + ID + "\",\"playerType\":\"embed\"}}"))["data"]["videoPlaybackAccessToken"]; // Get video streams + cancellationToken.ThrowIfCancellationRequested(); string[] response = (await client.DownloadStringTaskAsync($"http://usher.twitch.tv/vod/{ID}?nauth={videoAccessToken["value"]}&nauthsig={videoAccessToken["signature"]}&allow_source=true&player=twitchweb")).Split("\n"); // Init streams list @@ -147,74 +145,64 @@ namespace VDownload.Core.Services.Sources.Twitch } // Set Streams parameter - Streams = streams.ToArray(); + BaseStreams = streams.ToArray(); } // DOWNLOAD AND TRANSCODE VOD - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) + public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IBaseStream baseStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) { // Invoke DownloadingStarted event - if (!cancellationToken.IsCancellationRequested) DownloadingStarted?.Invoke(this, EventArgs.Empty); + DownloadingStarted?.Invoke(this, System.EventArgs.Empty); // Get video chunks - List<(Uri ChunkUrl, TimeSpan ChunkDuration)> chunksList = null; - if (!cancellationToken.IsCancellationRequested) chunksList = await ExtractChunksFromM3U8Async(audioVideoStream.Url); + cancellationToken.ThrowIfCancellationRequested(); + List<(Uri ChunkUrl, TimeSpan ChunkDuration)> chunksList = await ExtractChunksFromM3U8Async(baseStream.Url, cancellationToken); // Passive trim if ((bool)Config.GetValue("twitch_vod_passive_trim")) (trimStart, trimEnd) = PassiveVideoTrim(chunksList, trimStart, trimEnd, Duration); // Download - StorageFile rawFile = null; - if (!cancellationToken.IsCancellationRequested) + cancellationToken.ThrowIfCancellationRequested(); + StorageFile rawFile = await downloadingFolder.CreateFileAsync("raw.ts"); + + float chunksDownloaded = 0; + + Task downloadTask; + Task writeTask; + + cancellationToken.ThrowIfCancellationRequested(); + downloadTask = DownloadChunkAsync(chunksList[0].ChunkUrl); + await downloadTask; + for (int i = 1; i < chunksList.Count; i++) { - rawFile = await downloadingFolder.CreateFileAsync("raw.ts"); - float chunksDownloaded = 0; - - Task downloadTask; - Task writeTask; - - downloadTask = DownloadChunkAsync(chunksList[0].ChunkUrl); - await downloadTask; - for (int i = 1; i < chunksList.Count && !cancellationToken.IsCancellationRequested; i++) - { - writeTask = WriteChunkToFileAsync(rawFile, downloadTask.Result); - downloadTask = DownloadChunkAsync(chunksList[i].ChunkUrl); - await Task.WhenAll(writeTask, downloadTask); - DownloadingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(++chunksDownloaded * 100 / chunksList.Count), null)); - } - if (!cancellationToken.IsCancellationRequested) - { - await WriteChunkToFileAsync(rawFile, downloadTask.Result); - DownloadingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(++chunksDownloaded * 100 / chunksList.Count), null)); - - DownloadingCompleted?.Invoke(this, EventArgs.Empty); - } + cancellationToken.ThrowIfCancellationRequested(); + writeTask = WriteChunkToFileAsync(rawFile, downloadTask.Result); + downloadTask = DownloadChunkAsync(chunksList[i].ChunkUrl); + await Task.WhenAll(writeTask, downloadTask); + DownloadingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(++chunksDownloaded * 100 / chunksList.Count), null)); } + cancellationToken.ThrowIfCancellationRequested(); + await WriteChunkToFileAsync(rawFile, downloadTask.Result); + DownloadingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(++chunksDownloaded * 100 / chunksList.Count), null)); + + DownloadingCompleted?.Invoke(this, System.EventArgs.Empty); // Processing - StorageFile outputFile = null; - if (!cancellationToken.IsCancellationRequested) - { - outputFile = await downloadingFolder.CreateFileAsync($"transcoded.{extension.ToString().ToLower()}"); + cancellationToken.ThrowIfCancellationRequested(); + StorageFile outputFile = await downloadingFolder.CreateFileAsync($"transcoded.{extension.ToString().ToLower()}"); - MediaProcessor mediaProcessor = new MediaProcessor(outputFile, trimStart, trimEnd); - mediaProcessor.ProcessingStarted += ProcessingStarted; - mediaProcessor.ProcessingProgressChanged += ProcessingProgressChanged; - mediaProcessor.ProcessingCompleted += ProcessingCompleted; - await mediaProcessor.Run(rawFile, extension, mediaType, cancellationToken); - } + MediaProcessor mediaProcessor = new MediaProcessor(outputFile, trimStart, trimEnd); + mediaProcessor.ProcessingStarted += ProcessingStarted; + mediaProcessor.ProcessingProgressChanged += ProcessingProgressChanged; + mediaProcessor.ProcessingCompleted += ProcessingCompleted; + cancellationToken.ThrowIfCancellationRequested(); + await mediaProcessor.Run(rawFile, extension, mediaType, cancellationToken); + // Return output file return outputFile; } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, audioVideoStream, extension, mediaType, new TimeSpan(0), Duration, cancellationToken); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, IVStream videoStream, VideoFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) { throw new NotImplementedException("Twitch VOD download service doesn't support separate video and audio streams"); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, audioStream, videoStream, extension, new TimeSpan(0), Duration, cancellationToken); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) { throw new NotImplementedException("Twitch VOD download service doesn't support separate video and audio streams"); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, audioStream, extension, new TimeSpan(0), Duration, cancellationToken); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default) { throw new NotImplementedException("Twitch VOD download service doesn't support separate video and audio streams"); } - public async Task DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, videoStream, extension, new TimeSpan(0), Duration, cancellationToken); } #endregion @@ -223,14 +211,16 @@ namespace VDownload.Core.Services.Sources.Twitch #region LOCAL METHODS // GET CHUNKS DATA FROM M3U8 PLAYLIST - private static async Task> ExtractChunksFromM3U8Async(Uri streamUrl) + private static async Task> ExtractChunksFromM3U8Async(Uri streamUrl, CancellationToken cancellationToken = default) { // Create client WebClient client = new WebClient(); client.Headers.Add("Client-Id", Auth.GQLApiClientID); // Get playlist + cancellationToken.ThrowIfCancellationRequested(); string response = await client.DownloadStringTaskAsync(streamUrl); + // Create dictionary List<(Uri ChunkUrl, TimeSpan ChunkDuration)> chunks = new List<(Uri ChunkUrl, TimeSpan ChunkDuration)>(); @@ -273,11 +263,12 @@ namespace VDownload.Core.Services.Sources.Twitch } // DOWNLOAD CHUNK - private static async Task DownloadChunkAsync(Uri chunkUrl) + private static async Task DownloadChunkAsync(Uri chunkUrl, CancellationToken cancellationToken = default) { int retriesCount = 0; while ((bool)Config.GetValue("twitch_vod_downloading_chunk_retry_after_error") && retriesCount < (int)Config.GetValue("twitch_vod_downloading_chunk_max_retries")) { + cancellationToken.ThrowIfCancellationRequested(); try { using (WebClient client = new WebClient()) diff --git a/VDownload.Core/Services/TaskId.cs b/VDownload.Core/Services/TaskId.cs index 91161f8..dbb4e59 100644 --- a/VDownload.Core/Services/TaskId.cs +++ b/VDownload.Core/Services/TaskId.cs @@ -1,38 +1,56 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace VDownload.Core.Services { public class TaskId { - // VARIABLES + #region CONSTANTS + + // RANDOM private static readonly Random Random = new Random(); - private static readonly char[] CharsID = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); - private static readonly int LengthID = 10; + + // ID SETTINGS + private static readonly char[] IDChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); + private static readonly int IDLength = 10; + + #endregion + + + + #region PROPERTIES + + // USED IDS LIST private static readonly List UsedIDs = new List(); - // METHOD + #endregion + + + + #region METHODS + + // GET TASK ID public static string Get() { string id; do { id = ""; - while (id.Length < LengthID) + while (id.Length < IDLength) { - id += CharsID[Random.Next(0, CharsID.Length)]; + id += IDChars[Random.Next(0, IDChars.Length)]; } } while (UsedIDs.Contains(id)); UsedIDs.Add(id); return id; } + // DISPOSE TASK ID public static void Dispose(string id) { UsedIDs.Remove(id); } + + #endregion } } diff --git a/VDownload.Core/VDownload.Core.csproj b/VDownload.Core/VDownload.Core.csproj index 2c3a4cc..2604852 100644 --- a/VDownload.Core/VDownload.Core.csproj +++ b/VDownload.Core/VDownload.Core.csproj @@ -127,16 +127,15 @@ - - - - + + + + - + - diff --git a/VDownload/App.xaml.cs b/VDownload/App.xaml.cs index 53fdb16..f0c16c6 100644 --- a/VDownload/App.xaml.cs +++ b/VDownload/App.xaml.cs @@ -11,18 +11,27 @@ using Windows.Storage; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; -using System.Diagnostics; +using Windows.Storage.AccessCache; namespace VDownload { sealed partial class App : Application { + #region CONSTRUCTORS + public App() { InitializeComponent(); Suspending += OnSuspending; } + #endregion + + + + #region EVENT HANDLERS VOIDS + + // ON LAUNCHED protected override async void OnLaunched(LaunchActivatedEventArgs e) { // Rebuild configuration file @@ -31,7 +40,12 @@ namespace VDownload // Delete temp on start if ((bool)Config.GetValue("delete_temp_on_start")) { - IReadOnlyList tempItems = await ApplicationData.Current.TemporaryFolder.GetItemsAsync(); + IReadOnlyList tempItems; + if ((bool)Config.GetValue("custom_temp_location") && StorageApplicationPermissions.FutureAccessList.ContainsItem("custom_temp_location")) + tempItems = await (await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("custom_temp_location")).GetItemsAsync(); + else + tempItems = await ApplicationData.Current.TemporaryFolder.GetItemsAsync(); + List tasks = new List(); foreach (IStorageItem item in tempItems) tasks.Add(item.DeleteAsync().AsTask()); await Task.WhenAll(tasks); @@ -64,16 +78,20 @@ namespace VDownload } } + // ON NAVIGATION FAILED private void OnNavigationFailed(object sender, NavigationFailedEventArgs e) { throw new Exception("Failed to load Page " + e.SourcePageType.FullName); } + // ON SUSPENDING private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); //TODO: Save application state and stop any background activity deferral.Complete(); } + + #endregion } } diff --git a/VDownload/Assets/UnknownThumbnail.png b/VDownload/Assets/Images/UnknownThumbnail.png similarity index 100% rename from VDownload/Assets/UnknownThumbnail.png rename to VDownload/Assets/Images/UnknownThumbnail.png diff --git a/VDownload/Assets/Sources/Twitch.png b/VDownload/Assets/Sources/Twitch.png new file mode 100644 index 0000000..9989457 Binary files /dev/null and b/VDownload/Assets/Sources/Twitch.png differ diff --git a/VDownload/Resources/Images.xaml b/VDownload/Resources/Images.xaml new file mode 100644 index 0000000..764b264 --- /dev/null +++ b/VDownload/Resources/Images.xaml @@ -0,0 +1,5 @@ + + + diff --git a/VDownload/Strings/en-US/Resources.resw b/VDownload/Strings/en-US/Resources.resw index b8a1770..8d95290 100644 --- a/VDownload/Strings/en-US/Resources.resw +++ b/VDownload/Strings/en-US/Resources.resw @@ -196,6 +196,27 @@ The number in the numberbox indicades how many videos will be got from playlist. There is a problem with linked Twitch account. Check Twitch login status in Sources page. + + Cancelled + + + Done + + + Downloading + + + Finalizing + + + Idle + + + Processing + + + Queued + Downloading options @@ -220,27 +241,6 @@ The number in the numberbox indicades how many videos will be got from playlist. Trim - - Cancelled - - - Done - - - Downloading - - - Finalizing - - - Idle - - - Processing - - - Queued - Home diff --git a/VDownload/VDownload.csproj b/VDownload/VDownload.csproj index 15535cb..1cff800 100644 --- a/VDownload/VDownload.csproj +++ b/VDownload/VDownload.csproj @@ -140,10 +140,9 @@ HomeVideoAddingPanel.xaml - - HomeVideoPanel.xaml + + HomeTaskPanel.xaml - MainPage.xaml @@ -250,7 +249,8 @@ - + + @@ -269,6 +269,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -293,7 +297,7 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile diff --git a/VDownload/Views/Home/HomeMain.xaml b/VDownload/Views/Home/HomeMain.xaml index b4233a8..f4529d1 100644 --- a/VDownload/Views/Home/HomeMain.xaml +++ b/VDownload/Views/Home/HomeMain.xaml @@ -54,13 +54,13 @@ - + - + diff --git a/VDownload/Views/Home/HomeMain.xaml.cs b/VDownload/Views/Home/HomeMain.xaml.cs index c44ac7b..a691f85 100644 --- a/VDownload/Views/Home/HomeMain.xaml.cs +++ b/VDownload/Views/Home/HomeMain.xaml.cs @@ -6,12 +6,11 @@ using System.Net; using System.Threading; using System.Threading.Tasks; using VDownload.Core.Enums; -using VDownload.Core.EventArgsObjects; +using VDownload.Core.EventArgs; using VDownload.Core.Exceptions; using VDownload.Core.Interfaces; using VDownload.Core.Services; using Windows.ApplicationModel.Resources; -using Windows.UI.Core; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Imaging; @@ -42,8 +41,8 @@ namespace VDownload.Views.Home private CancellationTokenSource SearchingCancellationToken = new CancellationTokenSource(); // HOME VIDEOS LIST - private static StackPanel HomeVideosListOldPanel = null; - public static List VideoPanelsList = new List(); + private static StackPanel HomeTasksListParent = null; + public static List TaskPanelsList = new List(); #endregion @@ -54,9 +53,9 @@ namespace VDownload.Views.Home // ON NAVIGATED TO protected override async void OnNavigatedTo(NavigationEventArgs e) { - if (HomeVideosListOldPanel != null) HomeVideosListOldPanel.Children.Clear(); - HomeVideosListOldPanel = HomeVideosList; - foreach (HomeVideoPanel homeVideoPanel in VideoPanelsList) HomeVideosList.Children.Add(homeVideoPanel); + if (HomeTasksListParent != null) HomeTasksListParent.Children.Clear(); + HomeTasksListParent = HomeTasksList; + foreach (HomeTaskPanel homeVideoPanel in TaskPanelsList) HomeTasksList.Children.Add(homeVideoPanel); } // ADD VIDEO BUTTON CHECKED @@ -158,7 +157,7 @@ namespace VDownload.Views.Home HomeOptionBarAndAddingPanelRow.Height = new GridLength(1, GridUnitType.Star); - HomeVideosListRow.Height = new GridLength(0); + HomeTasksListRow.Height = new GridLength(0); HomeVideoAddingPanel addingPanel = new HomeVideoAddingPanel(videoService); addingPanel.VideoAddRequest += HomeVideoAddingPanel_VideoAddRequest; HomeAddingPanel.Content = addingPanel; @@ -170,19 +169,19 @@ namespace VDownload.Views.Home // Uncheck video button HomeOptionsBarAddVideoButton.IsChecked = false; - // Create video panel/task - HomeVideoPanel videoPanel = new HomeVideoPanel(e.VideoService, e.MediaType, e.Stream, e.TrimStart, e.TrimEnd, e.Filename, e.Extension, e.Location); + // Create video task + HomeTaskPanel taskPanel = new HomeTaskPanel(e.VideoService, e.MediaType, e.Stream, e.TrimStart, e.TrimEnd, e.Filename, e.Extension, e.Location); - videoPanel.VideoRemovingRequested += (s, a) => + taskPanel.TaskRemovingRequested += (s, a) => { - // Remove video panel/task from videos list - VideoPanelsList.Remove(videoPanel); - HomeVideosList.Children.Remove(videoPanel); + // Remove task from tasks lists + TaskPanelsList.Remove(taskPanel); + HomeTasksList.Children.Remove(taskPanel); }; - // Add video panel/task to videos list - HomeVideosList.Children.Add(videoPanel); - VideoPanelsList.Add(videoPanel); + // Add task to tasks lists + HomeTasksList.Children.Add(taskPanel); + TaskPanelsList.Add(taskPanel); } @@ -287,7 +286,7 @@ namespace VDownload.Views.Home SearchingCancellationToken = new CancellationTokenSource(); HomeOptionBarAndAddingPanelRow.Height = GridLength.Auto; - HomeVideosListRow.Height = new GridLength(1, GridUnitType.Star); + HomeTasksListRow.Height = new GridLength(1, GridUnitType.Star); HomeAddingPanel.Content = null; HomeOptionsBarAddingControl.Content = null; @@ -298,7 +297,7 @@ namespace VDownload.Views.Home // DOWNLOAD ALL BUTTON CLICKED private async void HomeOptionsBarDownloadAllButton_Click(object sender, RoutedEventArgs e) { - foreach (HomeVideoPanel videoPanel in HomeVideosList.Children.Where(video => ((HomeVideoPanel)video).VideoStatus == VideoStatus.Idle)) + foreach (HomeTaskPanel videoPanel in HomeTasksList.Children.Where((object video) => ((HomeTaskPanel)video).TaskStatus == Core.Enums.TaskStatus.Idle)) { await Task.Delay(50); videoPanel.Start(); @@ -314,7 +313,7 @@ namespace VDownload.Views.Home // WAIT IN QUEUE public static async Task WaitInQueue(CancellationToken token) { - while (VideoPanelsList.Where(video => video.VideoStatus == VideoStatus.InProgress).Count() >= (int)Config.GetValue("max_active_video_task") && !token.IsCancellationRequested) + while (TaskPanelsList.Where((HomeTaskPanel video) => video.TaskStatus == Core.Enums.TaskStatus.InProgress).Count() >= (int)Config.GetValue("max_active_video_task") && !token.IsCancellationRequested) { await Task.Delay(50); } diff --git a/VDownload/Views/Home/HomeOptionsBarAddPlaylistControl.xaml.cs b/VDownload/Views/Home/HomeOptionsBarAddPlaylistControl.xaml.cs index 7503ee9..4dea2db 100644 --- a/VDownload/Views/Home/HomeOptionsBarAddPlaylistControl.xaml.cs +++ b/VDownload/Views/Home/HomeOptionsBarAddPlaylistControl.xaml.cs @@ -1,5 +1,5 @@ using System; -using VDownload.Core.EventArgsObjects; +using VDownload.Core.EventArgs; using VDownload.Core.Services; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -24,9 +24,6 @@ namespace VDownload.Views.Home // MAX VIDEOS NUMBERBOX DEFAULT VALUE public int DefaultMaxPlaylistVideos = (int)Config.GetValue("default_max_playlist_videos"); - // SEARCH BUTTON EVENT HANDLER - public event EventHandler SearchButtonClicked; - #endregion @@ -56,5 +53,13 @@ namespace VDownload.Views.Home } #endregion + + + + #region EVENT HANDLERS + + public event EventHandler SearchButtonClicked; + + #endregion } } diff --git a/VDownload/Views/Home/HomeOptionsBarAddVideoControl.xaml.cs b/VDownload/Views/Home/HomeOptionsBarAddVideoControl.xaml.cs index a99852a..1b42947 100644 --- a/VDownload/Views/Home/HomeOptionsBarAddVideoControl.xaml.cs +++ b/VDownload/Views/Home/HomeOptionsBarAddVideoControl.xaml.cs @@ -1,5 +1,5 @@ using System; -using VDownload.Core.EventArgsObjects; +using VDownload.Core.EventArgs; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -18,16 +18,7 @@ namespace VDownload.Views.Home - #region PROPERTIES - - // SEARCH BUTTON EVENT HANDLER - public event EventHandler SearchButtonClicked; - - #endregion - - - - #region EVENT HANDLERS + #region EVENT HANDLERS VOIDS // SEARCH BUTTON CLICKED private void HomeOptionsBarAddVideoControlSearchButton_Click(object sender, RoutedEventArgs e) @@ -51,5 +42,13 @@ namespace VDownload.Views.Home } #endregion + + + + #region EVENT HANDLERS + + public event EventHandler SearchButtonClicked; + + #endregion } } diff --git a/VDownload/Views/Home/HomeVideoPanel.xaml b/VDownload/Views/Home/HomeTaskPanel.xaml similarity index 79% rename from VDownload/Views/Home/HomeVideoPanel.xaml rename to VDownload/Views/Home/HomeTaskPanel.xaml index dd1a4f0..6103ff1 100644 --- a/VDownload/Views/Home/HomeVideoPanel.xaml +++ b/VDownload/Views/Home/HomeTaskPanel.xaml @@ -1,10 +1,11 @@  - - - + + + - - - + + + diff --git a/VDownload/Views/Home/HomeVideoPanel.xaml.cs b/VDownload/Views/Home/HomeTaskPanel.xaml.cs similarity index 58% rename from VDownload/Views/Home/HomeVideoPanel.xaml.cs rename to VDownload/Views/Home/HomeTaskPanel.xaml.cs index 507a549..e619e78 100644 --- a/VDownload/Views/Home/HomeVideoPanel.xaml.cs +++ b/VDownload/Views/Home/HomeTaskPanel.xaml.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using VDownload.Core.Enums; using VDownload.Core.Interfaces; -using VDownload.Core.Objects; using VDownload.Core.Services; using Windows.ApplicationModel.ExtendedExecution; using Windows.ApplicationModel.Resources; @@ -16,15 +15,14 @@ using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Imaging; -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - namespace VDownload.Views.Home { - public sealed partial class HomeVideoPanel : UserControl + public sealed partial class HomeTaskPanel : UserControl { #region CONSTANTS ResourceDictionary IconsRes = new ResourceDictionary { Source = new Uri("ms-appx:///Resources/Icons.xaml") }; + ResourceDictionary ImagesRes = new ResourceDictionary { Source = new Uri("ms-appx:///Resources/Images.xaml") }; #endregion @@ -32,12 +30,12 @@ namespace VDownload.Views.Home #region CONSTRUCTORS - public HomeVideoPanel(IVideoService videoService, MediaType mediaType, Stream stream, TimeSpan trimStart, TimeSpan trimEnd, string filename, MediaFileExtension extension, StorageFolder location) + public HomeTaskPanel(IVideoService videoService, MediaType mediaType, IBaseStream stream, TimeSpan trimStart, TimeSpan trimEnd, string filename, MediaFileExtension extension, StorageFolder location) { this.InitializeComponent(); // Set video status - VideoStatus = VideoStatus.Idle; + TaskStatus = Core.Enums.TaskStatus.Idle; // Set video service object VideoService = videoService; @@ -55,8 +53,8 @@ namespace VDownload.Views.Home Location = location; // Set metadata - ThumbnailImage = new BitmapImage { UriSource = VideoService.Thumbnail ?? new Uri("ms-appx:///Assets/UnknownThumbnail.png") }; - SourceImage = new BitmapIcon { UriSource = new Uri($"ms-appx:///Assets/Icons/{VideoService.GetType().Namespace.Split(".").Last()}.png"), ShowAsMonochrome = false }; + ThumbnailImage = (BitmapImage)ImagesRes["UnknownThumbnailImage"]; + SourceImage = new BitmapIcon { UriSource = new Uri($"ms-appx:///Assets/Sources/{VideoService.GetType().Namespace.Split(".").Last()}.png"), ShowAsMonochrome = false }; Title = VideoService.Title; Author = VideoService.Author; TimeSpan newDuration = TrimEnd.Subtract(TrimStart); @@ -67,9 +65,9 @@ namespace VDownload.Views.Home File += $@"{(Location != null ? Location.Path : $@"{UserDataPaths.GetDefault().Downloads}\VDownload")}\{Filename}.{Extension.ToString().ToLower()}"; // Set state controls - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateIdleIcon"]; - HomeVideoPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextIdle"); - HomeVideoPanelStateProgressBar.Visibility = Visibility.Collapsed; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateIdleIcon"]; + HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextIdle"); + HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed; } #endregion @@ -79,9 +77,9 @@ namespace VDownload.Views.Home #region PROPERTIES // VIDEO STATUS - public VideoStatus VideoStatus { get; set; } + public Core.Enums.TaskStatus TaskStatus { get; set; } - // VIDEO CANECELLATION TOKEN + // TASK CANCELLATION TOKEN public CancellationTokenSource CancellationTokenSource { get; set; } // VIDEO SERVICE @@ -89,7 +87,7 @@ namespace VDownload.Views.Home // VIDEO OPTIONS private MediaType MediaType { get; set; } - private Stream Stream { get; set; } + private IBaseStream Stream { get; set; } private TimeSpan TrimStart { get; set; } private TimeSpan TrimEnd { get; set; } private string Filename { get; set; } @@ -114,26 +112,26 @@ namespace VDownload.Views.Home public async Task Start() { // Change icon - HomeVideoPanelStartStopButton.Icon = new SymbolIcon(Symbol.Stop); + HomeTaskPanelStartStopButton.Icon = new SymbolIcon(Symbol.Stop); // Create cancellation token CancellationTokenSource = new CancellationTokenSource(); - // Set video status - VideoStatus = VideoStatus.Waiting; + // Set task status + TaskStatus = Core.Enums.TaskStatus.Waiting; // Set state controls - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateWaitingIcon"]; - HomeVideoPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextWaiting"); - HomeVideoPanelStateProgressBar.Visibility = Visibility.Visible; - HomeVideoPanelStateProgressBar.IsIndeterminate = true; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateWaitingIcon"]; + HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextWaiting"); + HomeTaskPanelStateProgressBar.Visibility = Visibility.Visible; + HomeTaskPanelStateProgressBar.IsIndeterminate = true; // Wait in queue await HomeMain.WaitInQueue(CancellationTokenSource.Token); if (!CancellationTokenSource.IsCancellationRequested) { - // Set video status - VideoStatus = VideoStatus.InProgress; + // Set task status + TaskStatus = Core.Enums.TaskStatus.InProgress; // Get task unique ID string uniqueID = TaskId.Get(); @@ -148,7 +146,7 @@ namespace VDownload.Views.Home try { - // Set cancellation token to throw exception on request + // Throw exception if cancellation requested CancellationTokenSource.Token.ThrowIfCancellationRequested(); // Start stopwatch @@ -157,28 +155,28 @@ namespace VDownload.Views.Home // Set progress event handlers VideoService.DownloadingStarted += (s, a) => { - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateDownloadingIcon"]; - HomeVideoPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextDownloading")} (0%)"; - HomeVideoPanelStateProgressBar.IsIndeterminate = false; - HomeVideoPanelStateProgressBar.Value = 0; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateDownloadingIcon"]; + HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextDownloading")} (0%)"; + HomeTaskPanelStateProgressBar.IsIndeterminate = false; + HomeTaskPanelStateProgressBar.Value = 0; }; VideoService.DownloadingProgressChanged += (s, a) => { - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateDownloadingIcon"]; - HomeVideoPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextDownloading")} ({a.ProgressPercentage}%)"; - HomeVideoPanelStateProgressBar.Value = a.ProgressPercentage; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateDownloadingIcon"]; + HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextDownloading")} ({a.ProgressPercentage}%)"; + HomeTaskPanelStateProgressBar.Value = a.ProgressPercentage; }; VideoService.ProcessingStarted += (s, a) => { - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateProcessingIcon"]; - HomeVideoPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextProcessing")} (0%)"; - HomeVideoPanelStateProgressBar.Value = 0; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateProcessingIcon"]; + HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextProcessing")} (0%)"; + HomeTaskPanelStateProgressBar.Value = 0; }; VideoService.ProcessingProgressChanged += (s, a) => { - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateProcessingIcon"]; - HomeVideoPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextProcessing")} ({a.ProgressPercentage}%)"; - HomeVideoPanelStateProgressBar.Value = a.ProgressPercentage; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateProcessingIcon"]; + HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextProcessing")} ({a.ProgressPercentage}%)"; + HomeTaskPanelStateProgressBar.Value = a.ProgressPercentage; }; // Request extended session @@ -186,7 +184,8 @@ namespace VDownload.Views.Home await session.RequestExtensionAsync(); // Start task - StorageFile tempOutputFile = await VideoService.DownloadAndTranscodeAsync(tempFolder, Stream, Extension, MediaType, CancellationTokenSource.Token); + CancellationTokenSource.Token.ThrowIfCancellationRequested(); + StorageFile tempOutputFile = await VideoService.DownloadAndTranscodeAsync(tempFolder, Stream, Extension, MediaType, TrimStart, TrimEnd, CancellationTokenSource.Token); // Dispose session session.Dispose(); @@ -195,13 +194,12 @@ namespace VDownload.Views.Home CancellationTokenSource.Token.ThrowIfCancellationRequested(); // Set state controls - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateFinalizingIcon"]; - HomeVideoPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextFinalizing"); - HomeVideoPanelStateProgressBar.IsIndeterminate = true; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateFinalizingIcon"]; + HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextFinalizing"); + HomeTaskPanelStateProgressBar.IsIndeterminate = true; // Move to output location StorageFile outputFile; - Debug.WriteLine($"{Filename}.{Extension.ToString().ToLower()}"); if (Location != null) outputFile = await Location.CreateFileAsync($"{Filename}.{Extension.ToString().ToLower()}", (bool)Config.GetValue("replace_output_file_if_exists") ? CreationCollisionOption.ReplaceExisting : CreationCollisionOption.GenerateUniqueName); else outputFile = await DownloadsFolder.CreateFileAsync($"{Filename}.{Extension.ToString().ToLower()}", (bool)Config.GetValue("replace_output_file_if_exists") ? CreationCollisionOption.ReplaceExisting : CreationCollisionOption.GenerateUniqueName); await tempOutputFile.MoveAndReplaceAsync(outputFile); @@ -210,25 +208,25 @@ namespace VDownload.Views.Home taskStopwatch.Stop(); // Set state controls - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateDoneIcon"]; - HomeVideoPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextDone")} ({(Math.Floor(taskStopwatch.Elapsed.TotalHours) > 0 ? $"{ Math.Floor(taskStopwatch.Elapsed.TotalHours):0}:" : "")}{taskStopwatch.Elapsed.Minutes:00}:{taskStopwatch.Elapsed.Seconds:00})"; - HomeVideoPanelStateProgressBar.Visibility = Visibility.Collapsed; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateDoneIcon"]; + HomeTaskPanelStateText.Text = $"{ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextDone")} ({(Math.Floor(taskStopwatch.Elapsed.TotalHours) > 0 ? $"{ Math.Floor(taskStopwatch.Elapsed.TotalHours):0}:" : "")}{taskStopwatch.Elapsed.Minutes:00}:{taskStopwatch.Elapsed.Seconds:00})"; + HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed; } catch (OperationCanceledException) { // Set state controls - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateCancelledIcon"]; - HomeVideoPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextCancelled"); - HomeVideoPanelStateProgressBar.Visibility = Visibility.Collapsed; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateCancelledIcon"]; + HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextCancelled"); + HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed; } finally { // Change icon - HomeVideoPanelStartStopButton.Icon = new SymbolIcon(Symbol.Download); + HomeTaskPanelStartStopButton.Icon = new SymbolIcon(Symbol.Download); // Set video status - VideoStatus = VideoStatus.Idle; + TaskStatus = Core.Enums.TaskStatus.Idle; // Delete temporary files await tempFolder.DeleteAsync(); @@ -240,9 +238,9 @@ namespace VDownload.Views.Home else { // Set state controls - HomeVideoPanelStateIcon.Source = (SvgImageSource)IconsRes["StateCancelledIcon"]; - HomeVideoPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeVideoPanelStateTextCancelled"); - HomeVideoPanelStateProgressBar.Visibility = Visibility.Collapsed; + HomeTaskPanelStateIcon.Source = (SvgImageSource)IconsRes["StateCancelledIcon"]; + HomeTaskPanelStateText.Text = ResourceLoader.GetForCurrentView().GetString("HomeTaskPanelStateTextCancelled"); + HomeTaskPanelStateProgressBar.Visibility = Visibility.Collapsed; } } @@ -253,24 +251,24 @@ namespace VDownload.Views.Home #region EVENT HANDLERS VOIDS // SOURCE BUTTON CLICKED - private async void HomeVideoPanelSourceButton_Click(object sender, RoutedEventArgs e) + private async void HomeTaskPanelSourceButton_Click(object sender, RoutedEventArgs e) { // Launch the website await Windows.System.Launcher.LaunchUriAsync(VideoService.VideoUrl); } // START STOP BUTTON CLICKED - private async void HomeVideoPanelStartStopButton_Click(object sender, RoutedEventArgs e) + private async void HomeTaskPanelStartStopButton_Click(object sender, RoutedEventArgs e) { - if (VideoStatus == VideoStatus.InProgress || VideoStatus == VideoStatus.Waiting) CancellationTokenSource.Cancel(); + if (TaskStatus == Core.Enums.TaskStatus.InProgress || TaskStatus == Core.Enums.TaskStatus.Waiting) CancellationTokenSource.Cancel(); else await Start(); } // REMOVE BUTTON CLICKED - private void HomeVideoPanelRemoveButton_Click(object sender, RoutedEventArgs e) + private void HomeTaskPanelRemoveButton_Click(object sender, RoutedEventArgs e) { - if (VideoStatus == VideoStatus.InProgress || VideoStatus == VideoStatus.Waiting) CancellationTokenSource.Cancel(); - VideoRemovingRequested?.Invoke(sender, EventArgs.Empty); + if (TaskStatus == Core.Enums.TaskStatus.InProgress || TaskStatus == Core.Enums.TaskStatus.Waiting) CancellationTokenSource.Cancel(); + TaskRemovingRequested?.Invoke(sender, EventArgs.Empty); } #endregion @@ -279,7 +277,7 @@ namespace VDownload.Views.Home #region EVENT HANDLERS - public event EventHandler VideoRemovingRequested; + public event EventHandler TaskRemovingRequested; #endregion } diff --git a/VDownload/Views/Home/HomeVideoAddingPanel.xaml.cs b/VDownload/Views/Home/HomeVideoAddingPanel.xaml.cs index 59e400c..47a5c21 100644 --- a/VDownload/Views/Home/HomeVideoAddingPanel.xaml.cs +++ b/VDownload/Views/Home/HomeVideoAddingPanel.xaml.cs @@ -1,13 +1,11 @@ -using Microsoft.Toolkit.Uwp.UI; -using System; +using System; using System.Collections.Generic; -using System.Diagnostics; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using VDownload.Core.Enums; -using VDownload.Core.EventArgsObjects; +using VDownload.Core.EventArgs; using VDownload.Core.Interfaces; using VDownload.Core.Objects; using VDownload.Core.Services; @@ -20,12 +18,18 @@ using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Imaging; -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - namespace VDownload.Views.Home { public sealed partial class HomeVideoAddingPanel : UserControl { + #region CONSTANTS + + ResourceDictionary ImagesRes = new ResourceDictionary { Source = new Uri("ms-appx:///Resources/Images.xaml") }; + + #endregion + + + #region CONSTRUCTORS public HomeVideoAddingPanel(IVideoService videoService) @@ -36,8 +40,8 @@ namespace VDownload.Views.Home VideoService = videoService; // Set metadata - ThumbnailImage = new BitmapImage { UriSource = VideoService.Thumbnail ?? new Uri("ms-appx:///Assets/UnknownThumbnail.png") }; - SourceImage = new BitmapIcon { UriSource = new Uri($"ms-appx:///Assets/Icons/{VideoService.GetType().Namespace.Split(".").Last()}.png"), ShowAsMonochrome = false }; + ThumbnailImage = VideoService.Thumbnail != null ? new BitmapImage { UriSource = VideoService.Thumbnail } : (BitmapImage)ImagesRes["UnknownThumbnailImage"]; + SourceImage = new BitmapIcon { UriSource = new Uri($"ms-appx:///Assets/Sources/{VideoService.GetType().Namespace.Split(".").Last()}.png"), ShowAsMonochrome = false }; Title = VideoService.Title; Author = VideoService.Author; Views = VideoService.Views.ToString(); @@ -53,7 +57,7 @@ namespace VDownload.Views.Home HomeVideoAddingMediaTypeSettingControlComboBox.SelectedIndex = (int)Config.GetValue("default_media_type"); // Set quality - foreach (Stream stream in VideoService.Streams) + foreach (IBaseStream stream in VideoService.BaseStreams) { HomeVideoAddingQualitySettingControlComboBox.Items.Add($"{stream.Height}p{(stream.FrameRate > 0 ? stream.FrameRate.ToString() : "N/A")}"); } @@ -130,7 +134,7 @@ namespace VDownload.Views.Home // VIDEO OPTIONS private MediaType MediaType { get; set; } - private Stream Stream { get; set; } + private IBaseStream Stream { get; set; } private TimeSpan TrimStart { get; set; } private TimeSpan TrimEnd { get; set; } private string Filename { get; set; } @@ -150,7 +154,7 @@ namespace VDownload.Views.Home if (HomeVideoAddingMediaTypeSettingControlComboBox.SelectedIndex == (int)MediaType.OnlyAudio) { HomeVideoAddingQualitySettingControl.Visibility = Visibility.Collapsed; - HomeVideoAddingQualitySettingControlComboBox.SelectedIndex = VideoService.Streams.Count() - 1; + HomeVideoAddingQualitySettingControlComboBox.SelectedIndex = VideoService.BaseStreams.Count() - 1; HomeVideoAddingExtensionComboBox.Items.Clear(); foreach (AudioFileExtension extension in Enum.GetValues(typeof(AudioFileExtension))) @@ -176,7 +180,7 @@ namespace VDownload.Views.Home // QUALITY COMBOBOX SELECTION CHANGED private void HomeVideoAddingQualitySettingControlComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { - Stream = VideoService.Streams[HomeVideoAddingQualitySettingControlComboBox.SelectedIndex]; + Stream = VideoService.BaseStreams[HomeVideoAddingQualitySettingControlComboBox.SelectedIndex]; } // TRIM START TEXTBOX TEXT CHANGED diff --git a/VDownload/Views/Home/HomeVideosList.cs b/VDownload/Views/Home/HomeVideosList.cs deleted file mode 100644 index 0f9a9ef..0000000 --- a/VDownload/Views/Home/HomeVideosList.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VDownload.Views.Home -{ - public class HomeVideosList - { - } -} diff --git a/VDownload/Views/MainPage.xaml b/VDownload/Views/MainPage.xaml index 2fda7d2..dfa7bd9 100644 --- a/VDownload/Views/MainPage.xaml +++ b/VDownload/Views/MainPage.xaml @@ -10,9 +10,14 @@ - 0,48,0,0 - 0 - + + + + + 0,48,0,0 + 0 + + diff --git a/VDownload/Views/Sources/SourcesMain.xaml.cs b/VDownload/Views/Sources/SourcesMain.xaml.cs index d8b282a..bf56226 100644 --- a/VDownload/Views/Sources/SourcesMain.xaml.cs +++ b/VDownload/Views/Sources/SourcesMain.xaml.cs @@ -1,7 +1,6 @@ using Microsoft.UI.Xaml.Controls; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Net; using Windows.ApplicationModel.Resources;