/// <summary> /// Scan all tracks in the given playlist. /// </summary> /// <param name="list"></param> private void ScanTracks(PersistentIDCollection pids) { var tagger = new Tagger(); int total = pids.Count; int count = 0; foreach (PersistentID persistentID in pids) { if (!base.isActive) { Logger.WriteLine(base.name, "Information scanner cancelled while scanning"); break; } using (Track track = libraryPlaylist.GetTrack(persistentID)) { if ((track != null) && (track.Kind == TrackKind.File)) { Logger.WriteLine(base.name, String.Format( "Fetching tag information for '{0}' ({1})", track.MakeKey(), track.UniqueID)); try { // store into a temporary TrackFile so we can decide which // properties to update... var buffer = new TrackFile(track); tagger.RetrieveTags(buffer); Reconcile(track, buffer); } catch (Exception exc) { Logger.WriteLine(base.name, String.Format("Error fetching information {0}, {1}, {2}", track.Artist, track.Name, track.Album), exc); } } } count++; base.ProgressPercentage = (int)((double)count / (double)total * 100.0); } tagger = null; }
/// <summary> /// Compare the suspect track to existing candidates with the same key /// to determine which is most likely the better to preserve, if not both. /// </summary> /// <param name="key"></param> /// <param name="suspect"></param> /// <returns> /// The track to add to the duplicates list; this may be either the given suspect /// or one of the demoted candidates - in this latter case, the suspect would have /// swapped places with the demoted candidate in the collection. Or <b>null</b> /// if the given suspect is a valid candidate; in this case, the caller need not do /// aything further since we add it to the collection here. /// </returns> public Track Reconcile(Track suspect) { bool isTernary; string key = suspect.MakeKey(out isTernary); // promote first suspect to candidate if (!base.ContainsKey(key)) { Add(key, suspect); return(null); } int i = 0; Track candidate; Track demoted = null; Tracks tracks = base[key]; while ((i < tracks.Count) && (demoted == null)) { candidate = tracks[i]; if (isTernary) { // SIMPLE CASE: duplicates matching all indexes require // only simple comparison heuristics if (suspect.Duration == candidate.Duration) { if (suspect.IsBetterThan(candidate)) { // replace candidate with our preferred suspect tracks[i] = suspect; demoted = candidate; } else { // consider the suspect as our duplicate demoted = suspect; } // if both Tracks reference the same file then mark demoted as a // dead track so we remove it from library do not delete the file if (demoted.Location.Equals(tracks[i].Location)) { demoted.Location = null; } } } else { // COMPLEX CASE: update ID3 tags from online providers // and compare using PUIDs and other details if (tagger == null) { tagger = new Tagger(); } if (!candidate.IsAnalyzed) { tagger.RetrieveTags(candidate); } if (!suspect.IsAnalyzed) { tagger.RetrieveTags(suspect); } if (!String.IsNullOrEmpty(suspect.UniqueID) && !String.IsNullOrEmpty(candidate.UniqueID)) { if (suspect.UniqueID.Equals(candidate.UniqueID)) { if (suspect.IsBetterThan(candidate)) { // replace candidate with our preferred suspect tracks[i] = suspect; demoted = candidate; } else { // consider the suspect as our duplicate demoted = suspect; } // if both Tracks reference the same file then mark demoted as a // dead track so we remove it from library do not delete the file if (demoted.Location.Equals(tracks[i].Location)) { demoted.Location = null; } } } else { // else we'll move suspect into a new candidate slot // for later comparison, which is done below... // meanwhile, we'll just log here if (String.IsNullOrEmpty(suspect.UniqueID)) { Logger.WriteLine(Resx.I_ScanDuplicates, String.Format( "No tags found for suspect '{0}'", suspect.MakeKey())); } if (String.IsNullOrEmpty(candidate.UniqueID)) { Logger.WriteLine(Resx.I_ScanDuplicates, String.Format( "No tags found for candidate '{0}'", candidate.MakeKey())); } } } i++; } if (demoted == null) { // similar track not found so add suspect for later comparison // last chance to promote; apply buffered tags and reassess key if (suspect.IsAnalyzed && suspect.IsBuffered) { suspect.ApplyBuffer(); key = suspect.MakeKey(out isTernary); Add(key, suspect); } } return(demoted); }
public void RetrieveEmbeddedTags() { Tagger tagger = new Tagger(); Track track = new Track(null); track.Location = @"C:\iTuner\Research\genpuid\09-Little Martha.mp3"; track.IsBuffered = true; tagger.RetrieveTags(track); Assert.IsNotNull(track); Assert.IsNotNull(track.UniqueID); }