diff --git a/VDownload.Core/EventArgs/PlaylistSearchEventArgs.cs b/VDownload.Core/EventArgs/PlaylistSearchEventArgs.cs deleted file mode 100644 index 32946a0..0000000 --- a/VDownload.Core/EventArgs/PlaylistSearchEventArgs.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace VDownload.Core.EventArgs -{ - public class PlaylistSearchEventArgs : System.EventArgs - { - public string Url { get; set; } - public int VideosCount { get; set; } - } -} diff --git a/VDownload.Core/EventArgs/PlaylistSearchSuccessedEventArgs.cs b/VDownload.Core/EventArgs/PlaylistSearchSuccessedEventArgs.cs new file mode 100644 index 0000000..7e7c3ad --- /dev/null +++ b/VDownload.Core/EventArgs/PlaylistSearchSuccessedEventArgs.cs @@ -0,0 +1,9 @@ +using VDownload.Core.Interfaces; + +namespace VDownload.Core.EventArgs +{ + public class PlaylistSearchSuccessedEventArgs : System.EventArgs + { + public IPlaylistService PlaylistService { get; set; } + } +} diff --git a/VDownload.Core/EventArgs/VideoSearchEventArgs.cs b/VDownload.Core/EventArgs/VideoSearchEventArgs.cs deleted file mode 100644 index 7028722..0000000 --- a/VDownload.Core/EventArgs/VideoSearchEventArgs.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace VDownload.Core.EventArgs -{ - public class VideoSearchEventArgs : System.EventArgs - { - public string Url { get; set; } - } -} diff --git a/VDownload.Core/EventArgs/VideoSearchSuccessedEventArgs.cs b/VDownload.Core/EventArgs/VideoSearchSuccessedEventArgs.cs new file mode 100644 index 0000000..1a9d81f --- /dev/null +++ b/VDownload.Core/EventArgs/VideoSearchSuccessedEventArgs.cs @@ -0,0 +1,9 @@ +using VDownload.Core.Interfaces; + +namespace VDownload.Core.EventArgs +{ + public class VideoSearchSuccessedEventArgs : System.EventArgs + { + public IVideoService VideoService { get; set; } + } +} diff --git a/VDownload.Core/Exceptions/MediaNotFoundException.cs b/VDownload.Core/Exceptions/MediaNotFoundException.cs new file mode 100644 index 0000000..466a69b --- /dev/null +++ b/VDownload.Core/Exceptions/MediaNotFoundException.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VDownload.Core.Exceptions +{ + public class MediaNotFoundException : Exception + { + public MediaNotFoundException() { } + public MediaNotFoundException(string message) : base(message) { } + public MediaNotFoundException(string message, Exception inner) : base(message, inner) { } + } +} diff --git a/VDownload.Core/Services/Source.cs b/VDownload.Core/Services/Source.cs index 55e44e3..4c3f217 100644 --- a/VDownload.Core/Services/Source.cs +++ b/VDownload.Core/Services/Source.cs @@ -18,7 +18,7 @@ namespace VDownload.Core.Services // 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), + (new Regex(@"^https://www.twitch.tv/(?[^?/]+)"), PlaylistSource.TwitchChannel), }; #endregion diff --git a/VDownload.Core/Services/Sources/Twitch/Channel.cs b/VDownload.Core/Services/Sources/Twitch/Channel.cs index a1d031f..5a7aa28 100644 --- a/VDownload.Core/Services/Sources/Twitch/Channel.cs +++ b/VDownload.Core/Services/Sources/Twitch/Channel.cs @@ -49,7 +49,9 @@ namespace VDownload.Core.Services.Sources.Twitch using (WebClient client = await Client.Helix()) { client.QueryString.Add("login", ID); - response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/users"))["data"][0]; + response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/users"))["data"]; + if (((JArray)response).Count > 0) response = response[0]; + else throw new MediaNotFoundException($"Twitch Channel (ID: {ID}) was not found"); } // Create unified playlist url diff --git a/VDownload.Core/Services/Sources/Twitch/Clip.cs b/VDownload.Core/Services/Sources/Twitch/Clip.cs index a9a30d8..e8db616 100644 --- a/VDownload.Core/Services/Sources/Twitch/Clip.cs +++ b/VDownload.Core/Services/Sources/Twitch/Clip.cs @@ -54,7 +54,9 @@ namespace VDownload.Core.Services.Sources.Twitch using (WebClient client = await Client.Helix()) { client.QueryString.Add("id", ID); - response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/clips")).GetValue("data")[0]; + response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/clips")).GetValue("data"); + if (((JArray)response).Count > 0) response = response[0]; + else throw new MediaNotFoundException($"Twitch Clip (ID: {ID}) was not found"); } // Create unified video url diff --git a/VDownload.Core/Services/Sources/Twitch/Vod.cs b/VDownload.Core/Services/Sources/Twitch/Vod.cs index ce7d749..965734d 100644 --- a/VDownload.Core/Services/Sources/Twitch/Vod.cs +++ b/VDownload.Core/Services/Sources/Twitch/Vod.cs @@ -2,12 +2,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Net; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using VDownload.Core.Enums; +using VDownload.Core.Exceptions; using VDownload.Core.Interfaces; using VDownload.Core.Services.Sources.Twitch.Helpers; using VDownload.Core.Structs; @@ -52,7 +54,16 @@ namespace VDownload.Core.Services.Sources.Twitch { client.QueryString.Add("id", ID); cancellationToken.ThrowIfCancellationRequested(); - response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/videos")).GetValue("data")[0]; + try + { + response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/videos")).GetValue("data")[0]; + } + catch (WebException ex) + { + if (ex.Response != null && new StreamReader(ex.Response.GetResponseStream()).ReadToEnd().Contains("Not Found")) throw new MediaNotFoundException($"Twitch VOD (ID: {ID}) was not found"); + else if (ex.Response != null && new StreamReader(ex.Response.GetResponseStream()).ReadToEnd() == string.Empty && ex.Message.Contains("400")) throw new MediaNotFoundException($"Twitch VOD (ID: {ID}) was not found"); + else throw; + } } // Set parameters diff --git a/VDownload.Core/Services/TimeSpanCustomFormat.cs b/VDownload.Core/Services/TimeSpanCustomFormat.cs index 003748b..dfdda2b 100644 --- a/VDownload.Core/Services/TimeSpanCustomFormat.cs +++ b/VDownload.Core/Services/TimeSpanCustomFormat.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace VDownload.Core.Services { @@ -15,17 +12,15 @@ namespace VDownload.Core.Services string formattedTimeSpan = string.Empty; int maxTHLength = 0; - if (Math.Floor(timeSpan.TotalHours) > 0) + foreach (TimeSpan format in formatBase.Concat(new TimeSpan[] { timeSpan })) { - maxTHLength = Math.Floor(timeSpan.TotalHours).ToString().Length; - foreach (TimeSpan format in formatBase) - { - int THLength = Math.Floor(format.TotalHours) > 0 ? Math.Floor(timeSpan.TotalHours).ToString().Length : 0; - if (THLength > maxTHLength) maxTHLength = THLength; - } - formattedTimeSpan += $"{((int)Math.Floor(timeSpan.TotalHours)).ToString($"D{maxTHLength}")}:"; + int THLength = Math.Floor(format.TotalHours) > 0 ? Math.Floor(timeSpan.TotalHours).ToString().Length : 0; + if (THLength > maxTHLength) maxTHLength = THLength; } + formattedTimeSpan += $"{((int)Math.Floor(timeSpan.TotalHours)).ToString($"D{maxTHLength}")}:"; + formattedTimeSpan += maxTHLength == 0 ? $"{timeSpan.Minutes}:" : $"{timeSpan.Minutes:00}:"; + formattedTimeSpan += $"{timeSpan.Seconds:00}"; return formattedTimeSpan; @@ -37,22 +32,20 @@ namespace VDownload.Core.Services string formattedTimeSpan = string.Empty; int maxTHLength = 0; - if (Math.Floor(timeSpan.TotalHours) > 0) + foreach (TimeSpan format in formatBase.Concat(new TimeSpan[] { timeSpan })) { - maxTHLength = Math.Floor(timeSpan.TotalHours).ToString().Length; - foreach (TimeSpan format in formatBase) - { - int THLength = Math.Floor(format.TotalHours) > 0 ? Math.Floor(timeSpan.TotalHours).ToString().Length : 0; - if (THLength > maxTHLength) maxTHLength = THLength; - } - formattedTimeSpan += $"{((int)Math.Floor(timeSpan.TotalHours)).ToString($"D{maxTHLength}")}:"; + int THLength = Math.Floor(format.TotalHours) > 0 ? Math.Floor(timeSpan.TotalHours).ToString().Length : 0; + if (THLength > maxTHLength) maxTHLength = THLength; } + formattedTimeSpan += $"{((int)Math.Floor(timeSpan.TotalHours)).ToString($"D{maxTHLength}")}:"; + bool MM = false; - if (Math.Floor(timeSpan.TotalMinutes) > 0) + if (Math.Floor(timeSpan.TotalMinutes) > 0 || maxTHLength > 0) { formattedTimeSpan += maxTHLength > 0 ? $"{timeSpan.Minutes:00}:" : $"{timeSpan.Minutes}:"; MM = true; } + formattedTimeSpan += MM ? $"{timeSpan.Seconds:00}:" : $"{timeSpan.Seconds}:"; return formattedTimeSpan; diff --git a/VDownload.Core/Structs/TaskData.cs b/VDownload.Core/Structs/TaskData.cs index 74ddb4d..6598122 100644 --- a/VDownload.Core/Structs/TaskData.cs +++ b/VDownload.Core/Structs/TaskData.cs @@ -8,13 +8,6 @@ namespace VDownload.Core.Structs public struct TaskData { public IVideoService VideoService { get; set; } - public MediaType MediaType { get; set; } - public BaseStream Stream { get; set; } - public TimeSpan TrimStart { get; set; } - public TimeSpan TrimEnd { get; set; } - public string Filename { get; set; } - public MediaFileExtension Extension { get; set; } - public StorageFolder Location { get; set; } - public double Schedule { get; set; } + public TaskOptions TaskOptions { get; set; } } } diff --git a/VDownload.Core/Structs/TaskOptions.cs b/VDownload.Core/Structs/TaskOptions.cs new file mode 100644 index 0000000..8b83f51 --- /dev/null +++ b/VDownload.Core/Structs/TaskOptions.cs @@ -0,0 +1,18 @@ +using System; +using VDownload.Core.Enums; +using Windows.Storage; + +namespace VDownload.Core.Structs +{ + public struct TaskOptions + { + public MediaType MediaType { get; set; } + public BaseStream Stream { get; set; } + public TimeSpan TrimStart { get; set; } + public TimeSpan TrimEnd { get; set; } + public string Filename { get; set; } + public MediaFileExtension Extension { get; set; } + public StorageFolder Location { get; set; } + public double Schedule { get; set; } + } +} diff --git a/VDownload.Core/VDownload.Core.csproj b/VDownload.Core/VDownload.Core.csproj index 8375529..ed1813b 100644 --- a/VDownload.Core/VDownload.Core.csproj +++ b/VDownload.Core/VDownload.Core.csproj @@ -130,8 +130,9 @@ - - + + + @@ -149,6 +150,7 @@ + diff --git a/VDownload/Assets/Icons/Error.svg b/VDownload/Assets/Icons/Error.svg index a3bbfd7..ea72c79 100644 --- a/VDownload/Assets/Icons/Error.svg +++ b/VDownload/Assets/Icons/Error.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/VDownload/Strings/en-US/Resources.resw b/VDownload/Strings/en-US/Resources.resw index 267d523..cab8f20 100644 --- a/VDownload/Strings/en-US/Resources.resw +++ b/VDownload/Strings/en-US/Resources.resw @@ -120,6 +120,39 @@ OK + + Downloading options + + + File options + + + File + + + Browse + + + Location + + + Media type + + + Quality + + + Number of minutes to start the task (after clicking downloading button). + + + Schedule + + + Task options + + + Trim + No @@ -135,46 +168,6 @@ Metered connection detected - - Add playlist - - - 85 - - - - Twitch (Channel) - -Number of videos got from playlist -The number in the numberbox indicades how many videos will be got from playlist. 0 = all. - - - - Supported sources - - - Search - - - Playlist URL - - - Add video - - - 75 - - - - Twitch (VODs, Clips) - - - Supported sources - - - Search - - - Video URL - Download all @@ -187,6 +180,28 @@ The number in the numberbox indicades how many videos will be got from playlist. 120 + + Playlist search + + + 95 + + + - Twitch (Channel) + +Number of videos got from playlist +The number in the numberbox indicades how many videos will be got from playlist. 0 = all. + + + + Supported sources + + + Search + + + Playlist URL + Playlist search error @@ -199,6 +214,24 @@ 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. + + Video search + + + 90 + + + - Twitch (VODs, Clips) + + + Supported sources + + + Search + + + Video URL + Video search error @@ -341,40 +374,7 @@ The number in the numberbox indicades how many videos will be got from playlist. Metered connection detected - Click "Add video/playlist" button to start - - - Downloading options - - - File options - - - File - - - Browse - - - Location - - - Media type - - - Quality - - - Number of minutes to start the task (after clicking downloading button). - - - Schedule - - - Task options - - - Trim + Click "Video/Playlist search" button to start Home diff --git a/VDownload/VDownload.csproj b/VDownload/VDownload.csproj index 9c17aa0..3abd77d 100644 --- a/VDownload/VDownload.csproj +++ b/VDownload/VDownload.csproj @@ -125,11 +125,14 @@ AboutMain.xaml - - HomeOptionsBarAddPlaylistControl.xaml + + HomeAddingVideoOptions.xaml - - HomeOptionsBarAddVideoControl.xaml + + HomeOptionsBarPlaylistSearch.xaml + + + HomeOptionsBarVideoSearch.xaml SettingControl.xaml @@ -140,16 +143,16 @@ HomePlaylistAddingPanel.xaml - - HomePlaylistAddingPanelVideoPanel.xaml + + HomeSerialAddingVideoPanel.xaml - + HomeTasksListPlaceholder.xaml HomeVideoAddingPanel.xaml - + HomeTaskPanel.xaml @@ -295,11 +298,15 @@ Designer MSBuild:Compile - + + Designer + MSBuild:Compile + + MSBuild:Compile Designer - + Designer MSBuild:Compile @@ -315,11 +322,11 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile - + Designer MSBuild:Compile @@ -327,7 +334,7 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile diff --git a/VDownload/Views/Home/Controls/HomeAddingVideoOptions.xaml b/VDownload/Views/Home/Controls/HomeAddingVideoOptions.xaml new file mode 100644 index 0000000..c71806a --- /dev/null +++ b/VDownload/Views/Home/Controls/HomeAddingVideoOptions.xaml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +