예제 #1
0
        private void SearchWorker()
        {
            do
            {
                Album album = null;
                Dispatcher.Invoke(DispatcherPriority.Send, new ThreadStart(delegate
                {
                    album       = mQueueList.GetNextAlbum();
                    IsSearching = true;
                }));

                if (album == null)
                {
                    // No more albums
                    break;
                }

                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();
                        System.Diagnostics.Debug.Assert(mSearchResult == null);
                        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)
                        {
                            //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 (Properties.Settings.Default.Presets.Length > 0)
                            {
                                mSearchResult.Preset = Properties.Settings.Default.Presets[0].Value;
                            }

                            //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(this);

                            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;
                }
            } while (true);

            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();
            }));
        }
예제 #2
0
        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));
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Checks through a set of albums for those that should be concatenated into a single Various Artists album.
        /// </summary>
        private void DetectVariousArtistsAlbums(IList <Album> albums)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate
            {
                ProgressText = "Detecting Various Artists albums...";
            }));

            // First step, find folders with more than one album in them. All indexes of basePathGroup sharing the same value share the same folder. The folder can be found by the base path of the album at the albums[value - 1] (1 based, as 0 means no group)
            var basePathGroup       = new int[albums.Count];
            int maxGroupSize        = 0;
            int lastGroupStartIndex = 0;

            for (int i = 0; i < albums.Count; i++)
            {
                if (basePathGroup[i] == 0)                 // If this album has already been noted has having other albums sharing its folder, no need to search again.
                {
                    int groupSize = 1;
                    // Find other albums that share the same folder
                    for (int j = i; j < albums.Count; j++)
                    {
                        if (albums[j].BasePath == albums[i].BasePath)
                        {
                            // Both these albums have one other album in the same folder, then.
                            if (basePathGroup[i] == 0)
                            {
                                basePathGroup[i]    = i + 1;
                                lastGroupStartIndex = i;
                            }
                            basePathGroup[j] = basePathGroup[i];
                            groupSize++;
                        }
                    }
                    maxGroupSize = Math.Max(maxGroupSize, groupSize);
                }
            }

            if (maxGroupSize > 1)             // Don't bother with the rest if each album is in its own folder - there are no various artists albums in this case.
            {
                var albumsInFolder = new List <Album>(maxGroupSize);

                // Next step, for those albums whose folders have multiple albums in them, check if they have the same album name but different artists
                for (int i = 0; i <= lastGroupStartIndex; i++)         // No need to check past the last group start index, there won't be any more group starts past this point.
                {
                    if (basePathGroup[i] == i + 1)                     // If this album is the first one in a group of albums in the same folder, process it
                    {
                        string albumName = albums[i].Name;
                        string artist    = albums[i].Artist;

                        bool variousArtists = false;

                        // Multiple albums are in this folder, find them:
                        albumsInFolder.Clear();
                        albumsInFolder.Add(albums[i]);
                        for (int j = i; j < albums.Count; j++)
                        {
                            if (basePathGroup[j] == basePathGroup[i])
                            {
                                // albums[j] is in the same folder
                                if (albums[j].Name != albumName)
                                {
                                    //This is not all the same album
                                    variousArtists = false;
                                    break;
                                }
                                if (!variousArtists && albums[j].Artist != artist)
                                {
                                    // Album name matches, artist name differs. This is a various artists album
                                    variousArtists = true;
                                }

                                albumsInFolder.Add(albums[j]);
                            }
                        }

                        if (variousArtists)
                        {
                            //This is a various artists album, so replace them with a single Various Artists album
                            Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new ThreadStart(delegate
                            {
                                ProgressText = "Resolving Various Artists album... " + albumName;
                            }));

                            Album variousArtistsAlbum = new Album(albums[i].BasePath, sVariousArtistsName, albumName);
                            if (!mAlbums.Contains(variousArtistsAlbum))                             //If this album already exists, no need to add it again.
                            {
                                //Add replacement VA album
                                Dispatcher.Invoke(DispatcherPriority.DataBind, new ThreadStart(delegate
                                {
                                    mAlbums.Insert(mAlbums.IndexOf(albums[i]), variousArtistsAlbum);
                                }));
                            }

                            //Remove individual albums, but copy art from at least one of them (if present)
                            foreach (Album album in albumsInFolder)
                            {
                                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);
                                    }
                                    Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
                                    {
                                        mAlbums.Remove(album);
                                    }));
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #4
0
        /// <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);
                    }
                }));
            }
        }
예제 #5
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);
                            }
                        }
                    }));
                }
            }
        }
예제 #6
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;

            //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);
        }