private void buttonStart_Click(object sender, RoutedEventArgs e) { if (textBoxUrls.Text == Constants.UrlsHint) { // No URL to look Log("Paste some albums URLs to be downloaded", LogType.Error); return; } int coverArtMaxSize = 0; if (checkBoxResizeCoverArt.IsChecked.Value && !Int32.TryParse(textBoxCoverArtMaxSize.Text, out coverArtMaxSize)) { Log("Cover art max width/height must be an integer", LogType.Error); return; } this.userCancelled = false; this.pendingDownloads = new List <WebClient>(); // Set controls to "downloading..." state this.activeDownloads = true; UpdateControlsState(true); Log("Starting download...", LogType.Info); // Get user inputs List <String> userUrls = textBoxUrls.Text.Split(new String[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).ToList(); userUrls = userUrls.Distinct().ToList(); var urls = new List <String>(); var albums = new List <Album>(); Task.Factory.StartNew(() => { // Get URLs of albums to download if (userSettings.DownloadArtistDiscography) { urls = GetArtistDiscography(userUrls); } else { urls = userUrls; } urls = urls.Distinct().ToList(); }).ContinueWith(x => { // Get info on albums albums = GetAlbums(urls); }).ContinueWith(x => { // Save files to download (we'll need the list to update the progressBar) this.filesDownload = GetFilesToDownload(albums, userSettings.SaveCoverArtInTags || userSettings.SaveCoverArtInFolder); }).ContinueWith(x => { // Set progressBar max value long maxProgressBarValue; if (userSettings.RetrieveFilesizes) { maxProgressBarValue = this.filesDownload.Sum(f => f.Size); // Bytes to download } else { maxProgressBarValue = this.filesDownload.Count; // Number of files to download } if (maxProgressBarValue > 0) { this.Dispatcher.Invoke(new Action(() => { progressBar.IsIndeterminate = false; progressBar.Maximum = maxProgressBarValue; TaskbarItemInfo.ProgressState = TaskbarItemProgressState.Normal; })); } }).ContinueWith(x => { // Start downloading albums if (userSettings.DownloadOneAlbumAtATime) { // Download one album at a time foreach (Album album in albums) { DownloadAlbum(album, ParseDownloadLocation(userSettings.DownloadsLocation, album), userSettings.TagTracks, userSettings.SaveCoverArtInTags, userSettings.SaveCoverArtInFolder, userSettings.ConvertCoverArtToJpg, userSettings.ResizeCoverArt, userSettings.CoverArtMaxSize); } } else { // Parallel download Task[] tasks = new Task[albums.Count]; for (int i = 0; i < albums.Count; i++) { Album album = albums[i]; // Mandatory or else => race condition tasks[i] = Task.Factory.StartNew(() => DownloadAlbum(album, ParseDownloadLocation(userSettings.DownloadsLocation, album), userSettings.TagTracks, userSettings.SaveCoverArtInTags, userSettings.SaveCoverArtInFolder, userSettings.ConvertCoverArtToJpg, userSettings.ResizeCoverArt, userSettings.CoverArtMaxSize)); } // Wait for all albums to be downloaded Task.WaitAll(tasks); } }).ContinueWith(x => { if (this.userCancelled) { // Display message if user cancelled Log("Downloads cancelled by user", LogType.Info); } // Set controls to "ready" state this.activeDownloads = false; UpdateControlsState(false); // Play a sound try { (new SoundPlayer(@"C:\Windows\Media\Windows Ding.wav")).Play(); } catch { } }); }
/// <summary> /// Downloads the cover art. /// </summary> /// <param name="album">The album to download.</param> /// <param name="downloadsFolder">The downloads folder.</param> /// <param name="saveCovertArtInFolder">True to save cover art in the downloads folder; false otherwise.</param> /// <param name="convertCoverArtToJpg">True to convert the cover art to jpg; false otherwise.</param> /// <param name="resizeCoverArt">True to resize the covert art; false otherwise.</param> /// <param name="coverArtMaxSize">The maximum width/height of the cover art when resizing.</param> /// <returns></returns> private TagLib.Picture DownloadCoverArt(Album album, String downloadsFolder, Boolean saveCovertArtInFolder, Boolean convertCoverArtToJpg, Boolean resizeCoverArt, int coverArtMaxSize) { // Compute path where to save artwork String artworkPath = (saveCovertArtInFolder ? downloadsFolder : Path.GetTempPath()) + "\\" + album.Title.ToAllowedFileName() + Path.GetExtension(album.ArtworkUrl); if (artworkPath.Length > 256) { // Shorten the path (Windows doesn't support a path > 256 characters) artworkPath = (saveCovertArtInFolder ? downloadsFolder : Path.GetTempPath()) + "\\" + album.Title.ToAllowedFileName().Substring(0, 3) + Path.GetExtension(album.ArtworkUrl); } TagLib.Picture artwork = null; int tries = 0; Boolean artworkDownloaded = false; do { var doneEvent = new AutoResetEvent(false); using (var webClient = new WebClient()) { if (webClient.Proxy != null) { webClient.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials; } // Update progress bar when downloading webClient.DownloadProgressChanged += (s, e) => { UpdateProgress(album.ArtworkUrl, e.BytesReceived); }; // Warn when downloaded webClient.DownloadFileCompleted += (s, e) => { if (!e.Cancelled && e.Error == null) { artworkDownloaded = true; // Convert/resize artwork if (userSettings.ConvertCoverArtToJpg || userSettings.ResizeCoverArt) { var settings = new ResizeSettings(); if (convertCoverArtToJpg) { settings.Format = "jpg"; settings.Quality = 90; } if (resizeCoverArt) { settings.MaxHeight = userSettings.CoverArtMaxSize; settings.MaxWidth = userSettings.CoverArtMaxSize; } ImageBuilder.Current.Build(artworkPath, artworkPath, settings); } artwork = new TagLib.Picture(artworkPath) { Description = "Picture" }; // Delete the cover art file if it was saved in Temp if (!saveCovertArtInFolder) { try { System.IO.File.Delete(artworkPath); } catch { // Could not delete the file. Nevermind, it's in Temp/ folder... } } // Note the file as downloaded TrackFile currentFile = this.filesDownload.Where(f => f.Url == album.ArtworkUrl).First(); currentFile.Downloaded = true; Log($"Downloaded artwork for album \"{album.Title}\"", LogType.IntermediateSuccess); } else if (!e.Cancelled && e.Error != null) { if (tries < userSettings.DownloadMaxTries) { Log($"Unable to download artwork for album \"{album.Title}\". Try {tries} of {userSettings.DownloadMaxTries}", LogType.Warning); } else { Log($"Unable to download artwork for album \"{album.Title}\". Hit max retries of {userSettings.DownloadMaxTries}", LogType.Error); } } // Else the download has been cancelled (by the user) doneEvent.Set(); }; lock (this.pendingDownloads) { if (this.userCancelled) { // Abort return(null); } // Register current download this.pendingDownloads.Add(webClient); // Start download webClient.DownloadFileAsync(new Uri(album.ArtworkUrl), artworkPath); } // Wait for download to be finished doneEvent.WaitOne(); lock (this.pendingDownloads) { this.pendingDownloads.Remove(webClient); } } } while (!artworkDownloaded && tries < userSettings.DownloadMaxTries); return(artwork); }
/// <summary> /// Downloads and tags a track. Returns true if the track has been correctly downloaded; false otherwise. /// </summary> /// <param name="albumDirectoryPath">The path where to save the tracks.</param> /// <param name="album">The album of the track to download.</param> /// <param name="track">The track to download.</param> /// <param name="tagTrack">True to tag the track; false otherwise.</param> /// <param name="saveCoverArtInTags">True to save the cover art in the tag tracks; false otherwise.</param> /// <param name="artwork">The cover art.</param> private Boolean DownloadAndTagTrack(String albumDirectoryPath, Album album, Track track, Boolean tagTrack, Boolean saveCoverArtInTags, TagLib.Picture artwork) { Log($"Downloading track \"{track.Title}\" from url: {track.Mp3Url}", LogType.VerboseInfo); // Set location to save the file String trackPath = albumDirectoryPath + "\\" + GetFileName(album, track); if (trackPath.Length > 256) { // Shorten the path (Windows doesn't support a path > 256 characters) trackPath = albumDirectoryPath + "\\" + GetFileName(album, track).Substring(0, 3) + Path.GetExtension(trackPath); } int tries = 0; Boolean trackDownloaded = false; if (File.Exists(trackPath)) { long length = new FileInfo(trackPath).Length; foreach (TrackFile trackFile in filesDownload) { if (track.Mp3Url == trackFile.Url && trackFile.Size > length - (trackFile.Size * userSettings.AllowableFileSizeDifference) && trackFile.Size < length + (trackFile.Size * userSettings.AllowableFileSizeDifference)) { Log($"Track already exists within allowed filesize range: track \"{GetFileName(album, track)}\" from album \"{album.Title}\" - Skipping download!", LogType.IntermediateSuccess); return(false); } } } do { var doneEvent = new AutoResetEvent(false); using (var webClient = new WebClient()) { if (webClient.Proxy != null) { webClient.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials; } // Update progress bar when downloading webClient.DownloadProgressChanged += (s, e) => { UpdateProgress(track.Mp3Url, e.BytesReceived); }; // Warn & tag when downloaded webClient.DownloadFileCompleted += (s, e) => { WaitForCooldown(tries); tries++; if (!e.Cancelled && e.Error == null) { trackDownloaded = true; if (tagTrack) { // Tag (ID3) the file when downloaded TagLib.File tagFile = TagLib.File.Create(trackPath); tagFile.Tag.Album = album.Title; tagFile.Tag.AlbumArtists = new String[1] { album.Artist }; tagFile.Tag.Performers = new String[1] { album.Artist }; tagFile.Tag.Title = track.Title; tagFile.Tag.Track = (uint)track.Number; tagFile.Tag.Year = (uint)album.ReleaseDate.Year; tagFile.Tag.Lyrics = track.Lyrics; tagFile.Save(); } if (saveCoverArtInTags && artwork != null) { // Save cover in tags when downloaded TagLib.File tagFile = TagLib.File.Create(trackPath); tagFile.Tag.Pictures = new TagLib.IPicture[1] { artwork }; tagFile.Save(); } // Note the file as downloaded TrackFile currentFile = this.filesDownload.Where(f => f.Url == track.Mp3Url).First(); currentFile.Downloaded = true; Log($"Downloaded track \"{GetFileName(album, track)}\" from album \"{album.Title}\"", LogType.IntermediateSuccess); } else if (!e.Cancelled && e.Error != null) { if (tries < userSettings.DownloadMaxTries) { Log($"Unable to download track \"{GetFileName(album, track)}\" from album \"{album.Title}\". Try {tries} of {userSettings.DownloadMaxTries}", LogType.Warning); } else { Log($"Unable to download track \"{GetFileName(album, track)}\" from album \"{album.Title}\". Hit max retries of {userSettings.DownloadMaxTries}", LogType.Error); } } // Else the download has been cancelled (by the user) doneEvent.Set(); }; lock (this.pendingDownloads) { if (this.userCancelled) { // Abort return(false); } // Register current download this.pendingDownloads.Add(webClient); // Start download webClient.DownloadFileAsync(new Uri(track.Mp3Url), trackPath); } // Wait for download to be finished doneEvent.WaitOne(); lock (this.pendingDownloads) { this.pendingDownloads.Remove(webClient); } } } while (!trackDownloaded && tries < userSettings.DownloadMaxTries); return(trackDownloaded); }
/// <summary> /// Downloads an album. /// </summary> /// <param name="album">The album to download.</param> /// <param name="downloadsFolder">The downloads folder.</param> /// <param name="tagTracks">True to tag tracks; false otherwise.</param> /// <param name="saveCoverArtInTags">True to save cover art in tags; false otherwise.</param> /// <param name="saveCovertArtInFolder">True to save cover art in the downloads folder; false otherwise.</param> /// <param name="convertCoverArtToJpg">True to convert the cover art to jpg; false otherwise.</param> /// <param name="resizeCoverArt">True to resize the covert art; false otherwise.</param> /// <param name="coverArtMaxSize">The maximum width/height of the cover art when resizing.</param> private void DownloadAlbum(Album album, String downloadsFolder, Boolean tagTracks, Boolean saveCoverArtInTags, Boolean saveCovertArtInFolder, Boolean convertCoverArtToJpg, Boolean resizeCoverArt, int coverArtMaxSize) { if (this.userCancelled) { // Abort return; } // Create directory to place track files String directoryPath = downloadsFolder + "\\" + album.Title.ToAllowedFileName() + "\\"; try { Directory.CreateDirectory(directoryPath); } catch { Log("An error occured when creating the album folder. Make sure you have the rights to write files in the folder you chose", LogType.Error); return; } TagLib.Picture artwork = null; // Download artwork if (saveCoverArtInTags || saveCovertArtInFolder) { artwork = DownloadCoverArt(album, downloadsFolder, saveCovertArtInFolder, convertCoverArtToJpg, resizeCoverArt, coverArtMaxSize); } // Download & tag tracks Task[] tasks = new Task[album.Tracks.Count]; Boolean[] tracksDownloaded = new Boolean[album.Tracks.Count]; for (int i = 0; i < album.Tracks.Count; i++) { // Temporarily save the index or we will have a race condition exception when i hits its maximum value int currentIndex = i; tasks[currentIndex] = Task.Factory.StartNew(() => tracksDownloaded[currentIndex] = DownloadAndTagTrack(directoryPath, album, album.Tracks[currentIndex], tagTracks, saveCoverArtInTags, artwork)); } // Wait for all tracks to be downloaded before saying the album is downloaded Task.WaitAll(tasks); if (!this.userCancelled) { // Tasks have not been aborted if (tracksDownloaded.All(x => x == true)) { Log("Successfully downloaded album \"" + album.Title + "\"", LogType.Success); } else { Log("Finished downloading album \"" + album.Title + "\". Some tracks could not be downloaded", LogType.Success); } } }
/// <summary> /// Downloads the cover art. /// </summary> /// <param name="album">The album to download.</param> /// <param name="downloadsFolder">The downloads folder.</param> /// <param name="saveCovertArtInFolder">True to save cover art in the downloads folder; false otherwise.</param> /// <param name="convertCoverArtToJpg">True to convert the cover art to jpg; false otherwise.</param> /// <param name="resizeCoverArt">True to resize the covert art; false otherwise.</param> /// <param name="coverArtMaxSize">The maximum width/height of the cover art when resizing.</param> /// <returns></returns> private TagLib.Picture DownloadCoverArt(Album album, String downloadsFolder, Boolean saveCovertArtInFolder, Boolean convertCoverArtToJpg, Boolean resizeCoverArt, int coverArtMaxSize) { // Compute path where to save artwork String artworkPath = ( saveCovertArtInFolder ? downloadsFolder + "\\" + album.Title.ToAllowedFileName() : Path.GetTempPath() ) + "\\" + album.Title.ToAllowedFileName() + Path.GetExtension(album.ArtworkUrl); TagLib.Picture artwork = null; int tries = 0; Boolean artworkDownloaded = false; do { var doneEvent = new AutoResetEvent(false); using (var webClient = new WebClient()) { // Update progress bar when downloading webClient.DownloadProgressChanged += (s, e) => { UpdateProgress(album.ArtworkUrl, e.BytesReceived); }; // Warn when downloaded webClient.DownloadFileCompleted += (s, e) => { if (!e.Cancelled && e.Error == null) { artworkDownloaded = true; // Convert/resize artwork if (convertCoverArtToJpg || resizeCoverArt) { var settings = new ResizeSettings(); if (convertCoverArtToJpg) { settings.Format = "jpg"; settings.Quality = 90; } if (resizeCoverArt) { settings.MaxHeight = coverArtMaxSize; settings.MaxWidth = coverArtMaxSize; } ImageBuilder.Current.Build(artworkPath, artworkPath, settings); } artwork = new TagLib.Picture(artworkPath) { Description = "Picture" }; // Delete the cover art file if it was saved in Temp if (!saveCovertArtInFolder) { try { System.IO.File.Delete(artworkPath); } catch { // Could not delete the file. Nevermind, it's in Temp/ folder... } } Log("Downloaded artwork for album \"" + album.Title + "\"", LogType.IntermediateSuccess); } else if (!e.Cancelled && e.Error != null) { if (tries < Constants.DownloadMaxTries) { Log("Unable to download artwork for album \"" + album.Title + "\". " + "Try " + tries + " of " + Constants.DownloadMaxTries, LogType.Warning); } else { Log("Unable to download artwork for album \"" + album.Title + "\". " + "Hit max retries of " + Constants.DownloadMaxTries, LogType.Error); } } // Else the download has been cancelled (by the user) doneEvent.Set(); }; lock (this.pendingDownloads) { if (this.userCancelled) { // Abort return null; } // Register current download this.pendingDownloads.Add(webClient); // Start download webClient.DownloadFileAsync(new Uri(album.ArtworkUrl), artworkPath); } // Wait for download to be finished doneEvent.WaitOne(); lock (this.pendingDownloads) { this.pendingDownloads.Remove(webClient); } } } while (!artworkDownloaded && tries < Constants.DownloadMaxTries); return artwork; }
/// <summary> /// Downloads and tags a track. Returns true if the track has been correctly downloaded; false otherwise. /// </summary> /// <param name="albumDirectoryPath">The path where to save the tracks.</param> /// <param name="album">The album of the track to download.</param> /// <param name="track">The track to download.</param> /// <param name="tagTrack">True to tag the track; false otherwise.</param> /// <param name="saveCoverArtInTags">True to save the cover art in the tag tracks; false otherwise.</param> /// <param name="artwork">The cover art.</param> private Boolean DownloadAndTagTrack(String albumDirectoryPath, Album album, Track track, Boolean tagTrack, Boolean saveCoverArtInTags, TagLib.Picture artwork) { Log("Downloading track \"" + track.Title + "\" from url: " + track.Mp3Url, LogType.VerboseInfo); // Set location to save the file String trackPath = albumDirectoryPath + track.GetFileName(album.Artist); int tries = 0; Boolean trackDownloaded = false; do { var doneEvent = new AutoResetEvent(false); using (var webClient = new WebClient()) { // Update progress bar when downloading webClient.DownloadProgressChanged += (s, e) => { UpdateProgress(track.Mp3Url, e.BytesReceived); }; // Warn & tag when downloaded webClient.DownloadFileCompleted += (s, e) => { tries++; if (!e.Cancelled && e.Error == null) { trackDownloaded = true; if (tagTrack) { // Tag (ID3) the file when downloaded TagLib.File tagFile = TagLib.File.Create(trackPath); tagFile.Tag.Album = album.Title; tagFile.Tag.AlbumArtists = new String[1] { album.Artist }; tagFile.Tag.Performers = new String[1] { album.Artist }; tagFile.Tag.Title = track.Title; tagFile.Tag.Track = (uint) track.Number; tagFile.Tag.Year = (uint) album.ReleaseDate.Year; tagFile.Save(); } if (saveCoverArtInTags && artwork != null) { // Save cover in tags when downloaded TagLib.File tagFile = TagLib.File.Create(trackPath); tagFile.Tag.Pictures = new TagLib.IPicture[1] { artwork }; tagFile.Save(); } Log("Downloaded track \"" + track.GetFileName(album.Artist) + "\" from album \"" + album.Title + "\"", LogType.IntermediateSuccess); } else if (!e.Cancelled && e.Error != null) { if (tries < Constants.DownloadMaxTries) { Log("Unable to download track \"" + track.GetFileName(album.Artist) + "\" from album \"" + album.Title + "\". " + "Try " + tries + " of " + Constants.DownloadMaxTries, LogType.Warning); } else { Log("Unable to download track \"" + track.GetFileName(album.Artist) + "\" from album \"" + album.Title + "\". " + "Hit max retries of " + Constants.DownloadMaxTries, LogType.Error); } } // Else the download has been cancelled (by the user) doneEvent.Set(); }; lock (this.pendingDownloads) { if (this.userCancelled) { // Abort return false; } // Register current download this.pendingDownloads.Add(webClient); // Start download webClient.DownloadFileAsync(new Uri(track.Mp3Url), trackPath); } // Wait for download to be finished doneEvent.WaitOne(); lock (this.pendingDownloads) { this.pendingDownloads.Remove(webClient); } } } while (!trackDownloaded && tries < Constants.DownloadMaxTries); return trackDownloaded; }