public static TrackInfo Path2TrackInfo(string path, string artworkPrefix) { var ti = new TrackInfo(); try { var fmd = new FileMetadata(path); var fi = new FileInformation(path); ti.Path = path; ti.FileName = fi.NameWithoutExtension; ti.MimeType = fmd.MimeType; ti.FileSize = fi.SizeInBytes; ti.BitRate = fmd.BitRate; ti.SampleRate = fmd.SampleRate; ti.TrackTitle = MetadataUtils.SanitizeTag(fmd.Title.Value); ti.TrackNumber = MetadataUtils.SafeConvertToLong(fmd.TrackNumber.Value); ti.TrackCount = MetadataUtils.SafeConvertToLong(fmd.TrackCount.Value); ti.DiscNumber = MetadataUtils.SafeConvertToLong(fmd.DiscNumber.Value); ti.DiscCount = MetadataUtils.SafeConvertToLong(fmd.DiscCount.Value); ti.Duration = Convert.ToInt64(fmd.Duration.TotalMilliseconds); ti.Year = MetadataUtils.SafeConvertToLong(fmd.Year.Value); ti.ArtistName = GetFirstArtist(fmd); ti.GenreName = GetFirstGenre(fmd); ti.AlbumTitle = string.IsNullOrWhiteSpace(fmd.Album.Value) ? Defaults.UnknownAlbumString : MetadataUtils.SanitizeTag(fmd.Album.Value); ti.AlbumArtist = GetFirstAlbumArtist(fmd); var dummyAlbum = new Album { AlbumTitle = ti.AlbumTitle, AlbumArtist = ti.AlbumArtist }; IndexerUtils.UpdateAlbumYear(dummyAlbum, MetadataUtils.SafeConvertToLong(fmd.Year.Value)); IndexerUtils.CacheArtwork(dummyAlbum, ti.Path); } catch (Exception ex) { LogClient.Instance.Logger.Error("Error while creating TrackInfo from file '{0}'. Exception: {1}", path, ex.Message); // Make sure the file can be opened by creating a TrackInfo with some default values ti = new TrackInfo(); ti.Path = path; ti.FileName = System.IO.Path.GetFileNameWithoutExtension(path); ti.ArtistName = Defaults.UnknownArtistString; ti.GenreName = Defaults.UnknownGenreString; ti.AlbumTitle = Defaults.UnknownAlbumString; ti.AlbumArtist = Defaults.UnknownAlbumArtistString; } return(ti); }
private async Task <long> UpdateTracksAsync() { long numberUpdatedTracks = 0; await Task.Run(() => { try { using (var conn = this.factory.GetConnection()) { conn.BeginTransaction(); // Ignore Tracks which are in an unreachable folder List <Track> tracksToProcess = conn.Table <Track>().Select((t) => t).Where((t) => !this.unreachableFolderIDs.Contains(t.FolderID)).ToList(); long currentValue = 0; long totalValue = tracksToProcess.Count; foreach (Track dbTrack in tracksToProcess) { try { if (IndexerUtils.IsTrackOutdated(dbTrack)) { if (this.ProcessTrack(dbTrack, conn)) { conn.Update(dbTrack); numberUpdatedTracks += 1; } } } catch (Exception ex) { LogClient.Instance.Logger.Error("There was a problem while updating Track with path='{0}'. Exception: {1}", dbTrack.Path, ex.Message); } currentValue += 1; // Report progress if at least 1 track is updated if (numberUpdatedTracks > 0) { this.eventArgs.IndexingAction = IndexingAction.UpdateTracks; this.eventArgs.ProgressCurrent = currentValue; this.eventArgs.ProgressTotal = totalValue; this.eventArgs.ProgressPercent = IndexerUtils.CalculatePercent(currentValue, totalValue); this.IndexingStatusChanged(this.eventArgs); } } conn.Commit(); } } catch (Exception ex) { LogClient.Instance.Logger.Error("There was a problem while updating Tracks. Exception: {0}", ex.Message); } }); return(numberUpdatedTracks); }
public static void SplitMetadata(string path, ref Track track, ref Album album, ref Artist artist, ref Genre genre) { if (!string.IsNullOrEmpty(path)) { var fmd = new FileMetadata(path); var fi = new FileInformation(path); // Track information track.Path = path; track.FileName = fi.NameWithoutExtension; track.Duration = Convert.ToInt64(fmd.Duration.TotalMilliseconds); track.MimeType = fmd.MimeType; track.BitRate = fmd.BitRate; track.SampleRate = fmd.SampleRate; track.TrackTitle = MetadataUtils.SanitizeTag(fmd.Title.Value); track.TrackNumber = MetadataUtils.SafeConvertToLong(fmd.TrackNumber.Value); track.TrackCount = MetadataUtils.SafeConvertToLong(fmd.TrackCount.Value); track.DiscNumber = MetadataUtils.SafeConvertToLong(fmd.DiscNumber.Value); track.DiscCount = MetadataUtils.SafeConvertToLong(fmd.DiscCount.Value); track.Year = MetadataUtils.SafeConvertToLong(fmd.Year.Value); track.Rating = fmd.Rating.Value; // Before proceeding, get the available artists string albumArtist = GetFirstAlbumArtist(fmd); string trackArtist = GetFirstArtist(fmd); // will be used for the album if no album artist is found // Album information album.AlbumTitle = string.IsNullOrWhiteSpace(fmd.Album.Value) ? Defaults.UnknownAlbumString : MetadataUtils.SanitizeTag(fmd.Album.Value); album.AlbumArtist = (albumArtist == Defaults.UnknownAlbumArtistString ? trackArtist : albumArtist); album.DateAdded = FileOperations.GetDateCreated(path); IndexerUtils.UpdateAlbumYear(album, MetadataUtils.SafeConvertToLong(fmd.Year.Value)); // Artist information artist.ArtistName = trackArtist; // Genre information genre.GenreName = GetFirstGenre(fmd); // Metadata hash System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append(album.AlbumTitle); sb.Append(artist.ArtistName); sb.Append(genre.GenreName); sb.Append(track.TrackTitle); sb.Append(track.TrackNumber); sb.Append(track.Year); track.MetaDataHash = CryptographyUtils.MD5Hash(sb.ToString()); // File information track.FileSize = fi.SizeInBytes; track.DateFileModified = fi.DateModifiedTicks; track.DateLastSynced = DateTime.Now.Ticks; } }
private async Task <long> AddArtworkAsync(bool quickArtworkIndexing = true) { long numberUpdated = 0; await Task.Run(() => { using (SQLiteConnection conn = this.factory.GetConnection()) { conn.BeginTransaction(); foreach (Album alb in conn.Table <Album>()) { try { // Only update artwork if QuickArtworkIndexing is enabled AND there // is no ArtworkID set, OR when QuickArtworkIndexing is disabled. if ((quickArtworkIndexing & string.IsNullOrEmpty(alb.ArtworkID)) | !quickArtworkIndexing) { Track trk = this.GetLastModifiedTrack(alb); if (IndexerUtils.CacheArtwork(alb, trk.Path)) { conn.Update(alb); numberUpdated += 1; } } } catch (Exception ex) { LogClient.Instance.Logger.Error("There was a problem while updating the cover art for Album {0}/{1}. Exception: {2}", alb.AlbumTitle, alb.AlbumArtist, ex.Message); } // Report progress if at least 1 album is added if (numberUpdated > 0) { this.eventArgs.IndexingAction = IndexingAction.UpdateArtwork; this.eventArgs.ProgressPercent = 0; this.IndexingStatusChanged(this.eventArgs); } } conn.Commit(); } }); return(numberUpdated); }
private async Task <long> AddTracksAsync() { long numberAddedTracks = 0; await Task.Run(() => { try { long currentValue = 0; long totalValue = this.newDiskPaths.Count; long saveItemCount = IndexerUtils.CalculateSaveItemCount(this.newDiskPaths.Count); long unsavedItemCount = 0; using (var conn = this.factory.GetConnection()) { conn.BeginTransaction(); foreach (Tuple <long, string, long> newDiskPath in this.newDiskPaths) { Track diskTrack = new Track { FolderID = newDiskPath.Item1, Path = newDiskPath.Item2, DateAdded = DateTime.Now.Ticks }; try { if (this.ProcessTrack(diskTrack, conn)) { conn.Insert(diskTrack); numberAddedTracks += 1; unsavedItemCount += 1; } // Intermediate save to the database if 20% is reached if (unsavedItemCount == saveItemCount) { unsavedItemCount = 0; conn.Commit(); // Intermediate save conn.BeginTransaction(); } } catch (Exception ex) { LogClient.Error("There was a problem while updating Track with path='{0}'. Exception: {1}", diskTrack.Path, ex.Message); } currentValue += 1; // Report progress if at least 1 track is updated if (numberAddedTracks > 0) { this.eventArgs.IndexingAction = IndexingAction.AddTracks; this.eventArgs.ProgressCurrent = currentValue; this.eventArgs.ProgressTotal = totalValue; this.eventArgs.ProgressPercent = IndexerUtils.CalculatePercent(currentValue, totalValue); this.IndexingStatusChanged(this.eventArgs); } } conn.Commit(); // Final save } } catch (Exception ex) { LogClient.Error("There was a problem while adding Tracks. Exception: {0}", ex.Message); } }); return(numberAddedTracks); }
private bool ProcessTrack(Track track, SQLiteConnection conn) { bool processingSuccessful = false; var newAlbum = new Album(); var newArtist = new Artist(); var newGenre = new Genre(); try { IndexerUtils.SplitMetadata(track.Path, ref track, ref newAlbum, ref newArtist, ref newGenre); processingSuccessful = true; } catch (Exception ex) { processingSuccessful = false; LogClient.Instance.Logger.Error("Error while retrieving tag information for file {0}. File not added to the database. Exception: {1}", track.Path, ex.Message); } if (processingSuccessful) { // Check if such Artist already exists in the database if (!this.cache.GetCachedArtist(ref newArtist)) { // If not, add it. conn.Insert(newArtist); } // Check if such Genre already exists in the database if (!this.cache.GetCachedGenre(ref newGenre)) { // If not, add it. conn.Insert(newGenre); } // Check if such Album already exists in the database if (!this.cache.GetCachedAlbum(ref newAlbum)) { // If Not, add it. conn.Insert(newAlbum); } else { // Make sure the Year of the existing album is updated // TODO: can we prevent a database query here? Album dbAlbum = conn.Table <Album>().Where((a) => a.AlbumID.Equals(newAlbum.AlbumID)).FirstOrDefault(); if (dbAlbum != null) { dbAlbum.Year = newAlbum.Year; conn.Update(dbAlbum); } } track.AlbumID = newAlbum.AlbumID; track.ArtistID = newArtist.ArtistID; track.GenreID = newGenre.GenreID; } return(processingSuccessful); }
private async Task <long> AddArtworkAsync() { long numberUpdated = 0; await Task.Run(async() => { using (SQLiteConnection conn = this.factory.GetConnection()) { conn.BeginTransaction(); foreach (Album alb in conn.Table <Album>()) { try { Track trk = this.GetLastModifiedTrack(alb); alb.ArtworkID = await this.cacheService.CacheArtworkAsync(IndexerUtils.GetArtwork(alb, trk.Path)); if (!string.IsNullOrEmpty(alb.ArtworkID)) { alb.DateLastSynced = DateTime.Now.Ticks; conn.Update(alb); numberUpdated += 1; } } catch (Exception ex) { LogClient.Error("There was a problem while updating the cover art for Album {0}/{1}. Exception: {2}", alb.AlbumTitle, alb.AlbumArtist, ex.Message); } // Report progress if at least 1 album is added if (numberUpdated > 0) { this.eventArgs.IndexingAction = IndexingAction.UpdateArtwork; this.eventArgs.ProgressPercent = 0; this.IndexingStatusChanged(this.eventArgs); } } conn.Commit(); } }); return(numberUpdated); }
private async void AddArtworkInBackgroundAsync() { LogClient.Info("+++ STARTED ADDING ARTWORK IN THE BACKGROUND +++"); this.canIndexArtwork = true; this.isIndexingArtwork = true; long numberAdded = 0; DateTime startTime = DateTime.Now; await Task.Run(async() => { using (SQLiteConnection conn = this.factory.GetConnection()) { try { conn.BeginTransaction(); List <Album> albumsToCheck = conn.Table <Album>().ToList().Where(a => string.IsNullOrEmpty(a.ArtworkID)).ToList(); List <long> albumIds = new List <long>(); List <Album> albumsToIndex = conn.Table <Album>().ToList().Where(a => a.NeedsIndexing == 1).ToList(); foreach (Album alb in albumsToIndex) { if (!this.canIndexArtwork) { try { LogClient.Info("+++ ABORTED ADDING ARTWORK IN THE BACKGROUND. Time required: {0} ms +++", Convert.ToInt64(DateTime.Now.Subtract(startTime).TotalMilliseconds)); conn.Commit(); // Makes sure we commit what we already processed this.AlbumArtworkAdded(this, new AlbumArtworkAddedEventArgs() { AlbumIds = albumIds }); // Update UI } catch (Exception ex) { LogClient.Error("Failed to commit changes while aborting adding artwork in background. Exception: {0}", ex.Message); } this.isIndexingArtwork = false; return; } try { Track trk = this.GetLastModifiedTrack(alb); alb.ArtworkID = await this.cacheService.CacheArtworkAsync(IndexerUtils.GetArtwork(alb, trk.Path)); if (!string.IsNullOrEmpty(alb.ArtworkID)) { albumIds.Add(alb.AlbumID); alb.DateLastSynced = DateTime.Now.Ticks; conn.Update(alb); numberAdded += 1; if (albumIds.Count >= 20) { conn.Commit(); List <long> eventAlbumIds = new List <long>(albumIds); albumIds.Clear(); this.AlbumArtworkAdded(this, new AlbumArtworkAddedEventArgs() { AlbumIds = eventAlbumIds }); // Update UI } } } catch (Exception ex) { LogClient.Error("There was a problem while updating the cover art for Album {0}/{1}. Exception: {2}", alb.AlbumTitle, alb.AlbumArtist, ex.Message); } try { alb.NeedsIndexing = 0; conn.Update(alb); } catch (Exception ex) { LogClient.Error("There was a problem while updating the cover art for Album {0}/{1}. Exception: {2}", alb.AlbumTitle, alb.AlbumArtist, ex.Message); } } try { conn.Commit(); this.AlbumArtworkAdded(this, new AlbumArtworkAddedEventArgs() { AlbumIds = albumIds }); // Update UI } catch (Exception ex) { LogClient.Error("Failed to commit changes while finishing adding artwork in background. Exception: {0}", ex.Message); } } catch (Exception ex) { LogClient.Error("Unexpected error occurred while updating artwork in the background. Exception: {0}", ex.Message); } } }); this.isIndexingArtwork = false; LogClient.Error("+++ FINISHED ADDING ARTWORK IN THE BACKGROUND. Time required: {0} ms +++", Convert.ToInt64(DateTime.Now.Subtract(startTime).TotalMilliseconds)); }
private async Task <long> AddTracksAsync() { long numberAddedTracks = 0; var args = new IndexingStatusEventArgs() { IndexingAction = IndexingAction.AddTracks, ProgressPercent = 0 }; await Task.Run(() => { try { long currentValue = 0; long totalValue = this.newDiskPaths.Count; long saveItemCount = IndexerUtils.CalculateSaveItemCount(totalValue); long unsavedItemCount = 0; int lastPercent = 0; using (var conn = this.factory.GetConnection()) { conn.BeginTransaction(); foreach (FolderPathInfo newDiskPath in this.newDiskPaths) { Track diskTrack = Track.CreateDefault(newDiskPath.Path); try { this.ProcessTrack(diskTrack, conn); if (!this.cache.HasCachedTrack(ref diskTrack)) { conn.Insert(diskTrack); this.cache.AddTrack(diskTrack); numberAddedTracks += 1; unsavedItemCount += 1; } conn.Insert(new FolderTrack(newDiskPath.FolderId, diskTrack.TrackID)); // Intermediate save to the database if 20% is reached if (unsavedItemCount == saveItemCount) { unsavedItemCount = 0; conn.Commit(); // Intermediate save conn.BeginTransaction(); } } catch (Exception ex) { LogClient.Error("There was a problem while adding Track with path='{0}'. Exception: {1}", diskTrack.Path, ex.Message); } currentValue += 1; int percent = IndexerUtils.CalculatePercent(currentValue, totalValue); // Report progress if at least 1 track is added OR when the progress // interval has been exceeded OR the maximum has been reached. bool mustReportProgress = numberAddedTracks == 1 || percent >= lastPercent + 5 || percent == 100; if (mustReportProgress) { lastPercent = percent; args.ProgressCurrent = numberAddedTracks; args.ProgressPercent = percent; this.IndexingStatusChanged(args); } } conn.Commit(); // Final save } } catch (Exception ex) { LogClient.Error("There was a problem while adding Tracks. Exception: {0}", ex.Message); } }); return(numberAddedTracks); }
private async Task <long> UpdateTracksAsync() { long numberUpdatedTracks = 0; var args = new IndexingStatusEventArgs() { IndexingAction = IndexingAction.UpdateTracks, ProgressPercent = 0 }; await Task.Run(() => { try { using (var conn = this.factory.GetConnection()) { conn.BeginTransaction(); List <Track> alltracks = conn.Table <Track>().Select((t) => t).ToList(); long currentValue = 0; long totalValue = alltracks.Count; int lastPercent = 0; foreach (Track dbTrack in alltracks) { try { if (IndexerUtils.IsTrackOutdated(dbTrack) | dbTrack.NeedsIndexing == 1) { this.ProcessTrack(dbTrack, conn); conn.Update(dbTrack); numberUpdatedTracks += 1; } } catch (Exception ex) { LogClient.Error("There was a problem while updating Track with path='{0}'. Exception: {1}", dbTrack.Path, ex.Message); } currentValue += 1; int percent = IndexerUtils.CalculatePercent(currentValue, totalValue); // Report progress if at least 1 track is updated OR when the progress // interval has been exceeded OR the maximum has been reached. bool mustReportProgress = numberUpdatedTracks == 1 || percent >= lastPercent + 5 || percent == 100; if (mustReportProgress) { lastPercent = percent; args.ProgressPercent = percent; this.IndexingStatusChanged(args); } } conn.Commit(); } } catch (Exception ex) { LogClient.Error("There was a problem while updating Tracks. Exception: {0}", ex.Message); } }); return(numberUpdatedTracks); }
private async Task <string> GetArtworkFromFile(Album album) { Track trk = this.GetLastModifiedTrack(album); return(await this.cacheService.CacheArtworkAsync(IndexerUtils.GetArtwork(album, trk.Path))); }