diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe5963ad..de7b8255 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+# 0.2.8.2
+
+## Bug fixes
+
+* Fixed the track path stored in playlist files. [#82](https://github.com/Otiel/BandcampDownloader/issues/82)
+
# 0.2.8.1
## Bug fixes
diff --git a/src/BandcampDownloader/App.xaml.cs b/src/BandcampDownloader/App.xaml.cs
index 9f92b000..89b60108 100644
--- a/src/BandcampDownloader/App.xaml.cs
+++ b/src/BandcampDownloader/App.xaml.cs
@@ -7,6 +7,10 @@
namespace BandcampDownloader {
public partial class App: Application {
+ ///
+ /// Random class used to create random numbers.
+ ///
+ public static readonly Random Random = new Random();
///
/// The settings chosen by the user.
diff --git a/src/BandcampDownloader/Helpers/PlaylistHelper.cs b/src/BandcampDownloader/Helpers/PlaylistHelper.cs
index 75ddc0c7..84614abc 100644
--- a/src/BandcampDownloader/Helpers/PlaylistHelper.cs
+++ b/src/BandcampDownloader/Helpers/PlaylistHelper.cs
@@ -70,7 +70,7 @@ private static String CreateM3uPlaylist(Album album) {
Album = album.Title,
AlbumArtist = album.Artist,
Duration = TimeSpan.FromSeconds(track.Duration),
- Path = track.Title + ".mp3",
+ Path = Path.GetFileName(track.Path),
Title = track.Title,
});
}
@@ -88,7 +88,7 @@ private static String CreatePlsPlaylist(Album album) {
foreach (Track track in album.Tracks) {
playlist.PlaylistEntries.Add(new PlsPlaylistEntry() {
Length = TimeSpan.FromSeconds(track.Duration),
- Path = track.Title + ".mp3",
+ Path = Path.GetFileName(track.Path),
Title = track.Title,
});
}
@@ -110,7 +110,7 @@ private static String CreateWplPlaylist(Album album) {
AlbumArtist = album.Artist,
AlbumTitle = album.Title,
Duration = TimeSpan.FromSeconds(track.Duration),
- Path = track.Title + ".mp3",
+ Path = Path.GetFileName(track.Path),
TrackArtist = album.Artist,
TrackTitle = track.Title,
});
@@ -133,7 +133,7 @@ private static String CreateZplPlaylist(Album album) {
AlbumArtist = album.Artist,
AlbumTitle = album.Title,
Duration = TimeSpan.FromSeconds(track.Duration),
- Path = track.Title + ".mp3",
+ Path = Path.GetFileName(track.Path),
TrackArtist = album.Artist,
TrackTitle = track.Title,
});
diff --git a/src/BandcampDownloader/Model/Album.cs b/src/BandcampDownloader/Model/Album.cs
index 30fada41..76d86edf 100644
--- a/src/BandcampDownloader/Model/Album.cs
+++ b/src/BandcampDownloader/Model/Album.cs
@@ -4,17 +4,128 @@
namespace BandcampDownloader {
internal class Album {
+
+ ///
+ /// The album artist.
+ ///
public String Artist { get; set; }
+
+ ///
+ /// The local path (full path with file name) where the artwork file should be saved.
+ ///
+ public String ArtworkPath { get; private set; }
+
+ ///
+ /// The local path (full path with file name) to the %TEMP% folder where the artwork file should be saved.
+ ///
+ public String ArtworkTempPath { get; private set; }
+
+ ///
+ /// The URL where the artwork should be downloaded from.
+ ///
public String ArtworkUrl { get; set; }
+ ///
+ /// True if the album has an artwork; false otherwise.
+ ///
public Boolean HasArtwork {
get {
return ArtworkUrl != null;
}
}
+ ///
+ /// The local path (full path) to the folder where the album should be saved.
+ ///
+ public String Path { get; private set; }
+
+ ///
+ /// The release date of the album.
+ ///
public DateTime ReleaseDate { get; set; }
+
+ ///
+ /// The album title.
+ ///
public String Title { get; set; }
+
+ ///
+ /// The list of tracks contained in the album.
+ ///
public List
/// The album to download.
- /// The path where to save the album.
- private void DownloadAlbum(Album album, String downloadsFolder) {
+ private void DownloadAlbum(Album album) {
if (_userCancelled) {
// Abort
return;
@@ -137,7 +132,7 @@ private void DownloadAlbum(Album album, String downloadsFolder) {
// Create directory to place track files
try {
- Directory.CreateDirectory(downloadsFolder);
+ Directory.CreateDirectory(album.Path);
} 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;
@@ -147,7 +142,7 @@ private void DownloadAlbum(Album album, String downloadsFolder) {
// Download artwork
if ((App.UserSettings.SaveCoverArtInTags || App.UserSettings.SaveCoverArtInFolder) && album.HasArtwork) {
- artwork = DownloadCoverArt(album, downloadsFolder);
+ artwork = DownloadCoverArt(album);
}
// Download & tag tracks
@@ -156,7 +151,7 @@ private void DownloadAlbum(Album album, String downloadsFolder) {
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(downloadsFolder, album, album.Tracks[currentIndex], artwork));
+ tasks[currentIndex] = Task.Factory.StartNew(() => tracksDownloaded[currentIndex] = DownloadAndTagTrack(album, album.Tracks[currentIndex], artwork));
}
// Wait for all tracks to be downloaded before saying the album is downloaded
@@ -164,7 +159,7 @@ private void DownloadAlbum(Album album, String downloadsFolder) {
// Create playlist file
if (App.UserSettings.CreatePlaylist) {
- PlaylistHelper.SavePlaylistForAlbum(album, ParseDownloadPath(App.UserSettings.DownloadsPath, album));
+ PlaylistHelper.SavePlaylistForAlbum(album, album.Path);
Log($"Saved playlist for album \"{album.Title}\"", LogType.IntermediateSuccess);
}
@@ -181,31 +176,22 @@ private void DownloadAlbum(Album album, String downloadsFolder) {
///
/// Downloads and tags a track. Returns true if the track has been correctly downloaded; false otherwise.
///
- /// The path where to save the tracks.
/// The album of the track to download.
/// The track to download.
/// The cover art.
- private Boolean DownloadAndTagTrack(String albumDirectoryPath, Album album, Track track, TagLib.Picture artwork) {
+ private Boolean DownloadAndTagTrack(Album album, Track track, TagLib.Picture artwork) {
Log($"Downloading track \"{track.Title}\" from url: {track.Mp3Url}", LogType.VerboseInfo);
- // Set path to save the file
- String trackPath = albumDirectoryPath + "\\" + ParseTrackFileName(album, track);
- if (trackPath.Length >= 260) {
- // Windows doesn't do well with path + filename >= 260 characters (and path >= 248 characters)
- // Path has been shorten to 247 characters before, so we have 12 characters max left for filename.ext
- int fileNameMaxLength = 12 - Path.GetExtension(trackPath).ToString().Length;
- trackPath = albumDirectoryPath + "\\" + ParseTrackFileName(album, track).Substring(0, fileNameMaxLength) + Path.GetExtension(trackPath);
- }
int tries = 0;
Boolean trackDownloaded = false;
- if (File.Exists(trackPath)) {
- long length = new FileInfo(trackPath).Length;
+ if (File.Exists(track.Path)) {
+ long length = new FileInfo(track.Path).Length;
foreach (TrackFile trackFile in _filesDownload) {
if (track.Mp3Url == trackFile.Url &&
trackFile.Size > length - (trackFile.Size * App.UserSettings.AllowedFileSizeDifference) &&
trackFile.Size < length + (trackFile.Size * App.UserSettings.AllowedFileSizeDifference)) {
- Log($"Track already exists within allowed file size range: track \"{ParseTrackFileName(album, track)}\" from album \"{album.Title}\" - Skipping download!", LogType.IntermediateSuccess);
+ Log($"Track already exists within allowed file size range: track \"{Path.GetFileName(track.Path)}\" from album \"{album.Title}\" - Skipping download!", LogType.IntermediateSuccess);
return false;
}
}
@@ -244,7 +230,7 @@ private Boolean DownloadAndTagTrack(String albumDirectoryPath, Album album, Trac
if (App.UserSettings.ModifyTags) {
// Tag (ID3) the file when downloaded
- var tagFile = TagLib.File.Create(trackPath);
+ var tagFile = TagLib.File.Create(track.Path);
tagFile = TagHelper.UpdateArtist(tagFile, album.Artist, App.UserSettings.TagArtist);
tagFile = TagHelper.UpdateAlbumArtist(tagFile, album.Artist, App.UserSettings.TagAlbumArtist);
tagFile = TagHelper.UpdateAlbumTitle(tagFile, album.Title, App.UserSettings.TagAlbumTitle);
@@ -258,7 +244,7 @@ private Boolean DownloadAndTagTrack(String albumDirectoryPath, Album album, Trac
if (App.UserSettings.SaveCoverArtInTags && artwork != null) {
// Save cover in tags when downloaded
- var tagFile = TagLib.File.Create(trackPath);
+ var tagFile = TagLib.File.Create(track.Path);
tagFile.Tag.Pictures = new TagLib.IPicture[1] { artwork };
tagFile.Save();
}
@@ -266,12 +252,12 @@ private Boolean DownloadAndTagTrack(String albumDirectoryPath, Album album, Trac
// Note the file as downloaded
TrackFile currentFile = _filesDownload.Where(f => f.Url == track.Mp3Url).First();
currentFile.Downloaded = true;
- Log($"Downloaded track \"{ParseTrackFileName(album, track)}\" from album \"{album.Title}\"", LogType.IntermediateSuccess);
+ Log($"Downloaded track \"{Path.GetFileName(track.Path)}\" from album \"{album.Title}\"", LogType.IntermediateSuccess);
} else if (!e.Cancelled && e.Error != null) {
if (tries + 1 < App.UserSettings.DownloadMaxTries) {
- Log($"Unable to download track \"{ParseTrackFileName(album, track)}\" from album \"{album.Title}\". Try {tries + 1} of {App.UserSettings.DownloadMaxTries}", LogType.Warning);
+ Log($"Unable to download track \"{Path.GetFileName(track.Path)}\" from album \"{album.Title}\". Try {tries + 1} of {App.UserSettings.DownloadMaxTries}", LogType.Warning);
} else {
- Log($"Unable to download track \"{ParseTrackFileName(album, track)}\" from album \"{album.Title}\". Hit max retries of {App.UserSettings.DownloadMaxTries}", LogType.Error);
+ Log($"Unable to download track \"{Path.GetFileName(track.Path)}\" from album \"{album.Title}\". Hit max retries of {App.UserSettings.DownloadMaxTries}", LogType.Error);
}
} // Else the download has been cancelled (by the user)
@@ -291,7 +277,7 @@ private Boolean DownloadAndTagTrack(String albumDirectoryPath, Album album, Trac
// Register current download
_pendingDownloads.Add(webClient);
// Start download
- webClient.DownloadFileAsync(new Uri(track.Mp3Url), trackPath);
+ webClient.DownloadFileAsync(new Uri(track.Mp3Url), track.Path);
}
// Wait for download to be finished
doneEvent.WaitOne();
@@ -308,27 +294,7 @@ private Boolean DownloadAndTagTrack(String albumDirectoryPath, Album album, Trac
/// Downloads the cover art and returns the one to save in tags.
///
/// The album to download.
- /// The path where to save the cover art.
- private TagLib.Picture DownloadCoverArt(Album album, String downloadsFolder) {
- String artworkFileExt = Path.GetExtension(album.ArtworkUrl);
-
- // In order to prevent #54 (artworkTempPath used at the same time by another downloading thread), we'll add a random number to the name of the artwork file saved in Temp directory
- String randomNumber = _random.Next(1, 1000).ToString("00#");
-
- // Compute paths where to save artwork
- String artworkTempPath = Path.GetTempPath() + "\\" + ParseCoverArtFileName(album) + randomNumber + artworkFileExt;
- String artworkFolderPath = downloadsFolder + "\\" + ParseCoverArtFileName(album) + artworkFileExt;
-
- if (artworkTempPath.Length >= 260 || artworkFolderPath.Length >= 260) {
- // Windows doesn't do well with path + filename >= 260 characters (and path >= 248 characters)
- // Path has been shorten to 247 characters before, so we have 12 characters max left for filename.ext
- // There may be only one path needed to shorten, but it's better to use the same file name in both places
- int fileNameInTempMaxLength = 12 - randomNumber.Length - artworkFileExt.Length;
- int fileNameInFolderMaxLength = 12 - artworkFileExt.Length;
- artworkTempPath = Path.GetTempPath() + "\\" + ParseCoverArtFileName(album).Substring(0, fileNameInTempMaxLength) + randomNumber + artworkFileExt;
- artworkFolderPath = downloadsFolder + "\\" + ParseCoverArtFileName(album).Substring(0, fileNameInFolderMaxLength) + artworkFileExt;
- }
-
+ private TagLib.Picture DownloadCoverArt(Album album) {
TagLib.Picture artworkInTags = null;
int tries = 0;
@@ -376,9 +342,9 @@ private TagLib.Picture DownloadCoverArt(Album album, String downloadsFolder) {
settings.MaxHeight = App.UserSettings.CoverArtInFolderMaxSize;
settings.MaxWidth = App.UserSettings.CoverArtInFolderMaxSize;
}
- ImageBuilder.Current.Build(artworkTempPath, artworkFolderPath, settings); // Save it to the album folder
+ ImageBuilder.Current.Build(album.ArtworkTempPath, album.ArtworkPath, settings); // Save it to the album folder
} else if (App.UserSettings.SaveCoverArtInFolder) {
- File.Copy(artworkTempPath, artworkFolderPath, true);
+ File.Copy(album.ArtworkTempPath, album.ArtworkPath, true);
}
// Convert/resize artwork to be saved in tags
@@ -392,12 +358,12 @@ private TagLib.Picture DownloadCoverArt(Album album, String downloadsFolder) {
settings.MaxHeight = App.UserSettings.CoverArtInTagsMaxSize;
settings.MaxWidth = App.UserSettings.CoverArtInTagsMaxSize;
}
- ImageBuilder.Current.Build(artworkTempPath, artworkTempPath, settings); // Save it to %Temp%
+ ImageBuilder.Current.Build(album.ArtworkTempPath, album.ArtworkTempPath, settings); // Save it to %Temp%
}
- artworkInTags = new TagLib.Picture(artworkTempPath) { Description = "Picture" };
+ artworkInTags = new TagLib.Picture(album.ArtworkTempPath) { Description = "Picture" };
try {
- File.Delete(artworkTempPath);
+ File.Delete(album.ArtworkTempPath);
} catch {
// Could not delete the file. Nevermind, it's in %Temp% folder...
}
@@ -430,7 +396,7 @@ private TagLib.Picture DownloadCoverArt(Album album, String downloadsFolder) {
// Register current download
_pendingDownloads.Add(webClient);
// Start download
- webClient.DownloadFileAsync(new Uri(album.ArtworkUrl), artworkTempPath);
+ webClient.DownloadFileAsync(new Uri(album.ArtworkUrl), album.ArtworkTempPath);
}
// Wait for download to be finished
@@ -753,60 +719,6 @@ private void Log(String message, LogType logType) {
}
}
- ///
- /// Returns the file name to be used for the cover art of the specified album from the file name format saved in
- /// the UserSettings, by replacing the placeholders strings with their corresponding values.
- ///
- /// The album currently downloaded.
- private String ParseCoverArtFileName(Album album) {
- String fileName = App.UserSettings.CoverArtFileNameFormat
- .Replace("{year}", album.ReleaseDate.Year.ToString())
- .Replace("{month}", album.ReleaseDate.Month.ToString("00"))
- .Replace("{day}", album.ReleaseDate.Day.ToString("00"))
- .Replace("{album}", album.Title)
- .Replace("{artist}", album.Artist);
- return fileName.ToAllowedFileName();
- }
-
- ///
- /// Returns the download path for the specified album from the specified path format, by replacing the
- /// placeholders strings with their corresponding values.
- ///
- /// The download path to parse.
- /// The album currently downloaded.
- private String ParseDownloadPath(String downloadPath, Album album) {
- downloadPath = downloadPath.Replace("{year}", album.ReleaseDate.Year.ToString().ToAllowedFileName());
- downloadPath = downloadPath.Replace("{month}", album.ReleaseDate.Month.ToString("00").ToAllowedFileName());
- downloadPath = downloadPath.Replace("{day}", album.ReleaseDate.Day.ToString("00").ToAllowedFileName());
- downloadPath = downloadPath.Replace("{artist}", album.Artist.ToAllowedFileName());
- downloadPath = downloadPath.Replace("{album}", album.Title.ToAllowedFileName());
-
- if (downloadPath.Length >= 248) {
- // Windows doesn't do well with path >= 248 characters (and path + filename >= 260 characters)
- downloadPath = downloadPath.Substring(0, 247);
- }
-
- return downloadPath;
- }
-
- ///
- /// Returns the file name to be used for the specified track from the file name format saved in the UserSettings,
- /// by replacing the placeholders strings with their corresponding values.
- ///
- /// The album currently downloaded.
- /// The track currently downloaded.
- private String ParseTrackFileName(Album album, Track track) {
- String fileName = App.UserSettings.FileNameFormat
- .Replace("{year}", album.ReleaseDate.Year.ToString())
- .Replace("{month}", album.ReleaseDate.Month.ToString("00"))
- .Replace("{day}", album.ReleaseDate.Day.ToString("00"))
- .Replace("{album}", album.Title)
- .Replace("{artist}", album.Artist)
- .Replace("{title}", track.Title)
- .Replace("{tracknum}", track.Number.ToString("00"));
- return fileName.ToAllowedFileName();
- }
-
///
/// Updates the state of the controls.
///
@@ -992,7 +904,7 @@ private void ButtonStart_Click(object sender, RoutedEventArgs e) {
if (App.UserSettings.DownloadOneAlbumAtATime) {
// Download one album at a time
foreach (Album album in albums) {
- DownloadAlbum(album, ParseDownloadPath(App.UserSettings.DownloadsPath, album));
+ DownloadAlbum(album);
}
} else {
// Parallel download
@@ -1000,7 +912,7 @@ private void ButtonStart_Click(object sender, RoutedEventArgs e) {
for (int i = 0; i < albums.Count; i++) {
Album album = albums[i]; // Mandatory or else => race condition
tasks[i] = Task.Factory.StartNew(() =>
- DownloadAlbum(album, ParseDownloadPath(App.UserSettings.DownloadsPath, album)));
+ DownloadAlbum(album));
}
// Wait for all albums to be downloaded
Task.WaitAll(tasks);
@@ -1041,7 +953,7 @@ private void ButtonStop_Click(object sender, RoutedEventArgs e) {
}
buttonStop.IsEnabled = false;
- progressBar.Foreground = System.Windows.Media.Brushes.Red;
+ progressBar.Foreground = Brushes.Red;
progressBar.IsIndeterminate = true;
TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None;
TaskbarItemInfo.ProgressValue = 0;