public static void RenameArtFileCanExec(object sender, CanExecuteRoutedEventArgs e) { string filePath = e.Parameter as string; //TODO: Check for file existence and permissions here too? e.CanExecute = !String.IsNullOrEmpty(filePath) && !EmbeddedArtHelpers.IsEmbeddedArtPath(filePath); }
/// <summary> /// Sets all properties related to an album having a file present: /// <see cref="ArtFile"/> set to <paramref name="filePath"/> /// <see cref="ArtFileStatus"/> set to <see cref="ArtFileStatus.Present"/> /// <see cref="ArtFileSize"/> set to the file size (or 0 if it could not be determined) /// <see cref="ArtFileWidth"/> and <see cref="ArtFileHeight"/> to the file image dimensions (or 0 if they could not be determined) /// </summary> /// <param name="filePath"></param> public void SetArtFile(string filePath) { ArtFile = filePath; ArtFileStatus = ArtFileStatus.Present; if (EmbeddedArtHelpers.IsEmbeddedArtPath(filePath)) { //Get the size of the embedded image, not the size of the file itself try { var embeddedArt = EmbeddedArtHelpers.GetEmbeddedArt(filePath); if (embeddedArt != null) { ArtFileSize = embeddedArt.Data.Count; using (var dataStream = new MemoryStream(embeddedArt.Data.Data, false)) { var bitmapDecoder = BitmapDecoder.Create(dataStream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); ArtFileWidth = bitmapDecoder.Frames[0].PixelWidth; ArtFileHeight = bitmapDecoder.Frames[0].PixelHeight; } } } catch (Exception) { //Ignore exceptions when reading the embedded artwork; it's not important at this stage ArtFileSize = 0; ArtFileWidth = ArtFileHeight = 0; } } else { //Not an embedded image, but an image file itself try { ArtFileSize = new FileInfo(filePath).Length; } catch (Exception) { //Ignore exceptions when reading the filesize it's not important ArtFileSize = 0; } //Attempt to get the image dimesions try { using (var fileStream = File.OpenRead(filePath)) { var bitmapDecoder = BitmapDecoder.Create(fileStream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); ArtFileWidth = bitmapDecoder.Frames[0].PixelWidth; ArtFileHeight = bitmapDecoder.Frames[0].PixelHeight; } } catch (Exception) { //Ignore exceptions when reading the dimensions, they aren't important ArtFileWidth = ArtFileHeight = 0; } } }
private static void AddEmbeddedPictureToResults(AlbumArtDownloader.Scripts.IScriptResults results, TagLib.IPicture[] embeddedPictures, int embeddedIndex, string filename) { //Create an in-memory copy so that the bitmap file isn't in use, and can be replaced Bitmap bitmap = new Bitmap(new MemoryStream(embeddedPictures[embeddedIndex].Data.Data)); //NOTE: Do not dispose of MemoryStream, or it will cause later saving of the bitmap to throw a generic GDI+ error (annoyingly) results.Add(bitmap, EmbeddedArtHelpers.GetEmbeddedFilePath(Path.GetFileName(filename), embeddedIndex), filename, bitmap.Width, bitmap.Height, null); }
public static void ShowInExplorerExec(object sender, ExecutedRoutedEventArgs e) { string filePath = e.Parameter as string; if (!String.IsNullOrEmpty(filePath)) { //TODO: Validation that this is a valid file path? if (EmbeddedArtHelpers.IsEmbeddedArtPath(filePath)) { int ignored; EmbeddedArtHelpers.SplitToFilenameAndIndex(filePath, out filePath, out ignored); } System.Diagnostics.Process.Start("explorer.exe", "/select,\"" + filePath + "\""); } }
private void ReadFoobarWorker() { try { Foobar2000.Tracks07 tracks = SelectedPlaylist.GetTracks(null); //Now searching for something, so set the state to indicate that. //Also set the count of albums, for the progress bar Dispatcher.Invoke(DispatcherPriority.DataBind, new ThreadStart(delegate { State = BrowserState.FindingFiles; Progress = 0; ProgressMax = tracks.Count; ProgressText = "Reading Media Library..."; })); foreach (Foobar2000.Track07 track in tracks) { string artistName = track.FormatTitle("%album artist%"); string albumName = track.FormatTitle("%album%"); string filename = track.FormatTitle("%path%"); string path; try { path = System.IO.Path.GetDirectoryName(filename); } catch (Exception e) { System.Diagnostics.Trace.WriteLine("Could not get file path for \"" + artistName + "\" / \"" + albumName + "\": " + filename); System.Diagnostics.Trace.Indent(); System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.Unindent(); continue; //skip this one, can't find the path. } var album = new Album(path, artistName, albumName); bool addedAlbum = false; Dispatcher.Invoke(DispatcherPriority.DataBind, new ThreadStart(delegate { Progress++; if (!(String.IsNullOrEmpty(artistName) && String.IsNullOrEmpty(albumName))) //No point adding it if no artist or album could be found. { addedAlbum = mAlbums.Add(album); } })); if (addedAlbum) { // Check for embedded art int? embeddedArtIndex = null; TagLib.File fileTags = null; try { fileTags = TagLib.File.Create(filename, TagLib.ReadStyle.None); embeddedArtIndex = EmbeddedArtHelpers.GetEmbeddedFrontCoverIndex(fileTags); } catch (Exception e) { System.Diagnostics.Trace.WriteLine("TagLib# could not get embedded artwork for file: " + filename); System.Diagnostics.Trace.Indent(); System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.Unindent(); //If embedded images couldn't be read, ignore that } finally { if (fileTags != null) { fileTags.Mode = TagLib.File.AccessMode.Closed; } } if (embeddedArtIndex.HasValue) { //Read the picture from the data album.SetArtFile(EmbeddedArtHelpers.GetEmbeddedFilePath(filename, embeddedArtIndex.Value)); } } } //Finished with the FindingFiles state, so now set the state to whatever the results state is (either FindingArt, or Done). Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate { ProgressText = mResults.ProgressText; State = mResults.State; })); } catch (ThreadAbortException) { Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate { State = BrowserState.Stopped; })); } catch (Exception e) { uint hResult = (uint)System.Runtime.InteropServices.Marshal.GetHRForException(e); if (e is COMException || (hResult == 0x800706BE || //RPC failed hResult == 0x80004002)) //No interface { SetErrorState("Lost connection to Foobar automation server while reading media library"); } else { SetErrorState(String.Format("Error occurred while reading media library: {0}", e.Message)); } } }
protected override void SearchInternal(string artist, string album, AlbumArtDownloader.Scripts.IScriptResults results) { //Add the pattern used to the history list. CustomSettingsUI.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.DataBind, new System.Threading.ThreadStart(delegate { ((LocalFilesSourceSettings)CustomSettingsUI).mSearchPathPatternBox.AddPatternToHistory(); })); int lastMinImageSizeSet = 0; //Avoid duplicates StringDictionary addedFiles = new StringDictionary(); string pathPattern = GetSearchPath(artist, album); foreach (string alternate in pathPattern.Split('|')) { int? embeddedIndex = null; string unembeddedPathPattern = alternate; if (EmbeddedArtHelpers.IsEmbeddedArtPath(alternate)) { //TODO: Allow a pattern to specify multiple embedded images as "<?>" or similar. int i; EmbeddedArtHelpers.SplitToFilenameAndIndex(alternate, out unembeddedPathPattern, out i); embeddedIndex = i; } //Match path with wildcards foreach (string filename in Common.ResolvePathPattern(unembeddedPathPattern)) { if (!addedFiles.ContainsKey(filename)) //Don't re-add a file that's already been added { addedFiles.Add(filename, null); if (embeddedIndex.HasValue) { //Read embedded image from file, rather than the file itself as an image TagLib.File fileTags = null; try { fileTags = TagLib.File.Create(filename, TagLib.ReadStyle.None); var embeddedPictures = fileTags.Tag.Pictures; if (embeddedIndex.Value == -1) //Special value indicating "all embedded images" { for (int i = 0; i < embeddedPictures.Length; i++) { AddEmbeddedPictureToResults(results, embeddedPictures, i, filename); } } else if (embeddedPictures.Length > embeddedIndex.Value) { //Found the embedded image AddEmbeddedPictureToResults(results, embeddedPictures, embeddedIndex.Value, filename); } else { System.Diagnostics.Trace.WriteLine("Skipping file missing specified embedded image in local file search: " + EmbeddedArtHelpers.GetEmbeddedFilePath(filename, embeddedIndex.Value)); } } catch (Exception e) { System.Diagnostics.Trace.WriteLine("Skipping unreadable embedded image from file in local file search: " + EmbeddedArtHelpers.GetEmbeddedFilePath(filename, embeddedIndex.Value)); System.Diagnostics.Trace.Indent(); System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.Unindent(); } finally { if (fileTags != null) { fileTags.Mode = TagLib.File.AccessMode.Closed; } } } else { //Each filename is potentially an image, so try to load it try { using (var filestream = File.OpenRead(filename)) { var decoder = BitmapDecoder.Create(filestream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); //Don't cache, only want the width and height, and delay creation as no need to actually read the data. var frame = decoder.Frames[0]; int width = frame.PixelWidth; int height = frame.PixelHeight; results.Add(File.OpenRead(filename), Path.GetFileName(filename), filename, width, height, null); if (SetMinimumSizeFilter) { var minImageSize = Math.Min(width, height); if (lastMinImageSizeSet == 0) { Properties.Settings.Default.UseMinimumImageSize = true; Properties.Settings.Default.MinimumImageSize = lastMinImageSizeSet = minImageSize; } else if (Properties.Settings.Default.UseMinimumImageSize && Properties.Settings.Default.MinimumImageSize == lastMinImageSizeSet) // Don't override during a search if the user has made manual changes { Properties.Settings.Default.MinimumImageSize = Math.Max(lastMinImageSizeSet, minImageSize); // If this image is bigger, use it as the minimum size } } } } catch (Exception e) { System.Diagnostics.Trace.WriteLine("Skipping unreadable file in local file search: " + filename); System.Diagnostics.Trace.Indent(); System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.Unindent(); } } } } } }
private static void AddEmbeddedPictureToResults(AlbumArtDownloader.Scripts.IScriptResults results, TagLib.IPicture[] embeddedPictures, int embeddedIndex, string filename) { results.Add(new MemoryStream(embeddedPictures[embeddedIndex].Data.Data), EmbeddedArtHelpers.GetEmbeddedFilePath(Path.GetFileName(filename), embeddedIndex), filename, -1, -1, null); }
protected override void SearchInternal(string artist, string album, AlbumArtDownloader.Scripts.IScriptResults results) { //Add the pattern used to the history list. CustomSettingsUI.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.DataBind, new System.Threading.ThreadStart(delegate { ((LocalFilesSourceSettings)CustomSettingsUI).mSearchPathPatternBox.AddPatternToHistory(); })); //Avoid duplicates StringDictionary addedFiles = new StringDictionary(); string pathPattern = GetSearchPath(artist, album); foreach (string alternate in pathPattern.Split('|')) { int? embeddedIndex = null; string unembeddedPathPattern = alternate; if (EmbeddedArtHelpers.IsEmbeddedArtPath(alternate)) { //TODO: Allow a pattern to specify multiple embedded images as "<?>" or similar. int i; EmbeddedArtHelpers.SplitToFilenameAndIndex(alternate, out unembeddedPathPattern, out i); embeddedIndex = i; } //Match path with wildcards foreach (string filename in Common.ResolvePathPattern(unembeddedPathPattern)) { if (!addedFiles.ContainsKey(filename)) //Don't re-add a file that's already been added { addedFiles.Add(filename, null); if (embeddedIndex.HasValue) { //Read embedded image from file, rather than the file itself as an image TagLib.File fileTags = null; try { fileTags = TagLib.File.Create(filename, TagLib.ReadStyle.None); var embeddedPictures = fileTags.Tag.Pictures; if (embeddedIndex.Value == -1) //Special value indicating "all embedded images" { for (int i = 0; i < embeddedPictures.Length; i++) { AddEmbeddedPictureToResults(results, embeddedPictures, i, filename); } } else if (embeddedPictures.Length > embeddedIndex.Value) { //Found the embedded image AddEmbeddedPictureToResults(results, embeddedPictures, embeddedIndex.Value, filename); } else { System.Diagnostics.Trace.WriteLine("Skipping file missing specified embedded image in local file search: " + EmbeddedArtHelpers.GetEmbeddedFilePath(filename, embeddedIndex.Value)); } } catch (Exception e) { System.Diagnostics.Trace.WriteLine("Skipping unreadable embedded image from file in local file search: " + EmbeddedArtHelpers.GetEmbeddedFilePath(filename, embeddedIndex.Value)); System.Diagnostics.Trace.Indent(); System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.Unindent(); } finally { if (fileTags != null) { fileTags.Mode = TagLib.File.AccessMode.Closed; } } } else { //Each filename is potentially an image, so try to load it try { IntPtr hBitmap; int status = GdipCreateBitmapFromFile(filename, out hBitmap); GdipDisposeImage(new HandleRef(this, hBitmap)); if (status == 0) { //Successfully opened as image //Create an in-memory copy so that the bitmap file isn't in use, and can be replaced byte[] fileBytes = File.ReadAllBytes(filename); //Read the file, closing it after use Bitmap bitmap = new Bitmap(new MemoryStream(fileBytes)); //NOTE: Do not dispose of MemoryStream, or it will cause later saving of the bitmap to throw a generic GDI+ error (annoyingly) results.Add(bitmap, Path.GetFileName(filename), filename, bitmap.Width, bitmap.Height, null); } else { System.Diagnostics.Trace.WriteLine("Skipping non-bitmap file in local file search: " + filename); } } catch (Exception e) { System.Diagnostics.Trace.WriteLine("Skipping unreadable file in local file search: " + filename); System.Diagnostics.Trace.Indent(); System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.Unindent(); } } } } } }
/// <summary>Reads the album and artist data from specified media file or folder. Adds it to the <see cref="mAlbums"/> collection, and if it does so, also adds it to <paramref name="addedAlbums"/>.</summary> /// <param name="filePathPattern">Use null to use the ID3 tags instead</param> /// <returns>The <see cref="Album"/> that was added to <see cref="mAlbums"/>, or <c>null</c> if none could be read.</returns> private void ReadMediaFile(FileSystemInfo file, Regex filePathPattern, IList <Album> addedAlbums) { if (file is DirectoryInfo && filePathPattern == null) //If a DirectoryInfo is used, then the filePathPattern must have ended in \. { throw new ArgumentException("Directories are only supported for pattern matching, not ID3 tags", "file"); } Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate { ProgressText = "Searching... " + file.Name; })); string artistName = null; string albumName = null; int? embeddedArtIndex = null; if (filePathPattern == null) { //Read ID3 Tags TagLib.File fileTags = null; try { fileTags = TagLib.File.Create(file.FullName, TagLib.ReadStyle.None); if (fileTags.Tag.AlbumArtists.Length == 0) { artistName = String.Join(" / ", fileTags.Tag.Performers); } else { artistName = String.Join(" / ", fileTags.Tag.AlbumArtists); } albumName = fileTags.Tag.Album; embeddedArtIndex = EmbeddedArtHelpers.GetEmbeddedFrontCoverIndex(fileTags); } catch (Exception e) { System.Diagnostics.Trace.WriteLine("TagLib# could not get artist and album information for file: " + file.FullName); System.Diagnostics.Trace.Indent(); System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.Unindent(); return; //If this media file couldn't be read, just go on to the next one. } finally { if (fileTags != null) { fileTags.Mode = TagLib.File.AccessMode.Closed; } } } else { //Read from file path Match match = filePathPattern.Match(file.FullName); if (match.Success) { artistName = match.Groups["artist"].Value; albumName = match.Groups["album"].Value; } } if (!(String.IsNullOrEmpty(artistName) && String.IsNullOrEmpty(albumName))) //No point adding it if no artist or album could be found. { string basePath; if (file is FileInfo) { basePath = ((FileInfo)file).DirectoryName; } else { System.Diagnostics.Debug.Assert(file is DirectoryInfo, "Expecting file to be one of FileInfo or DirectoryInfo"); basePath = ((DirectoryInfo)file).FullName; } Album album = new Album(basePath, artistName, albumName); if (embeddedArtIndex.HasValue) { //Read the picture from the data album.SetArtFile(EmbeddedArtHelpers.GetEmbeddedFilePath(file.FullName, embeddedArtIndex.Value)); } Dispatcher.Invoke(DispatcherPriority.DataBind, new ThreadStart(delegate { if (mAlbums.Add(album)) { addedAlbums.Add(album); } })); } }
/// <summary>Reads the album and artist data from specified media file or folder, and adds it to the <see cref="mAlbums"/> collection.</summary> /// <param name="filePathPattern">Use null to use the ID3 tags instead</param> /// <returns>The <see cref="Album"/> that was added to <see cref="mAlbums"/>, or <c>null</c> if none could be read.</returns> private Album ReadMediaFile(FileSystemInfo file, Regex filePathPattern) { if (file is DirectoryInfo && filePathPattern == null) //If a DirectoryInfo is used, then the filePathPattern must have ended in \. { throw new ArgumentException("Directories are only supported for pattern matching, not ID3 tags", "file"); } Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate { ProgressText = "Searching... " + file.Name; })); string artistName = null; string albumName = null; int? embeddedArtIndex = null; //Read ID3 Tags TagLib.File fileTags = null; if (filePathPattern == null) { try { fileTags = TagLib.File.Create(file.FullName, TagLib.ReadStyle.None); if (fileTags.Tag.AlbumArtists.Length == 0) { artistName = String.Join(" / ", fileTags.Tag.Performers); } else { artistName = String.Join(" / ", fileTags.Tag.AlbumArtists); } albumName = fileTags.Tag.Album; var embeddedPictures = fileTags.Tag.Pictures; if (embeddedPictures.Length > 0) { //There's an embedded picture //Check to see if there's a picture described as the front cover, to use in preference for (int i = 0; i < embeddedPictures.Length; i++) { if (embeddedPictures[i].Type == TagLib.PictureType.FrontCover) { embeddedArtIndex = i; break; } } if (!embeddedArtIndex.HasValue) { //None of the embedded pictures were tagged as "FrontCover", so just use the first picture embeddedArtIndex = 0; } } } catch (Exception e) { System.Diagnostics.Trace.WriteLine("TagLib# could not get artist and album information for file: " + file.FullName); System.Diagnostics.Trace.Indent(); System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.Unindent(); return(null); //If this media file couldn't be read, just go on to the next one. } finally { if (fileTags != null) { fileTags.Mode = TagLib.File.AccessMode.Closed; } } } else { //Read from file path Match match = filePathPattern.Match(file.FullName); if (match.Success) { artistName = match.Groups["artist"].Value; albumName = match.Groups["album"].Value; } } if (!(String.IsNullOrEmpty(artistName) && String.IsNullOrEmpty(albumName))) //No point adding it if no artist or album could be found. { string basePath; bool addTracks = false; if (file is FileInfo) { basePath = ((FileInfo)file).DirectoryName; addTracks = true; } else { System.Diagnostics.Debug.Assert(file is DirectoryInfo, "Expecting file to be one of FileInfo or DirectoryInfo"); basePath = ((DirectoryInfo)file).FullName; } Album album = findInAlbums(basePath, artistName, albumName); if (addTracks) { album.AddTrack(fileTags); } if (embeddedArtIndex.HasValue) { //Read the picture from the data album.SetArtFile(EmbeddedArtHelpers.GetEmbeddedFilePath(file.FullName, embeddedArtIndex.Value)); } Dispatcher.Invoke(DispatcherPriority.DataBind, new ThreadStart(delegate { mAlbums.Add(album); })); return(album); } return(null); }