diff --git a/QobuzDownloaderX/Form1.Designer.cs b/QobuzDownloaderX/Form1.Designer.cs index b02b8a3..4770591 100644 --- a/QobuzDownloaderX/Form1.Designer.cs +++ b/QobuzDownloaderX/Form1.Designer.cs @@ -101,6 +101,8 @@ this.logoutLabel = new System.Windows.Forms.Label(); this.downloadLabelBG = new System.ComponentModel.BackgroundWorker(); this.hiddenTextPanel = new System.Windows.Forms.Panel(); + this.downloadFaveAlbumsBG = new System.ComponentModel.BackgroundWorker(); + this.downloadFaveArtistsBG = new System.ComponentModel.BackgroundWorker(); ((System.ComponentModel.ISupportInitialize)(this.albumArtPicBox)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.logoBox)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.profilePictureBox)).BeginInit(); @@ -927,6 +929,14 @@ this.hiddenTextPanel.TabIndex = 87; this.hiddenTextPanel.Visible = false; // + // downloadFaveAlbumsBG + // + this.downloadFaveAlbumsBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.downloadFaveAlbumsBG_DoWork); + // + // downloadFaveArtistsBG + // + this.downloadFaveArtistsBG.DoWork += new System.ComponentModel.DoWorkEventHandler(this.downloadFaveArtistsBG_DoWork); + // // QobuzDownloaderX // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1088,6 +1098,8 @@ private System.Windows.Forms.Label logoutLabel; private System.ComponentModel.BackgroundWorker downloadLabelBG; private System.Windows.Forms.Panel hiddenTextPanel; + private System.ComponentModel.BackgroundWorker downloadFaveAlbumsBG; + private System.ComponentModel.BackgroundWorker downloadFaveArtistsBG; } } diff --git a/QobuzDownloaderX/Form1.cs b/QobuzDownloaderX/Form1.cs index d4ae4d6..8ca435b 100644 --- a/QobuzDownloaderX/Form1.cs +++ b/QobuzDownloaderX/Form1.cs @@ -47,12 +47,15 @@ namespace QobuzDownloaderX public string userAuth { get; set; } public string profilePic { get; set; } public string displayName { get; set; } + public string userID { get; set; } public string accountType { get; set; } public string appSecret { get; set; } public string albumId { get; set; } public string trackIdString { get; set; } public string formatIdString { get; set; } public string audioFileType { get; set; } + public string trackRequest { get; set; } + public int MaxLength { get; set; } public int devClickEggThingValue { get; set; } searchForm searchF = new searchForm(); @@ -145,16 +148,16 @@ namespace QobuzDownloaderX #endregion } - // Set DateTime for new date formatting. - System.DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0); + //// Set DateTime for new date formatting. + //System.DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0); - public string DateConvertion(string Input) - { - var date = DateTime.ParseExact(Input, "M/d/yyyy hh:mm:ss tt", - CultureInfo.InvariantCulture); + //public string DateConvertion(string Input) + //{ + // var date = DateTime.ParseExact(Input, "M/d/yyyy hh:mm:ss tt", + // CultureInfo.InvariantCulture); - return date.ToString("yyyy-MM-dd"); - } + // return date.ToString("yyyy-MM-dd"); + //} static string DecodeEncodedNonAsciiCharacters(string value) @@ -389,6 +392,28 @@ namespace QobuzDownloaderX { downloadLabelBG.RunWorkerAsync(); } + else if (linkType == "user") + { + if (albumId == @"library/favorites/albums") + { + downloadFaveAlbumsBG.RunWorkerAsync(); + } + //else if (albumId == @"library/favorites/artists") + //{ + // downloadFaveArtistsBG.RunWorkerAsync(); + //} + else + { + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("Downloading favorites only works on favorite albums at the moment. More options will be added in the future.\r\n\r\nIf you'd like to go ahead and grab your favorite albums, paste this link in the URL section - https://play.qobuz.com/user/library/favorites/albums"))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + } else if (linkType == "playlist") { // Say what isn't available at the moment. @@ -720,13 +745,10 @@ namespace QobuzDownloaderX string unicodeGenre = genre; string decodedGenre = DecodeEncodedNonAsciiCharacters(unicodeGenre); genre = decodedGenre.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); - + // Release Date tag, grabs the available "stream" date - //var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; - var releaseDateLog = Regex.Match(trackRequest, ",\"released_at\":(?.*?),").Groups; - long dateLong = long.Parse(releaseDateLog[1].Value); - var releaseDate = dateTime.AddSeconds(dateLong).ToString(); - releaseDate = DateConvertion(releaseDate); + var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; + var releaseDate = releaseDateLog[1].Value; // Display release date in text box under cover art. releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate)); @@ -1830,11 +1852,8 @@ namespace QobuzDownloaderX genre = decodedGenre.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); // Release Date tag, grabs the available "stream" date - //var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; - var releaseDateLog = Regex.Match(trackRequest, ",\"released_at\":(?.*?),").Groups; - long dateLong = long.Parse(releaseDateLog[1].Value); - var releaseDate = dateTime.AddSeconds(dateLong).ToString(); - releaseDate = DateConvertion(releaseDate); + var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; + var releaseDate = releaseDateLog[1].Value; // Display release date in text box under cover art. releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate)); @@ -2625,6 +2644,2210 @@ namespace QobuzDownloaderX #endregion } + // For downloading "favorites" (Albums only at the moment) [IN DEV] + + #region If URL is for "favorites" + + // Favorite Albums + private async void downloadFaveAlbumsBG_DoWork(object sender, DoWorkEventArgs e) + { + #region Albums + string loc = folderBrowserDialog.SelectedPath; + + trackIdString = albumId; + + WebRequest artistwr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/favorite/getUserFavorites?type=albums&limit=9999999999&user_id=" + userID + "&app_id=" + appid + "&user_auth_token=" + userAuth); + + // Empty output, then say Starting Downloads. + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("FAVORITE DOWNLOADS MAY HAVE SOME ERRORS, THIS IS A NEW FEATURE, AND CURRENTLY ONLY SUPPORTS FAVORITED ALBUMS. IF YOU RUN INTO AN ISSUE, PLEASE REPORT IT ON GITHUB!\r\n"))); + output.Invoke(new Action(() => output.AppendText("Grabbing Album IDs...\r\n\r\n"))); + + try + { + WebResponse artistws = artistwr.GetResponse(); + StreamReader artistsr = new StreamReader(artistws.GetResponseStream()); + + string artistRequest = artistsr.ReadToEnd(); + + // Grab all Track IDs listed on the API. + string artistAlbumIdspattern = "\"url\":\"(?:.*?)\",\"id\":\"(?.*?)\""; + string input = artistRequest; + RegexOptions options = RegexOptions.Multiline; + + foreach (Match m in Regex.Matches(input, artistAlbumIdspattern, options)) + { + string albumIdDiscog = string.Format("{0}", m.Groups["albumIds"].Value); + + WebRequest wr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/album/get?album_id=" + albumIdDiscog + "&app_id=" + appid + "&user_auth_token=" + userAuth); + + // Empty output, then say Starting Downloads. + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("FAVORITE DOWNLOADS MAY HAVE SOME ERRORS, THIS IS A NEW FEATURE, AND CURRENTLY ONLY SUPPORTS FAVORITED ALBUMS. IF YOU RUN INTO AN ISSUE, PLEASE REPORT IT ON GITHUB!\r\n"))); + output.Invoke(new Action(() => output.AppendText("Starting Downloads...\r\n\r\n"))); + + try + { + // Set "loc" as the selected path. + loc = folderBrowserDialog.SelectedPath; + + WebResponse ws = wr.GetResponse(); + StreamReader sr = new StreamReader(ws.GetResponseStream()); + + string albumRequest = sr.ReadToEnd(); + + string text = albumRequest; + + var tracksLog = Regex.Match(albumRequest, "tracks_count\":(?\\d+)").Groups; + var tracks = tracksLog[1].Value; + + // Album Name tag + var labelDiscogAlbumLog = Regex.Match(albumRequest, "\"title\":\"(?.*?)\",\\\"").Groups; + var labelDiscogAlbum = labelDiscogAlbumLog[1].Value; + + // For converting unicode characters to ASCII + string unicodeDiscogAlbum = labelDiscogAlbum; + string decodedDiscogAlbum = DecodeEncodedNonAsciiCharacters(unicodeDiscogAlbum); + labelDiscogAlbum = decodedDiscogAlbum; + + output.Invoke(new Action(() => output.AppendText("Downloading Album - " + labelDiscogAlbum + " ......\r\n\r\n"))); + + #region Cover Art URL + // Grab Cover Art URL + var frontCoverLog = Regex.Match(albumRequest, "\"image\":{\"thumbnail\":\"(?[A-Za-z0-9:().,\\\\\\/._\\-']+)").Groups; + var frontCover = frontCoverLog[1].Value; + + // Remove backslashes from the stream URL to have a proper URL. + string imagepattern = @"(?[^\\]+)"; + string imageinput = frontCover; + RegexOptions imageoptions = RegexOptions.Multiline; + + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty)); + + foreach (Match mImg in Regex.Matches(imageinput, imagepattern, imageoptions)) + { + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mImg.Value)))); + } + + string frontCoverImg = imageURLTextbox.Text; + string frontCoverImgBox = frontCoverImg.Replace("_50.jpg", "_150.jpg"); + frontCoverImg = frontCoverImg.Replace("_50.jpg", "_max.jpg"); + + albumArtPicBox.Invoke(new Action(() => albumArtPicBox.ImageLocation = frontCoverImgBox)); + + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail)); + #endregion + + #region "Goodies" URL (Digital Booklets) + // Look for "Goodies" (digital booklet) + var goodiesLog = Regex.Match(albumRequest, "\"goodies\":\\[{\"id\":(?.*?),\"original_url\":\"(?.*?)\",\\\"").Groups; + var goodies = goodiesLog[2].Value; + + // Remove backslashes from the stream URL to have a proper URL. + string bookpattern = @"(?[^\\]+)"; + string bookinput = goodies; + RegexOptions bookoptions = RegexOptions.Multiline; + + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty)); + + foreach (Match mBook in Regex.Matches(bookinput, bookpattern, bookoptions)) + { + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mBook.Value)))); + } + + string goodiesPDF = imageURLTextbox.Text; + + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail)); + #endregion + + // Grab sample rate and bit depth for album. + var qualityLog = Regex.Match(albumRequest, "\"maximum_sampling_rate\":(?.*?),(?:.*?)\"maximum_bit_depth\":(?.*?),\"duration\"").Groups; + var sampleRate = qualityLog[1].Value; + var bitDepth = qualityLog[2].Value; + var quality = "FLAC (" + bitDepth + "bit/" + sampleRate + "kHz)"; + var qualityPath = quality.Replace(@"\", "-").Replace(@"/", "-"); + + if (formatIdString == "5") + { + quality = "MP3 320kbps CBR"; + qualityPath = "MP3"; + } + else if (formatIdString == "6") + { + quality = "FLAC (16bit/44.1kHz)"; + qualityPath = "FLAC (16bit-44.1kHz)"; + } + else if (formatIdString == "7") + { + if (quality == "FLAC (24bit/192kHz)") + { + quality = "FLAC (24bit/96kHz)"; + qualityPath = "FLAC (24bit-96kHz)"; + } + } + + // Grab all Track IDs listed on the API. + string trackIdspattern = "\"version\":(?:.*?),\"id\":(?.*?),"; + string trackinput = text; + RegexOptions trackoptions = RegexOptions.Multiline; + + + foreach (Match mtrack in Regex.Matches(trackinput, trackIdspattern, trackoptions)) + { + // Set default value for max length. + const int MaxLength = 36; + + //output.Invoke(new Action(() => output.AppendText(string.Format("{0}\r\n", m.Groups["trackId"].Value)))); + trackIdString = string.Format("{0}", mtrack.Groups["trackId"].Value); + + WebRequest trackwr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/track/get?track_id=" + trackIdString + "&app_id=" + appid + "&user_auth_token=" + userAuth); + + WebResponse trackws = trackwr.GetResponse(); + StreamReader tracksr = new StreamReader(trackws.GetResponseStream()); + + string trackRequest = tracksr.ReadToEnd(); + + #region Availability Check (Valid Link?) + // Check if available at all. + var errorCheckLog = Regex.Match(trackRequest, "\"code\":404,\"message\":\"(?.*?)\\\"").Groups; + var errorCheck = errorCheckLog[1].Value; + + if (errorCheck == "No result matching given argument") + { + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("ERROR: 404\r\n"))); + output.Invoke(new Action(() => output.AppendText("Error message is \"No result matching given argument\"\r\n"))); + output.Invoke(new Action(() => output.AppendText("This could mean either the link is invalid, or isn't available in the region you're downloading from (even if the account is in the correct region). If the latter is true, use a VPN for the region it's available in to download."))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + #endregion + + // Display album quality in quality textbox. + qualityTextbox.Invoke(new Action(() => qualityTextbox.Text = quality)); + + #region Get Information (Tags, Titles, etc.) + // Track Number tag + var trackNumberLog = Regex.Match(trackRequest, "\"track_number\":(?[0-9]+)").Groups; + var trackNumber = trackNumberLog[1].Value; + + // Disc Number tag + var discNumberLog = Regex.Match(trackRequest, "\"media_number\":(?.*?),\\\"").Groups; + var discNumber = discNumberLog[1].Value; + + // Album Artist tag + var albumArtistLog = Regex.Match(trackRequest, "\"artist\":{\"picture\":(?.*?),\"id\"(?.*?),\"albums_count\":(?.*?),\"name\":\"(?.*?)\",\\\"").Groups; + var albumArtist = albumArtistLog[4].Value; + + // For converting unicode characters to ASCII + string unicodeAlbumArtist = albumArtist; + string decodedAlbumArtist = DecodeEncodedNonAsciiCharacters(unicodeAlbumArtist); + albumArtist = decodedAlbumArtist; + + albumArtist = albumArtist.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var albumArtistPath = albumArtist.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // Display album artist in text box under cover art. + albumArtistTextBox.Invoke(new Action(() => albumArtistTextBox.Text = albumArtist)); + + // If name goes over 200 characters, limit it to 200 + if (albumArtistPath.Length > MaxLength) + { + albumArtistPath = albumArtistPath.Substring(0, MaxLength); + } + + // Track Artist tag + var performerNameLog = Regex.Match(trackRequest, "\"performer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups; + var performerName = performerNameLog[2].Value; + + // For converting unicode characters to ASCII + string unicodePerformerName = performerName; + string decodedPerformerName = DecodeEncodedNonAsciiCharacters(unicodePerformerName); + performerName = decodedPerformerName; + + performerName = performerName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var performerNamePath = performerName.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // If name goes over 200 characters, limit it to 200 + if (performerNamePath.Length > MaxLength) + { + performerNamePath = performerNamePath.Substring(0, MaxLength); + } + + // Track Composer tag + var composerNameLog = Regex.Match(trackRequest, "\"composer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups; + var composerName = composerNameLog[2].Value; + + // Track Explicitness + var advisoryLog = Regex.Match(trackRequest, "\"performers\":(?:.*?)\"parental_warning\":(?.*?),").Groups; + var advisory = advisoryLog[1].Value; + + // For converting unicode characters to ASCII + string unicodeComposerName = composerName; + string decodedComposerName = DecodeEncodedNonAsciiCharacters(unicodeComposerName); + composerName = decodedComposerName; + + composerName = composerName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + + // Album Name tag + var albumNameLog = Regex.Match(trackRequest, "\"title\":\"(?.*?)\",\\\"").Groups; + var albumName = albumNameLog[1].Value; + + // For converting unicode characters to ASCII + string unicodeAlbumName = albumName; + string decodedAlbumName = DecodeEncodedNonAsciiCharacters(unicodeAlbumName); + albumName = decodedAlbumName; + + albumName = albumName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var albumNamePath = albumName.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // Display album name in text box under cover art. + albumTextBox.Invoke(new Action(() => albumTextBox.Text = albumName)); + + // If name goes over 200 characters, limit it to 200 + if (albumNamePath.Length > MaxLength) + { + albumNamePath = albumNamePath.Substring(0, MaxLength); + } + + // Track Name tag + var trackNameLog = Regex.Match(trackRequest, "\"version\":(?.*?),\"id\":(?.*?),\"maximum_bit_depth\":(?.*?),\"title\":\"(?.*?)\",\\\"").Groups; + var trackName = trackNameLog[4].Value; + trackName = trackName.Trim(); // Remove spaces from end of track name + + // For converting unicode characters to ASCII + string unicodeTrackName = trackName; + string decodedTrackName = DecodeEncodedNonAsciiCharacters(unicodeTrackName); + trackName = decodedTrackName; + + trackName = trackName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var trackNamePath = trackName.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // If name goes over 200 characters, limit it to 200 + if (trackNamePath.Length > MaxLength) + { + trackNamePath = trackNamePath.Substring(0, MaxLength); + } + + // Version Name tag + var versionNameLog = Regex.Match(trackRequest, "\"version\":\"(?.*?)\",\\\"").Groups; + var versionName = versionNameLog[1].Value; + + // For converting unicode characters to ASCII + string unicodeVersionName = versionName; + string decodedVersionName = DecodeEncodedNonAsciiCharacters(unicodeVersionName); + versionName = decodedVersionName; + + versionName = versionName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var versionNamePath = versionName.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // Genre tag + var genreLog = Regex.Match(trackRequest, "\"genre\":{\"id\":(?.*?),\"color\":\"(?.*?)\",\"name\":\"(?.*?)\",\\\"").Groups; + var genre = genreLog[3].Value; + + // For converting unicode characters to ASCII + string unicodeGenre = genre; + string decodedGenre = DecodeEncodedNonAsciiCharacters(unicodeGenre); + genre = decodedGenre.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + + // Release Date tag, grabs the available "stream" date + var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; + var releaseDate = releaseDateLog[1].Value; + + // Display release date in text box under cover art. + releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate)); + + // Copyright tag + var copyrightLog = Regex.Match(trackRequest, "\"copyright\":\"(?.*?)\"copyright\":\"(?.*?)\\\"").Groups; + var copyright = copyrightLog[2].Value; + + // For converting unicode characters to ASCII + string unicodeCopyright = copyright; + string decodedCopyright = DecodeEncodedNonAsciiCharacters(unicodeCopyright); + copyright = decodedCopyright; + + copyright = copyright.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/").Replace(@"\u2117", @"℗"); + + // UPC tag + var upcLog = Regex.Match(trackRequest, "\"upc\":\"(?.*?)\",\\\"").Groups; + var upc = upcLog[1].Value; + + // Display UPC in text box under cover art. + upcTextBox.Invoke(new Action(() => upcTextBox.Text = upc)); + + // ISRC tag + var isrcLog = Regex.Match(trackRequest, "\"isrc\":\"(?.*?)\",\\\"").Groups; + var isrc = isrcLog[1].Value; + + // Total Tracks tag + var trackTotalLog = Regex.Match(trackRequest, "\"tracks_count\":(?[0-9]+)").Groups; + var trackTotal = trackTotalLog[1].Value; + + // Display Total Tracks in text box under cover art. + totalTracksTextbox.Invoke(new Action(() => totalTracksTextbox.Text = trackTotal)); + + // Total Discs tag + var discTotalLog = Regex.Match(trackRequest, "\"media_count\":(?[0-9]+)").Groups; + var discTotal = discTotalLog[1].Value; + #endregion + + #region Filename Number Padding + // Set default track number padding length + var paddingLength = 2; + + // Prepare track number padding in filename. + string paddingLog = trackTotal.Length.ToString(); + if (paddingLog == "1") + { + paddingLength = 2; + } + else + { + paddingLength = trackTotal.Length; + } + + // Set default disc number padding length + var paddingDiscLength = 2; + + // Prepare disc number padding in filename. + string paddingDiscLog = discTotal.Length.ToString(); + if (paddingDiscLog == "1") + { + paddingDiscLength = 1; + } + else + { + paddingDiscLength = discTotal.Length; + } + #endregion + + #region Create Directories + // Create strings for disc folders + string discFolder = null; + string discFolderCreate = null; + + // If more than 1 disc, create folders for discs. Otherwise, strings will remain null. + if (discTotal != "1") + { + discFolder = "CD " + discNumber.PadLeft(paddingDiscLength, '0') + "\\"; + discFolderCreate = "\\CD " + discNumber.PadLeft(paddingDiscLength, '0') + "\\"; + } + + System.IO.Directory.CreateDirectory(loc + "\\" + "- Favorites" + "\\" + albumArtistPath); + System.IO.Directory.CreateDirectory(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]"); + System.IO.Directory.CreateDirectory(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath); + System.IO.Directory.CreateDirectory(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + discFolderCreate); + + string discogPath = loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + discFolderCreate; + #endregion + + #region Availability Check (Streamable?) + // Check if available for streaming. + var streamCheckLog = Regex.Match(trackRequest, "\"track_number\":(?.*?)\"streamable\":(?.*?),\"").Groups; + var streamCheck = streamCheckLog[2].Value; + + if (streamCheck != "true") + { + if (streamableCheckbox.Checked == true) + { + output.Invoke(new Action(() => output.AppendText("Track " + trackNumber + " \"" + trackName + "\" is not available for streaming. Skipping track...\r\n"))); + System.Threading.Thread.Sleep(800); + continue; + } + else + { + output.Invoke(new Action(() => output.AppendText("\r\nTrack " + trackNumber + " \"" + trackName + "\" is not available for streaming. But stremable check is being ignored for debugging, or messed up releases. Attempting to download...\r\n"))); + } + } + #endregion + + #region Check if File Exists + // Check if there is a version name. + if (versionName == null | versionName == "") + { + if (System.IO.File.Exists(discogPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + audioFileType)) + { + output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + "\" already exists. Skipping.\r\n"))); + System.Threading.Thread.Sleep(800); + continue; + } + } + else + { + if (System.IO.File.Exists(discogPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + " (" + versionNamePath + ")" + audioFileType)) + { + output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + " (" + versionName + ")" + "\" already exists. Skipping.\r\n"))); + System.Threading.Thread.Sleep(800); + continue; + } + } + #endregion + + // Close web request and create streaming URL. + trackwr.Abort(); + createURL(sender, e); + + try + { + #region Downloading + // Check if there is a version name. + if (versionName == null | versionName == "") + { + output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " ......"))); + } + else + { + output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " (" + versionName + ")" + " ......"))); + } + // Being download process. + var client = new HttpClient(); + // Run through TLS to allow secure connection. + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3; + // Set "range" header to nearly unlimited. + client.DefaultRequestHeaders.Range = new RangeHeaderValue(0, 999999999999); + // Set user-agent to Firefox. + client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0"); + // Set referer URL to album ID. + client.DefaultRequestHeaders.Add("Referer", "https://play.qobuz.com/album/" + albumIdDiscog); + // Download the URL in the "Streamed URL" Textbox (Will most likely be replaced). + using (var stream = await client.GetStreamAsync(testURLBox.Text)) + + // Save single track in selected path. + if (versionNamePath == null | versionNamePath == "") + { + // If there is NOT a version name. + using (var output = System.IO.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + audioFileType)) + { + await stream.CopyToAsync(output); + } + } + else + { + // If there is a version name. + using (var output = System.IO.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + " (" + versionNamePath + ")" + audioFileType)) + { + await stream.CopyToAsync(output); + } + } + #endregion + + #region Cover Art Saving + if (System.IO.File.Exists(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg")) + { + // Skip, don't re-download. + } + else + { + if (imageCheckbox.Checked == true) + { + // Save cover art to selected path (Currently happens every time a track is downloaded). + using (WebClient imgClient = new WebClient()) + { + // Download max quality Cover Art to "Cover.jpg" file in chosen path. + imgClient.DownloadFile(new Uri(frontCoverImg), loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + } + } + } + #endregion + + #region Tagging + // Check if audio file type is FLAC or MP3 + if (audioFileType == ".mp3") + { + #region MP3 Tagging (Needs Work) + // Select the downloaded file to prepare for tagging. + // Check if there's a version name or not + if (versionName == null | versionName == "") + { + // If there is NOT a version name. + var tfile = TagLib.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + audioFileType); + // For custom / troublesome tags. + TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2); + + + // Saving cover art to file(s) + if (imageCheckbox.Checked == true) + { + // Define cover art to use for MP3 file(s) + TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame(); + pic.TextEncoding = TagLib.StringType.Latin1; + pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg; + pic.Type = TagLib.PictureType.FrontCover; + pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + + // Save cover art to MP3 file. + tfile.Tag.Pictures = new TagLib.IPicture[1] { pic }; + tfile.Save(); + } + + // Track Title tag + if (trackTitleCheckbox.Checked == true) + { + tfile.Tag.Title = trackName; + } + + // Album Title tag + if (albumCheckbox.Checked == true) + { + tfile.Tag.Album = albumName; + } + + // Album Artits tag + if (albumArtistCheckbox.Checked == true) + { + tfile.Tag.AlbumArtists = new string[] { albumArtist }; + } + + // Track Artist tag + if (artistCheckbox.Checked == true) + { + tfile.Tag.Performers = new string[] { performerName }; + } + + // Composer tag + if (composerCheckbox.Checked == true) + { + tfile.Tag.Composers = new string[] { composerName }; + } + + // Release Date tag + if (releaseCheckbox.Checked == true) + { + releaseDate = releaseDate.Substring(0, 4); + tfile.Tag.Year = UInt32.Parse(releaseDate); + } + + // Genre tag + if (genreCheckbox.Checked == true) + { + tfile.Tag.Genres = new string[] { genre }; + } + + // Track Number tag + if (trackNumberCheckbox.Checked == true) + { + tfile.Tag.Track = UInt32.Parse(trackNumber); + } + + // Disc Number tag + if (discNumberCheckbox.Checked == true) + { + tfile.Tag.Disc = UInt32.Parse(discNumber); + } + + // Total Discs tag + if (discTotalCheckbox.Checked == true) + { + tfile.Tag.DiscCount = UInt32.Parse(discTotal); + } + + // Total Tracks tag + if (trackTotalCheckbox.Checked == true) + { + tfile.Tag.TrackCount = UInt32.Parse(trackTotal); + } + + // Comment tag + if (commentCheckbox.Checked == true) + { + tfile.Tag.Comment = commentTextbox.Text; + } + + // Copyright tag + if (copyrightCheckbox.Checked == true) + { + tfile.Tag.Copyright = copyright; + } + // UPC tag + if (upcCheckbox.Checked == true) + { + // Not available on MP3 at the moment + } + + // ISRC tag + if (isrcCheckbox.Checked == true) + { + TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true); + tag.SetTextFrame("TSRC", isrc); + } + + // Explicit tag + if (explicitCheckbox.Checked == true) + { + // Not available on MP3 at the moment + } + + // Save all selected tags to file + tfile.Save(); + } + else + { + // If there is a version name. + var tfile = TagLib.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + " (" + versionNamePath + ")" + audioFileType); + // For custom / troublesome tags. + TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2); + + + // Saving cover art to file(s) + if (imageCheckbox.Checked == true) + { + // Define cover art to use for FLAC file(s) + TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame(); + pic.TextEncoding = TagLib.StringType.Latin1; + pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg; + pic.Type = TagLib.PictureType.FrontCover; + pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + + // Save cover art to FLAC file. + tfile.Tag.Pictures = new TagLib.IPicture[1] { pic }; + tfile.Save(); + } + + // Track Title tag + if (trackTitleCheckbox.Checked == true) + { + tfile.Tag.Title = trackName + " (" + versionName + ")"; + } + + // Album Title tag + if (albumCheckbox.Checked == true) + { + tfile.Tag.Album = albumName; + } + + // Album Artits tag + if (albumArtistCheckbox.Checked == true) + { + tfile.Tag.AlbumArtists = new string[] { albumArtist }; + } + + // Track Artist tag + if (artistCheckbox.Checked == true) + { + tfile.Tag.Performers = new string[] { performerName }; + } + + // Composer tag + if (composerCheckbox.Checked == true) + { + tfile.Tag.Composers = new string[] { composerName }; + } + + // Release Date tag + if (releaseCheckbox.Checked == true) + { + releaseDate = releaseDate.Substring(0, 4); + tfile.Tag.Year = UInt32.Parse(releaseDate); + } + + // Genre tag + if (genreCheckbox.Checked == true) + { + tfile.Tag.Genres = new string[] { genre }; + } + + // Track Number tag + if (trackNumberCheckbox.Checked == true) + { + tfile.Tag.Track = UInt32.Parse(trackNumber); + } + + // Disc Number tag + if (discNumberCheckbox.Checked == true) + { + tfile.Tag.Disc = UInt32.Parse(discNumber); + } + + // Total Discs tag + if (discTotalCheckbox.Checked == true) + { + tfile.Tag.DiscCount = UInt32.Parse(discTotal); + } + + // Total Tracks tag + if (trackTotalCheckbox.Checked == true) + { + tfile.Tag.TrackCount = UInt32.Parse(trackTotal); + } + + // Comment tag + if (commentCheckbox.Checked == true) + { + tfile.Tag.Comment = commentTextbox.Text; + } + + // Copyright tag + if (copyrightCheckbox.Checked == true) + { + tfile.Tag.Copyright = copyright; + } + // UPC tag + if (upcCheckbox.Checked == true) + { + // Not available on MP3 at the moment + } + + // ISRC tag + if (isrcCheckbox.Checked == true) + { + TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true); + tag.SetTextFrame("TSRC", isrc); + } + + // Explicit tag + if (explicitCheckbox.Checked == true) + { + // Not available on MP3 at the moment + } + + // Save all selected tags to file + tfile.Save(); + } + #endregion + } + else + { + #region FLAC Tagging + // Select the downloaded file to prepare for tagging. + // Check if there's a version name or not + if (versionName == null | versionName == "") + { + // If there is NOT a version name. + var tfile = TagLib.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + audioFileType); + // For custom / troublesome tags. + var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph); + + + // Saving cover art to file(s) + if (imageCheckbox.Checked == true) + { + // Define cover art to use for FLAC file(s) + TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame(); + pic.TextEncoding = TagLib.StringType.Latin1; + pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg; + pic.Type = TagLib.PictureType.FrontCover; + pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + + // Save cover art to FLAC file. + tfile.Tag.Pictures = new TagLib.IPicture[1] { pic }; + tfile.Save(); + } + + // Track Title tag + if (trackTitleCheckbox.Checked == true) + { + tfile.Tag.Title = trackName; + } + + // Album Title tag + if (albumCheckbox.Checked == true) + { + tfile.Tag.Album = albumName; + } + + // Album Artits tag + if (albumArtistCheckbox.Checked == true) + { + custom.SetField("ALBUMARTIST", new string[] { albumArtist }); + } + + // Track Artist tag + if (artistCheckbox.Checked == true) + { + custom.SetField("ARTIST", new string[] { performerName }); + } + + // Composer tag + if (composerCheckbox.Checked == true) + { + custom.SetField("COMPOSER", new string[] { composerName }); + } + + // Release Date tag + if (releaseCheckbox.Checked == true) + { + custom.SetField("YEAR", new string[] { releaseDate }); + } + + // Genre tag + if (genreCheckbox.Checked == true) + { + custom.SetField("GENRE", new string[] { genre }); + } + + // Track Number tag + if (trackNumberCheckbox.Checked == true) + { + tfile.Tag.Track = UInt32.Parse(trackNumber); + } + + // Disc Number tag + if (discNumberCheckbox.Checked == true) + { + tfile.Tag.Disc = UInt32.Parse(discNumber); + } + + // Total Discs tag + if (discTotalCheckbox.Checked == true) + { + tfile.Tag.DiscCount = UInt32.Parse(discTotal); + } + + // Total Tracks tag + if (trackTotalCheckbox.Checked == true) + { + tfile.Tag.TrackCount = UInt32.Parse(trackTotal); + } + + // Comment tag + if (commentCheckbox.Checked == true) + { + custom.SetField("COMMENT", new string[] { commentTextbox.Text }); + } + + // Copyright tag + if (copyrightCheckbox.Checked == true) + { + custom.SetField("COPYRIGHT", new string[] { copyright }); + } + // UPC tag + if (upcCheckbox.Checked == true) + { + custom.SetField("UPC", new string[] { upc }); + } + + // ISRC tag + if (isrcCheckbox.Checked == true) + { + custom.SetField("ISRC", new string[] { isrc }); + } + + // Explicit tag + if (explicitCheckbox.Checked == true) + { + if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); } + } + + // Save all selected tags to file + tfile.Save(); + } + else + { + // If there is a version name. + var tfile = TagLib.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + " (" + versionNamePath + ")" + audioFileType); + // For custom / troublesome tags. + var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph); + + + // Saving cover art to file(s) + if (imageCheckbox.Checked == true) + { + // Define cover art to use for FLAC file(s) + TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame(); + pic.TextEncoding = TagLib.StringType.Latin1; + pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg; + pic.Type = TagLib.PictureType.FrontCover; + pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + + // Save cover art to FLAC file. + tfile.Tag.Pictures = new TagLib.IPicture[1] { pic }; + tfile.Save(); + } + + // Track Title tag + if (trackTitleCheckbox.Checked == true) + { + tfile.Tag.Title = trackName + " (" + versionName + ")"; + } + + // Album Title tag + if (albumCheckbox.Checked == true) + { + tfile.Tag.Album = albumName; + } + + // Album Artits tag + if (albumArtistCheckbox.Checked == true) + { + custom.SetField("ALBUMARTIST", new string[] { albumArtist }); + } + + // Track Artist tag + if (artistCheckbox.Checked == true) + { + custom.SetField("ARTIST", new string[] { performerName }); + } + + // Composer tag + if (composerCheckbox.Checked == true) + { + custom.SetField("COMPOSER", new string[] { composerName }); + } + + // Release Date tag + if (releaseCheckbox.Checked == true) + { + custom.SetField("YEAR", new string[] { releaseDate }); + } + + // Genre tag + if (genreCheckbox.Checked == true) + { + custom.SetField("GENRE", new string[] { genre }); + } + + // Track Number tag + if (trackNumberCheckbox.Checked == true) + { + tfile.Tag.Track = UInt32.Parse(trackNumber); + } + + // Disc Number tag + if (discNumberCheckbox.Checked == true) + { + tfile.Tag.Disc = UInt32.Parse(discNumber); + } + + // Total Discs tag + if (discTotalCheckbox.Checked == true) + { + tfile.Tag.DiscCount = UInt32.Parse(discTotal); + } + + // Total Tracks tag + if (trackTotalCheckbox.Checked == true) + { + tfile.Tag.TrackCount = UInt32.Parse(trackTotal); + } + + // Comment tag + if (commentCheckbox.Checked == true) + { + custom.SetField("COMMENT", new string[] { commentTextbox.Text }); + } + + // Copyright tag + if (copyrightCheckbox.Checked == true) + { + custom.SetField("COPYRIGHT", new string[] { copyright }); + } + // UPC tag + if (upcCheckbox.Checked == true) + { + custom.SetField("UPC", new string[] { upc }); + } + + // ISRC tag + if (isrcCheckbox.Checked == true) + { + custom.SetField("ISRC", new string[] { isrc }); + } + + // Explicit tag + if (explicitCheckbox.Checked == true) + { + if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); } + } + + // Save all selected tags to file + tfile.Save(); + } + #endregion + } + #endregion + + #region Digital Booklet + // If a booklet was found, save it. + if (goodiesPDF == null | goodiesPDF == "") + { + // No need to download something that doesn't exist. + } + else + { + if (System.IO.File.Exists(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Digital Booklet.pdf")) + { + // Skip, don't re-download. + } + else + { + // Save digital booklet to selected path + output.Invoke(new Action(() => output.AppendText("\r\nGoodies found, downloading..."))); + using (WebClient bookClient = new WebClient()) + { + // Download max quality Cover Art to "Cover.jpg" file in chosen path. + bookClient.DownloadFile(new Uri(goodiesPDF), loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Digital Booklet.pdf"); + } + } + } + #endregion + } + catch (Exception downloadError) + { + // If there is an issue trying to, or during the download, show error info. + string error = downloadError.ToString(); + output.Invoke(new Action(() => output.AppendText("\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText("Track Download ERROR. Information below.\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText(error))); + output.Invoke(new Action(() => output.AppendText("\r\n\r\nIf some tracks aren't available for streaming on the album you're trying to download, try to manually download the available tracks individually."))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + + // Say when a track is done downloading, then wait for the next track / end. + output.Invoke(new Action(() => output.AppendText("Track Download Done!\r\n"))); + System.Threading.Thread.Sleep(800); + } + + // Say that downloading is completed. + output.Invoke(new Action(() => output.AppendText("\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText("Downloading job completed! All downloaded files will be located in your chosen path."))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + } + catch (Exception ex) + { + string error = ex.ToString(); + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("Failed to download (First Phase). Error information below.\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText(error))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + } + } + catch (Exception downloadError) + { + // If there is an issue trying to, or during the download, show error info. + string error = downloadError.ToString(); + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("Label Download ERROR. Information below.\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText(error))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + #endregion + } + + // Favorite Artists [Not worked on at all yet] + private async void downloadFaveArtistsBG_DoWork(object sender, DoWorkEventArgs e) + { + #region Artists + string loc = folderBrowserDialog.SelectedPath; + + trackIdString = albumId; + + WebRequest artistwr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/favorite/getUserFavorites?type=albums&limit=9999999999&user_id=" + userID + "&app_id=" + appid + "&user_auth_token=" + userAuth); + + // Empty output, then say Starting Downloads. + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("FAVORITE DOWNLOADS MAY HAVE SOME ERRORS, THIS IS A NEW FEATURE, AND CURRENTLY ONLY SUPPORTS FAVORITED ALBUMS. IF YOU RUN INTO AN ISSUE, PLEASE REPORT IT ON GITHUB!\r\n"))); + output.Invoke(new Action(() => output.AppendText("Grabbing Album IDs...\r\n\r\n"))); + + try + { + WebResponse artistws = artistwr.GetResponse(); + StreamReader artistsr = new StreamReader(artistws.GetResponseStream()); + + string artistRequest = artistsr.ReadToEnd(); + + // Grab all Track IDs listed on the API. + string artistAlbumIdspattern = "\"url\":\"(?:.*?)\",\"id\":\"(?.*?)\""; + string input = artistRequest; + RegexOptions options = RegexOptions.Multiline; + + foreach (Match m in Regex.Matches(input, artistAlbumIdspattern, options)) + { + string albumIdDiscog = string.Format("{0}", m.Groups["albumIds"].Value); + + WebRequest wr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/album/get?album_id=" + albumIdDiscog + "&app_id=" + appid + "&user_auth_token=" + userAuth); + + // Empty output, then say Starting Downloads. + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("FAVORITE DOWNLOADS MAY HAVE SOME ERRORS, THIS IS A NEW FEATURE, AND CURRENTLY ONLY SUPPORTS FAVORITED ALBUMS. IF YOU RUN INTO AN ISSUE, PLEASE REPORT IT ON GITHUB!\r\n"))); + output.Invoke(new Action(() => output.AppendText("Starting Downloads...\r\n\r\n"))); + + try + { + // Set "loc" as the selected path. + loc = folderBrowserDialog.SelectedPath; + + WebResponse ws = wr.GetResponse(); + StreamReader sr = new StreamReader(ws.GetResponseStream()); + + string albumRequest = sr.ReadToEnd(); + + string text = albumRequest; + + var tracksLog = Regex.Match(albumRequest, "tracks_count\":(?\\d+)").Groups; + var tracks = tracksLog[1].Value; + + // Album Name tag + var labelDiscogAlbumLog = Regex.Match(albumRequest, "\"title\":\"(?.*?)\",\\\"").Groups; + var labelDiscogAlbum = labelDiscogAlbumLog[1].Value; + + // For converting unicode characters to ASCII + string unicodeDiscogAlbum = labelDiscogAlbum; + string decodedDiscogAlbum = DecodeEncodedNonAsciiCharacters(unicodeDiscogAlbum); + labelDiscogAlbum = decodedDiscogAlbum; + + output.Invoke(new Action(() => output.AppendText("Downloading Album - " + labelDiscogAlbum + " ......\r\n\r\n"))); + + #region Cover Art URL + // Grab Cover Art URL + var frontCoverLog = Regex.Match(albumRequest, "\"image\":{\"thumbnail\":\"(?[A-Za-z0-9:().,\\\\\\/._\\-']+)").Groups; + var frontCover = frontCoverLog[1].Value; + + // Remove backslashes from the stream URL to have a proper URL. + string imagepattern = @"(?[^\\]+)"; + string imageinput = frontCover; + RegexOptions imageoptions = RegexOptions.Multiline; + + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty)); + + foreach (Match mImg in Regex.Matches(imageinput, imagepattern, imageoptions)) + { + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mImg.Value)))); + } + + string frontCoverImg = imageURLTextbox.Text; + string frontCoverImgBox = frontCoverImg.Replace("_50.jpg", "_150.jpg"); + frontCoverImg = frontCoverImg.Replace("_50.jpg", "_max.jpg"); + + albumArtPicBox.Invoke(new Action(() => albumArtPicBox.ImageLocation = frontCoverImgBox)); + + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail)); + #endregion + + #region "Goodies" URL (Digital Booklets) + // Look for "Goodies" (digital booklet) + var goodiesLog = Regex.Match(albumRequest, "\"goodies\":\\[{\"id\":(?.*?),\"original_url\":\"(?.*?)\",\\\"").Groups; + var goodies = goodiesLog[2].Value; + + // Remove backslashes from the stream URL to have a proper URL. + string bookpattern = @"(?[^\\]+)"; + string bookinput = goodies; + RegexOptions bookoptions = RegexOptions.Multiline; + + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = String.Empty)); + + foreach (Match mBook in Regex.Matches(bookinput, bookpattern, bookoptions)) + { + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.AppendText(string.Format("{0}", mBook.Value)))); + } + + string goodiesPDF = imageURLTextbox.Text; + + imageURLTextbox.Invoke(new Action(() => imageURLTextbox.Text = Settings.Default.savedEmail)); + #endregion + + // Grab sample rate and bit depth for album. + var qualityLog = Regex.Match(albumRequest, "\"maximum_sampling_rate\":(?.*?),(?:.*?)\"maximum_bit_depth\":(?.*?),\"duration\"").Groups; + var sampleRate = qualityLog[1].Value; + var bitDepth = qualityLog[2].Value; + var quality = "FLAC (" + bitDepth + "bit/" + sampleRate + "kHz)"; + var qualityPath = quality.Replace(@"\", "-").Replace(@"/", "-"); + + if (formatIdString == "5") + { + quality = "MP3 320kbps CBR"; + qualityPath = "MP3"; + } + else if (formatIdString == "6") + { + quality = "FLAC (16bit/44.1kHz)"; + qualityPath = "FLAC (16bit-44.1kHz)"; + } + else if (formatIdString == "7") + { + if (quality == "FLAC (24bit/192kHz)") + { + quality = "FLAC (24bit/96kHz)"; + qualityPath = "FLAC (24bit-96kHz)"; + } + } + + // Grab all Track IDs listed on the API. + string trackIdspattern = "\"version\":(?:.*?),\"id\":(?.*?),"; + string trackinput = text; + RegexOptions trackoptions = RegexOptions.Multiline; + + + foreach (Match mtrack in Regex.Matches(trackinput, trackIdspattern, trackoptions)) + { + // Set default value for max length. + const int MaxLength = 36; + + //output.Invoke(new Action(() => output.AppendText(string.Format("{0}\r\n", m.Groups["trackId"].Value)))); + trackIdString = string.Format("{0}", mtrack.Groups["trackId"].Value); + + WebRequest trackwr = WebRequest.Create("https://www.qobuz.com/api.json/0.2/track/get?track_id=" + trackIdString + "&app_id=" + appid + "&user_auth_token=" + userAuth); + + WebResponse trackws = trackwr.GetResponse(); + StreamReader tracksr = new StreamReader(trackws.GetResponseStream()); + + string trackRequest = tracksr.ReadToEnd(); + + #region Availability Check (Valid Link?) + // Check if available at all. + var errorCheckLog = Regex.Match(trackRequest, "\"code\":404,\"message\":\"(?.*?)\\\"").Groups; + var errorCheck = errorCheckLog[1].Value; + + if (errorCheck == "No result matching given argument") + { + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("ERROR: 404\r\n"))); + output.Invoke(new Action(() => output.AppendText("Error message is \"No result matching given argument\"\r\n"))); + output.Invoke(new Action(() => output.AppendText("This could mean either the link is invalid, or isn't available in the region you're downloading from (even if the account is in the correct region). If the latter is true, use a VPN for the region it's available in to download."))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + #endregion + + // Display album quality in quality textbox. + qualityTextbox.Invoke(new Action(() => qualityTextbox.Text = quality)); + + #region Get Information (Tags, Titles, etc.) + // Track Number tag + var trackNumberLog = Regex.Match(trackRequest, "\"track_number\":(?[0-9]+)").Groups; + var trackNumber = trackNumberLog[1].Value; + + // Disc Number tag + var discNumberLog = Regex.Match(trackRequest, "\"media_number\":(?.*?),\\\"").Groups; + var discNumber = discNumberLog[1].Value; + + // Album Artist tag + var albumArtistLog = Regex.Match(trackRequest, "\"artist\":{\"picture\":(?.*?),\"id\"(?.*?),\"albums_count\":(?.*?),\"name\":\"(?.*?)\",\\\"").Groups; + var albumArtist = albumArtistLog[4].Value; + + // For converting unicode characters to ASCII + string unicodeAlbumArtist = albumArtist; + string decodedAlbumArtist = DecodeEncodedNonAsciiCharacters(unicodeAlbumArtist); + albumArtist = decodedAlbumArtist; + + albumArtist = albumArtist.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var albumArtistPath = albumArtist.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // Display album artist in text box under cover art. + albumArtistTextBox.Invoke(new Action(() => albumArtistTextBox.Text = albumArtist)); + + // If name goes over 200 characters, limit it to 200 + if (albumArtistPath.Length > MaxLength) + { + albumArtistPath = albumArtistPath.Substring(0, MaxLength); + } + + // Track Artist tag + var performerNameLog = Regex.Match(trackRequest, "\"performer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups; + var performerName = performerNameLog[2].Value; + + // For converting unicode characters to ASCII + string unicodePerformerName = performerName; + string decodedPerformerName = DecodeEncodedNonAsciiCharacters(unicodePerformerName); + performerName = decodedPerformerName; + + performerName = performerName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var performerNamePath = performerName.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // If name goes over 200 characters, limit it to 200 + if (performerNamePath.Length > MaxLength) + { + performerNamePath = performerNamePath.Substring(0, MaxLength); + } + + // Track Composer tag + var composerNameLog = Regex.Match(trackRequest, "\"composer\":{\"id\":(?.*?),\"name\":\"(?.*?)\"},\\\"").Groups; + var composerName = composerNameLog[2].Value; + + // Track Explicitness + var advisoryLog = Regex.Match(trackRequest, "\"performers\":(?:.*?)\"parental_warning\":(?.*?),").Groups; + var advisory = advisoryLog[1].Value; + + // For converting unicode characters to ASCII + string unicodeComposerName = composerName; + string decodedComposerName = DecodeEncodedNonAsciiCharacters(unicodeComposerName); + composerName = decodedComposerName; + + composerName = composerName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + + // Album Name tag + var albumNameLog = Regex.Match(trackRequest, "\"title\":\"(?.*?)\",\\\"").Groups; + var albumName = albumNameLog[1].Value; + + // For converting unicode characters to ASCII + string unicodeAlbumName = albumName; + string decodedAlbumName = DecodeEncodedNonAsciiCharacters(unicodeAlbumName); + albumName = decodedAlbumName; + + albumName = albumName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var albumNamePath = albumName.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // Display album name in text box under cover art. + albumTextBox.Invoke(new Action(() => albumTextBox.Text = albumName)); + + // If name goes over 200 characters, limit it to 200 + if (albumNamePath.Length > MaxLength) + { + albumNamePath = albumNamePath.Substring(0, MaxLength); + } + + // Track Name tag + var trackNameLog = Regex.Match(trackRequest, "\"version\":(?.*?),\"id\":(?.*?),\"maximum_bit_depth\":(?.*?),\"title\":\"(?.*?)\",\\\"").Groups; + var trackName = trackNameLog[4].Value; + trackName = trackName.Trim(); // Remove spaces from end of track name + + // For converting unicode characters to ASCII + string unicodeTrackName = trackName; + string decodedTrackName = DecodeEncodedNonAsciiCharacters(unicodeTrackName); + trackName = decodedTrackName; + + trackName = trackName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var trackNamePath = trackName.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // If name goes over 200 characters, limit it to 200 + if (trackNamePath.Length > MaxLength) + { + trackNamePath = trackNamePath.Substring(0, MaxLength); + } + + // Version Name tag + var versionNameLog = Regex.Match(trackRequest, "\"version\":\"(?.*?)\",\\\"").Groups; + var versionName = versionNameLog[1].Value; + + // For converting unicode characters to ASCII + string unicodeVersionName = versionName; + string decodedVersionName = DecodeEncodedNonAsciiCharacters(unicodeVersionName); + versionName = decodedVersionName; + + versionName = versionName.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + var versionNamePath = versionName.Replace("\\\"", "-").Replace("\"", "-").Replace(@"\", "-").Replace(@"/", "-").Replace(":", "-").Replace("<", "-").Replace(">", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + + // Genre tag + var genreLog = Regex.Match(trackRequest, "\"genre\":{\"id\":(?.*?),\"color\":\"(?.*?)\",\"name\":\"(?.*?)\",\\\"").Groups; + var genre = genreLog[3].Value; + + // For converting unicode characters to ASCII + string unicodeGenre = genre; + string decodedGenre = DecodeEncodedNonAsciiCharacters(unicodeGenre); + genre = decodedGenre.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); + + // Release Date tag, grabs the available "stream" date + var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; + var releaseDate = releaseDateLog[1].Value; + + // Display release date in text box under cover art. + releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate)); + + // Copyright tag + var copyrightLog = Regex.Match(trackRequest, "\"copyright\":\"(?.*?)\"copyright\":\"(?.*?)\\\"").Groups; + var copyright = copyrightLog[2].Value; + + // For converting unicode characters to ASCII + string unicodeCopyright = copyright; + string decodedCopyright = DecodeEncodedNonAsciiCharacters(unicodeCopyright); + copyright = decodedCopyright; + + copyright = copyright.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/").Replace(@"\u2117", @"℗"); + + // UPC tag + var upcLog = Regex.Match(trackRequest, "\"upc\":\"(?.*?)\",\\\"").Groups; + var upc = upcLog[1].Value; + + // Display UPC in text box under cover art. + upcTextBox.Invoke(new Action(() => upcTextBox.Text = upc)); + + // ISRC tag + var isrcLog = Regex.Match(trackRequest, "\"isrc\":\"(?.*?)\",\\\"").Groups; + var isrc = isrcLog[1].Value; + + // Total Tracks tag + var trackTotalLog = Regex.Match(trackRequest, "\"tracks_count\":(?[0-9]+)").Groups; + var trackTotal = trackTotalLog[1].Value; + + // Display Total Tracks in text box under cover art. + totalTracksTextbox.Invoke(new Action(() => totalTracksTextbox.Text = trackTotal)); + + // Total Discs tag + var discTotalLog = Regex.Match(trackRequest, "\"media_count\":(?[0-9]+)").Groups; + var discTotal = discTotalLog[1].Value; + #endregion + + #region Filename Number Padding + // Set default track number padding length + var paddingLength = 2; + + // Prepare track number padding in filename. + string paddingLog = trackTotal.Length.ToString(); + if (paddingLog == "1") + { + paddingLength = 2; + } + else + { + paddingLength = trackTotal.Length; + } + + // Set default disc number padding length + var paddingDiscLength = 2; + + // Prepare disc number padding in filename. + string paddingDiscLog = discTotal.Length.ToString(); + if (paddingDiscLog == "1") + { + paddingDiscLength = 1; + } + else + { + paddingDiscLength = discTotal.Length; + } + #endregion + + #region Create Directories + // Create strings for disc folders + string discFolder = null; + string discFolderCreate = null; + + // If more than 1 disc, create folders for discs. Otherwise, strings will remain null. + if (discTotal != "1") + { + discFolder = "CD " + discNumber.PadLeft(paddingDiscLength, '0') + "\\"; + discFolderCreate = "\\CD " + discNumber.PadLeft(paddingDiscLength, '0') + "\\"; + } + + System.IO.Directory.CreateDirectory(loc + "\\" + "- Favorites" + "\\" + albumArtistPath); + System.IO.Directory.CreateDirectory(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]"); + System.IO.Directory.CreateDirectory(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath); + System.IO.Directory.CreateDirectory(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + discFolderCreate); + + string discogPath = loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + discFolderCreate; + #endregion + + #region Availability Check (Streamable?) + // Check if available for streaming. + var streamCheckLog = Regex.Match(trackRequest, "\"track_number\":(?.*?)\"streamable\":(?.*?),\"").Groups; + var streamCheck = streamCheckLog[2].Value; + + if (streamCheck != "true") + { + if (streamableCheckbox.Checked == true) + { + output.Invoke(new Action(() => output.AppendText("Track " + trackNumber + " \"" + trackName + "\" is not available for streaming. Skipping track...\r\n"))); + System.Threading.Thread.Sleep(800); + continue; + } + else + { + output.Invoke(new Action(() => output.AppendText("\r\nTrack " + trackNumber + " \"" + trackName + "\" is not available for streaming. But stremable check is being ignored for debugging, or messed up releases. Attempting to download...\r\n"))); + } + } + #endregion + + #region Check if File Exists + // Check if there is a version name. + if (versionName == null | versionName == "") + { + if (System.IO.File.Exists(discogPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + audioFileType)) + { + output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + "\" already exists. Skipping.\r\n"))); + System.Threading.Thread.Sleep(800); + continue; + } + } + else + { + if (System.IO.File.Exists(discogPath + "\\" + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + " (" + versionNamePath + ")" + audioFileType)) + { + output.Invoke(new Action(() => output.AppendText("File for \"" + trackNumber.PadLeft(paddingLength, '0') + " " + trackName + " (" + versionName + ")" + "\" already exists. Skipping.\r\n"))); + System.Threading.Thread.Sleep(800); + continue; + } + } + #endregion + + // Close web request and create streaming URL. + trackwr.Abort(); + createURL(sender, e); + + try + { + #region Downloading + // Check if there is a version name. + if (versionName == null | versionName == "") + { + output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " ......"))); + } + else + { + output.Invoke(new Action(() => output.AppendText("Downloading - " + trackNumber.PadLeft(paddingLength, '0') + " - " + trackName + " (" + versionName + ")" + " ......"))); + } + // Being download process. + var client = new HttpClient(); + // Run through TLS to allow secure connection. + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3; + // Set "range" header to nearly unlimited. + client.DefaultRequestHeaders.Range = new RangeHeaderValue(0, 999999999999); + // Set user-agent to Firefox. + client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0"); + // Set referer URL to album ID. + client.DefaultRequestHeaders.Add("Referer", "https://play.qobuz.com/album/" + albumIdDiscog); + // Download the URL in the "Streamed URL" Textbox (Will most likely be replaced). + using (var stream = await client.GetStreamAsync(testURLBox.Text)) + + // Save single track in selected path. + if (versionNamePath == null | versionNamePath == "") + { + // If there is NOT a version name. + using (var output = System.IO.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + audioFileType)) + { + await stream.CopyToAsync(output); + } + } + else + { + // If there is a version name. + using (var output = System.IO.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + " (" + versionNamePath + ")" + audioFileType)) + { + await stream.CopyToAsync(output); + } + } + #endregion + + #region Cover Art Saving + if (System.IO.File.Exists(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg")) + { + // Skip, don't re-download. + } + else + { + if (imageCheckbox.Checked == true) + { + // Save cover art to selected path (Currently happens every time a track is downloaded). + using (WebClient imgClient = new WebClient()) + { + // Download max quality Cover Art to "Cover.jpg" file in chosen path. + imgClient.DownloadFile(new Uri(frontCoverImg), loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + } + } + } + #endregion + + #region Tagging + // Check if audio file type is FLAC or MP3 + if (audioFileType == ".mp3") + { + #region MP3 Tagging (Needs Work) + // Select the downloaded file to prepare for tagging. + // Check if there's a version name or not + if (versionName == null | versionName == "") + { + // If there is NOT a version name. + var tfile = TagLib.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + audioFileType); + // For custom / troublesome tags. + TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2); + + + // Saving cover art to file(s) + if (imageCheckbox.Checked == true) + { + // Define cover art to use for MP3 file(s) + TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame(); + pic.TextEncoding = TagLib.StringType.Latin1; + pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg; + pic.Type = TagLib.PictureType.FrontCover; + pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + + // Save cover art to MP3 file. + tfile.Tag.Pictures = new TagLib.IPicture[1] { pic }; + tfile.Save(); + } + + // Track Title tag + if (trackTitleCheckbox.Checked == true) + { + tfile.Tag.Title = trackName; + } + + // Album Title tag + if (albumCheckbox.Checked == true) + { + tfile.Tag.Album = albumName; + } + + // Album Artits tag + if (albumArtistCheckbox.Checked == true) + { + tfile.Tag.AlbumArtists = new string[] { albumArtist }; + } + + // Track Artist tag + if (artistCheckbox.Checked == true) + { + tfile.Tag.Performers = new string[] { performerName }; + } + + // Composer tag + if (composerCheckbox.Checked == true) + { + tfile.Tag.Composers = new string[] { composerName }; + } + + // Release Date tag + if (releaseCheckbox.Checked == true) + { + releaseDate = releaseDate.Substring(0, 4); + tfile.Tag.Year = UInt32.Parse(releaseDate); + } + + // Genre tag + if (genreCheckbox.Checked == true) + { + tfile.Tag.Genres = new string[] { genre }; + } + + // Track Number tag + if (trackNumberCheckbox.Checked == true) + { + tfile.Tag.Track = UInt32.Parse(trackNumber); + } + + // Disc Number tag + if (discNumberCheckbox.Checked == true) + { + tfile.Tag.Disc = UInt32.Parse(discNumber); + } + + // Total Discs tag + if (discTotalCheckbox.Checked == true) + { + tfile.Tag.DiscCount = UInt32.Parse(discTotal); + } + + // Total Tracks tag + if (trackTotalCheckbox.Checked == true) + { + tfile.Tag.TrackCount = UInt32.Parse(trackTotal); + } + + // Comment tag + if (commentCheckbox.Checked == true) + { + tfile.Tag.Comment = commentTextbox.Text; + } + + // Copyright tag + if (copyrightCheckbox.Checked == true) + { + tfile.Tag.Copyright = copyright; + } + // UPC tag + if (upcCheckbox.Checked == true) + { + // Not available on MP3 at the moment + } + + // ISRC tag + if (isrcCheckbox.Checked == true) + { + TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true); + tag.SetTextFrame("TSRC", isrc); + } + + // Explicit tag + if (explicitCheckbox.Checked == true) + { + // Not available on MP3 at the moment + } + + // Save all selected tags to file + tfile.Save(); + } + else + { + // If there is a version name. + var tfile = TagLib.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + " (" + versionNamePath + ")" + audioFileType); + // For custom / troublesome tags. + TagLib.Id3v2.Tag t = (TagLib.Id3v2.Tag)tfile.GetTag(TagLib.TagTypes.Id3v2); + + + // Saving cover art to file(s) + if (imageCheckbox.Checked == true) + { + // Define cover art to use for FLAC file(s) + TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame(); + pic.TextEncoding = TagLib.StringType.Latin1; + pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg; + pic.Type = TagLib.PictureType.FrontCover; + pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + + // Save cover art to FLAC file. + tfile.Tag.Pictures = new TagLib.IPicture[1] { pic }; + tfile.Save(); + } + + // Track Title tag + if (trackTitleCheckbox.Checked == true) + { + tfile.Tag.Title = trackName + " (" + versionName + ")"; + } + + // Album Title tag + if (albumCheckbox.Checked == true) + { + tfile.Tag.Album = albumName; + } + + // Album Artits tag + if (albumArtistCheckbox.Checked == true) + { + tfile.Tag.AlbumArtists = new string[] { albumArtist }; + } + + // Track Artist tag + if (artistCheckbox.Checked == true) + { + tfile.Tag.Performers = new string[] { performerName }; + } + + // Composer tag + if (composerCheckbox.Checked == true) + { + tfile.Tag.Composers = new string[] { composerName }; + } + + // Release Date tag + if (releaseCheckbox.Checked == true) + { + releaseDate = releaseDate.Substring(0, 4); + tfile.Tag.Year = UInt32.Parse(releaseDate); + } + + // Genre tag + if (genreCheckbox.Checked == true) + { + tfile.Tag.Genres = new string[] { genre }; + } + + // Track Number tag + if (trackNumberCheckbox.Checked == true) + { + tfile.Tag.Track = UInt32.Parse(trackNumber); + } + + // Disc Number tag + if (discNumberCheckbox.Checked == true) + { + tfile.Tag.Disc = UInt32.Parse(discNumber); + } + + // Total Discs tag + if (discTotalCheckbox.Checked == true) + { + tfile.Tag.DiscCount = UInt32.Parse(discTotal); + } + + // Total Tracks tag + if (trackTotalCheckbox.Checked == true) + { + tfile.Tag.TrackCount = UInt32.Parse(trackTotal); + } + + // Comment tag + if (commentCheckbox.Checked == true) + { + tfile.Tag.Comment = commentTextbox.Text; + } + + // Copyright tag + if (copyrightCheckbox.Checked == true) + { + tfile.Tag.Copyright = copyright; + } + // UPC tag + if (upcCheckbox.Checked == true) + { + // Not available on MP3 at the moment + } + + // ISRC tag + if (isrcCheckbox.Checked == true) + { + TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)tfile.GetTag(TagTypes.Id3v2, true); + tag.SetTextFrame("TSRC", isrc); + } + + // Explicit tag + if (explicitCheckbox.Checked == true) + { + // Not available on MP3 at the moment + } + + // Save all selected tags to file + tfile.Save(); + } + #endregion + } + else + { + #region FLAC Tagging + // Select the downloaded file to prepare for tagging. + // Check if there's a version name or not + if (versionName == null | versionName == "") + { + // If there is NOT a version name. + var tfile = TagLib.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + audioFileType); + // For custom / troublesome tags. + var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph); + + + // Saving cover art to file(s) + if (imageCheckbox.Checked == true) + { + // Define cover art to use for FLAC file(s) + TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame(); + pic.TextEncoding = TagLib.StringType.Latin1; + pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg; + pic.Type = TagLib.PictureType.FrontCover; + pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + + // Save cover art to FLAC file. + tfile.Tag.Pictures = new TagLib.IPicture[1] { pic }; + tfile.Save(); + } + + // Track Title tag + if (trackTitleCheckbox.Checked == true) + { + tfile.Tag.Title = trackName; + } + + // Album Title tag + if (albumCheckbox.Checked == true) + { + tfile.Tag.Album = albumName; + } + + // Album Artits tag + if (albumArtistCheckbox.Checked == true) + { + custom.SetField("ALBUMARTIST", new string[] { albumArtist }); + } + + // Track Artist tag + if (artistCheckbox.Checked == true) + { + custom.SetField("ARTIST", new string[] { performerName }); + } + + // Composer tag + if (composerCheckbox.Checked == true) + { + custom.SetField("COMPOSER", new string[] { composerName }); + } + + // Release Date tag + if (releaseCheckbox.Checked == true) + { + custom.SetField("YEAR", new string[] { releaseDate }); + } + + // Genre tag + if (genreCheckbox.Checked == true) + { + custom.SetField("GENRE", new string[] { genre }); + } + + // Track Number tag + if (trackNumberCheckbox.Checked == true) + { + tfile.Tag.Track = UInt32.Parse(trackNumber); + } + + // Disc Number tag + if (discNumberCheckbox.Checked == true) + { + tfile.Tag.Disc = UInt32.Parse(discNumber); + } + + // Total Discs tag + if (discTotalCheckbox.Checked == true) + { + tfile.Tag.DiscCount = UInt32.Parse(discTotal); + } + + // Total Tracks tag + if (trackTotalCheckbox.Checked == true) + { + tfile.Tag.TrackCount = UInt32.Parse(trackTotal); + } + + // Comment tag + if (commentCheckbox.Checked == true) + { + custom.SetField("COMMENT", new string[] { commentTextbox.Text }); + } + + // Copyright tag + if (copyrightCheckbox.Checked == true) + { + custom.SetField("COPYRIGHT", new string[] { copyright }); + } + // UPC tag + if (upcCheckbox.Checked == true) + { + custom.SetField("UPC", new string[] { upc }); + } + + // ISRC tag + if (isrcCheckbox.Checked == true) + { + custom.SetField("ISRC", new string[] { isrc }); + } + + // Explicit tag + if (explicitCheckbox.Checked == true) + { + if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); } + } + + // Save all selected tags to file + tfile.Save(); + } + else + { + // If there is a version name. + var tfile = TagLib.File.Create(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + discFolder + trackNumber.PadLeft(paddingLength, '0') + " " + trackNamePath.Trim() + " (" + versionNamePath + ")" + audioFileType); + // For custom / troublesome tags. + var custom = (TagLib.Ogg.XiphComment)tfile.GetTag(TagLib.TagTypes.Xiph); + + + // Saving cover art to file(s) + if (imageCheckbox.Checked == true) + { + // Define cover art to use for FLAC file(s) + TagLib.Id3v2.AttachedPictureFrame pic = new TagLib.Id3v2.AttachedPictureFrame(); + pic.TextEncoding = TagLib.StringType.Latin1; + pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg; + pic.Type = TagLib.PictureType.FrontCover; + pic.Data = TagLib.ByteVector.FromPath(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Cover.jpg"); + + // Save cover art to FLAC file. + tfile.Tag.Pictures = new TagLib.IPicture[1] { pic }; + tfile.Save(); + } + + // Track Title tag + if (trackTitleCheckbox.Checked == true) + { + tfile.Tag.Title = trackName + " (" + versionName + ")"; + } + + // Album Title tag + if (albumCheckbox.Checked == true) + { + tfile.Tag.Album = albumName; + } + + // Album Artits tag + if (albumArtistCheckbox.Checked == true) + { + custom.SetField("ALBUMARTIST", new string[] { albumArtist }); + } + + // Track Artist tag + if (artistCheckbox.Checked == true) + { + custom.SetField("ARTIST", new string[] { performerName }); + } + + // Composer tag + if (composerCheckbox.Checked == true) + { + custom.SetField("COMPOSER", new string[] { composerName }); + } + + // Release Date tag + if (releaseCheckbox.Checked == true) + { + custom.SetField("YEAR", new string[] { releaseDate }); + } + + // Genre tag + if (genreCheckbox.Checked == true) + { + custom.SetField("GENRE", new string[] { genre }); + } + + // Track Number tag + if (trackNumberCheckbox.Checked == true) + { + tfile.Tag.Track = UInt32.Parse(trackNumber); + } + + // Disc Number tag + if (discNumberCheckbox.Checked == true) + { + tfile.Tag.Disc = UInt32.Parse(discNumber); + } + + // Total Discs tag + if (discTotalCheckbox.Checked == true) + { + tfile.Tag.DiscCount = UInt32.Parse(discTotal); + } + + // Total Tracks tag + if (trackTotalCheckbox.Checked == true) + { + tfile.Tag.TrackCount = UInt32.Parse(trackTotal); + } + + // Comment tag + if (commentCheckbox.Checked == true) + { + custom.SetField("COMMENT", new string[] { commentTextbox.Text }); + } + + // Copyright tag + if (copyrightCheckbox.Checked == true) + { + custom.SetField("COPYRIGHT", new string[] { copyright }); + } + // UPC tag + if (upcCheckbox.Checked == true) + { + custom.SetField("UPC", new string[] { upc }); + } + + // ISRC tag + if (isrcCheckbox.Checked == true) + { + custom.SetField("ISRC", new string[] { isrc }); + } + + // Explicit tag + if (explicitCheckbox.Checked == true) + { + if (advisory == "false") { custom.SetField("ITUNESADVISORY", new string[] { "0" }); } else { custom.SetField("ITUNESADVISORY", new string[] { "1" }); } + } + + // Save all selected tags to file + tfile.Save(); + } + #endregion + } + #endregion + + #region Digital Booklet + // If a booklet was found, save it. + if (goodiesPDF == null | goodiesPDF == "") + { + // No need to download something that doesn't exist. + } + else + { + if (System.IO.File.Exists(loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Digital Booklet.pdf")) + { + // Skip, don't re-download. + } + else + { + // Save digital booklet to selected path + output.Invoke(new Action(() => output.AppendText("\r\nGoodies found, downloading..."))); + using (WebClient bookClient = new WebClient()) + { + // Download max quality Cover Art to "Cover.jpg" file in chosen path. + bookClient.DownloadFile(new Uri(goodiesPDF), loc + "\\" + "- Favorites" + "\\" + albumArtistPath + "\\" + albumNamePath + " [" + albumIdDiscog + "]" + "\\" + qualityPath + "\\" + "Digital Booklet.pdf"); + } + } + } + #endregion + } + catch (Exception downloadError) + { + // If there is an issue trying to, or during the download, show error info. + string error = downloadError.ToString(); + output.Invoke(new Action(() => output.AppendText("\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText("Track Download ERROR. Information below.\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText(error))); + output.Invoke(new Action(() => output.AppendText("\r\n\r\nIf some tracks aren't available for streaming on the album you're trying to download, try to manually download the available tracks individually."))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + + // Say when a track is done downloading, then wait for the next track / end. + output.Invoke(new Action(() => output.AppendText("Track Download Done!\r\n"))); + System.Threading.Thread.Sleep(800); + } + + // Say that downloading is completed. + output.Invoke(new Action(() => output.AppendText("\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText("Downloading job completed! All downloaded files will be located in your chosen path."))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + } + catch (Exception ex) + { + string error = ex.ToString(); + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("Failed to download (First Phase). Error information below.\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText(error))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + } + } + catch (Exception downloadError) + { + // If there is an issue trying to, or during the download, show error info. + string error = downloadError.ToString(); + output.Invoke(new Action(() => output.Text = String.Empty)); + output.Invoke(new Action(() => output.AppendText("Label Download ERROR. Information below.\r\n\r\n"))); + output.Invoke(new Action(() => output.AppendText(error))); + mp3Checkbox.Invoke(new Action(() => mp3Checkbox.Visible = true)); + flacLowCheckbox.Invoke(new Action(() => flacLowCheckbox.Visible = true)); + flacMidCheckbox.Invoke(new Action(() => flacMidCheckbox.Visible = true)); + flacHighCheckbox.Invoke(new Action(() => flacHighCheckbox.Visible = true)); + downloadButton.Invoke(new Action(() => downloadButton.Enabled = true)); + return; + } + #endregion + } + + #endregion + // For downloading "album" links private async void downloadAlbumBG_DoWork(object sender, DoWorkEventArgs e) { @@ -2906,11 +5129,8 @@ namespace QobuzDownloaderX genre = decodedGenre.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); // Release Date tag, grabs the available "stream" date - //var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; - var releaseDateLog = Regex.Match(trackRequest, ",\"released_at\":(?.*?),").Groups; - long dateLong = long.Parse(releaseDateLog[1].Value); - var releaseDate = dateTime.AddSeconds(dateLong).ToString(); - releaseDate = DateConvertion(releaseDate); + var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; + var releaseDate = releaseDateLog[1].Value; // Display release date in text box under cover art. releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate)); @@ -3917,11 +6137,11 @@ namespace QobuzDownloaderX genre = genre.Replace("\\\"", "\"").Replace(@"\\/", @"/").Replace(@"\\", @"\").Replace(@"\/", @"/"); // Release Date tag, grabs the available "stream" date - //var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; - var releaseDateLog = Regex.Match(trackRequest, ",\"released_at\":(?.*?),").Groups; - long dateLong = long.Parse(releaseDateLog[1].Value); - var releaseDate = dateTime.AddSeconds(dateLong).ToString(); - releaseDate = DateConvertion(releaseDate); + var releaseDateLog = Regex.Match(trackRequest, "\"release_date_stream\":\"(?.*?)\",\\\"").Groups; + var releaseDate = releaseDateLog[1].Value; + + // Display release date in text box under cover art. + releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate)); // Display release date in text box under cover art. releaseDateTextBox.Invoke(new Action(() => releaseDateTextBox.Text = releaseDate)); diff --git a/QobuzDownloaderX/Form1.resx b/QobuzDownloaderX/Form1.resx index 7db22b9..0c6fece 100644 --- a/QobuzDownloaderX/Form1.resx +++ b/QobuzDownloaderX/Form1.resx @@ -138,6 +138,12 @@ 901, 13 + + 1065, 13 + + + 1229, 13 + diff --git a/QobuzDownloaderX/LoginForm-v2.Designer.cs b/QobuzDownloaderX/LoginForm-v2.Designer.cs index ee44d92..bf72fd2 100644 --- a/QobuzDownloaderX/LoginForm-v2.Designer.cs +++ b/QobuzDownloaderX/LoginForm-v2.Designer.cs @@ -30,6 +30,7 @@ { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LoginFrm)); this.panel1 = new System.Windows.Forms.Panel(); + this.disableLogin = new System.Windows.Forms.CheckBox(); this.verNumLabel2 = new System.Windows.Forms.Label(); this.exitLabel = new System.Windows.Forms.Label(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); @@ -43,7 +44,6 @@ this.getSecretBG = new System.ComponentModel.BackgroundWorker(); this.loginBG = new System.ComponentModel.BackgroundWorker(); this.visableCheckbox = new System.Windows.Forms.CheckBox(); - this.disableLogin = new System.Windows.Forms.CheckBox(); this.panel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.SuspendLayout(); @@ -53,6 +53,7 @@ this.panel1.BackgroundImage = global::QobuzDownloaderX.Properties.Resources.login_frame; this.panel1.Controls.Add(this.disableLogin); this.panel1.Controls.Add(this.verNumLabel2); + this.panel1.Controls.Add(this.md5Button); this.panel1.Controls.Add(this.exitLabel); this.panel1.Controls.Add(this.pictureBox1); this.panel1.Dock = System.Windows.Forms.DockStyle.Top; @@ -62,6 +63,18 @@ this.panel1.TabIndex = 0; this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove); // + // disableLogin + // + this.disableLogin.AutoSize = true; + this.disableLogin.ForeColor = System.Drawing.Color.Transparent; + this.disableLogin.Location = new System.Drawing.Point(12, 155); + this.disableLogin.Name = "disableLogin"; + this.disableLogin.Size = new System.Drawing.Size(90, 17); + this.disableLogin.TabIndex = 34; + this.disableLogin.Text = "Disable Login"; + this.disableLogin.UseVisualStyleBackColor = true; + this.disableLogin.Visible = false; + // // verNumLabel2 // this.verNumLabel2.BackColor = System.Drawing.Color.Transparent; @@ -167,16 +180,18 @@ // md5Button // this.md5Button.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(112)))), ((int)(((byte)(239))))); + this.md5Button.Enabled = false; this.md5Button.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); this.md5Button.FlatAppearance.BorderSize = 2; this.md5Button.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.md5Button.ForeColor = System.Drawing.Color.White; - this.md5Button.Location = new System.Drawing.Point(227, 250); + this.md5Button.Location = new System.Drawing.Point(227, 122); this.md5Button.Name = "md5Button"; this.md5Button.Size = new System.Drawing.Size(43, 27); this.md5Button.TabIndex = 9; this.md5Button.Text = "MD5"; this.md5Button.UseVisualStyleBackColor = false; + this.md5Button.Visible = false; this.md5Button.Click += new System.EventHandler(this.md5Button_Click); // // loginText @@ -201,25 +216,13 @@ // visableCheckbox // this.visableCheckbox.AutoSize = true; - this.visableCheckbox.Location = new System.Drawing.Point(206, 257); + this.visableCheckbox.Location = new System.Drawing.Point(255, 256); this.visableCheckbox.Name = "visableCheckbox"; this.visableCheckbox.Size = new System.Drawing.Size(15, 14); this.visableCheckbox.TabIndex = 31; this.visableCheckbox.UseVisualStyleBackColor = true; this.visableCheckbox.CheckedChanged += new System.EventHandler(this.visableCheckbox_CheckedChanged); // - // disableLogin - // - this.disableLogin.AutoSize = true; - this.disableLogin.ForeColor = System.Drawing.Color.Transparent; - this.disableLogin.Location = new System.Drawing.Point(12, 155); - this.disableLogin.Name = "disableLogin"; - this.disableLogin.Size = new System.Drawing.Size(90, 17); - this.disableLogin.TabIndex = 34; - this.disableLogin.Text = "Disable Login"; - this.disableLogin.UseVisualStyleBackColor = true; - this.disableLogin.Visible = false; - // // LoginFrm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -228,7 +231,6 @@ this.ClientSize = new System.Drawing.Size(282, 377); this.Controls.Add(this.visableCheckbox); this.Controls.Add(this.loginText); - this.Controls.Add(this.md5Button); this.Controls.Add(this.panel4); this.Controls.Add(this.panel3); this.Controls.Add(this.passwordTextbox); diff --git a/QobuzDownloaderX/LoginForm-v2.cs b/QobuzDownloaderX/LoginForm-v2.cs index 471f8e3..80b36bd 100644 --- a/QobuzDownloaderX/LoginForm-v2.cs +++ b/QobuzDownloaderX/LoginForm-v2.cs @@ -192,12 +192,6 @@ namespace QobuzDownloaderX private void loginButton_Click(object sender, EventArgs e) { - //if (appidTextbox.Text == "app_id" | appidTextbox.Text == null | appidTextbox.Text == "") - //{ - // // If there's no app_id typed in. - // loginText.Invoke(new Action(() => loginText.Text = "No app_id, please input app_id first.")); - // return; - //} if (emailTextbox.Text == "Email" | emailTextbox.Text == null | emailTextbox.Text == "") { // If there's no email typed in. @@ -205,13 +199,37 @@ namespace QobuzDownloaderX return; } - var passMD5CheckLog = Regex.Match(passwordTextbox.Text, "(?^[0-9a-f]{32}$)").Groups; + if (passwordTextbox.Text == "Password") + { + // If there's no password typed in. + loginText.Invoke(new Action(() => loginText.Text = "No password typed, please input password first.")); + return; + } + + string plainTextPW = passwordTextbox.Text; + + var passMD5CheckLog = Regex.Match(plainTextPW, "(?^[0-9a-f]{32}$)").Groups; var passMD5Check = passMD5CheckLog[1].Value; if (passMD5Check == null | passMD5Check == "") { - loginText.Text = "Password not MD5! Hit \"MD5\" before logging in!"; - return; + // Generate the MD5 hash using the string created above. + using (MD5 md5PassHash = MD5.Create()) + { + string hashedPW = GetMd5Hash(md5PassHash, plainTextPW); + + if (VerifyMd5Hash(md5PassHash, plainTextPW, hashedPW)) + { + // If the MD5 hash is verified, proceed to get the streaming URL. + passwordTextbox.Text = hashedPW; + } + else + { + // If the hash can't be verified. + loginText.Invoke(new Action(() => loginText.Text = "Hashing failed. Please retry.")); + return; + } + } } // Save info locally to be used on next launch. @@ -373,32 +391,32 @@ namespace QobuzDownloaderX private void md5Button_Click(object sender, EventArgs e) { - if (passwordTextbox.Text == "Password") - { - // If there's no password typed in. - loginText.Invoke(new Action(() => loginText.Text = "No password typed, please input password first.")); - return; - } + //if (passwordTextbox.Text == "Password") + //{ + // // If there's no password typed in. + // loginText.Invoke(new Action(() => loginText.Text = "No password typed, please input password first.")); + // return; + //} - string plainTextPW = passwordTextbox.Text; + //string plainTextPW = passwordTextbox.Text; - // Generate the MD5 hash using the string created above. - using (MD5 md5PassHash = MD5.Create()) - { - string hashedPW = GetMd5Hash(md5PassHash, plainTextPW); + //// Generate the MD5 hash using the string created above. + //using (MD5 md5PassHash = MD5.Create()) + //{ + // string hashedPW = GetMd5Hash(md5PassHash, plainTextPW); - if (VerifyMd5Hash(md5PassHash, plainTextPW, hashedPW)) - { - // If the MD5 hash is verified, proceed to get the streaming URL. - passwordTextbox.Text = hashedPW; - } - else - { - // If the hash can't be verified. - loginText.Invoke(new Action(() => loginText.Text = "Hashing failed. Please retry.")); - return; - } - } + // if (VerifyMd5Hash(md5PassHash, plainTextPW, hashedPW)) + // { + // // If the MD5 hash is verified, proceed to get the streaming URL. + // passwordTextbox.Text = hashedPW; + // } + // else + // { + // // If the hash can't be verified. + // loginText.Invoke(new Action(() => loginText.Text = "Hashing failed. Please retry.")); + // return; + // } + //} } private void getSecretBG_DoWork(object sender, DoWorkEventArgs e) @@ -486,6 +504,11 @@ namespace QobuzDownloaderX string loginRequest = sr.ReadToEnd(); string text = loginRequest; + // Grab user_id + var userIDLog = Regex.Match(loginRequest, "{\"user\":{\"id\":(?.*?),\"publicId").Groups; + var userID = userIDLog[1].Value; + qbdlx.userID = userID; + // Grab display name var displayNameLog = Regex.Match(loginRequest, "\"display_name\":\"(?.*?)\",\\\"").Groups; var displayName = displayNameLog[1].Value; diff --git a/QobuzDownloaderX/Properties/AssemblyInfo.cs b/QobuzDownloaderX/Properties/AssemblyInfo.cs index ae6dacd..e7b5d87 100644 --- a/QobuzDownloaderX/Properties/AssemblyInfo.cs +++ b/QobuzDownloaderX/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // 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("0.9.9.10")] -[assembly: AssemblyFileVersion("0.9.9.10")] +[assembly: AssemblyVersion("0.9.9.11")] +[assembly: AssemblyFileVersion("0.9.9.11")]