diff --git a/LLCD.CourseExtractor.Tests/ExtractorTest.cs b/LLCD.CourseExtractor.Tests/ExtractorTest.cs index fd142a4..9ce9b53 100644 --- a/LLCD.CourseExtractor.Tests/ExtractorTest.cs +++ b/LLCD.CourseExtractor.Tests/ExtractorTest.cs @@ -12,30 +12,46 @@ namespace LLCD.CourseExtractor.Tests [TestClass] public class ExtractorTest { - private const string VALID_TOKEN = ""; + private const string VALID_CHROME_TOKEN = ""; + private const string VALID_FIREFOX_TOKEN = ""; private const string EXPIRED_TOKEN = ""; - private const string INVALID_TOKEN = "QEGAGQBAAAAAAVW6BkPg4R_VgAAR3VybjpsaTplbnRlcnByaXNlUHJvZmlsZToodXJuOmxpOmVudGVycHJpc2VBY2NvdW50OjEwNDk0MjIxMCwxMjY5MzU4NjgpvFufSjdKltNIvqBCEfUtk_v1dKyDW1v4v4T-ULf5HfsBuTtkjYwXKhAq4tzlv77b0TAKjaEB9KG88zz46-O34O-ymauMqZ_C8mWvdKTctBXPEPM0"; + private const string INVALID_CHROME_TOKEN = "QEGAGQBAAAAAAVW6BkPg4R_VgAAR3VybjpsaTplbnRlcnByaXNlUHJvZmlsZToodXJuOmxpOmVudGVycHJpc2VBY2NvdW50OjEwNDk0MjIxMCwxMjY5MzU4NjgpvFufSjdKltNIvqBCEfUtk_v1dKyDW1v4v4T-ULf5HfsBuTtkjYwXKhAq4tzlv77b0TAKjaEB9KG88zz46-O34O-ymauMqZ_C8mWvdKTctBXPEPM0"; + private const string INVALID_FIREFOX_TOKEN = "QEGAGQBAAAAAAVW6BkPg4R_VgAAR3VybjpsaTplbnRlcnByaXNlUHJvZmlsZToodXJuOmxpOmVudGVycHJpc2VBY2NvdW50OjEwNDk0MjIxMCwxMjY5MzU4NjgpvFufSjdKltNIvqBCEfUtk_v1dKyDW1v4v4T-ULf5HfsBuTtkjYwXKhAq4tzlv77b0TAKjaEB9KG88zz46-O34O-ymauMqZ_C8mWvdKTctBXPEPM0"; private const string VALID_EnterpriseProfileHash = ""; [TestMethod] [TestCategory("Cookie Extraction")] - public void ExtractToken_ValidCookieExtraction_ReturnsEqualTokenValue() + public void ExtractToken_ValidFirefoxCookieExtraction_ReturnsEqualTokenValue() { - Assert.AreEqual(VALID_TOKEN, Extractor.ExtractToken(Browser.Firefox)); + Assert.AreEqual(VALID_FIREFOX_TOKEN, Extractor.ExtractToken(Browser.Firefox)); } [TestMethod] [TestCategory("Cookie Extraction")] - public void ExtractToken_InvalidCookieExtraction_ReturnsNonEqualTokenValue() + public void ExtractToken_InvalidFirefoxCookieExtraction_ReturnsNonEqualTokenValue() { - Assert.AreNotEqual(INVALID_TOKEN, Extractor.ExtractToken(Browser.Firefox)); + Assert.AreNotEqual(INVALID_FIREFOX_TOKEN, Extractor.ExtractToken(Browser.Firefox)); + } + + [TestMethod] + [TestCategory("Cookie Extraction")] + public void ExtractToken_ValidChromeCookieExtraction_ReturnsEqualTokenValue() + { + Assert.AreEqual(VALID_CHROME_TOKEN, Extractor.ExtractToken(Browser.Chrome)); + } + + [TestMethod] + [TestCategory("Cookie Extraction")] + public void ExtractToken_InvalidChromeCookieExtraction_ReturnsNonEqualTokenValue() + { + Assert.AreNotEqual(INVALID_CHROME_TOKEN, Extractor.ExtractToken(Browser.Chrome)); } [TestMethod] [TestCategory("Token Validity")] public async Task ExtractToken_ValidToken_ReturnsTrue() { - var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_TOKEN); + var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_FIREFOX_TOKEN); Assert.IsTrue(await extractor.HasValidToken()); } @@ -43,7 +59,7 @@ public async Task ExtractToken_ValidToken_ReturnsTrue() [TestCategory("Token Validity")] public async Task ExtractToken_InvalidToken_ReturnsFalse() { - var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, INVALID_TOKEN); + var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_FIREFOX_TOKEN); Assert.IsFalse(await extractor.HasValidToken()); } @@ -51,7 +67,7 @@ public async Task ExtractToken_InvalidToken_ReturnsFalse() [TestCategory("Course Extraction")] public async Task GetCourse_ValidCourse_ReturnsEqualCourseData() { - var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_TOKEN); + var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_FIREFOX_TOKEN); var progress = new Progress(progressPercent => ConsoleOutput.Instance.WriteLine((progressPercent * 100).ToString(), OutputLevel.Information)); var course = await extractor.GetCourse(progress); CompareLogic compareLogic = new CompareLogic(); @@ -93,7 +109,7 @@ public async Task GetCourse_CoursesExtractionStressTest_ReturnsNumberOfExtractio foreach (var link in links) { i++; - var extractor = new Extractor(link, Quality.Low, VALID_TOKEN); + var extractor = new Extractor(link, Quality.Low, VALID_FIREFOX_TOKEN); var course = await extractor.GetCourse(); } ConsoleOutput.Instance.WriteLine($"Extracted {i} courses", OutputLevel.Information); @@ -103,7 +119,7 @@ public async Task GetCourse_CoursesExtractionStressTest_ReturnsNumberOfExtractio [TestCategory("Course Extraction")] public async Task GetCourse_InValidCourse_ReturnsNonEqualCourseData() { - var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_TOKEN); + var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_FIREFOX_TOKEN); var course = await extractor.GetCourse(); Assert.AreNotEqual(CourseObjects.INVALIDCOURSE, course); } @@ -112,7 +128,7 @@ public async Task GetCourse_InValidCourse_ReturnsNonEqualCourseData() [TestCategory("Link Validity")] public void HasValidUrl_ValidUrl_ReturnsTrue() { - var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive/welcome?u=104942210", Quality.Low, VALID_TOKEN); + var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive/welcome?u=104942210", Quality.Low, VALID_FIREFOX_TOKEN); Assert.IsTrue(extractor.HasValidUrl()); } @@ -120,7 +136,7 @@ public void HasValidUrl_ValidUrl_ReturnsTrue() [TestCategory("EnterpriseProfileHash Validity")] public async Task GetEnterpriseProfileHash_ValidEnterpriseProfileHash_ReturnsSameValue() { - var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_TOKEN); + var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_FIREFOX_TOKEN); await extractor.GetCourse(); Assert.AreEqual(VALID_EnterpriseProfileHash, extractor.EnterpriseProfileHash); } @@ -129,7 +145,7 @@ public async Task GetEnterpriseProfileHash_ValidEnterpriseProfileHash_ReturnsSam [TestCategory("EnterpriseProfileHash Validity")] public async Task GetEnterpriseProfileHash_InvalidToken_ReturnsNull() { - var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, INVALID_TOKEN); + var extractor = new Extractor("https://www.linkedin.com/learning/learning-to-be-assertive?autoplay=true&u=104942210", Quality.Low, VALID_FIREFOX_TOKEN); await extractor.GetCourse(); Assert.IsNull(extractor.EnterpriseProfileHash); } diff --git a/LLCD.CourseExtractor/CookiesExtractor.cs b/LLCD.CourseExtractor/CookiesExtractor.cs index d48e9e4..d623805 100644 --- a/LLCD.CourseExtractor/CookiesExtractor.cs +++ b/LLCD.CourseExtractor/CookiesExtractor.cs @@ -10,6 +10,7 @@ using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; using System.IO; +using Serilog; namespace LLCD.CourseExtractor { @@ -58,15 +59,32 @@ internal List ReadFirefoxCookies() } private List ReadChromiumCookies(string profilePath) { - var cookies = new List(); - - - // Big thanks to https://stackoverflow.com/a/60611673/6481581 for answering how Chrome 80 and up changed the way cookies are encrypted. - string dbPath = Path.Combine(profilePath, @"Default\Cookies"); string encKey = File.ReadAllText(Path.Combine(profilePath, "Local State")); encKey = JObject.Parse(encKey)["os_crypt"]["encrypted_key"].ToString(); var decodedKey = ProtectedData.Unprotect(Convert.FromBase64String(encKey).Skip(5).ToArray(), null, DataProtectionScope.LocalMachine); + // Big thanks to https://stackoverflow.com/a/60611673/6481581 for answering how Chrome 80 and up changed the way cookies are encrypted. + + List cookies; + try + { + string dbPath = Path.Combine(profilePath, @"Default\Network\Cookies"); + cookies = GetChromeCookiesFromDB(dbPath, decodedKey); + } + catch (SQLiteException ex) + { + Log.Error(ex, @"Cookies not found at ""Default\Network\Cookies"". Trying ""Default\Cookies"""); + string dbPath = Path.Combine(profilePath, @"Default\Cookies"); + cookies = GetChromeCookiesFromDB(dbPath, decodedKey); + } + + + return cookies; + } + + private List GetChromeCookiesFromDB(string dbPath, byte[] decodedKey) + { + var cookies = new List(); var connectionString = "Data Source=" + dbPath + ";pooling=false"; using (var conn = new SQLiteConnection(connectionString)) @@ -94,7 +112,6 @@ private List ReadChromiumCookies(string profilePath) return cookies; } - private string DecryptWithKey(byte[] message, byte[] key, int nonSecretPayloadLength) { const int KEY_BIT_SIZE = 256; diff --git a/LLCD.CourseExtractor/Extractor.cs b/LLCD.CourseExtractor/Extractor.cs index b281ceb..d9e95e4 100644 --- a/LLCD.CourseExtractor/Extractor.cs +++ b/LLCD.CourseExtractor/Extractor.cs @@ -12,6 +12,7 @@ using LLCD.CourseContent; using Microsoft.CSharp; using Newtonsoft.Json; +using Serilog; namespace LLCD.CourseExtractor { @@ -19,18 +20,21 @@ public class Extractor { public delegate void LinksExtractionEventHandler(); private readonly Quality _quality; + private readonly int _delay; private string _courseUrl; private string _courseSlug; private HttpClient _client; private CookieContainer _cookieContainer; private string _linkedinHomeRaw; private bool _isTokenChecked = false; + public string EnterpriseProfileHash { get; set; } - public Extractor(string courseUrl, Quality quality, string token) + public Extractor(string courseUrl, Quality quality, string token, int delay = 0) { _courseUrl = courseUrl; _quality = quality; + _delay = delay; _cookieContainer = new CookieContainer(); _cookieContainer.Add(new Cookie("li_at", token, "/", ".www.linkedin.com")); var clienthandler = new HttpClientHandler { UseCookies = true, CookieContainer = _cookieContainer }; @@ -80,7 +84,25 @@ public async Task GetCourse(IProgress progress = null) } var courseResponse = await _client.GetAsync($"https://www.linkedin.com/learning-api/detailedCourses?courseSlug={_courseSlug}&fields=chapters,title,exerciseFiles&addParagraphsToTranscript=true&q=slugs"); var courseResponseText = await courseResponse.Content.ReadAsStringAsync(); - var course = Course.FromJson(courseResponseText); + + Course course; + try + { + course = Course.FromJson(courseResponseText); + } + catch (Exception ex) + { + if (courseResponseText.Contains("CSRF check failed")) + { + throw new ArgumentException("Token is expired. Please use a new one.", ex); + } + else + { + Log.Error("Course Deserialization failed. \nResponse text : " + courseResponseText); + throw; + } + } + course.Slug = _courseSlug; float j = 1; float totalCount = course.Chapters.SelectMany(c => c.Videos).Count(); @@ -92,7 +114,15 @@ public async Task GetCourse(IProgress progress = null) string slug = video.Slug; var videoResponse = await _client.GetAsync($"https://www.linkedin.com/learning-api/detailedCourses?courseSlug={_courseSlug}&resolution=_{_quality.ToHeight()}&q=slugs&fields=selectedVideo&videoSlug={video.Slug}"); var videoResponseText = await videoResponse.Content.ReadAsStringAsync(); - video = Video.FromJson(videoResponseText); + try + { + video = Video.FromJson(videoResponseText); + } + catch (Exception) + { + Log.Error("Video Deserialization failed. \nResponse text : " + videoResponseText); + throw; + } video.Slug = slug; if (String.IsNullOrWhiteSpace(video.DownloadUrl)) { @@ -101,6 +131,7 @@ public async Task GetCourse(IProgress progress = null) } chapter.Videos[i] = video; progress?.Report(j / totalCount); + await Task.Delay(_delay * 1000); } } return course; diff --git a/LLCD.CourseExtractor/LLCD.CourseExtractor.csproj b/LLCD.CourseExtractor/LLCD.CourseExtractor.csproj index 52c45ae..bfe2f1b 100644 --- a/LLCD.CourseExtractor/LLCD.CourseExtractor.csproj +++ b/LLCD.CourseExtractor/LLCD.CourseExtractor.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/LLCD.DownloaderGUI/App.config b/LLCD.DownloaderGUI/App.config index 24c49e7..71c41b9 100644 --- a/LLCD.DownloaderGUI/App.config +++ b/LLCD.DownloaderGUI/App.config @@ -1,7 +1,7 @@  - +
@@ -13,10 +13,5 @@ - - - - - - + \ No newline at end of file diff --git a/LLCD.DownloaderGUI/CourseStatusUserControl.cs b/LLCD.DownloaderGUI/CourseStatusUserControl.cs index 62d68a3..2840dbc 100644 --- a/LLCD.DownloaderGUI/CourseStatusUserControl.cs +++ b/LLCD.DownloaderGUI/CourseStatusUserControl.cs @@ -29,21 +29,25 @@ public CourseStatus Status switch (value) { case CourseStatus.NotRunning: - lblCourseStatus.Text = "Not Running"; - lblCourseStatus.BackColor = Color.Maroon; + lblCourseStatus.Text = "Not running"; + lblCourseStatus.BackColor = Color.FromArgb(249, 222, 220); + lblCourseStatus.ForeColor = Color.FromArgb(65, 14, 11); break; case CourseStatus.Starting: case CourseStatus.Running: lblCourseStatus.Text = value.ToString(); - lblCourseStatus.BackColor = Color.DarkBlue; + lblCourseStatus.BackColor = Color.FromArgb(3, 218, 198); + lblCourseStatus.ForeColor = Color.Black; break; case CourseStatus.Finished: lblCourseStatus.Text = value.ToString(); - lblCourseStatus.BackColor = Color.DarkGreen; + lblCourseStatus.BackColor = Color.FromArgb(183, 243, 151); + lblCourseStatus.ForeColor = Color.FromArgb(4, 33, 0); break; case CourseStatus.Failed: lblCourseStatus.Text = value.ToString(); - lblCourseStatus.BackColor = Color.DarkRed; + lblCourseStatus.BackColor = Color.FromArgb(207, 102, 121); + lblCourseStatus.ForeColor = Color.Black; break; } _status = value; diff --git a/LLCD.DownloaderGUI/CourseStatusUserControl.designer.cs b/LLCD.DownloaderGUI/CourseStatusUserControl.designer.cs index 6187287..9b45485 100644 --- a/LLCD.DownloaderGUI/CourseStatusUserControl.designer.cs +++ b/LLCD.DownloaderGUI/CourseStatusUserControl.designer.cs @@ -33,15 +33,15 @@ private void InitializeComponent() // // lblCourseStatus // - this.lblCourseStatus.BackColor = System.Drawing.Color.Maroon; + this.lblCourseStatus.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(249)))), ((int)(((byte)(222)))), ((int)(((byte)(220))))); this.lblCourseStatus.Dock = System.Windows.Forms.DockStyle.Fill; - this.lblCourseStatus.Font = new System.Drawing.Font("Barlow Condensed", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblCourseStatus.ForeColor = System.Drawing.Color.White; + this.lblCourseStatus.Font = new System.Drawing.Font("Quicksand", 14.25F); + this.lblCourseStatus.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(65)))), ((int)(((byte)(14)))), ((int)(((byte)(11))))); this.lblCourseStatus.Location = new System.Drawing.Point(0, 0); this.lblCourseStatus.Name = "lblCourseStatus"; - this.lblCourseStatus.Size = new System.Drawing.Size(99, 27); + this.lblCourseStatus.Size = new System.Drawing.Size(131, 27); this.lblCourseStatus.TabIndex = 1; - this.lblCourseStatus.Text = "Not Running"; + this.lblCourseStatus.Text = "Not running"; this.lblCourseStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // CourseStatusUserControl @@ -51,7 +51,7 @@ private void InitializeComponent() this.BackColor = System.Drawing.Color.Black; this.Controls.Add(this.lblCourseStatus); this.Name = "CourseStatusUserControl"; - this.Size = new System.Drawing.Size(99, 27); + this.Size = new System.Drawing.Size(131, 27); this.ResumeLayout(false); } diff --git a/LLCD.DownloaderGUI/DownloaderForm.cs b/LLCD.DownloaderGUI/DownloaderForm.cs index e61bfa8..de4d547 100644 --- a/LLCD.DownloaderGUI/DownloaderForm.cs +++ b/LLCD.DownloaderGUI/DownloaderForm.cs @@ -21,6 +21,7 @@ public partial class DownloaderForm : Form private List _courses; private DirectoryInfo _courseRootDirectory; private readonly bool _toDownloadExerciseFiles; + private readonly bool _toDownloadSubtitles; private int _videosCount; private int _currentVideoIndex = 1; private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); @@ -29,23 +30,16 @@ public partial class DownloaderForm : Form public CourseStatus DownloaderStatus { get; set; } = CourseStatus.Running; - public DownloaderForm(List courses, DirectoryInfo courseRootDirectory,bool toDownloadExerciseFiles, Font font) + public DownloaderForm(List courses, DirectoryInfo courseRootDirectory,bool toDownloadExerciseFiles,bool toDownloadSubtitles) { _courses = courses; _courseRootDirectory = courseRootDirectory; _toDownloadExerciseFiles = toDownloadExerciseFiles; + _toDownloadSubtitles = toDownloadSubtitles; _cancellationToken = _cancellationTokenSource.Token; InitializeComponent(); Text = "Downloading Courses"; - foreach (var control in flowLayoutPanel.Controls) - { - switch (control) - { - case Label lbl: - lbl.Font = font; - break; - } - } + FormHelpers.SetFonts(flowLayoutPanel); } private async void DownloaderForm_Load(object sender, EventArgs e) @@ -57,7 +51,7 @@ private async void DownloaderForm_Load(object sender, EventArgs e) lblTotal.Text = $"Downloading Course : {course.Title} [{i + 1}/{_courses.Count}]"; if (_cancellationToken.IsCancellationRequested) return; await DownloadCourse(course); - progressBarTotal.Value = (i + 1) * 100 / _courses.Count; + progressBarTotal.Value = (i + 1) * 100 / _courses.Count; } DownloaderStatus = CourseStatus.Finished; Close(); @@ -93,7 +87,7 @@ private async Task DownloadCourse(Course course) int i = 1; foreach (var chapter in course.Chapters) { - var chapterDirectory = courseDirectory.CreateSubdirectory($"[{i}] {ToSafeFileName(chapter.Title)}"); + var chapterDirectory = courseDirectory.CreateSubdirectory($"{i:D2} - {ToSafeFileName(chapter.Title)}"); int j = 1; foreach (var video in chapter.Videos) { @@ -104,10 +98,10 @@ private async Task DownloadCourse(Course course) lblVideo.Text = video.Title + " - [Chapter " + i + "]"; lblCourse.Text = _currentVideoIndex++ + "/" + _videosCount; - string videoName = $"[{j}] { ToSafeFileName(video.Title)}.mp4"; - if (!String.IsNullOrWhiteSpace(video.Transcript)) + string videoName = $"{j:D2} - { ToSafeFileName(video.Title)}.mp4"; + if (!String.IsNullOrWhiteSpace(video.Transcript) && _toDownloadSubtitles) { - string captionName = $"[{j}] { ToSafeFileName(video.Title)}.srt"; + string captionName = $"{j:D2} - { ToSafeFileName(video.Title)}.srt"; await SaveSubtitles(Path.Combine(chapterDirectory.FullName, ToSafeFileName(captionName)), video.Transcript); } using (var fileStream = File.Create(Path.Combine(chapterDirectory.FullName, videoName))) diff --git a/LLCD.DownloaderGUI/DownloaderForm.designer.cs b/LLCD.DownloaderGUI/DownloaderForm.designer.cs index b27e0e8..d9bf457 100644 --- a/LLCD.DownloaderGUI/DownloaderForm.designer.cs +++ b/LLCD.DownloaderGUI/DownloaderForm.designer.cs @@ -45,7 +45,7 @@ private void InitializeComponent() // // progressBarCourse // - this.progressBarCourse.Location = new System.Drawing.Point(3, 116); + this.progressBarCourse.Location = new System.Drawing.Point(13, 132); this.progressBarCourse.Name = "progressBarCourse"; this.progressBarCourse.Size = new System.Drawing.Size(631, 32); this.progressBarCourse.Style = System.Windows.Forms.ProgressBarStyle.Continuous; @@ -54,37 +54,40 @@ private void InitializeComponent() // label5 // this.label5.AutoSize = true; - this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label5.Location = new System.Drawing.Point(0, 88); + this.label5.Font = new System.Drawing.Font("Quicksand", 14.25F); + this.label5.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label5.Location = new System.Drawing.Point(10, 101); this.label5.Margin = new System.Windows.Forms.Padding(0, 25, 0, 0); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(185, 25); + this.label5.Size = new System.Drawing.Size(164, 28); this.label5.TabIndex = 5; this.label5.Text = "Course Progress :"; // // lblDownloadingVideo // this.lblDownloadingVideo.AutoSize = true; - this.lblDownloadingVideo.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblDownloadingVideo.Location = new System.Drawing.Point(0, 0); + this.lblDownloadingVideo.Font = new System.Drawing.Font("Quicksand", 14.25F); + this.lblDownloadingVideo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.lblDownloadingVideo.Location = new System.Drawing.Point(10, 10); this.lblDownloadingVideo.Margin = new System.Windows.Forms.Padding(0); this.lblDownloadingVideo.Name = "lblDownloadingVideo"; - this.lblDownloadingVideo.Size = new System.Drawing.Size(209, 25); + this.lblDownloadingVideo.Size = new System.Drawing.Size(193, 28); this.lblDownloadingVideo.TabIndex = 5; this.lblDownloadingVideo.Text = "Downloading Video :"; // // progressBarVideo // - this.progressBarVideo.Location = new System.Drawing.Point(3, 28); + this.progressBarVideo.Location = new System.Drawing.Point(13, 41); this.progressBarVideo.MarqueeAnimationSpeed = 30; this.progressBarVideo.Name = "progressBarVideo"; - this.progressBarVideo.Size = new System.Drawing.Size(582, 32); + this.progressBarVideo.Size = new System.Drawing.Size(578, 32); this.progressBarVideo.Style = System.Windows.Forms.ProgressBarStyle.Continuous; this.progressBarVideo.TabIndex = 6; // // flowLayoutPanel // this.flowLayoutPanel.AutoSize = true; + this.flowLayoutPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(29)))), ((int)(((byte)(29))))); this.flowLayoutPanel.Controls.Add(this.lblDownloadingVideo); this.flowLayoutPanel.Controls.Add(this.lblVideo); this.flowLayoutPanel.Controls.Add(this.progressBarVideo); @@ -95,70 +98,78 @@ private void InitializeComponent() this.flowLayoutPanel.Controls.Add(this.label1); this.flowLayoutPanel.Controls.Add(this.lblTotal); this.flowLayoutPanel.Controls.Add(this.progressBarTotal); - this.flowLayoutPanel.Location = new System.Drawing.Point(4, 12); - this.flowLayoutPanel.MaximumSize = new System.Drawing.Size(640, 0); + this.flowLayoutPanel.Location = new System.Drawing.Point(15, 15); + this.flowLayoutPanel.Margin = new System.Windows.Forms.Padding(6); + this.flowLayoutPanel.MaximumSize = new System.Drawing.Size(660, 0); this.flowLayoutPanel.Name = "flowLayoutPanel"; - this.flowLayoutPanel.Size = new System.Drawing.Size(640, 239); + this.flowLayoutPanel.Padding = new System.Windows.Forms.Padding(10); + this.flowLayoutPanel.Size = new System.Drawing.Size(657, 268); this.flowLayoutPanel.TabIndex = 7; // // lblVideo // this.lblVideo.AutoSize = true; - this.lblVideo.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblVideo.Location = new System.Drawing.Point(209, 0); + this.lblVideo.Font = new System.Drawing.Font("Quicksand", 14.25F); + this.lblVideo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.lblVideo.Location = new System.Drawing.Point(203, 10); this.lblVideo.Margin = new System.Windows.Forms.Padding(0); this.lblVideo.Name = "lblVideo"; - this.lblVideo.Size = new System.Drawing.Size(363, 25); + this.lblVideo.Size = new System.Drawing.Size(348, 28); this.lblVideo.TabIndex = 7; this.lblVideo.Text = "[Video Name] in Chapter [Chapter Id]"; // // lblPercentage // this.lblPercentage.AutoSize = true; - this.lblPercentage.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblPercentage.Location = new System.Drawing.Point(588, 32); + this.lblPercentage.Font = new System.Drawing.Font("Quicksand", 14.25F); + this.lblPercentage.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.lblPercentage.Location = new System.Drawing.Point(594, 45); this.lblPercentage.Margin = new System.Windows.Forms.Padding(0, 7, 0, 0); this.lblPercentage.Name = "lblPercentage"; - this.lblPercentage.Size = new System.Drawing.Size(43, 25); + this.lblPercentage.Size = new System.Drawing.Size(38, 28); this.lblPercentage.TabIndex = 5; this.lblPercentage.Text = "0%"; + this.lblPercentage.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // lblCourse // this.lblCourse.AutoSize = true; - this.lblCourse.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblCourse.Location = new System.Drawing.Point(185, 88); + this.lblCourse.Font = new System.Drawing.Font("Quicksand", 14.25F); + this.lblCourse.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.lblCourse.Location = new System.Drawing.Point(174, 101); this.lblCourse.Margin = new System.Windows.Forms.Padding(0, 25, 0, 0); this.lblCourse.Name = "lblCourse"; - this.lblCourse.Size = new System.Drawing.Size(363, 25); + this.lblCourse.Size = new System.Drawing.Size(343, 28); this.lblCourse.TabIndex = 8; this.lblCourse.Text = "[Current Video]/[Total Videos Count] "; // // label1 // this.label1.AutoSize = true; - this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label1.Location = new System.Drawing.Point(0, 176); + this.label1.Font = new System.Drawing.Font("Quicksand", 14.25F); + this.label1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label1.Location = new System.Drawing.Point(10, 192); this.label1.Margin = new System.Windows.Forms.Padding(0, 25, 0, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(164, 25); + this.label1.Size = new System.Drawing.Size(145, 28); this.label1.TabIndex = 12; this.label1.Text = "Total Progress :"; // // lblTotal // this.lblTotal.AutoSize = true; - this.lblTotal.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblTotal.Location = new System.Drawing.Point(164, 176); + this.lblTotal.Font = new System.Drawing.Font("Quicksand", 14.25F); + this.lblTotal.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.lblTotal.Location = new System.Drawing.Point(155, 192); this.lblTotal.Margin = new System.Windows.Forms.Padding(0, 25, 0, 0); this.lblTotal.Name = "lblTotal"; - this.lblTotal.Size = new System.Drawing.Size(391, 25); + this.lblTotal.Size = new System.Drawing.Size(363, 28); this.lblTotal.TabIndex = 14; this.lblTotal.Text = "[Current Course]/[Total Courses Count] "; // // progressBarTotal // - this.progressBarTotal.Location = new System.Drawing.Point(3, 204); + this.progressBarTotal.Location = new System.Drawing.Point(13, 223); this.progressBarTotal.Name = "progressBarTotal"; this.progressBarTotal.Size = new System.Drawing.Size(631, 32); this.progressBarTotal.Style = System.Windows.Forms.ProgressBarStyle.Continuous; @@ -169,8 +180,8 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; - this.BackColor = System.Drawing.Color.Black; - this.ClientSize = new System.Drawing.Size(650, 261); + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(18)))), ((int)(((byte)(18)))), ((int)(((byte)(18))))); + this.ClientSize = new System.Drawing.Size(687, 297); this.Controls.Add(this.flowLayoutPanel); this.ForeColor = System.Drawing.Color.White; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; diff --git a/LLCD.DownloaderGUI/FormHelpers.cs b/LLCD.DownloaderGUI/FormHelpers.cs new file mode 100644 index 0000000..af7e738 --- /dev/null +++ b/LLCD.DownloaderGUI/FormHelpers.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Text; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace LLCD.DownloaderGUI +{ + static class FormHelpers + { + private static PrivateFontCollection _fontCollection = new PrivateFontCollection(); + internal static FontFamily QuicksandFontFamilyRegular { get; set; } + internal static FontFamily QuicksandFontFamilyMedium { get; set; } + internal static FontFamily QuicksandFontFamilySemiBold { get; set; } + + static FormHelpers() + { + _fontCollection.AddFontFile("./fonts/Quicksand-Regular.ttf"); + _fontCollection.AddFontFile("./fonts/Quicksand-Medium.ttf"); + _fontCollection.AddFontFile("./fonts/Quicksand-SemiBold.ttf"); + _fontCollection.AddFontFile("./fonts/Quicksand-Bold.ttf"); + QuicksandFontFamilyRegular = _fontCollection.Families[0]; + QuicksandFontFamilyMedium = _fontCollection.Families[1]; + QuicksandFontFamilySemiBold = _fontCollection.Families[2]; + } + internal static void SetFonts(Control control) + { + var fontRegular = new Font(QuicksandFontFamilyRegular, 14); + if (control.HasChildren) + { + foreach (Control childControl in control.Controls) + { + SetFonts(childControl); + } + } + else + { + switch (control) + { + case Button btn: + btn.Font = new Font(QuicksandFontFamilyMedium, 14); + break; + default: + control.Font = fontRegular; + break; + } + + + } + } + internal static void SetLoadingStatus(bool isLoading, Control control, Form form, Control[] exceptions = null,bool changeCursor = true) + { + if (changeCursor) + { + form.Cursor = isLoading ? Cursors.WaitCursor : Cursors.Default; + } + if ((!exceptions?.Contains(control) ?? true) && !(control is Label) && !control.HasChildren) + { + control.Enabled = !isLoading; + } + + if (control.HasChildren) + { + foreach (Control child in control.Controls) + { + SetLoadingStatus(isLoading, child, form,exceptions, changeCursor); + } + } + return; + } + + } +} diff --git a/LLCD.DownloaderGUI/LLCD.DownloaderGUI.csproj b/LLCD.DownloaderGUI/LLCD.DownloaderGUI.csproj index 901abd6..464fe24 100644 --- a/LLCD.DownloaderGUI/LLCD.DownloaderGUI.csproj +++ b/LLCD.DownloaderGUI/LLCD.DownloaderGUI.csproj @@ -1,6 +1,5 @@  - @@ -77,8 +76,8 @@ true - - ..\packages\Portable.BouncyCastle.1.8.10\lib\net40\BouncyCastle.Crypto.dll + + ..\packages\Portable.BouncyCastle.1.9.0\lib\net40\BouncyCastle.Crypto.dll ..\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll @@ -89,12 +88,6 @@ ..\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll - - ..\packages\EntityFramework.6.3.0\lib\net45\EntityFramework.dll - - - ..\packages\EntityFramework.6.3.0\lib\net45\EntityFramework.SqlServer.dll - ..\packages\Mono.Cecil.0.11.2\lib\net40\Mono.Cecil.dll @@ -116,8 +109,8 @@ ..\packages\Serilog.2.10.0\lib\net46\Serilog.dll - - ..\packages\Serilog.Sinks.File.4.1.0\lib\net45\Serilog.Sinks.File.dll + + ..\packages\Serilog.Sinks.File.5.0.0\lib\net45\Serilog.Sinks.File.dll ..\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll @@ -128,18 +121,12 @@ - - ..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.113.3\lib\net46\System.Data.SQLite.dll - - - ..\packages\System.Data.SQLite.EF6.1.0.113.0\lib\net46\System.Data.SQLite.EF6.dll - - - ..\packages\System.Data.SQLite.Linq.1.0.113.0\lib\net46\System.Data.SQLite.Linq.dll + + ..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.115.5\lib\net46\System.Data.SQLite.dll - - ..\packages\System.Security.Cryptography.ProtectedData.5.0.0\lib\net461\System.Security.Cryptography.ProtectedData.dll + + ..\packages\System.Security.Cryptography.ProtectedData.6.0.0\lib\net461\System.Security.Cryptography.ProtectedData.dll @@ -166,6 +153,7 @@ DownloaderForm.cs + UserControl @@ -211,10 +199,17 @@ UpdaterForm.cs - + + PreserveNewest + + + + PreserveNewest + + PreserveNewest - + PreserveNewest @@ -269,10 +264,7 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + - - + \ No newline at end of file diff --git a/LLCD.DownloaderGUI/MainForm.cs b/LLCD.DownloaderGUI/MainForm.cs index 495ccca..838d1fd 100644 --- a/LLCD.DownloaderGUI/MainForm.cs +++ b/LLCD.DownloaderGUI/MainForm.cs @@ -19,17 +19,17 @@ namespace LLCD.DownloaderGUI { public partial class MainForm : Form { - private Font _font; - private readonly PrivateFontCollection _fontCollection = new PrivateFontCollection(); + private Control[] _exceptionControls; public MainForm() { InitializeComponent(); lblCurrentExtractionOperation.Text = "Waiting for input from user"; UC_CourseExtractorStatus.Status = CourseStatus.NotRunning; - UC_CourseDownloaderStatus.Status = CourseStatus.NotRunning; + UCCourseDownloaderStatus.Status = CourseStatus.NotRunning; cmboxQuality.SelectedIndex = 0; cmboxBrowser.SelectedIndex = 0; Focus(); + _exceptionControls = new Control[] { panelStatus }; } private void btnBrowse_Click(object sender, EventArgs e) @@ -40,7 +40,8 @@ private void btnBrowse_Click(object sender, EventArgs e) private async void btnDownload_Click(object sender, EventArgs e) { - UC_CourseDownloaderStatus.Status = CourseStatus.NotRunning; + FormHelpers.SetLoadingStatus(true, panelBody, this, _exceptionControls, false); + UCCourseDownloaderStatus.Status = CourseStatus.NotRunning; UC_CourseExtractorStatus.Status = CourseStatus.NotRunning; progressBarExtractor.Value = 0; progressBarCourses.Value = 0; @@ -51,7 +52,7 @@ private async void btnDownload_Click(object sender, EventArgs e) Quality quality = (Quality)cmboxQuality.SelectedIndex; foreach (var courseUrl in txtCourseUrls.Text.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) { - extractors.Add(new Extractor(courseUrl.Trim(), quality, txtToken.Text.Trim())); + extractors.Add(new Extractor(courseUrl.Trim(), quality, txtToken.Text.Trim(),(int)numericUpDownDelay.Value)); } UC_CourseExtractorStatus.Status = CourseStatus.Starting; Log.Information("Validating Input"); @@ -62,11 +63,11 @@ private async void btnDownload_Click(object sender, EventArgs e) UC_CourseExtractorStatus.Status = CourseStatus.NotRunning; lblCurrentExtractionOperation.Text = "Please recheck your input"; Log.Information("Input Invalid"); + FormHelpers.SetLoadingStatus(false, panelBody, this, _exceptionControls, false); return; } Log.Information("Input Valid"); - UC_CourseDownloaderStatus.Status = CourseStatus.NotRunning; - EnableControls(false); + UCCourseDownloaderStatus.Status = CourseStatus.NotRunning; try { await ExtractAndDownloadAsync(extractors); @@ -78,18 +79,19 @@ private async void btnDownload_Click(object sender, EventArgs e) Log.Error(ex, "Unknown error occured. Courses : " + courses); UC_CourseExtractorStatus.Status = CourseStatus.Failed; lblCurrentExtractionOperation.Text = "Course Extraction Failed"; - lblCurrentCourse.Text = "..."; progressBarCourses.Value = 0; } - - EnableControls(true); + finally + { + FormHelpers.SetLoadingStatus(false, panelBody, this, _exceptionControls, false); + } } private void IncrementlblCurrentCourse() { Regex patternlblCurrentCourse = new Regex(@"Extracting Courses \((?\d+)\/(?\d+)\)"); - int currentCourse = int.Parse(patternlblCurrentCourse.Match(lblCurrentCourse.Text).Groups["currentCourse"].Value); - int totalCourses = int.Parse(patternlblCurrentCourse.Match(lblCurrentCourse.Text).Groups["totalCourses"].Value); - lblCurrentCourse.Text = $"Extracting Courses ({currentCourse + 1}/{totalCourses})"; + int currentCourse = int.Parse(patternlblCurrentCourse.Match(lblCurrentExtractionOperation.Text).Groups["currentCourse"].Value); + int totalCourses = int.Parse(patternlblCurrentCourse.Match(lblCurrentExtractionOperation.Text).Groups["totalCourses"].Value); + lblCurrentExtractionOperation.Text = $"Extracting Courses ({currentCourse + 1}/{totalCourses})"; progressBarCourses.PerformStep(); } private async Task IsInputValid(List extractors) @@ -146,9 +148,9 @@ private async Task IsInputValid(List extractors) } private async Task ExtractAndDownloadAsync(List extractors) { - lblCurrentCourse.Text = $"Extracting Courses (1/{extractors.Count})"; progressBarCourses.Step = 100 / extractors.Count; await SaveConfig(); + lblCurrentExtractionOperation.Text = $"Extracting Courses (1/{extractors.Count})"; var courses = new List(); foreach (var extractor in extractors) { @@ -161,12 +163,11 @@ private async Task ExtractAndDownloadAsync(List extractors) progressBarCourses.Value = progressBarCourses.Maximum; progressBarExtractor.Value = progressBarExtractor.Maximum; - lblCurrentCourse.Text = "Courses Extracted Successfully"; - lblCurrentExtractionOperation.Text = $"Extracted Courses({extractors.Count}/{extractors.Count})"; + lblCurrentExtractionOperation.Text = "Courses Extracted Successfully"; UC_CourseExtractorStatus.Status = CourseStatus.Finished; - var downloaderForm = new DownloaderForm(courses, new DirectoryInfo(txtCourseDirectory.Text), checkBoxExerciseFiles.Checked, _font); - UC_CourseDownloaderStatus.Status = CourseStatus.Running; + var downloaderForm = new DownloaderForm(courses, new DirectoryInfo(txtCourseDirectory.Text), checkBoxExerciseFiles.Checked,checkBoxSubtitles.Checked); + UCCourseDownloaderStatus.Status = CourseStatus.Running; try { downloaderForm.ShowDialog(); @@ -175,33 +176,36 @@ private async Task ExtractAndDownloadAsync(List extractors) { MessageBox.Show($"A fatal error occured while downloading the course.\nCheck the logs for more info", "Unknown Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Log.Error(ex, "An fatal error occured while downloading the course"); - UC_CourseDownloaderStatus.Status = CourseStatus.Failed; + UCCourseDownloaderStatus.Status = CourseStatus.Failed; lblCurrentExtractionOperation.Text = "Course Download Failed"; return; } if (downloaderForm.DownloaderStatus == CourseStatus.Finished) { - UC_CourseDownloaderStatus.Status = CourseStatus.Finished; + UCCourseDownloaderStatus.Status = CourseStatus.Finished; MessageBox.Show("Course Downloaded Successfully :)", "Hooray", MessageBoxButtons.OK, MessageBoxIcon.Information); lblCurrentExtractionOperation.Text = "Course Downloaded Successfully"; } else { - UC_CourseDownloaderStatus.Status = CourseStatus.Failed; + UCCourseDownloaderStatus.Status = CourseStatus.Failed; lblCurrentExtractionOperation.Text = "Course Download Failed"; } } private async Task ExtractCourse(Extractor extractor) { - lblCurrentExtractionOperation.Text = $"Extracting Course Download Links..."; UC_CourseExtractorStatus.Status = CourseStatus.Running; Course course; try { - var progress = new Progress(progressPercent => UpdateUI(() => progressBarExtractor.Value = (int)(progressPercent * 100))); + var progress = new Progress(progressPercent => + { + int progressValue = (int)(progressPercent * 100); + UpdateUI(() => progressBarExtractor.Value = progressValue == 100 ? 0 : progressValue); + }); course = await extractor.GetCourse(progress); } catch (Exception ex) @@ -209,10 +213,9 @@ private async Task ExtractCourse(Extractor extractor) MessageBox.Show(ex.Message, "Course Extraction Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); string courses = String.Join(" -- ", txtCourseUrls.Text.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); Log.Error(ex, "Course Extraction Failed" + courses); - EnableControls(true); + FormHelpers.SetLoadingStatus(false, panelBody, this, _exceptionControls, false); UC_CourseExtractorStatus.Status = CourseStatus.Failed; - lblCurrentExtractionOperation.Text = "Course Extraction Failed"; - lblCurrentCourse.Text = "..."; + lblCurrentExtractionOperation.Text = "Courses Extraction Failed"; progressBarCourses.Value = 0; progressBarExtractor.Value = 0; return null; @@ -224,28 +227,46 @@ private async Task ExtractCourse(Extractor extractor) private void UpdateUI(Action updateAction) { - Invoke(updateAction); + if (IsHandleCreated) + { + if (InvokeRequired) + { + Invoke(updateAction); + } + else + { + updateAction(); + } + } + else + { + Log.Error("Window handle not created. Can't UpdateUI"); + } } private T GetFromUI(Func getterAction) { - return (T)Invoke(getterAction); - } - private void EnableControls(bool isEnabled) - { - txtCourseDirectory.Enabled = isEnabled; - txtCourseUrls.Enabled = isEnabled; - txtToken.Enabled = isEnabled; - cmboxQuality.Enabled = isEnabled; - btnDownload.Enabled = isEnabled; - btnBrowse.Enabled = isEnabled; - btnExtractToken.Enabled = isEnabled; - checkBoxExerciseFiles.Enabled = isEnabled; - cmboxBrowser.Enabled = isEnabled; + if (IsHandleCreated) + { + if (InvokeRequired) + { + return (T)Invoke(getterAction); + } + else + { + return (T)getterAction(); + } + } + else + { + Log.Error("Window handle not created. Can't GetFromUI"); + return default; + } } + private async Task SaveConfig() { - UpdateUI(() => lblCurrentExtractionOperation.Text = "Saving config file"); + lblCurrentExtractionOperation.Text = "Saving config file"; Config config = new Config { AuthenticationToken = txtToken.Text, @@ -258,7 +279,7 @@ private async Task SaveConfig() catch (Exception) { MessageBox.Show("There was a problem with the course directory you entered.\nPlease enter another one", "Invalid Input", MessageBoxButtons.OK, MessageBoxIcon.Error); - EnableControls(true); + FormHelpers.SetLoadingStatus(false, panelBody, this, _exceptionControls, false); } try { @@ -267,7 +288,7 @@ private async Task SaveConfig() catch (Exception ex) { MessageBox.Show("An error occured while trying to save config", "Failed to solve", MessageBoxButtons.OK, MessageBoxIcon.Error); - EnableControls(true); + FormHelpers.SetLoadingStatus(false, panelBody, this, _exceptionControls, false); Log.Error(ex, "An error occured while trying to save config"); } @@ -294,9 +315,9 @@ private async Task CheckForUpdates() .AppendLine("If you choose to update, the app will automatically restart after the update.") .AppendLine($"Would you like to update?") .ToString(); - UpdaterForm updaterForm = new UpdaterForm(message, updateManager, _font); + UpdaterForm updaterForm = new UpdaterForm(message, updateManager); UpdateUI(() => updaterForm.ShowDialog()); - restartApp = updaterForm.isUpdated; + restartApp = updaterForm.IsUpdated; } else { @@ -317,43 +338,14 @@ private async Task CheckForUpdates() private async void MainForm_Load(object sender, EventArgs e) { - _fontCollection.AddFontFile("./fonts/Barlow.ttf"); - _fontCollection.AddFontFile("./fonts/SegoeUI.ttf"); - var fontBarlow16 = new Font(_fontCollection.Families[0], 16); - _font = fontBarlow16; - var fontBarlow20 = new Font(_fontCollection.Families[0], 20); - var fontBarlow12 = new Font(_fontCollection.Families[0], 12); - var fontBarlow14 = new Font(_fontCollection.Families[0], 14); - var fontSegoeUI12 = new Font(_fontCollection.Families[1], 12); - foreach (var control in panel.Controls) - { - switch (control) - { - case Label lbl: - lbl.Font = fontBarlow16; - break; - case Button btn: - btn.Font = fontBarlow16; - break; - case TextBox txt: - txt.Font = fontSegoeUI12; - break; - case ComboBox cmbox: - cmbox.Font = fontBarlow12; - break; - case UserControl uc: - (uc.Controls[0] as Label).Font = fontBarlow16; - break; - case CheckBox chbox: - chbox.Font = fontBarlow16; - break; - } + foreach (Control control in this.Controls) + { + FormHelpers.SetFonts(control); } - btnBrowse.Font = fontBarlow12; - cmboxBrowser.Font = fontBarlow14; - btnExtractToken.Font = fontBarlow14; - lblCurrentExtractionOperation.Font = fontBarlow20; - lblCurrentCourse.Font = fontBarlow20; + + btnBrowse.Font = new Font(FormHelpers.QuicksandFontFamilySemiBold, 12, FontStyle.Bold); + txtCourseUrls.Font = new Font(FormHelpers.QuicksandFontFamilyRegular, 12); + if (File.Exists("./Config.json")) { try @@ -404,5 +396,32 @@ private void btnExtractToken_Click(object sender, EventArgs e) } } + + private void checkBoxDelay_CheckedChanged(object sender, EventArgs e) + { + CoupleDelay(); + } + + private void CoupleDelay() + { + if (checkBoxDelay.Checked) + { + numericUpDownDelay.Enabled = true; + numericUpDownDelay.Value = 2; + } + else + { + numericUpDownDelay.Enabled = false; + numericUpDownDelay.Value = 0; + } + } + + private void numericUpDownDelay_KeyPress(object sender, KeyPressEventArgs e) + { + if (e.KeyChar < 48 || e.KeyChar > 57) + { + e.Handled = true; + } + } } } diff --git a/LLCD.DownloaderGUI/MainForm.designer.cs b/LLCD.DownloaderGUI/MainForm.designer.cs index 7419437..fe06375 100644 --- a/LLCD.DownloaderGUI/MainForm.designer.cs +++ b/LLCD.DownloaderGUI/MainForm.designer.cs @@ -29,322 +29,396 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); - this.panel = new System.Windows.Forms.Panel(); - this.cmboxBrowser = new System.Windows.Forms.ComboBox(); - this.btnExtractToken = new System.Windows.Forms.Button(); - this.lblCurrentCourse = new System.Windows.Forms.Label(); - this.progressBarCourses = new System.Windows.Forms.ProgressBar(); + this.panelBody = new System.Windows.Forms.Panel(); + this.panelStatus = new System.Windows.Forms.Panel(); this.lblCurrentExtractionOperation = new System.Windows.Forms.Label(); - this.UC_CourseDownloaderStatus = new LLCD.DownloaderGUI.CourseStatusUserControl(); - this.UC_CourseExtractorStatus = new LLCD.DownloaderGUI.CourseStatusUserControl(); + this.label10 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.progressBarCourses = new System.Windows.Forms.ProgressBar(); this.progressBarExtractor = new System.Windows.Forms.ProgressBar(); + this.panelInput = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); this.btnDownload = new System.Windows.Forms.Button(); this.btnBrowse = new System.Windows.Forms.Button(); + this.txtCourseUrls = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); this.txtCourseDirectory = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); this.txtToken = new System.Windows.Forms.TextBox(); - this.txtCourseUrls = new System.Windows.Forms.TextBox(); - this.label3 = new System.Windows.Forms.Label(); - this.cmboxQuality = new System.Windows.Forms.ComboBox(); - this.label10 = new System.Windows.Forms.Label(); - this.label8 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.btnExtractToken = new System.Windows.Forms.Button(); + this.cmboxQuality = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.cmboxBrowser = new System.Windows.Forms.ComboBox(); + this.numericUpDownDelay = new System.Windows.Forms.NumericUpDown(); this.checkBoxExerciseFiles = new System.Windows.Forms.CheckBox(); - this.panel.SuspendLayout(); + this.checkBoxDelay = new System.Windows.Forms.CheckBox(); + this.checkBoxSubtitles = new System.Windows.Forms.CheckBox(); + this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.UCCourseDownloaderStatus = new LLCD.DownloaderGUI.CourseStatusUserControl(); + this.UC_CourseExtractorStatus = new LLCD.DownloaderGUI.CourseStatusUserControl(); + this.panelBody.SuspendLayout(); + this.panelStatus.SuspendLayout(); + this.panelInput.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownDelay)).BeginInit(); this.SuspendLayout(); // - // panel - // - this.panel.Controls.Add(this.cmboxBrowser); - this.panel.Controls.Add(this.btnExtractToken); - this.panel.Controls.Add(this.lblCurrentCourse); - this.panel.Controls.Add(this.progressBarCourses); - this.panel.Controls.Add(this.lblCurrentExtractionOperation); - this.panel.Controls.Add(this.UC_CourseDownloaderStatus); - this.panel.Controls.Add(this.UC_CourseExtractorStatus); - this.panel.Controls.Add(this.progressBarExtractor); - this.panel.Controls.Add(this.btnDownload); - this.panel.Controls.Add(this.btnBrowse); - this.panel.Controls.Add(this.txtCourseDirectory); - this.panel.Controls.Add(this.txtToken); - this.panel.Controls.Add(this.txtCourseUrls); - this.panel.Controls.Add(this.label3); - this.panel.Controls.Add(this.cmboxQuality); - this.panel.Controls.Add(this.label10); - this.panel.Controls.Add(this.label8); - this.panel.Controls.Add(this.label5); - this.panel.Controls.Add(this.label4); - this.panel.Controls.Add(this.label2); - this.panel.ForeColor = System.Drawing.Color.White; - this.panel.Location = new System.Drawing.Point(12, 12); - this.panel.Name = "panel"; - this.panel.Size = new System.Drawing.Size(666, 554); - this.panel.TabIndex = 0; + // panelBody + // + this.panelBody.Controls.Add(this.panelStatus); + this.panelBody.Controls.Add(this.panelInput); + this.panelBody.ForeColor = System.Drawing.Color.White; + this.panelBody.Location = new System.Drawing.Point(12, 12); + this.panelBody.Name = "panelBody"; + this.panelBody.Size = new System.Drawing.Size(697, 690); + this.panelBody.TabIndex = 0; + // + // panelStatus + // + this.panelStatus.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(29)))), ((int)(((byte)(29))))); + this.panelStatus.Controls.Add(this.UCCourseDownloaderStatus); + this.panelStatus.Controls.Add(this.UC_CourseExtractorStatus); + this.panelStatus.Controls.Add(this.lblCurrentExtractionOperation); + this.panelStatus.Controls.Add(this.label10); + this.panelStatus.Controls.Add(this.label8); + this.panelStatus.Controls.Add(this.progressBarCourses); + this.panelStatus.Controls.Add(this.progressBarExtractor); + this.panelStatus.Location = new System.Drawing.Point(13, 479); + this.panelStatus.Name = "panelStatus"; + this.panelStatus.Size = new System.Drawing.Size(671, 207); + this.panelStatus.TabIndex = 22; // - // cmboxBrowser + // lblCurrentExtractionOperation // - this.cmboxBrowser.BackColor = System.Drawing.Color.Black; - this.cmboxBrowser.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.cmboxBrowser.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.cmboxBrowser.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.cmboxBrowser.ForeColor = System.Drawing.Color.White; - this.cmboxBrowser.FormattingEnabled = true; - this.cmboxBrowser.Items.AddRange(new object[] { - "From Google Chrome", - "From Mozilla Firefox", - "From Microsoft Edge"}); - this.cmboxBrowser.Location = new System.Drawing.Point(338, 88); - this.cmboxBrowser.Name = "cmboxBrowser"; - this.cmboxBrowser.Size = new System.Drawing.Size(312, 28); - this.cmboxBrowser.TabIndex = 12; + this.lblCurrentExtractionOperation.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(39)))), ((int)(((byte)(39))))); + this.lblCurrentExtractionOperation.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblCurrentExtractionOperation.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.lblCurrentExtractionOperation.Location = new System.Drawing.Point(16, 65); + this.lblCurrentExtractionOperation.Name = "lblCurrentExtractionOperation"; + this.lblCurrentExtractionOperation.Size = new System.Drawing.Size(634, 53); + this.lblCurrentExtractionOperation.TabIndex = 6; + this.lblCurrentExtractionOperation.Text = "Waiting for login data"; + this.lblCurrentExtractionOperation.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // - // btnExtractToken + // label10 // - this.btnExtractToken.BackColor = System.Drawing.Color.Navy; - this.btnExtractToken.FlatAppearance.BorderColor = System.Drawing.Color.Black; - this.btnExtractToken.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); - this.btnExtractToken.FlatAppearance.MouseOverBackColor = System.Drawing.Color.DimGray; - this.btnExtractToken.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnExtractToken.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnExtractToken.ForeColor = System.Drawing.Color.White; - this.btnExtractToken.Location = new System.Drawing.Point(19, 87); - this.btnExtractToken.Name = "btnExtractToken"; - this.btnExtractToken.Size = new System.Drawing.Size(312, 36); - this.btnExtractToken.TabIndex = 11; - this.btnExtractToken.Text = "Extract token"; - this.btnExtractToken.UseVisualStyleBackColor = false; - this.btnExtractToken.Click += new System.EventHandler(this.btnExtractToken_Click); + this.label10.AutoSize = true; + this.label10.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label10.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label10.Location = new System.Drawing.Point(333, 20); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(192, 28); + this.label10.TabIndex = 0; + this.label10.Text = "Course downloader: "; // - // lblCurrentCourse + // label8 // - this.lblCurrentCourse.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblCurrentCourse.ForeColor = System.Drawing.Color.Gold; - this.lblCurrentCourse.Location = new System.Drawing.Point(19, 480); - this.lblCurrentCourse.Name = "lblCurrentCourse"; - this.lblCurrentCourse.Size = new System.Drawing.Size(630, 33); - this.lblCurrentCourse.TabIndex = 10; - this.lblCurrentCourse.Text = "..."; - this.lblCurrentCourse.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.label8.AutoSize = true; + this.label8.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label8.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label8.Location = new System.Drawing.Point(11, 20); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(172, 28); + this.label8.TabIndex = 0; + this.label8.Text = "Course extractor : "; // // progressBarCourses // - this.progressBarCourses.Location = new System.Drawing.Point(19, 519); + this.progressBarCourses.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(218)))), ((int)(((byte)(197))))); + this.progressBarCourses.Location = new System.Drawing.Point(16, 170); this.progressBarCourses.MarqueeAnimationSpeed = 30; this.progressBarCourses.Name = "progressBarCourses"; - this.progressBarCourses.Size = new System.Drawing.Size(631, 32); + this.progressBarCourses.Size = new System.Drawing.Size(634, 20); this.progressBarCourses.Style = System.Windows.Forms.ProgressBarStyle.Continuous; this.progressBarCourses.TabIndex = 9; // - // lblCurrentExtractionOperation - // - this.lblCurrentExtractionOperation.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblCurrentExtractionOperation.ForeColor = System.Drawing.Color.Gold; - this.lblCurrentExtractionOperation.Location = new System.Drawing.Point(20, 392); - this.lblCurrentExtractionOperation.Name = "lblCurrentExtractionOperation"; - this.lblCurrentExtractionOperation.Size = new System.Drawing.Size(630, 33); - this.lblCurrentExtractionOperation.TabIndex = 8; - this.lblCurrentExtractionOperation.Text = "Waiting for input from user"; - this.lblCurrentExtractionOperation.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // - // UC_CourseDownloaderStatus - // - this.UC_CourseDownloaderStatus.BackColor = System.Drawing.Color.Black; - this.UC_CourseDownloaderStatus.Location = new System.Drawing.Point(545, 354); - this.UC_CourseDownloaderStatus.Name = "UC_CourseDownloaderStatus"; - this.UC_CourseDownloaderStatus.Size = new System.Drawing.Size(105, 29); - this.UC_CourseDownloaderStatus.Status = LLCD.DownloaderGUI.CourseStatus.NotRunning; - this.UC_CourseDownloaderStatus.TabIndex = 5; - // - // UC_CourseExtractorStatus - // - this.UC_CourseExtractorStatus.BackColor = System.Drawing.Color.Black; - this.UC_CourseExtractorStatus.Location = new System.Drawing.Point(181, 354); - this.UC_CourseExtractorStatus.Name = "UC_CourseExtractorStatus"; - this.UC_CourseExtractorStatus.Size = new System.Drawing.Size(105, 29); - this.UC_CourseExtractorStatus.Status = LLCD.DownloaderGUI.CourseStatus.NotRunning; - this.UC_CourseExtractorStatus.TabIndex = 5; - // // progressBarExtractor // - this.progressBarExtractor.Location = new System.Drawing.Point(20, 431); + this.progressBarExtractor.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(3)))), ((int)(((byte)(218)))), ((int)(((byte)(197))))); + this.progressBarExtractor.Location = new System.Drawing.Point(16, 138); this.progressBarExtractor.MarqueeAnimationSpeed = 30; this.progressBarExtractor.Name = "progressBarExtractor"; - this.progressBarExtractor.Size = new System.Drawing.Size(631, 32); + this.progressBarExtractor.Size = new System.Drawing.Size(634, 20); this.progressBarExtractor.Style = System.Windows.Forms.ProgressBarStyle.Continuous; this.progressBarExtractor.TabIndex = 4; // + // panelInput + // + this.panelInput.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(29)))), ((int)(((byte)(29))))); + this.panelInput.Controls.Add(this.label1); + this.panelInput.Controls.Add(this.btnDownload); + this.panelInput.Controls.Add(this.btnBrowse); + this.panelInput.Controls.Add(this.txtCourseUrls); + this.panelInput.Controls.Add(this.label2); + this.panelInput.Controls.Add(this.txtCourseDirectory); + this.panelInput.Controls.Add(this.label4); + this.panelInput.Controls.Add(this.txtToken); + this.panelInput.Controls.Add(this.label5); + this.panelInput.Controls.Add(this.btnExtractToken); + this.panelInput.Controls.Add(this.cmboxQuality); + this.panelInput.Controls.Add(this.label3); + this.panelInput.Controls.Add(this.cmboxBrowser); + this.panelInput.Controls.Add(this.numericUpDownDelay); + this.panelInput.Controls.Add(this.checkBoxExerciseFiles); + this.panelInput.Controls.Add(this.checkBoxDelay); + this.panelInput.Controls.Add(this.checkBoxSubtitles); + this.panelInput.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.panelInput.Location = new System.Drawing.Point(13, 0); + this.panelInput.Name = "panelInput"; + this.panelInput.Size = new System.Drawing.Size(671, 459); + this.panelInput.TabIndex = 21; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label1.Location = new System.Drawing.Point(11, 194); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(132, 28); + this.label1.TabIndex = 21; + this.label1.Text = "Courses urls : "; + // // btnDownload // - this.btnDownload.BackColor = System.Drawing.Color.DarkGreen; - this.btnDownload.FlatAppearance.BorderColor = System.Drawing.Color.Black; - this.btnDownload.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); - this.btnDownload.FlatAppearance.MouseOverBackColor = System.Drawing.Color.DimGray; + this.btnDownload.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(187)))), ((int)(((byte)(134)))), ((int)(((byte)(252))))); + this.btnDownload.Cursor = System.Windows.Forms.Cursors.Default; this.btnDownload.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnDownload.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnDownload.ForeColor = System.Drawing.Color.White; - this.btnDownload.Location = new System.Drawing.Point(19, 296); + this.btnDownload.Font = new System.Drawing.Font("Quicksand Medium", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnDownload.ForeColor = System.Drawing.Color.Black; + this.btnDownload.Location = new System.Drawing.Point(429, 392); this.btnDownload.Name = "btnDownload"; - this.btnDownload.Size = new System.Drawing.Size(631, 40); - this.btnDownload.TabIndex = 3; - this.btnDownload.Text = "Start Downloading"; + this.btnDownload.Size = new System.Drawing.Size(221, 45); + this.btnDownload.TabIndex = 17; + this.btnDownload.Text = "DOWNLOAD"; this.btnDownload.UseVisualStyleBackColor = false; this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click); // // btnBrowse // - this.btnBrowse.BackColor = System.Drawing.Color.DarkGray; - this.btnBrowse.FlatAppearance.BorderColor = System.Drawing.Color.Black; - this.btnBrowse.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); - this.btnBrowse.FlatAppearance.MouseOverBackColor = System.Drawing.Color.DimGray; + this.btnBrowse.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(187)))), ((int)(((byte)(134)))), ((int)(((byte)(252))))); + this.btnBrowse.Cursor = System.Windows.Forms.Cursors.Default; this.btnBrowse.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnBrowse.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnBrowse.ForeColor = System.Drawing.Color.White; - this.btnBrowse.Location = new System.Drawing.Point(615, 137); + this.btnBrowse.Font = new System.Drawing.Font("Quicksand", 12F, System.Drawing.FontStyle.Bold); + this.btnBrowse.ForeColor = System.Drawing.Color.Black; + this.btnBrowse.Location = new System.Drawing.Point(615, 149); this.btnBrowse.Name = "btnBrowse"; - this.btnBrowse.Size = new System.Drawing.Size(35, 29); - this.btnBrowse.TabIndex = 3; - this.btnBrowse.Text = ". . ."; + this.btnBrowse.Size = new System.Drawing.Size(35, 31); + this.btnBrowse.TabIndex = 17; + this.btnBrowse.Text = "..."; this.btnBrowse.UseVisualStyleBackColor = false; this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); // + // txtCourseUrls + // + this.txtCourseUrls.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(53)))), ((int)(((byte)(53)))), ((int)(((byte)(53))))); + this.txtCourseUrls.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtCourseUrls.Font = new System.Drawing.Font("Quicksand", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtCourseUrls.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.txtCourseUrls.Location = new System.Drawing.Point(187, 192); + this.txtCourseUrls.Multiline = true; + this.txtCourseUrls.Name = "txtCourseUrls"; + this.txtCourseUrls.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtCourseUrls.Size = new System.Drawing.Size(463, 126); + this.txtCourseUrls.TabIndex = 20; + this.txtCourseUrls.Text = "One course url per line"; + this.txtCourseUrls.Enter += new System.EventHandler(this.txtCourseUrls_Enter); + this.txtCourseUrls.Leave += new System.EventHandler(this.txtCourseUrls_Leave); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label2.Location = new System.Drawing.Point(409, 332); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(85, 28); + this.label2.TabIndex = 0; + this.label2.Text = "seconds"; + // // txtCourseDirectory // - this.txtCourseDirectory.BackColor = System.Drawing.Color.DarkGray; + this.txtCourseDirectory.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(53)))), ((int)(((byte)(53)))), ((int)(((byte)(53))))); this.txtCourseDirectory.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtCourseDirectory.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.txtCourseDirectory.ForeColor = System.Drawing.Color.White; - this.txtCourseDirectory.Location = new System.Drawing.Point(150, 137); + this.txtCourseDirectory.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtCourseDirectory.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.txtCourseDirectory.Location = new System.Drawing.Point(187, 149); this.txtCourseDirectory.Name = "txtCourseDirectory"; - this.txtCourseDirectory.Size = new System.Drawing.Size(459, 29); - this.txtCourseDirectory.TabIndex = 2; + this.txtCourseDirectory.Size = new System.Drawing.Size(422, 31); + this.txtCourseDirectory.TabIndex = 20; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label4.Location = new System.Drawing.Point(11, 13); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(142, 28); + this.label4.TabIndex = 0; + this.label4.Text = "Video quality : "; // // txtToken // - this.txtToken.BackColor = System.Drawing.Color.DarkGray; + this.txtToken.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(53)))), ((int)(((byte)(53)))), ((int)(((byte)(53))))); this.txtToken.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtToken.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.txtToken.ForeColor = System.Drawing.Color.White; - this.txtToken.Location = new System.Drawing.Point(150, 43); + this.txtToken.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtToken.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.txtToken.Location = new System.Drawing.Point(187, 55); this.txtToken.Name = "txtToken"; - this.txtToken.Size = new System.Drawing.Size(500, 29); - this.txtToken.TabIndex = 2; + this.txtToken.Size = new System.Drawing.Size(463, 31); + this.txtToken.TabIndex = 19; // - // txtCourseUrls + // label5 // - this.txtCourseUrls.BackColor = System.Drawing.Color.DarkGray; - this.txtCourseUrls.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.txtCourseUrls.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.txtCourseUrls.ForeColor = System.Drawing.Color.White; - this.txtCourseUrls.Location = new System.Drawing.Point(150, 183); - this.txtCourseUrls.Multiline = true; - this.txtCourseUrls.Name = "txtCourseUrls"; - this.txtCourseUrls.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.txtCourseUrls.Size = new System.Drawing.Size(500, 100); - this.txtCourseUrls.TabIndex = 2; - this.txtCourseUrls.Text = "One course url per line"; - this.txtCourseUrls.Enter += new System.EventHandler(this.txtCourseUrls_Enter); - this.txtCourseUrls.Leave += new System.EventHandler(this.txtCourseUrls_Leave); + this.label5.AutoSize = true; + this.label5.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label5.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label5.Location = new System.Drawing.Point(11, 149); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(166, 28); + this.label5.TabIndex = 0; + this.label5.Text = "Download folder: "; // - // label3 + // btnExtractToken // - this.label3.AutoSize = true; - this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label3.Location = new System.Drawing.Point(15, 43); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(163, 25); - this.label3.TabIndex = 0; - this.label3.Text = "Token Cookie : "; + this.btnExtractToken.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(187)))), ((int)(((byte)(134)))), ((int)(((byte)(252))))); + this.btnExtractToken.Cursor = System.Windows.Forms.Cursors.Default; + this.btnExtractToken.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btnExtractToken.Font = new System.Drawing.Font("Quicksand Medium", 14.25F, System.Drawing.FontStyle.Bold); + this.btnExtractToken.ForeColor = System.Drawing.Color.Black; + this.btnExtractToken.Location = new System.Drawing.Point(16, 100); + this.btnExtractToken.Name = "btnExtractToken"; + this.btnExtractToken.Size = new System.Drawing.Size(316, 43); + this.btnExtractToken.TabIndex = 18; + this.btnExtractToken.Text = "Import Token"; + this.btnExtractToken.UseVisualStyleBackColor = false; + this.btnExtractToken.Click += new System.EventHandler(this.btnExtractToken_Click); // // cmboxQuality // - this.cmboxQuality.BackColor = System.Drawing.Color.Black; + this.cmboxQuality.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(53)))), ((int)(((byte)(53)))), ((int)(((byte)(53))))); this.cmboxQuality.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cmboxQuality.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.cmboxQuality.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.cmboxQuality.ForeColor = System.Drawing.Color.White; + this.cmboxQuality.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.cmboxQuality.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); this.cmboxQuality.FormattingEnabled = true; this.cmboxQuality.Items.AddRange(new object[] { "720 (High)", "540 (Medium)", "360 (Low)"}); - this.cmboxQuality.Location = new System.Drawing.Point(150, 0); + this.cmboxQuality.Location = new System.Drawing.Point(187, 10); this.cmboxQuality.Name = "cmboxQuality"; - this.cmboxQuality.Size = new System.Drawing.Size(181, 28); + this.cmboxQuality.Size = new System.Drawing.Size(463, 36); this.cmboxQuality.TabIndex = 1; // - // label10 - // - this.label10.AutoSize = true; - this.label10.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label10.Location = new System.Drawing.Point(373, 354); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(213, 25); - this.label10.TabIndex = 0; - this.label10.Text = "Course Downloader: "; - // - // label8 - // - this.label8.AutoSize = true; - this.label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label8.Location = new System.Drawing.Point(15, 354); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(191, 25); - this.label8.TabIndex = 0; - this.label8.Text = "Course Extractor : "; - // - // label5 + // label3 // - this.label5.AutoSize = true; - this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label5.Location = new System.Drawing.Point(15, 137); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(187, 25); - this.label5.TabIndex = 0; - this.label5.Text = "Course Location : "; + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.label3.Location = new System.Drawing.Point(11, 57); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(140, 28); + this.label3.TabIndex = 0; + this.label3.Text = "Token cookie : "; // - // label4 + // cmboxBrowser // - this.label4.AutoSize = true; - this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label4.Location = new System.Drawing.Point(14, 0); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(158, 25); - this.label4.TabIndex = 0; - this.label4.Text = "Video Quality : "; + this.cmboxBrowser.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(53)))), ((int)(((byte)(53)))), ((int)(((byte)(53))))); + this.cmboxBrowser.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cmboxBrowser.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.cmboxBrowser.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.cmboxBrowser.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.cmboxBrowser.FormattingEnabled = true; + this.cmboxBrowser.Items.AddRange(new object[] { + "From Google Chrome", + "From Mozilla Firefox", + "From Microsoft Edge"}); + this.cmboxBrowser.Location = new System.Drawing.Point(338, 104); + this.cmboxBrowser.Name = "cmboxBrowser"; + this.cmboxBrowser.Size = new System.Drawing.Size(312, 36); + this.cmboxBrowser.TabIndex = 12; // - // label2 + // numericUpDownDelay // - this.label2.AutoSize = true; - this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.Location = new System.Drawing.Point(15, 183); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(143, 25); - this.label2.TabIndex = 0; - this.label2.Text = "Course Urls : "; + this.numericUpDownDelay.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(53)))), ((int)(((byte)(53)))), ((int)(((byte)(53))))); + this.numericUpDownDelay.Enabled = false; + this.numericUpDownDelay.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.numericUpDownDelay.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.numericUpDownDelay.Location = new System.Drawing.Point(338, 330); + this.numericUpDownDelay.Name = "numericUpDownDelay"; + this.numericUpDownDelay.Size = new System.Drawing.Size(65, 31); + this.numericUpDownDelay.TabIndex = 16; + this.numericUpDownDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + this.numericUpDownDelay.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.numericUpDownDelay_KeyPress); // // checkBoxExerciseFiles // this.checkBoxExerciseFiles.AutoSize = true; this.checkBoxExerciseFiles.Checked = true; this.checkBoxExerciseFiles.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkBoxExerciseFiles.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.checkBoxExerciseFiles.Location = new System.Drawing.Point(423, 12); + this.checkBoxExerciseFiles.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.checkBoxExerciseFiles.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.checkBoxExerciseFiles.Location = new System.Drawing.Point(16, 367); this.checkBoxExerciseFiles.Name = "checkBoxExerciseFiles"; - this.checkBoxExerciseFiles.Size = new System.Drawing.Size(238, 28); + this.checkBoxExerciseFiles.Size = new System.Drawing.Size(237, 32); this.checkBoxExerciseFiles.TabIndex = 13; - this.checkBoxExerciseFiles.Text = "Download Exercise Files"; + this.checkBoxExerciseFiles.Text = "Download exercise files"; this.checkBoxExerciseFiles.UseVisualStyleBackColor = true; // + // checkBoxDelay + // + this.checkBoxDelay.AutoSize = true; + this.checkBoxDelay.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.checkBoxDelay.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.checkBoxDelay.Location = new System.Drawing.Point(19, 329); + this.checkBoxDelay.Name = "checkBoxDelay"; + this.checkBoxDelay.Size = new System.Drawing.Size(320, 32); + this.checkBoxDelay.TabIndex = 15; + this.checkBoxDelay.Text = "Delay between video extractions"; + this.checkBoxDelay.UseVisualStyleBackColor = true; + this.checkBoxDelay.CheckedChanged += new System.EventHandler(this.checkBoxDelay_CheckedChanged); + // + // checkBoxSubtitles + // + this.checkBoxSubtitles.AutoSize = true; + this.checkBoxSubtitles.Checked = true; + this.checkBoxSubtitles.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxSubtitles.Font = new System.Drawing.Font("Quicksand", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.checkBoxSubtitles.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(210)))), ((int)(((byte)(214))))); + this.checkBoxSubtitles.Location = new System.Drawing.Point(16, 405); + this.checkBoxSubtitles.Name = "checkBoxSubtitles"; + this.checkBoxSubtitles.Size = new System.Drawing.Size(197, 32); + this.checkBoxSubtitles.TabIndex = 14; + this.checkBoxSubtitles.Text = "Download subtitles"; + this.checkBoxSubtitles.UseVisualStyleBackColor = true; + // + // UCCourseDownloaderStatus + // + this.UCCourseDownloaderStatus.BackColor = System.Drawing.Color.Black; + this.UCCourseDownloaderStatus.Location = new System.Drawing.Point(520, 20); + this.UCCourseDownloaderStatus.Name = "UCCourseDownloaderStatus"; + this.UCCourseDownloaderStatus.Size = new System.Drawing.Size(130, 29); + this.UCCourseDownloaderStatus.Status = LLCD.DownloaderGUI.CourseStatus.NotRunning; + this.UCCourseDownloaderStatus.TabIndex = 5; + // + // UC_CourseExtractorStatus + // + this.UC_CourseExtractorStatus.BackColor = System.Drawing.Color.Black; + this.UC_CourseExtractorStatus.Location = new System.Drawing.Point(177, 19); + this.UC_CourseExtractorStatus.Name = "UC_CourseExtractorStatus"; + this.UC_CourseExtractorStatus.Size = new System.Drawing.Size(130, 29); + this.UC_CourseExtractorStatus.Status = LLCD.DownloaderGUI.CourseStatus.NotRunning; + this.UC_CourseExtractorStatus.TabIndex = 5; + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.BackColor = System.Drawing.Color.Black; - this.ClientSize = new System.Drawing.Size(693, 578); - this.Controls.Add(this.checkBoxExerciseFiles); - this.Controls.Add(this.panel); + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(18)))), ((int)(((byte)(18)))), ((int)(((byte)(18))))); + this.ClientSize = new System.Drawing.Size(717, 711); + this.Controls.Add(this.panelBody); this.ForeColor = System.Drawing.Color.White; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); @@ -353,22 +427,21 @@ private void InitializeComponent() this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Linkedin Learning Courses Downloader - By ahmedayman4a"; this.Load += new System.EventHandler(this.MainForm_Load); - this.panel.ResumeLayout(false); - this.panel.PerformLayout(); + this.panelBody.ResumeLayout(false); + this.panelStatus.ResumeLayout(false); + this.panelStatus.PerformLayout(); + this.panelInput.ResumeLayout(false); + this.panelInput.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownDelay)).EndInit(); this.ResumeLayout(false); - this.PerformLayout(); } #endregion - private System.Windows.Forms.Panel panel; + private System.Windows.Forms.Panel panelBody; private System.Windows.Forms.Label label2; private System.Windows.Forms.ProgressBar progressBarExtractor; - private System.Windows.Forms.Button btnDownload; - private System.Windows.Forms.Button btnBrowse; - private System.Windows.Forms.TextBox txtCourseDirectory; - private System.Windows.Forms.TextBox txtToken; private System.Windows.Forms.Label label3; private System.Windows.Forms.ComboBox cmboxQuality; private System.Windows.Forms.Label label5; @@ -377,14 +450,23 @@ private void InitializeComponent() private System.Windows.Forms.Label label10; private System.Windows.Forms.Label label8; private CourseStatusUserControl UC_CourseExtractorStatus; - private CourseStatusUserControl UC_CourseDownloaderStatus; - private System.Windows.Forms.TextBox txtCourseUrls; - private System.Windows.Forms.Label lblCurrentExtractionOperation; - private System.Windows.Forms.Label lblCurrentCourse; + private CourseStatusUserControl UCCourseDownloaderStatus; private System.Windows.Forms.ProgressBar progressBarCourses; private System.Windows.Forms.ComboBox cmboxBrowser; - private System.Windows.Forms.Button btnExtractToken; private System.Windows.Forms.CheckBox checkBoxExerciseFiles; + private System.Windows.Forms.Panel panelInput; + private System.Windows.Forms.TextBox txtCourseUrls; + private System.Windows.Forms.TextBox txtCourseDirectory; + private System.Windows.Forms.TextBox txtToken; + private System.Windows.Forms.Button btnExtractToken; + private System.Windows.Forms.Button btnBrowse; + private System.Windows.Forms.Button btnDownload; + private System.Windows.Forms.NumericUpDown numericUpDownDelay; + private System.Windows.Forms.CheckBox checkBoxDelay; + private System.Windows.Forms.CheckBox checkBoxSubtitles; + private System.Windows.Forms.Panel panelStatus; + private System.Windows.Forms.Label lblCurrentExtractionOperation; + private System.Windows.Forms.Label label1; } } diff --git a/LLCD.DownloaderGUI/MainForm.resx b/LLCD.DownloaderGUI/MainForm.resx index 2995cd0..5012202 100644 --- a/LLCD.DownloaderGUI/MainForm.resx +++ b/LLCD.DownloaderGUI/MainForm.resx @@ -120,6 +120,9 @@ 17, 17 + + 73 + diff --git a/LLCD.DownloaderGUI/Properties/AssemblyInfo.cs b/LLCD.DownloaderGUI/Properties/AssemblyInfo.cs index 3517336..77a908f 100644 --- a/LLCD.DownloaderGUI/Properties/AssemblyInfo.cs +++ b/LLCD.DownloaderGUI/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.1.0.0")] -[assembly: AssemblyFileVersion("1.1.0.0")] +[assembly: AssemblyVersion("1.2.0.0")] +[assembly: AssemblyFileVersion("1.2.0.0")] diff --git a/LLCD.DownloaderGUI/UpdaterForm.cs b/LLCD.DownloaderGUI/UpdaterForm.cs index f28f420..ea49fa1 100644 --- a/LLCD.DownloaderGUI/UpdaterForm.cs +++ b/LLCD.DownloaderGUI/UpdaterForm.cs @@ -16,24 +16,13 @@ namespace LLCD.DownloaderGUI public partial class UpdaterForm : Form { private UpdateManager _updateManager; - public bool isUpdated { get; set; } - public UpdaterForm(string message ,UpdateManager updateManager, Font font) + public bool IsUpdated { get; set; } + public UpdaterForm(string message ,UpdateManager updateManager) { _updateManager = updateManager; InitializeComponent(); lblMessage.Text = message; - foreach (var control in flowLayoutPanel.Controls) - { - switch (control) - { - case Label lbl: - lbl.Font = font; - break; - case Button btn: - btn.Font = font; - break; - } - } + FormHelpers.SetFonts(flowLayoutPanel); } private async void btnYes_Click(object sender, EventArgs e) @@ -47,14 +36,14 @@ private async void btnYes_Click(object sender, EventArgs e) var updateResult = await _updateManager.UpdateApp(); Log.Information($"Download complete. App will restart into version {updateResult.Version} after backing up config file."); Config.Backup(); - isUpdated = true; + IsUpdated = true; Close(); } private void btnNo_Click(object sender, EventArgs e) { Log.Information("Update declined by user."); - isUpdated = false; + IsUpdated = false; Close(); } } diff --git a/LLCD.DownloaderGUI/UpdaterForm.designer.cs b/LLCD.DownloaderGUI/UpdaterForm.designer.cs index f09f4e2..667e87b 100644 --- a/LLCD.DownloaderGUI/UpdaterForm.designer.cs +++ b/LLCD.DownloaderGUI/UpdaterForm.designer.cs @@ -28,10 +28,9 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdaterForm)); this.lblMessage = new System.Windows.Forms.Label(); - this.btnYes = new System.Windows.Forms.Button(); this.flowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.btnYes = new System.Windows.Forms.Button(); this.btnNo = new System.Windows.Forms.Button(); this.gifLoading = new System.Windows.Forms.PictureBox(); this.flowLayoutPanel.SuspendLayout(); @@ -42,30 +41,14 @@ private void InitializeComponent() // this.lblMessage.Anchor = System.Windows.Forms.AnchorStyles.None; this.lblMessage.AutoSize = true; - this.lblMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblMessage.Font = new System.Drawing.Font("Quicksand", 14.25F); this.lblMessage.Location = new System.Drawing.Point(3, 0); + this.lblMessage.Margin = new System.Windows.Forms.Padding(3, 0, 3, 5); this.lblMessage.Name = "lblMessage"; - this.lblMessage.Size = new System.Drawing.Size(211, 200); + this.lblMessage.Size = new System.Drawing.Size(200, 224); this.lblMessage.TabIndex = 1; this.lblMessage.Text = "App is 2 versions behind.\r\nIf you choose to update, the app will automatically re" + "start after the update.\r\nWould you like to update?"; - // - // btnYes - // - this.btnYes.BackColor = System.Drawing.Color.DarkGreen; - this.btnYes.FlatAppearance.BorderColor = System.Drawing.Color.Black; - this.btnYes.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); - this.btnYes.FlatAppearance.MouseOverBackColor = System.Drawing.Color.DimGray; - this.btnYes.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnYes.Font = new System.Drawing.Font("Microsoft Sans Serif", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnYes.ForeColor = System.Drawing.Color.White; - this.btnYes.Location = new System.Drawing.Point(3, 203); - this.btnYes.Name = "btnYes"; - this.btnYes.Size = new System.Drawing.Size(107, 40); - this.btnYes.TabIndex = 4; - this.btnYes.Text = "Yes"; - this.btnYes.UseVisualStyleBackColor = false; - this.btnYes.Click += new System.EventHandler(this.btnYes_Click); // // flowLayoutPanel // @@ -79,31 +62,44 @@ private void InitializeComponent() this.flowLayoutPanel.MaximumSize = new System.Drawing.Size(230, 1000); this.flowLayoutPanel.MinimumSize = new System.Drawing.Size(230, 50); this.flowLayoutPanel.Name = "flowLayoutPanel"; - this.flowLayoutPanel.Size = new System.Drawing.Size(230, 326); + this.flowLayoutPanel.Size = new System.Drawing.Size(230, 355); this.flowLayoutPanel.TabIndex = 5; // + // btnYes + // + this.btnYes.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(187)))), ((int)(((byte)(134)))), ((int)(((byte)(252))))); + this.btnYes.Cursor = System.Windows.Forms.Cursors.Default; + this.btnYes.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btnYes.Font = new System.Drawing.Font("Quicksand Medium", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnYes.ForeColor = System.Drawing.Color.Black; + this.btnYes.Location = new System.Drawing.Point(3, 232); + this.btnYes.Name = "btnYes"; + this.btnYes.Size = new System.Drawing.Size(107, 40); + this.btnYes.TabIndex = 19; + this.btnYes.Text = "Yes"; + this.btnYes.UseVisualStyleBackColor = false; + this.btnYes.Click += new System.EventHandler(this.btnYes_Click); + // // btnNo // - this.btnNo.BackColor = System.Drawing.Color.Maroon; - this.btnNo.FlatAppearance.BorderColor = System.Drawing.Color.Black; - this.btnNo.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); - this.btnNo.FlatAppearance.MouseOverBackColor = System.Drawing.Color.DimGray; + this.btnNo.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(207)))), ((int)(((byte)(102)))), ((int)(((byte)(121))))); + this.btnNo.Cursor = System.Windows.Forms.Cursors.Default; this.btnNo.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnNo.Font = new System.Drawing.Font("Microsoft Sans Serif", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnNo.ForeColor = System.Drawing.Color.White; - this.btnNo.Location = new System.Drawing.Point(116, 203); + this.btnNo.Font = new System.Drawing.Font("Quicksand Medium", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnNo.ForeColor = System.Drawing.Color.Black; + this.btnNo.Location = new System.Drawing.Point(116, 232); this.btnNo.Name = "btnNo"; this.btnNo.Size = new System.Drawing.Size(107, 40); - this.btnNo.TabIndex = 4; + this.btnNo.TabIndex = 20; this.btnNo.Text = "No"; this.btnNo.UseVisualStyleBackColor = false; this.btnNo.Click += new System.EventHandler(this.btnNo_Click); // // gifLoading // - this.gifLoading.ErrorImage = global::LLCD.DownloaderGUI.Properties.Resources.Loading; this.gifLoading.Image = global::LLCD.DownloaderGUI.Properties.Resources.Loading; - this.gifLoading.Location = new System.Drawing.Point(3, 249); + this.gifLoading.InitialImage = global::LLCD.DownloaderGUI.Properties.Resources.Loading; + this.gifLoading.Location = new System.Drawing.Point(3, 278); this.gifLoading.Name = "gifLoading"; this.gifLoading.Size = new System.Drawing.Size(224, 74); this.gifLoading.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; @@ -117,12 +113,11 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.BackColor = System.Drawing.Color.Black; - this.ClientSize = new System.Drawing.Size(248, 277); + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(29)))), ((int)(((byte)(29)))), ((int)(((byte)(29))))); + this.ClientSize = new System.Drawing.Size(248, 296); this.Controls.Add(this.flowLayoutPanel); this.ForeColor = System.Drawing.Color.White; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximumSize = new System.Drawing.Size(264, 1000); this.MinimumSize = new System.Drawing.Size(264, 50); this.Name = "UpdaterForm"; @@ -139,9 +134,9 @@ private void InitializeComponent() #endregion private System.Windows.Forms.Label lblMessage; - private System.Windows.Forms.Button btnYes; private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel; - private System.Windows.Forms.Button btnNo; private System.Windows.Forms.PictureBox gifLoading; + private System.Windows.Forms.Button btnYes; + private System.Windows.Forms.Button btnNo; } } \ No newline at end of file diff --git a/LLCD.DownloaderGUI/UpdaterForm.resx b/LLCD.DownloaderGUI/UpdaterForm.resx index 08ed288..1af7de1 100644 --- a/LLCD.DownloaderGUI/UpdaterForm.resx +++ b/LLCD.DownloaderGUI/UpdaterForm.resx @@ -117,383 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - AAABAAMAQEAAAAEAIAAoQgAANgAAACAgAAABACAAqBAAAF5CAAAQEAAAAQAgAGgEAAAGUwAAKAAAAEAA - AACAAAAAAQAgAAAAAAAAQAAAEgsAABILAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAERE - RAB9fX0AHBwcDQ8PDy4KCgpbBwcHigUFBbEEBATPBAQE5AUFBfoAAAD/AAAA/wUFBfsEBATlBAQE0AUF - BbMHBweMCgoKXhAQEDEbGxsOZGRkAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AABWVlYAAAAAABsbGw0ODg49CAgIgAQEBLwCAgLkAQEB+AAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wEBAfkCAgLmBAQEvwcHB4MMDAxAGxsbDwAAAAA+Pj4AAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAADU1NQBmZmYBFBQUHgoKCmoFBQW+AgIC8QAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC8gQE - BMIJCQlvFBQUIVdXVwE3NzcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAR0dHAAAAAAAVFRUdCQkJeAQEBNUBAQH8AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AQEB/QQEBNkKCgp+ExMTIOzs7AA3NzcAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAExMTABsbGwwLCwthBAQE0AEBAf0AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/gQEBNQKCgpnHR0dDgUF - BQDBwcEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtLS0AAAAAABAQEC0GBgaqAQEB+AAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AQEB+QYGBrAREREy7OzsADMzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdHR0AKioqBAwM - DFgDAwPaAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AwMD3gwMDF8mJiYGGhoaAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAVFRUAHh4eCwkJCXwCAgLwAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8CAgLzCQkJhBsb - Gw4UFBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAASEhIAFhYWEAgICJIBAQH5AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wEBAfsHBwebGBgYFBMTEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODg4AFhYWEAUFBZgBAQH8AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/QYGBqIYGBgUEhISAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYGBgAICAgCwgICJIBAQH8AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8BAQH+BwcHmxoa - Gg4VFRUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAANzc3BAkJ - CXsBAQH5AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wEBAfsICAiEJiYmBhoaGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAA4ODgAAAAAAAwMDFYCAgLwAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC8wsLC2AAAAAALy8vAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAABEREQACAgIABERESwDAwPXAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAQH/AAUG/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wQEBP8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8DAwPeEBAQMwcH - BwA1NTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhoaACEhIQsHBwenAAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAcJ/wBNZf8ADhL/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/xISEv+QkJD/cHBw/x4eHv8BAQH/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wYGBrAaGhoPFhYWAAAAAAAAAAAAAAAAAAAAAAAAAAAANzc3AAAAAAALCwteAQEB9wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wATGf8An9H/AF99/wADBP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/FBQU/0NDQ/8DAwP/AAAA/wAAAP8AAAD/AAAA/wAAAP9dXV3/+vr6//39/f/W1tb/enp6/yAg - IP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8BAQH6CQkJaAAAAAArKysAAAAAAAAAAAAAAAAAAAAAABAQ - EAAUFBQaBAQEzAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AKjj/ALbx/wC48v8AVW//AAUG/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/2dnZ//i4uL/Pj4+/wAAAP8AAAD/AAAA/wAAAP8KCgr/tbW1//// - //////////////39/f/V1dX/bm5u/xMTE/8AAAD/AAAA/wAAAP8AAAD/AAAA/wQEBNQUFBQhDw8PAAAA - AAAAAAAAAAAAADSCmgAAAAAACg0OdAEBAf4AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AEph/wDA - /v8Awv//ALr0/wBpiv8AEBT/AAAA/wAAAP8AAAD/AAAA/xQUFP/Gxsb//////7W1tf8QEBD/AAAA/wAA - AP8AAAD/PT09/+/v7/////////////////////////////v7+/+9vb3/QkJC/wICAv8AAAD/AAAA/wAA - AP8BAQH/CQkJfgAAAAApKSkAAAAAAAAAAAASi7IAFJC3HAQaIdEAAAD/AAAA/wAAAP8AAAD/AQEB/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wBtj/8AxP//AMH//wDC//8Awfz/AI+7/wAwP/8AAwP/AAAA/wAAAP9SUlL/+Pj4//// - ///6+vr/bW1t/wAAAP8AAAD/CAgI/6Ghof///////////////////////////////////////////+rq - 6v90dHT/CgoK/wAAAP8AAAD/AAAA/wMDA9gREREhEBAQAAAAAAA0x/kAAE9oAAmPtmUBGiL8AAAA/wAA - AP8AAAD/CwsL/11dXf96enr/WVlZ/zMzM/8YGBj/BwcH/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAHCf8Ajrr/AMT//wDB//8Awf//AMH//wDD//8As+r/AG2P/wAg - Kv8AAgL/mJeX/////////////////+Xl5f9AQED/AAAA/ywsLP+6urr/4+Pj//r6+v////////////// - ////////////////////////+Pj4/46Ojv8MDAz/AAAA/wAAAP8BAAD+CAUEcAAAAAAmFxMAGcn+AB3/ - /wsFhKm5AAwP/wAAAP8AAAD/CwsL/4qKiv+zs7P/lpWU//n5+f/x8fH/1tbW/7S0tP+MjIz/YmJi/zw8 - PP8eHh7/CgoK/wEBAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AGB//AKnd/wDD//8Awf//AMH//wDB - //8Awf//AML//wDD/v8Aq+D/BUdb/6iko//////////////////Z2dn/WFhY/3Z2dv+CgoL/dXV1/2Rk - ZP9ubm7/paWl/+jo6P/////////////////////////////////7+/v/fHx8/wIFBv8AFh3/ADVE/wRm - hMIYwfQQFrPjAAnH/wAO1v84Am+P7gABAf8AAAD/DAwM/4uLi//9/f3/np+g/w8rM/9zenz/2tfW//z8 - /P/////////////////19fX/39/f/8DAwP+YmJj/bm5u/0ZGRv8mJib/Dw8P/wMDA/8AAAD/ADJA/wC6 - 9P8Awv//AML//wDC//8Awv//AML//wDC//8Awv//AMX//wCax/8kT1z/pqal//z8/P/+/v7/enp6/6io - qP////////////39/f/v7+//yMjI/4WFhf9fX1//oaGh//Pz8////////////////////////Pv7/5aU - k/8IPU7/AKPV/wC79f8CxP/yDcf+QQbG/wAAufUACMb/eQBRaf8AAAD/Dg4O/5CQkP/7+/v/8/Hx/1Ji - Zv8Ajbn/AX+l/x9TY/9aaW3/kJGR/7Sxsf/Kx8b/2NXU/+Le3v/o5eX/7erq/+7s6//p5+f/3Nra/7e0 - tP8pNjr/AElg/wB8ov8Awv//AML//wDC//8Awv//AML//wDC//8Awv//AML//wDC//8AxP//AKvg/xJU - aP+Xl5f/3t3d/2NjY//r6+v////////////////////////////+/v7/29vb/3t7e/9sbGz/29vb//// - /////////fz8/5KTk/8NV23/AKre/wDE//8Awv//AML//wfF/4QAvf8AH9v/CgW47rYAMUD/EQ8O/5eY - mP/7+vr/2NXV/2Ztb/8Gaon/AMD7/wDF//8AuPH/AJnJ/wB7oP8GZ4T/D110/xhZbf8gV2j/Jldl/ypX - ZP8xWWT/Oltm/0dhaf9GWV//CWuJ/wDB+/8Aw///AML//wDC//8Awv//AML//wDC//8Awv//AML//wDC - //8Awv//AML//wDE//8As+n/Dl94/0FKTf9+fX3///////////////////////////////////////// - ///6+vr/q6ur/11dXf/Ly8v//////6impf8SVGj/ALXr/wDE//8Awv//AML//wDC//8ExP+/G8r+Dg/V - /ygCpdXfABce/15aWf/JxsX/dnx9/yBSYP8Bgqj/AL73/wDE//8Aw///AMP//wDF//8Axv//AMX//wDC - /v8Av/r/ALz2/wC68v8At+//ALTs/wCw5/8Aqd7/AKPV/wC89P8AxP//AMP//wDE//8Axf//AMb//wDG - //8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMj//wC/9v8JTWL/tbOy//////////////////// - ///////////////////////////////////Dw8P/VFRV/2dwc/8YWGv/AK7h/wDI//8Axv//AMb//wDE - //8Aw///AsT/5g7I/jEJzv9TAaLS9gBvj/8MZX//FFRm/wGBqP8Atu7/AMX//wDD//8Aw///AMP//wDD - //8Aw///AMP//wDD//8Aw///AMP//wDD//8Aw///AMT//wDE//8AxP//AMT//wDF//8Aw///AMT//wDE - /v8Atev/AJvJ/wCFrP8Ad5v/AHCS/wBvkf8Ab5H/AG+R/wBvkf8Ab5H/AG+R/wBwkf8Aaor/LUxV/+fl - 5f///////////////////////v7+/7CwsP+Hh4f/iIiI/4eHh/+Hh4f/hYWE/ysvMP8AKjj/AFlz/wBn - hf8AZoP/AGuK/wCHsP8AtOr/AMX//wHE//kKx/9fB8f/gADC/f8AxP7/AMP9/wC++f8Axf//AMT//wDD - //8Aw///AMP//wDD//8Aw///AMP//wDD//8Aw///AMP//wDD//8Aw///AMP//wDD//8Aw///AMP//wDD - //8Aw///AMT//wC16/8AaYj/ACcy/wAMEP8AAwT/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/2lpaf/+/v7///////////////////////z8/P9UVFT/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAEB/wAAAP8AAAD/AAAA/wAAAP8ABAb/ADA+/wCbyf8Axf//B8b/jQbG/6cAxP//AMT//wDE - //8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE - //8AxP//AMT//wDE//8AxP//AMT//wC68f8ASF3/AAEC/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wYGBv+urq7////////////////////////////8/Pz/VVVV/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AKzf/AK/j/wXJ - /7QEx//FAMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE - //8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDH//8AfKD/AAUG/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8CAgL/BQUF/wICAv8AAAD/AAAA/wAAAP8rKyv/5eXl//////////////////// - /////////Pz8/1VVVf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wBujv8Eyf/RA8X/2gDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE - //8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AvfX/ADhI/wAA - AP8AAAD/AAAA/wAAAP8AAAD/BQUF/z09Pf+Dg4P/p6en/7Gxsf+kpKT/g4OD/0lJSf8ODg7/MDAw/9/f - 3/////////////////////////////z8/P9VVVX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AO0z/BL/25gPG/+YAxP//AMT//wDE//8AxP//AMT//wDE - //8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE//8AxP//AMT//wDE - //8Axv//AKfY/wAVGv8AAAD/AAAA/wAAAP8AAAD/AQEB/29vb//u7u7///////////////////////// - ///29vb/wMDA/1paWv9YWFj/4ODg///////////////////////8/Pz/VVVV/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/ACcy/wS26vwLyP/3AMX//wDF - //8Axf//AMX//wDF//8Axf//AMX//wDF//8Axf//AMX//wDF//8Axf//AMX//wDF//8Axf//AMX//wDF - //8Axf//AMX//wDF//8Axf//AMj//wCOt/8ABgj/AAAA/wAAAP8AAAD/AAAA/yQkJP/d3d3///////// - ///////////////////////////////////39/f/rKys/4KCgv/j4+P//////////////////Pz8/1VV - Vf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAk - Lv8As+j/Csj/9QDF//8Axf//AMX//wDF//8Axf//AMX//wDF//8Axf//AMX//wDF//8Axf//AMX//wDF - //8Axf//AMX//wDF//8Axf//AMX//wDF//8Axf//AMX//wDI//8AeJr/AAAA/wAAAP8AAAD/AAAA/wAA - AP9hYWH//f39///////////////////////////////////////////////////////g4OD/u7u7//Dw - 8P////////////z8/P9VVVX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8ALDj/ALnu/wPH/+YAxv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG - //8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8AyP//AGWC/wAA - AP8AAAD/AAAA/wAAAP8CAgL/lZWV/9nZ2f/Ly8v/39/f//n5+f////////////////////////////// - //////////////f39//x8fH////////////8/Pz/VVVV/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AD5Q/wTD+fsEx//aAMb//wDG//8Axv//AMb//wDG - //8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG - //8Axv//AMj//wBZcf8AAAD/AAAA/wAAAP8AAAD/ICAg/6Ojo/+np6f/pqam/52dnf+srKz/7+/v//// - /////////////////////////////////////////////////////////Pz8/1VVVf8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wBbdP8Eyv/mBMn/xADG - //8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG - //8Axv//AMb//wDG//8Axv//AMb//wDH//8AUGf/AAAA/wAAAP8AAAD/AAAA/35+fv+qqqr/VVVV/19f - X/9oaGj/lJSU/+vr6/////////////////////////////////////////////////////////////z8 - /P9VVVX/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAB - Av8Af6H/BMz/0AbJ/6YAxv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG - //8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AEth/wAAAP8AAAD/AAAA/ygo - KP/e3t7/tra2/3x8fP93d3f/u7u7//Ly8v////////////////////////////////////////////// - ///////////////////8/Pz/VVVV/x4eHv8eHh7/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8ADxP/AKLO/wXN/7MHyv9+AMf//gDH//8Ax///AMf//wDH//8Ax///AMf//wDH - //8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wBL - X/8AAAD/AAAA/wAAAP98fHz////////////8/Pz//Pz8//////////////////////////////////// - ////////////////////////////////////////+/v7/2NjY/+6urr/qqqq/wYGBv8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AC05/wC88P8HzP+LCsv/UQHI//UAx///AMf//wDH - //8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH - //8Ax///AMf//wDH//8ATWP/AAAA/wAAAP8UFBT/zMzM//Ly8v+EhIT/XFxc/4qKiv/Y2Nj///////// - //////////////////////////////////////////////////////////////z8/P9cXFz/aWlp/1hY - WP8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wBbdP8Byf/4Ccv/XQ7M - /ycCyP/eAMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH - //8Ax///AMf//wDH//8Ax///AMf//wDH//8AyP//AFNp/wAAAP8AAAD/R0dH//f39//Nzc3/kJCQ/7+/ - v//m5ub/9/f3/////////////////////////////////////////////////////////////////+/v - 7//p6en/o6Oj/7Kysv8vLy//AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAH - Cf8Aj7X/Asz/5Q7M/y8h0f8JBcr/tADI//8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMj//wDI - //8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMr//wBcdP8AAAD/AAAA/4SE - hP///////f39//////////////////////////////////////////////////////////////////// - //////////////39/f+EhIT/k5OT//j4+P/+/v7/X19f/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AJC3/ALbo/wTL/70d0P4NAMf/AAjL/3YAyP//AMj//wDI//8AyP//AMj//wDI - //8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMj//wDL - //8AaIP/AAAA/wcHB/+1tbX///////////////////////////////////////////////////////// - //////////////////////////////////+8vLz/ERER/2pqav/Jycn/6urq/2dnZ/8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AFhu/wDJ//8Hy/+BAMP/AAnM/wAMzP41Asn/7ADI - //8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMj//wDI//8AyP//AMj//wDI - //8AyP//AMj//wDI//8Ay///AHeW/wAAAP8XFhb/1NTU//////////////////////////////////// - ////////////////////////////////////////////////////////f39//wAAAP86Ojr/paWl/+vr - 6/+RkZH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAgL/wCSuP8CzP/xDMz/PgfM - /wAaz/8AH9H+CgXL/7YAyf//AMn//wDJ//8Ayf//AMn//wDJ//8Ayf//AMn//wDJ//8Ayf//AMn//wDJ - //8Ayf//AMn//wDJ//8Ayf//AMn//wDJ//8Ayf//AMz//wCKrP8AAgP/FBMT/42Njf/Hx8f/9/f3//// - ///////////////////y8vL/vb29/5ycnP+pqan/3d3d//7+/v///////////////////////////6io - qP8GBgb/AgIC/3BwcP/39/f/zc3N/xQUFP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAu - Ov8AvO7/BMz/vxrQ/g4Xz/4AOdD7AADK/wAKzf9hAcr/+wDJ//8Ayf//AMn//wDJ//8Ayf//AMn//wDJ - //8Ayf//AMn//wDJ//8Ayf//AMn//wDJ//8Ayf//AMn//wDJ//8Ayf//AMn//wDJ/v8Dbor/QkND/46O - jv+Xl5f/a2tr/39/f//y8vL////////////m5ub/bW1t/3Nzc/+ZmZn/ioqK/15eXv+zs7P///////// - ///////////////////x8fH/TExM/wAAAP8ODg7/sLCw/+3t7f8sLCz/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wABAf8AcI3/Acz//gnN/2wAyP8AK9L/AAAAAAATz/8AFc//GQTL/80Ayf//AMn//wDJ - //8Ayf//AMn//wDJ//8Ayf//AMn//wDJ//8Ayf//AMn//wDJ//8Ayf//AMn//wDJ//8Ayf//AMn//wDJ - //8Aos7/RFth/9vZ2f+srKz/lpaW/8/Pz/9dXV3/q6ur////////////kJCQ/4yMjP/b29v/ioqK/7q6 - uv+vr6//UVFR/+Pj4////////v7+//j4+P/39/f/+/v7/6ioqP8GBgb/AAAA/2FhYf/Hx8f/FhYW/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AHyf/ALDe/wPN/9USz/4fEM7+AAAAAAAAAAAAK9T/AADG - /wAHzf9uAcr//QDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK - //8Ayv//AMr//wDM//8Ao83/AEFS/2BlZv++vr7/Xl5e/1dXV/9ubm7/MjIy/3Z2dv/7+/v/8fHx/1pa - Wv+np6f/kpKS/1JSUv9jY2P/Y2Nj/yEhIf9mZmb/4uLi/+7u7v99fX3/aWlp/2tra/9PT0//BAQE/wAA - AP8oKCj/ODg4/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AGmE/wHM//8Kzf96ALX/ADDT - /QAAAAAAAAAAAAAAAAAR0P8AFND/GATM/8gAyv//AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK - //8Ayv//AMr//wDK//8Ayv//AMr//wDK//8Ayv//AML0/wCr1v8RWmz/hIWG/8/Pzv/S09P/mZmZ/1RU - VP9iYmL/aWlp/2VlZf9kZGT/W1tb/6qqqv/T09P/xMTE/3Fxcf98fHz/3t7e//j4+P/7+/v/4eHh/93d - 3f/d3d3/XFxc/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/ACYv/wC0 - 4f8Ezv/QFND+HhDP/gAAAAAAAAAAAAAAAAAAAAAAQNH4AADL/wALzv9ZAsv/9QDK//8Ayv//AMr//wDK - //8Ayv//AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK//8AzP//ALzs/wNc - cv8WFxf/S0tL/4aGhv/Z2dn/9fX1/9TU1P/Z2dn/+fn5/8vLy/98fHz/aGho/25ubv+jo6P/8/Pz//// - ///////////////////s7Oz/np6e/xkZGf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAYH/wB+nf8Bzf/4Cs7/YwDH/wAy1f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAb0f4AI9L9CQfN - /6EAy///AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMr//wDK - //8Ayv//AMr//wDO//8AqND/AA8T/2FgX//7+/v//////////////////////////////////v7+//j4 - +P/7+/v///////////////////////Ly8v+enp7/NTU1/wUFBf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wBEVf8AwvP/Bs7/qx3S/g0Y0f4AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAATNr/AAvP/wAS0f4oBM3/1ADL//8Ay///AMv//wDL//8Ay///AMv//wDL//8Ay///AMv//wDL - //8Ay///AMv//wDL//8Ay///AMv//wDL//8Ay///AMX2/wA6Sf8bGBj/0NDQ//////////////////// - /////////////////////////////////////////////9nZ2f9XV1f/BwcH/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAdJP8Ap9D/A8//2hDQ/i8Iz/8ANc73AAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA11PkAAMn/AAzP/1ECzP/tAMv//wDL//8Ay///AMv//wDL - //8Ay///AMv//wDL//8Ay///AMv//wDL//8Ay///AMv//wDL//8Ay///AMv//wDO//8AfJr/AAAB/25u - bv/8/Pz//////////////////////////////////////////////////////8nJyf80NDT/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAKDf8AhKT/As7/8QzP - /1oAw/8ANNb/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTU/gBH3P0DCs//dQHM - //gAy///AMv//wDL//8Ay///AMv//wDL//8Ay///AMv//wDL//8Ay///AMv//wDL//8Ay///AMv//wDL - //8Azf//ALbj/wAjLP8UEhL/vb29/////////////////////////////////////////////////8zM - zP8tLS3/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAD - BP8AZX3/Acr6+gnP/34v2P4EHtT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAGNL+ACHU/gkI0P+LAc3/+wDM//8AzP//AMz//wDM//8AzP//AMz//wDM//8AzP//AMz//wDM - //8AzP//AMz//wDM//8AzP//AMz//wDO//8AdI//AAAA/0BAQP/n5+f///////////////////////// - /////////////+Dg4P88PDz/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wABAv8AUmb/AcPx/QjR/5Qd1f8MF9T/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAV1P8AHtb/DQfQ/5IBzf/7AMz//wDM//8AzP//AMz//wDM - //8AzP//AMz//wDM//8AzP//AMz//wDM//8AzP//AMz//wDM//8Azf//AL3q/wA0QP8BAAD/bGxs//b2 - 9v////////////////////////////f39/9kZGT/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wACAv8ATF7/Ab/s/AnS/50d0/4RFdL+AAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABXU/wAd1v8OCND/iwHN - //gAzP//AMz//wDM//8AzP//AMz//wDM//8AzP//AMz//wDM//8AzP//AMz//wDM//8AzP//AMz//wDP - //8Am8D/ABUa/wcGBv+Ghob/+vr6//////////////////////+mpqb/CgoK/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAEBf8AVGf/Ab/s+QjS/5Ma0/8REdL/AAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAGNL8ACLU/AkK0f91As7/7gDN//8Azf//AM3//wDN//8Azf//AM3//wDN//8Azf//AM3//wDN - //8Azf//AM3//wDN//8Azf//AM7//wCCoP8ADRD/DAsL/4qKiv/4+Pj////////////n5+f/NjY2/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAOEf8Aa4T/Asby8AnT - /30e1f4LFdT+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAi1/wAMtv7Aw3S/1EEz//VAM3//wDN//8Azf//AM3//wDN - //8Azf//AM3//wDN//8Azf//AM3//wDN//8Azf//AM3//wDN//8AzPz/AICe/wATF/8KCQj/enp6//Dw - 8P//////lJSU/wICAv8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAEB/wAq - NP8AkbL/A8772QzU/1gu2P4EH9f+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADPW+gAAw/8AEtP+KAbQ - /6IBzv/1AM3//wDN//8Azf//AM3//wDN//8Azf//AM3//wDN//8Azf//AM3//wDN//8Azf//AM7//wDO - /v8Amb3/ADE9/wQFBf9WU1P/xMPD/zs6Ov8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAQH/ABog/wBogP8BuOL3BtT/qRHV/y0Axv8AKdb5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAABTT/QAe1v0KC9L+WQTQ/8oBzv/8AM7//wDO//8Azv//AM7//wDO//8Azv//AM7//wDO - //8Azv//AM7//wDO//8Azv//AND//wC+6v8Aepb/ATA7/xciJP8HBwf/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAEB/wAMDv8ALjj/AG2G/wGw2P0E0f3OCtb/XxvW/wsT1f8AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOt//AADD/wAW1v8YCtL/bwTQ/88Bz//7AM7//wDO - //8Azv//AM7//wDO//8Azv//AM7//wDO//8Azv//AM7//wDO//8Az///ANH//wDD8P8AncL/AHWP/wBV - aP8AQE//ADhE/wA4Rf8AQlH/AFdr/wB4k/8AoMX/AcLu/ATS/9MJ1v91FdX+GwC7/gAx3f8AAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALNr+AJfv - +QAW1v8ZC9L/YgXQ/7cCz//tAc7//wDO//8Azv//AM7//wDO//8Azv//AM7//wDO//8Azv//AM7//wDO - //8Az///ANH//wDR//8Az///AMv6/wDI9/8AyPf/AMv7/wDP//8C0//vBdT/ugrU/2YV1P4bbdnnATTX - 9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAUeP/AADO/QAd1/4KD9P+NgnS/ncF0f+1A9D/3wHP//YAz//+AM///wDP - //8Az///AM///wDP//8Az///AM///wDP//8Az///AM///wDP//4B0P/2A9D/4QXR/7cI0v96DNP/OB3W - /QwAvf8Adef3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFvj+QAAX/8AItn+CRHV - /icM0/9SCNL/fwbS/6cF0f/GBND/2wPR/+cL0f/6C9H/+wTR/+gE0P/cBdH/xwbR/6kI0v+CCtP/VBLU - /ioh2P0L///qAGfk9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///4AAH//////8AAAD/////+AAAAB - /////wAAAAD////8AAAAAD////gAAAAAH///4AAAAAAH///AAAAAAAP//4AAAAAAAf//AAAAAAAA//4A - AAAAAAB//AAAAAAAAD/8AAAAAAAAP/gAAAAAAAAf8AAAAAAAAA/wAAAAAAAAD+AAAAAAAAAH4AAAAAAA - AAfAAAAAAAAAA8AAAAAAAAADgAAAAAAAAAGAAAAAAAAAAYAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAgAAAAAAAAAGAAAAAAAAAAYAAAAAAAAABwAAAAAAAAAPAAAAAAAAAA+AAAAAAAAAH4AAAAAAA - AAfwAAAAAAAAD/AAAAAAAAAP+AAAAAAAAB/8AAAAAAAAP/wAAAAAAAA//gAAAAAAAH//AAAAAAAA//+A - AAAAAAH//8AAAAAAA///4AAAAAAH///4AAAAAB////wAAAAAP////wAAAAD/////wAAAAf/////wAAAP - //////4AAH///ygAAAAgAAAAQAAAAAEAIAAAAAAAABAAABILAAASCwAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAABMTEwAaGhoDCgoKJQUFBWYDAwOmAgIC1AICAu4BAQH9AQEB/gIC - Au8CAgLVAwMDqAUFBWgJCQkmGBgYAxEREQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAABISEgAbGxsCCAgIMgQEBJECAgLbAAAA+gAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA+gEBAd0EBASTCAgINBgYGAMREREAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4+PgAAAAAACwsLFgQEBIIBAQHnAAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8BAQHoBAQEhgwMDBgAAAAAODg4AAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhISEAAAAAAAgICDADAwO8AAAA/QAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD+AwMDvwgI - CDMAAAAAGhoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBwcAAAAAAAGBgY7AgIC0wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AgIC1wcHBz8AAAAAICAgAAAAAAAAAAAAAAAAACYmJgADAwMACQkJMAICAtMAAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AgIC1ggICDMAAAAAODg4AAAAAAAAAAAACQkJAAwMDBYDAwO6AAAA/wAA - AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAEB/wADBP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAAA/wUFBf8DAwP/AAAA/wAAAP8AAAD/AwMDvwsLCxgJCQkAAAAAABMTEwBMTEwBBAQEgQAA - AP4AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AERb/AEph/wAGCP8AAAD/AAAA/wAA - AP8ZGRn/BwcH/wAAAP8BAQH/dnZ2/5aWlv80NDT/AwMD/wAAAP8AAAD/BAQEhi0tLQIREREABQMDAAgO - DzEBAQLkAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAoNP8AreT/AGGA/wAK - Dv8AAAD/EBAQ/6ysrP9OTk7/AAAA/yIiIv/b29v//////+jo6P+Li4v/HR0d/wAAAP8BAQHnCAgINQUF - BQBx//8BBCw4jgAAAf8KCgr/OTg4/zMzM/8WFhb/BQUF/wAAAP8AAAD/AAAA/wAAAP8AAAD/AEZc/wDB - /v8Av/r/AIaw/wAqOP9FSEn/+Pf3/8XFxf8YGBj/X19f/+fn5//8/Pz////////////Hx8f/NjY2/wAA - AP8DBQaTNXqNAgnB9iMBNUTYCgkI/4OCgv+EjpH/rLO1/8zIx/+zsK//jImJ/2JgYP89Ozv/Hx0d/wQD - A/8Aaov/AMT//wDC//8AxP//ALDo/zqCmP/e3t7/0tHR/52dnf++vr7/sbGx/62trf/b29v//v7+//// - //+qq6z/CEhc/wGCqtwJtusnA6DOYg0yPfmFgH7/tr7A/yGMrf8SmcP/R5au/22hsf+AqLT/haiy/4Og - qf9thY3/EW2K/wCu4v8Axf//AMX//wDF//8Ax///ALfv/zmRrf+HjpD/7ezs////////////7Ozs/7Oz - s//Gxsb/19rb/z2Trf8AuvD/AMb/+gXF/2gAnsyhHWN4/1OPof8UmcL/AL32/wDF//8Av/v/ALnz/wC0 - 7P8Asej/AK/l/wGt4v8AwPf/ALnw/wCf0P8Ak8D/AJG9/wCRvf8Akr//AIGq/3aSmv////7//////+bm - 5v+7u7v/tra2/2xubv8nVWL/AYCn/wCYxv8AufH/A8b/qALC/M8Avfb/ALv0/wDF//8AxP//AMP//wDD - //8AxP//AMT//wDE//8Axf//AMf//wCYxP8AMD7/AA4S/wAGCP8AAgT/AAIE/wACBP8LEBL/ury8//// - ////////pKSk/wgICP8HBwf/BgYG/wAEBv8ABgf/AAgL/wBJX/8CtOnVAcX/6QDE//8AxP//AMT//wDE - //8AxP//AMT//wDE//8AxP//AMT//wDF//8AvPT/ADhJ/wAAAP8AAAD/HBsb/1NSUv9dXV3/Ozs7/y0t - Lf/a2tr///////////+hoaH/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAcJ/wJ4m+8Dxv/3AMX//wDF - //8Axf//AMX//wDF//8Axf//AMX//wDF//8Axf//AMf//wCl1f8AEhf/AAAA/xUVFf+9vb3//v7+//// - ///z8/P/vLy8/6ysrP/y8vL//////6Ghof8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AWB7/gPG - //cAxf//AMX//wDF//8Axf//AMX//wDF//8Axf//AMX//wDF//8AyP//AJK8/wAHCP8AAAD/RkZG/+Hh - 4f/x8fH//v7+////////////7+/v/+np6f//////oaGh/wEBAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAB - Af8Ba4n+Acf/6QDG//8Axv//AMb//wDG//8Axv//AMb//wDG//8Axv//AMb//wDJ//8Ah63/AAID/wUF - Bf9zc3P/iYmJ/6Ojo//z8/P///////////////////////////+hoaH/AQEB/wAAAP8AAAD/AAAA/wAA - AP8AAAD/AAkL/wKGq+8CyP/OAMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH//8Ax///AMr//wCC - p/8AAAD/Nzc3/87Ozv+tra3/3d3d//7+/v///////////////////////////62trf9RUVH/CQkJ/wAA - AP8AAAD/AAAA/wAAAP8AHib/AqjV1APJ/6AAx///AMf//wDH//8Ax///AMf//wDH//8Ax///AMf//wDH - //8Ay///AIWq/wAAAf+FhYX/xsbG/7e3t//09PT////////////////////////////6+vr/v7+//21t - bf8FBQX/AAAA/wAAAP8AAAD/AAAA/wBFV/8Dw/emBcr/YADI//kAyP//AMj//wDI//8AyP//AMj//wDI - //8AyP//AMj//wDL//8AjbP/DBAS/8LBwf/9/f3//f39/////////////////////////////////5mZ - mf+tra3/oaGh/wMDA/8AAAD/AAAA/wAAAP8AAQL/AHmZ+gXS/2cJzP8iAcn/1wDI//8AyP//AMj//wDI - //8AyP//AMj//wDI//8AyP//AMv//wCZwv8bJCb/vLu7//n5+f//////9PT0/9TU1P/c3Nz/+/v7//// - ///8/Pz/WFhY/1hYWP+6urr/ExMT/wAAAP8AAAD/AAAA/wAbIf8BqdXbCNn/Jsj/+gAEy/+MAMn//wDJ - //8Ayf//AMn//wDJ//8Ayf//AMn//wDJ//8Ax/z/G46s/4GEhP+NjY3/p6en//r6+v+rq6v/lZWV/4uL - i/+1tbX/+/v7//Hx8f+enp7/FhYW/5SUlP8gICD/AAAA/wAAAP8AAAD/AFZs/wTJ/JJB/P8BBcz/AAfN - /y8Byv/jAMr//wDK//8Ayv//AMr//wDK//8Ayv//AMv//wC87v8kfZT/j5OU/4aGhv9wcHD/ra2t/4OD - g/+VlZX/fX19/4yMjP/r6+v/wsLC/35+fv8HBwf/Ghoa/wQEBP8AAAD/AAAA/wAVGv8BnsXmCNj/MwXN - /wAU0P4Acuz7AQTM/34Ayv/+AMr//wDK//8Ayv//AMr//wDK//8Ayv//AMv//wDB8/8VXG7/j4yM/+fn - 5//h4eH/4uLi/8HBwf/Jycn/9vb2//X19f+pqan/Nzc3/wAAAP8AAAD/AAAA/wAAAP8AAQH/AGR8/gTM - /IM49/8BEtD+AAAAAAAJzv8ADM//FQPM/7gAy///AMv//wDL//8Ay///AMv//wDL//8Ay///AM///wCI - qv9fZGX/+vn5///////////////////////n5+f/YWFh/wgICP8AAAD/AAAA/wAAAP8AAAD/AAAA/wA3 - Rf8DteC8C93/FwnQ/wAAAAAAAAAAACnV/QADzf8ACc7/LgLM/9EAzP//AMz//wDM//8AzP//AMz//wDM - //8AzP//AL3s/w4+Sf+uq6r/////////////////7u7u/1dXV/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA - AP8AIyz/Ap7D1Aja/zEC0v4AI9P9AAAAAAAAAAAAAAAAAB/X/wAAyv8ACND/OALN/9EAzP//AMz//wDM - //8AzP//AMz//wDM//8Az///AIyu/yo1OP/Pzc3///////7+/v+Dg4P/AgIC/wAAAP8AAAD/AAAA/wAA - AP8AAAD/ACQs/wKTtdQI2P88AMX1ABrX/wAAAAAAAAAAAAAAAAAAAAAAAAAAACTZ/wAAyv8ACdD/LQPO - /7kAzf/9AM3//wDN//8Azf//AM3//wDN//8Ay/z/AHKN/zU/Qv/Nysn/0dHQ/xwcHP8AAAD/AAAA/wAA - AP8AAAD/AAUG/wA8Sv0Dm768Cdv/MACz8gAg5v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDc - /wADz/8ADNH+FATP/34Bzv/kAM7//wDN//8Azf//AM3//wDO//8AzPv/AIyu/yZbZ/9EUFL/AQEC/wAA - AP8AAgL/AA4R/wAzP/8Bc47mBLfegQzq/xYB1P4AQf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAT1f4AHNj9AgjS/y8E0P+NAs//2AHO//kAzv//AM7//wDO//8A0P//AMLw/wCg - x/8Ah6b/AH2a/wCGpfoBncDaBLvljwjd/zEY//8CEfr/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFNX+ABvX/gIK0v4iBtH/YQPQ/6EC0P/PAc//6gPQ - //kE0P/5AdP/6gLV/9AD1v+iBdv/Ywnm/yMd//8DFPr/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA/4AB//4AAH/8AAA/+AAAH/AAAA/gAAAHwAAAA4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAACAAAABgAAAAcAAAAPgAAAH8AAAD/gA - AB/8AAA//gAAf/+AAf8oAAAAEAAAACAAAAABACAAAAAAAAAEAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAA - AAAHBwcACgoKBgQEBEUCAgKkAQEB4QEBAfsBAQH7AQEB4gICAqUEBARHCgoKBgcHBwAAAAAAAAAAABER - EQADAwMABgYGFgICAo4BAQHtAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB7gICApAGBgYXAwMDADU1 - NQAEBAQABgYGFgEBAa0AAAD+AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEBrwYG - BhcEBAQADg4OBQICAo4AAAD/AAAA/wAAAP8AAAD/AAkM/wAXGP8AAAD/AwMC/wAAAP8mJib/PT09/wAA - AP8BAQGQDQoJBQAeJUUBAADrJCEY/xkLCf8AAAD/AAAA/wAcJf8Aqd//ACMy/46Cf/9PTUz/iIiI//// - //+joaD/EAcE7AAAAEcPP0+ibmZq/2Wmuv+Lrrj/fo+P/1BbWP8IbYv/AN///wDN//9Uutj/xsS9/+bl - 5f/g39///vz7/z6fvf8As+ylDpzH3iCr1v8Avv//AL39/wK8+/8Lyf//ApXD/wBGX/8APlb/ADVN/9HY - 2v/y8PD/XVpa/yIuMv8ATmX/AZzL4QHG//gAxf//AMX//wDF//8Axv//AL72/wACBv9CLij/tail/4V6 - d//n5uX/1NTU/wAAAP8AAAD/AAAA/wEyQfoBxv/3AMb//wDG//8Axv//AMj//wCn2P8AAAD/hoWF//j4 - +P///////////9HR0f8AAAD/AAAA/wAAAP8BNkT6Acf/3gDH//8Ax///AMf//wDK//8AmcX/MS0r/8PB - wf/s7Oz////////////l5eX/LCws/wAAAP8AAAD/AWJ84QLJ/6EAyP//AMj//wDI//8Ayv//AKDM/2xt - bf//////9fX1//Dw8P//////lZWV/15eXv8AAAD/AAgK/wKUuqQDy/9EAMr/6wDJ//8Ayf//AMv//xSn - zf+EfHn/t7e2/5SUlP+Wlpb/+fn5/1FRUf8qKir/AAAA/wE5SOwExvtHDs//BALL/4wAy///AMv//wDL - //8AwPv/SnaC//nt6v/s7e3/8fHx/35+fv8EBAT/AAAA/wAMD/8ChKOPDf//BQTN/wAGzv8WAsz/qwDM - //4AzP//ANX//wCMsP+wo6D//////3h4eP8AAAD/AAAA/wAFBv4CZXytBvL/FwSz6AAq9f8AA+D/AAbP - /xYCzv+MAc3/7ADO//8A0P//CoGd/3+Pj/8GAAD/AAAA/wEhKe0CYICOBtz/FgOm2QBH//8AAAAAAAAA - AAAH5f8ACtL/BgTQ/0MCz/+iAc//3wDW//gAseP5AZm94AKTtKMEq9NFCv//Bgf0/wAAAAAAAAAAAOAH - AADAAwAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAAwAMAAOAH - AAA= - - \ No newline at end of file diff --git a/LLCD.DownloaderGUI/fonts/Barlow.ttf b/LLCD.DownloaderGUI/fonts/Barlow.ttf deleted file mode 100644 index 5f9df90..0000000 Binary files a/LLCD.DownloaderGUI/fonts/Barlow.ttf and /dev/null differ diff --git a/LLCD.DownloaderGUI/fonts/Quicksand-Bold.ttf b/LLCD.DownloaderGUI/fonts/Quicksand-Bold.ttf new file mode 100644 index 0000000..725ee41 Binary files /dev/null and b/LLCD.DownloaderGUI/fonts/Quicksand-Bold.ttf differ diff --git a/LLCD.DownloaderGUI/fonts/Quicksand-Light.ttf b/LLCD.DownloaderGUI/fonts/Quicksand-Light.ttf new file mode 100644 index 0000000..c7859e1 Binary files /dev/null and b/LLCD.DownloaderGUI/fonts/Quicksand-Light.ttf differ diff --git a/LLCD.DownloaderGUI/fonts/Quicksand-Medium.ttf b/LLCD.DownloaderGUI/fonts/Quicksand-Medium.ttf new file mode 100644 index 0000000..d4b02c5 Binary files /dev/null and b/LLCD.DownloaderGUI/fonts/Quicksand-Medium.ttf differ diff --git a/LLCD.DownloaderGUI/fonts/Quicksand-Regular.ttf b/LLCD.DownloaderGUI/fonts/Quicksand-Regular.ttf new file mode 100644 index 0000000..980edda Binary files /dev/null and b/LLCD.DownloaderGUI/fonts/Quicksand-Regular.ttf differ diff --git a/LLCD.DownloaderGUI/fonts/Quicksand-SemiBold.ttf b/LLCD.DownloaderGUI/fonts/Quicksand-SemiBold.ttf new file mode 100644 index 0000000..77f20d6 Binary files /dev/null and b/LLCD.DownloaderGUI/fonts/Quicksand-SemiBold.ttf differ diff --git a/LLCD.DownloaderGUI/fonts/SegoeUI.ttf b/LLCD.DownloaderGUI/fonts/SegoeUI.ttf deleted file mode 100644 index 0f52cbd..0000000 Binary files a/LLCD.DownloaderGUI/fonts/SegoeUI.ttf and /dev/null differ diff --git a/LLCD.DownloaderGUI/img/LinkedInDownloaderScreenshot.png b/LLCD.DownloaderGUI/img/LinkedInDownloaderScreenshot.png deleted file mode 100644 index 7628b8f..0000000 Binary files a/LLCD.DownloaderGUI/img/LinkedInDownloaderScreenshot.png and /dev/null differ diff --git a/LLCD.DownloaderGUI/img/Linkedin-Learning-Downloader-Screenshot.png b/LLCD.DownloaderGUI/img/Linkedin-Learning-Downloader-Screenshot.png new file mode 100644 index 0000000..969abf6 Binary files /dev/null and b/LLCD.DownloaderGUI/img/Linkedin-Learning-Downloader-Screenshot.png differ diff --git a/LLCD.DownloaderGUI/packages.config b/LLCD.DownloaderGUI/packages.config index ca33a40..8f5d714 100644 --- a/LLCD.DownloaderGUI/packages.config +++ b/LLCD.DownloaderGUI/packages.config @@ -1,18 +1,14 @@  - - + - + - - - - - - + + + \ No newline at end of file diff --git a/LLCD.DownloaderTUI/CourseDownloader.cs b/LLCD.DownloaderTUI/CourseDownloader.cs index e429dd7..a73b8dc 100644 --- a/LLCD.DownloaderTUI/CourseDownloader.cs +++ b/LLCD.DownloaderTUI/CourseDownloader.cs @@ -55,16 +55,16 @@ public static void DownloadCourse(Course course, DirectoryInfo courseRootDirecto { try { - int exerciseFilesCount = course.ExerciseFiles is null ? 0 : course.ExerciseFiles.Count(); + int exerciseFilesCount = course.ExerciseFiles is null ? 0 : course.ExerciseFiles.Count; using var pbarCourse = new ProgressBar(course.Chapters.ToList().Count + +exerciseFilesCount, "Downloading Course : " + course.Title, optionsCourse); var courseDirectory = courseRootDirectory.CreateSubdirectory(ToSafeFileName(course.Title)); - for (int i = 0; i < course.Chapters.Count(); i++) + for (int i = 0; i < course.Chapters.Count; i++) { var chapter = course.Chapters[i]; - var chapterDirectory = courseDirectory.CreateSubdirectory($"[{i + 1}] {ToSafeFileName(chapter.Title)}"); + var chapterDirectory = courseDirectory.CreateSubdirectory($"{(i + 1):D2} - {ToSafeFileName(chapter.Title)}"); using var pbarChapter = pbarCourse.Spawn(chapter.Videos.ToList().Count, $"Downloading Chapter {i + 1} : {chapter.Title}", optionsChapter); - for (int j = 0; j < chapter.Videos.Count(); j++) + for (int j = 0; j < chapter.Videos.Count; j++) { var video = chapter.Videos[j]; currentVideo = video.Title; @@ -75,7 +75,7 @@ public static void DownloadCourse(Course course, DirectoryInfo courseRootDirecto pbarChapter.Message = $"Chapter {i + 1} : {chapter.Title} chapter has been downloaded successfully"; pbarCourse.Tick(); } - if (course.ExerciseFiles != null && course.ExerciseFiles.Count() > 0) + if (course.ExerciseFiles != null && course.ExerciseFiles.Count > 0) { foreach (var exerciseFile in course.ExerciseFiles) { @@ -111,10 +111,10 @@ private static void DownloadVideo(DirectoryInfo chapterDirectory, ChildProgressB using var downloadClient = new WebClient(); downloadClient.DownloadProgressChanged += VideoDownloadClient_DownloadProgressChanged; downloadClient.DownloadFileCompleted += VideoDownloadClient_DownloadFileCompleted; - string videoName = $"[{ currentIndex}] { ToSafeFileName(video.Title)}.mp4"; + string videoName = $"{currentIndex:D2} - { ToSafeFileName(video.Title)}.mp4"; if (!String.IsNullOrWhiteSpace(video.Transcript)) { - string captionName = $"[{ currentIndex}] { ToSafeFileName(video.Title)}.srt"; + string captionName = $"{currentIndex:D2} - { ToSafeFileName(video.Title)}.srt"; File.WriteAllText($"{Path.Combine(chapterDirectory.FullName, ToSafeFileName(captionName))}", video.Transcript); } downloadClient.DownloadFileTaskAsync(new Uri(video.DownloadUrl), Path.Combine(chapterDirectory.FullName, videoName)).Wait(); diff --git a/LLCD.DownloaderTUI/LLCD.DownloaderTUI.csproj b/LLCD.DownloaderTUI/LLCD.DownloaderTUI.csproj index 93e1627..917f8eb 100644 --- a/LLCD.DownloaderTUI/LLCD.DownloaderTUI.csproj +++ b/LLCD.DownloaderTUI/LLCD.DownloaderTUI.csproj @@ -2,13 +2,13 @@ Exe - netcoreapp3.0 + net5.0 ahmedayman4a Linkedin Learning Courses Downloader Linkedin Learning Courses Downloader ahmedayman4a 2021 - 1.0 + 1.2 Linkedin Learning Courses Downloader linked-learning-favicon.ico Download linkedin learning courses to watch them offline @@ -40,10 +40,9 @@ - - - - + + + diff --git a/LLCD.DownloaderTUI/TUI.cs b/LLCD.DownloaderTUI/TUI.cs index 2af55f6..ebbfc79 100644 --- a/LLCD.DownloaderTUI/TUI.cs +++ b/LLCD.DownloaderTUI/TUI.cs @@ -70,7 +70,7 @@ public static string GetLoginToken() string loginToken = ""; while (string.IsNullOrEmpty(loginToken)) { - Console.WriteLine(CONTINUEGLYPH + "What is the linkedin learning security token?(It should appear as li_at if you are loged into linkedin learning)"); + Console.WriteLine(CONTINUEGLYPH + "What is the linkedin learning security token?(It should appear as li_at if you are logged into linkedin learning)"); Console.Write(ANSWERGLYPH); loginToken = Console.ReadLine().Clean(false); } diff --git a/README.md b/README.md index bbeec51..83d10db 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,14 @@ ## Features -* Simple and easy to use GUI for windows +* Simple and easy to use GUI for Windows * Download in the video quality you like (720p, 540p or 360p) -* Download Exercise files automatically +* Download Exercise files and subtitles automatically * Download multiple courses at a time -* Automatically extract LinkedIn Learning login token from Chrome, Firefox or Microsoft Edge +* Automatically import LinkedIn Learning login token from Chrome, Firefox or Microsoft Edge * Automatically detect the *enterpriseProfileHash* or the *x-li-identity header* so all organization and library accounts should work -![Downloader Screenshot](https://raw.githubusercontent.com/ahmedayman4a/Linkedin-Learning-Courses-Downloader/main/LLCD.DownloaderGUI/img/LinkedInDownloaderScreenshot.png) +![Downloader Screenshot](https://raw.githubusercontent.com/ahmedayman4a/Linkedin-Learning-Courses-Downloader/d82584942ed880733edc9445910b7d457c19bb7f/LLCD.DownloaderGUI/img/Linkedin-Learning-Downloader-Screenshot.png) ## Easy install Just go to the [releases section](https://github.com/ahmedayman4a/Linkedin-Learning-Courses-Downloader/releases), download the version that suits your platform and make sure you follow the requirements. @@ -32,7 +32,7 @@ Just run the Setup file. A shortcut will be added to your desktop and start menu Open a terminal in the directory of the LinkedIn Learning Courses Downloader program then type : ```bash - chmod 777 ./LyndaCoursesDownloader + chmod 777 ./Linkedin Learning Courses Downloader ``` @@ -40,7 +40,7 @@ Open a terminal in the directory of the LinkedIn Learning Courses Downloader pro and to run the program type: ```bash - ./LyndaCoursesDownloader + ./Linkedin Learning Courses Downloader ``` ## Getting the LinkedIn Learning login token cookie