Пример #1
0
        /// <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;

            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;

                    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;
                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
                {
                    mAlbums.Add(album);
                }));

                return(album);
            }

            return(null);
        }
Пример #2
0
        /// <summary>
        /// Checks through a set of albums for those that should be concatenated into a single Various Artists album.
        /// </summary>
        /// <param name="addedAlbums"></param>
        private void DetectVariousArtistsAlbums(IList <Album> albums)
        {
            //Get the albums in each folder
            Dictionary <String, List <Album> > folders = new Dictionary <string, List <Album> >(albums.Count);

            foreach (Album album in albums)
            {
                if (album != null)
                {
                    List <Album> folderAlbums;
                    if (!folders.TryGetValue(album.BasePath, out folderAlbums))
                    {
                        folderAlbums = new List <Album>(albums.Count);
                        folders.Add(album.BasePath, folderAlbums);
                    }

                    folderAlbums.Add(album);
                }
            }

            foreach (List <Album> folder in folders.Values)
            {
                //If the folder contains all the same album name, but different artists, then it is VA
                string albumName = folder[0].Name;
                string artist    = folder[0].Artist;
                string basePath  = folder[0].BasePath;

                bool variousArtists = false;
                foreach (Album album in folder)
                {
                    if (album.Name != albumName)
                    {
                        //This is not all the same album
                        variousArtists = false;
                        break;
                    }
                    if (!variousArtists && album.Artist != artist)
                    {
                        variousArtists = true;
                    }
                }

                if (variousArtists)
                {
                    //This is a various artists album, so replace them with a single Various Artists album
                    Dispatcher.Invoke(DispatcherPriority.DataBind, new ThreadStart(delegate
                    {
                        Album variousArtistsAlbum = new Album(basePath, sVariousArtistsName, albumName);
                        if (!mAlbums.Contains(variousArtistsAlbum))                         //If this album already exists, no need to add it again.
                        {
                            //Add replacement VA album
                            mAlbums.Insert(mAlbums.IndexOf(folder[0]), variousArtistsAlbum);
                        }

                        //Remove individual albums, but copy art from at least one of them (if present)
                        foreach (Album album in folder)
                        {
                            if (album.Artist != sVariousArtistsName)                            //If, by chance, one of the albums was already called "Various Artists", then it will have merged with the newly added one.
                            {
                                if (variousArtistsAlbum.ArtFileStatus != ArtFileStatus.Present && album.ArtFile != null)
                                {
                                    variousArtistsAlbum.SetArtFile(album.ArtFile);
                                }
                                mAlbums.Remove(album);
                            }
                        }
                    }));
                }
            }
        }
Пример #3
0
        private void SearchWorker()
        {
            Album album = null;

            Dispatcher.Invoke(DispatcherPriority.Send, new ThreadStart(delegate
            {
                album       = mQueueList.GetNextAlbum();
                IsSearching = true;
            }));

            while (album != null)
            {
                album.ArtFileStatus = ArtFileStatus.Searching;

                Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate
                {
                    if (mQueueList.ShouldAutoscroll)
                    {
                        mQueueList.ScrollIntoView(album);
                    }
                }));

                try
                {
                    List <Source> currentSourcesToSearch;
                    lock (mSourcesToSearch)
                    {
                        //Take a copy of the source list so that it doesn't get affected by changes)
                        currentSourcesToSearch = new List <Source>(mSourcesToSearch);
                    }
                    foreach (var source in currentSourcesToSearch)                     //Try each source in turn
                    {
                        Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate
                        {
                            ProgressText = String.Format("Searching {0} for {1} / {2}", source.Name, album.Artist, album.Name);
                        }));

                        source.Results.CollectionChanged += OnSourceFoundResult;
                        source.QueryContinueSearch       += OnSourceQueryContinue;
                        source.SearchCompleted           += OnSourceSearchComplete;

                        mWaitForSourceCompleted.Reset();
                        Dispatcher.BeginInvoke(DispatcherPriority.Normal, new ThreadStart(delegate
                        {
                            //source.Search must be done in the main dispatcher thread, as that's the thread which the observable collection will be updated on.
                            source.Search(album.Artist, album.Name);
                        }));

                        //Wait for the source to have finished searching
                        mWaitForSourceCompleted.WaitOne();

                        System.Diagnostics.Debug.Assert(source.IsSearching == false, "Source is supposed to have completed by now");

                        //Done with this source - stop listening to its events.
                        source.Results.CollectionChanged -= OnSourceFoundResult;
                        source.QueryContinueSearch       -= OnSourceQueryContinue;
                        source.SearchCompleted           -= OnSourceSearchComplete;

                        //Was a valid result found in this source?
                        if (mSearchResult != null)
                        {
                            var observableCollectionOfDisposables = source.Results as ObservableCollectionOfDisposables <AlbumArt>;
                            if (observableCollectionOfDisposables != null)
                            {
                                //Detach the result from the collection so that it isn't disposed of when the source is re-used.
                                observableCollectionOfDisposables.Detach(mSearchResult);
                                //Responsibility for disposing of mSearchResult is now taken here, and will be passed on to mResults when it is added to that collection.
                            }

                            //No need to search other sources.
                            break;
                        }
                    }

                    //Was a valid result found in any source?
                    if (mSearchResult != null)
                    {
                        //Yes, so save it and add it to the results list.

                        Dispatcher.Invoke(DispatcherPriority.DataBind, new ThreadStart(delegate
                        {
                            mSearchResult.DefaultFilePathPattern = album.ArtFile;
                            //If the file already exists, overwrite it
                            if (System.IO.File.Exists(mSearchResult.FilePath))
                            {
                                try
                                {
                                    System.IO.File.Delete(mSearchResult.FilePath);
                                }
                                catch (Exception ex)
                                {
                                    System.Diagnostics.Trace.TraceError("Could not delete file \"{0}\": {1}", mSearchResult.FilePath, ex.Message);
                                }
                            }
                            mSearchResult.Save();

                            mResults.Add(mSearchResult);

                            album.SetArtFile(mSearchResult.FilePath);

                            Progress++;
                        }));

                        mResultsLookup.Add(album, mSearchResult);
                        mReverseLookup.Add(mSearchResult, album);

                        mSearchResult = null;
                    }
                    else
                    {
                        mAlbumsMissingResults.Add(album);
                        album.ArtFileStatus = ArtFileStatus.Missing;
                    }
                }
                catch (ThreadAbortException)
                {
                    album.ArtFileStatus = ArtFileStatus.Queued;
                    return;
                }


                //Get the next album
                Dispatcher.Invoke(DispatcherPriority.Send, new ThreadStart(delegate
                {
                    album = mQueueList.GetNextAlbum();
                }));
            }

            Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate
            {
                IsSearching = false;
                System.Diagnostics.Debug.Assert(mQueueList.Items.Count - mResults.Count == mAlbumsMissingResults.Count, "Unexpected albums missing results count");
                ProgressText = String.Format("Done. {0} albums found, {1} not found.", mResults.Count, mAlbumsMissingResults.Count);

                mSearchThread = null;

                ReEnableStartButton();
            }));
        }