1.0-dev10 (Code cleaning)

This commit is contained in:
2022-03-02 22:13:28 +01:00
Unverified
parent 25041f9d43
commit d8eb103dcc
36 changed files with 338 additions and 336 deletions

View File

@@ -1,6 +1,6 @@
namespace VDownload.Core.Enums
{
public enum VideoStatus
public enum TaskStatus
{
Idle,
Waiting,

View File

@@ -0,0 +1,8 @@
namespace VDownload.Core.EventArgs
{
public class PlaylistSearchEventArgs : System.EventArgs
{
public string Phrase { get; set; }
public int Count { get; set; }
}
}

View File

@@ -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; }

View File

@@ -0,0 +1,7 @@
namespace VDownload.Core.EventArgs
{
public class VideoSearchEventArgs : System.EventArgs
{
public string Phrase { get; set; }
}
}

View File

@@ -1,10 +0,0 @@
using System;
namespace VDownload.Core.EventArgsObjects
{
public class PlaylistSearchEventArgs : EventArgs
{
public string Phrase { get; set; }
public int Count { get; set; }
}
}

View File

@@ -1,9 +0,0 @@
using System;
namespace VDownload.Core.EventArgsObjects
{
public class VideoSearchEventArgs : EventArgs
{
public string Phrase { get; set; }
}
}

View File

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

View File

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

View File

@@ -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

View File

@@ -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<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default);
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, CancellationToken cancellationToken = default);
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, IVStream videoStream, VideoFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default);
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default);
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default);
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, CancellationToken cancellationToken = default);
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default);
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default);
Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IBaseStream baseStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default);
#endregion

View File

@@ -4,7 +4,7 @@ using VDownload.Core.Interfaces;
namespace VDownload.Core.Objects
{
public class Stream : IVStream, IAStream
public class Stream : IBaseStream
{
#region CONSTRUCTORS

View File

@@ -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;

View File

@@ -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<double> transcodingTask = transcodingPreparated.TranscodeAsync();
try
{
await transcodingTask.AsTask(cancellationToken, new Progress<double>((percent) => { ProcessingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(percent), null)); }));
await outputFileOpened.FlushAsync();
}
catch (TaskCanceledException) { }
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<MediaClip> getVideoFileTask = MediaClip.CreateFromFileAsync(videoFile).AsTask();
Task<BackgroundAudioTrack> 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); }

View File

@@ -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/(?<id>\d+)"), VideoSource.TwitchVod),
@@ -19,6 +15,7 @@ namespace VDownload.Core.Services
(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),
@@ -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)

View File

@@ -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

View File

@@ -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"];

View File

@@ -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<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default)
public async Task<StorageFile> 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<StorageFile> 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<StorageFile> 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<StorageFile> 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<StorageFile> 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<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, audioStream, extension, new TimeSpan(0), Duration, cancellationToken); }
public async Task<StorageFile> 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<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IVStream videoStream, VideoFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, videoStream, extension, new TimeSpan(0), Duration, cancellationToken); }
#endregion

View File

@@ -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<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, Stream audioVideoStream, MediaFileExtension extension, MediaType mediaType, TimeSpan trimStart, TimeSpan trimEnd, CancellationToken cancellationToken = default)
public async Task<StorageFile> 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)
{
rawFile = await downloadingFolder.CreateFileAsync("raw.ts");
cancellationToken.ThrowIfCancellationRequested();
StorageFile rawFile = await downloadingFolder.CreateFileAsync("raw.ts");
float chunksDownloaded = 0;
Task<byte[]> downloadTask;
Task writeTask;
cancellationToken.ThrowIfCancellationRequested();
downloadTask = DownloadChunkAsync(chunksList[0].ChunkUrl);
await downloadTask;
for (int i = 1; i < chunksList.Count && !cancellationToken.IsCancellationRequested; i++)
for (int i = 1; i < chunksList.Count; i++)
{
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));
}
if (!cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteChunkToFileAsync(rawFile, downloadTask.Result);
DownloadingProgressChanged(this, new ProgressChangedEventArgs((int)Math.Round(++chunksDownloaded * 100 / chunksList.Count), null));
DownloadingCompleted?.Invoke(this, EventArgs.Empty);
}
}
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;
cancellationToken.ThrowIfCancellationRequested();
await mediaProcessor.Run(rawFile, extension, mediaType, cancellationToken);
}
// Return output file
return outputFile;
}
public async Task<StorageFile> 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<StorageFile> 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<StorageFile> 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<StorageFile> 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<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, IAStream audioStream, AudioFileExtension extension, CancellationToken cancellationToken = default) { return await DownloadAndTranscodeAsync(downloadingFolder, audioStream, extension, new TimeSpan(0), Duration, cancellationToken); }
public async Task<StorageFile> 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<StorageFile> 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<List<(Uri ChunkUrl, TimeSpan ChunkDuration)>> ExtractChunksFromM3U8Async(Uri streamUrl)
private static async Task<List<(Uri ChunkUrl, TimeSpan ChunkDuration)>> 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<byte[]> DownloadChunkAsync(Uri chunkUrl)
private static async Task<byte[]> 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())

View File

@@ -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<string> UsedIDs = new List<string>();
// 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
}
}

View File

@@ -127,16 +127,15 @@
<Compile Include="Enums\StreamType.cs" />
<Compile Include="Enums\VideoFileExtension.cs" />
<Compile Include="Enums\VideoSource.cs" />
<Compile Include="Enums\VideoStatus.cs" />
<Compile Include="EventArgsObjects\VideoAddEventArgs.cs" />
<Compile Include="EventArgsObjects\VideoSearchEventArgs.cs" />
<Compile Include="EventArgsObjects\PlaylistSearchEventArgs.cs" />
<Compile Include="Enums\TaskStatus.cs" />
<Compile Include="EventArgs\VideoAddEventArgs.cs" />
<Compile Include="EventArgs\VideoSearchEventArgs.cs" />
<Compile Include="EventArgs\PlaylistSearchEventArgs.cs" />
<Compile Include="Exceptions\TwitchAccessTokenNotFoundException.cs" />
<Compile Include="Exceptions\TwitchAccessTokenNotValidException.cs" />
<Compile Include="Interfaces\IAStream.cs" />
<Compile Include="Interfaces\IBaseStream.cs" />
<Compile Include="Interfaces\IPlaylistService.cs" />
<Compile Include="Interfaces\IVideoService.cs" />
<Compile Include="Interfaces\IVStream.cs" />
<Compile Include="Objects\Stream.cs" />
<Compile Include="Services\Config.cs" />
<Compile Include="Services\MediaProcessor.cs" />

View File

@@ -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<IStorageItem> tempItems = await ApplicationData.Current.TemporaryFolder.GetItemsAsync();
IReadOnlyList<IStorageItem> 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<Task> tasks = new List<Task>();
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
}
}

View File

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

View File

@@ -0,0 +1,5 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<BitmapImage x:Name="UnknownThumbnailImage" UriSource="ms-appx:///Assets/Images/UnknownThumbnail.png"/>
</ResourceDictionary>

View File

@@ -196,6 +196,27 @@ The number in the numberbox indicades how many videos will be got from playlist.
<data name="HomeOptionsBarVideoSearchingTwitchAccessTokenNotValidErrorDialogDescription" xml:space="preserve">
<value>There is a problem with linked Twitch account. Check Twitch login status in Sources page.</value>
</data>
<data name="HomeTaskPanelStateTextCancelled" xml:space="preserve">
<value>Cancelled</value>
</data>
<data name="HomeTaskPanelStateTextDone" xml:space="preserve">
<value>Done</value>
</data>
<data name="HomeTaskPanelStateTextDownloading" xml:space="preserve">
<value>Downloading</value>
</data>
<data name="HomeTaskPanelStateTextFinalizing" xml:space="preserve">
<value>Finalizing</value>
</data>
<data name="HomeTaskPanelStateTextIdle" xml:space="preserve">
<value>Idle</value>
</data>
<data name="HomeTaskPanelStateTextProcessing" xml:space="preserve">
<value>Processing</value>
</data>
<data name="HomeTaskPanelStateTextWaiting" xml:space="preserve">
<value>Queued</value>
</data>
<data name="HomeVideoAddingDownloadingOptionsHeaderTextBlock.Text" xml:space="preserve">
<value>Downloading options</value>
</data>
@@ -220,27 +241,6 @@ The number in the numberbox indicades how many videos will be got from playlist.
<data name="HomeVideoAddingTrimSettingControl.Title" xml:space="preserve">
<value>Trim</value>
</data>
<data name="HomeVideoPanelStateTextCancelled" xml:space="preserve">
<value>Cancelled</value>
</data>
<data name="HomeVideoPanelStateTextDone" xml:space="preserve">
<value>Done</value>
</data>
<data name="HomeVideoPanelStateTextDownloading" xml:space="preserve">
<value>Downloading</value>
</data>
<data name="HomeVideoPanelStateTextFinalizing" xml:space="preserve">
<value>Finalizing</value>
</data>
<data name="HomeVideoPanelStateTextIdle" xml:space="preserve">
<value>Idle</value>
</data>
<data name="HomeVideoPanelStateTextProcessing" xml:space="preserve">
<value>Processing</value>
</data>
<data name="HomeVideoPanelStateTextWaiting" xml:space="preserve">
<value>Queued</value>
</data>
<data name="MainPageNavigationPanelHomeItem.Content" xml:space="preserve">
<value>Home</value>
</data>

View File

@@ -140,10 +140,9 @@
<Compile Include="Views\Home\HomeVideoAddingPanel.xaml.cs">
<DependentUpon>HomeVideoAddingPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Home\HomeVideoPanel.xaml.cs">
<DependentUpon>HomeVideoPanel.xaml</DependentUpon>
<Compile Include="Views\Home\HomeTaskPanel.xaml.cs">
<DependentUpon>HomeTaskPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Home\HomeVideosList.cs" />
<Compile Include="Views\MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
@@ -250,7 +249,8 @@
<Content Include="Assets\Logo\Wide310x150Logo.scale-200.png" />
<Content Include="Assets\Logo\Wide310x150Logo.scale-400.png" />
<Content Include="Assets\Icons\Twitch.png" />
<Content Include="Assets\UnknownThumbnail.png" />
<Content Include="Assets\Images\UnknownThumbnail.png" />
<Content Include="Assets\Sources\Twitch.png" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
@@ -269,6 +269,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Resources\Images.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\About\AboutMain.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -293,7 +297,7 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Home\HomeVideoPanel.xaml">
<Page Include="Views\Home\HomeTaskPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>

View File

@@ -54,13 +54,13 @@
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition x:Name="HomeVideosListRow" Height="1*"/>
<RowDefinition x:Name="HomeTasksListRow" Height="1*"/>
<RowDefinition x:Name="HomeOptionBarAndAddingPanelRow" Height="Auto"/>
</Grid.RowDefinitions>
<!-- VIDEOS LIST -->
<ScrollViewer Margin="0,0,0,10" CornerRadius="{ThemeResource ControlCornerRadius}">
<StackPanel x:Name="HomeVideosList" Spacing="10"/>
<StackPanel x:Name="HomeTasksList" Spacing="10"/>
</ScrollViewer>
<!-- OPTIONS BAR AND ADDING PANEL -->

View File

@@ -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<HomeVideoPanel> VideoPanelsList = new List<HomeVideoPanel>();
private static StackPanel HomeTasksListParent = null;
public static List<HomeTaskPanel> TaskPanelsList = new List<HomeTaskPanel>();
#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);
}

View File

@@ -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<PlaylistSearchEventArgs> SearchButtonClicked;
#endregion
@@ -56,5 +53,13 @@ namespace VDownload.Views.Home
}
#endregion
#region EVENT HANDLERS
public event EventHandler<PlaylistSearchEventArgs> SearchButtonClicked;
#endregion
}
}

View File

@@ -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<VideoSearchEventArgs> 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<VideoSearchEventArgs> SearchButtonClicked;
#endregion
}
}

View File

@@ -1,10 +1,11 @@
<UserControl
x:Class="VDownload.Views.Home.HomeVideoPanel"
x:Class="VDownload.Views.Home.HomeTaskPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VDownload.Views.Home"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d"
CornerRadius="{ThemeResource ControlCornerRadius}"
d:DesignHeight="150"
@@ -52,12 +53,12 @@
<TextBlock Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" VerticalAlignment="Center" FontSize="{StaticResource MetadataTextSize}" Text="{x:Bind Duration}"/>
<Image Grid.Row="2" Grid.Column="0" Width="{StaticResource MetadataIconSize}" Source="{ThemeResource FileIcon}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" VerticalAlignment="Center" FontSize="{StaticResource MetadataTextSize}" Text="{x:Bind File}"/>
<Image x:Name="HomeVideoPanelStateIcon" Grid.Row="3" Grid.Column="0" Width="{StaticResource MetadataIconSize}"/>
<TextBlock x:Name="HomeVideoPanelStateText" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" FontSize="{StaticResource MetadataTextSize}"/>
<muxc:ProgressBar x:Name="HomeVideoPanelStateProgressBar" Grid.Row="3" Grid.Column="2" Margin="10,0,0,0" VerticalAlignment="Center"/>
<Image x:Name="HomeTaskPanelStateIcon" Grid.Row="3" Grid.Column="0" Width="{StaticResource MetadataIconSize}"/>
<TextBlock x:Name="HomeTaskPanelStateText" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" FontSize="{StaticResource MetadataTextSize}"/>
<muxc:ProgressBar x:Name="HomeTaskPanelStateProgressBar" Grid.Row="3" Grid.Column="2" Margin="10,0,0,0" VerticalAlignment="Center"/>
</Grid>
<AppBarButton Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" Width="40" Height="48" Margin="-3" Icon="{x:Bind SourceImage}" Click="HomeVideoPanelSourceButton_Click"/>
<AppBarButton x:Name="HomeVideoPanelStartStopButton" Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Width="40" Height="48" Margin="-3" Icon="Download" Click="HomeVideoPanelStartStopButton_Click"/>
<AppBarButton Grid.Row="2" Grid.Column="2" VerticalAlignment="Center" Width="40" Height="48" Margin="-3" Icon="Cancel" Click="HomeVideoPanelRemoveButton_Click"/>
<AppBarButton Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" Width="40" Height="48" Margin="-3" Icon="{x:Bind SourceImage}" Click="HomeTaskPanelSourceButton_Click"/>
<AppBarButton x:Name="HomeTaskPanelStartStopButton" Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Width="40" Height="48" Margin="-3" Icon="Download" Click="HomeTaskPanelStartStopButton_Click"/>
<AppBarButton Grid.Row="2" Grid.Column="2" VerticalAlignment="Center" Width="40" Height="48" Margin="-3" Icon="Cancel" Click="HomeTaskPanelRemoveButton_Click"/>
</Grid>
</UserControl>

View File

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

View File

@@ -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

View File

@@ -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
{
}
}

View File

@@ -10,9 +10,14 @@
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///Resources/Icons.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Thickness x:Key="NavigationViewContentMargin">0,48,0,0</Thickness>
<Thickness x:Key="NavigationViewContentGridBorderThickness">0</Thickness>
<SolidColorBrush x:Key="NavigationViewContentBackground" Color="Transparent"></SolidColorBrush>
<SolidColorBrush x:Key="NavigationViewContentBackground" Color="Transparent"/>
</ResourceDictionary>
</Page.Resources>

View File

@@ -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;