private void CloseDatabase() { if (DBContext != null) { DBContext.Dispose(); DBContext = null; } }
private static Dictionary <string, string> GetOldSongs(mediadbContext dbContext) { Dictionary <string, string> oldSongs = new Dictionary <string, string>(); var songs = dbContext.Song.Select(x => new KeyValuePair <string, string>(x.Hash, x.Path)); foreach (var song in songs) { oldSongs.Add(song.Key, song.Value); } return(oldSongs); }
private static void ScrubArtistTable(mediadbContext dbContext) { var artists = dbContext.Artist; foreach (var artist in artists) { int albumCount = dbContext.Album.Where(a => a.ArtistName == artist.Name).Count(); int songCount = dbContext.ArtistSong.Where(a => a.ArtistName == artist.Name).Count(); if (albumCount == 0 && songCount == 0) { dbContext.Artist.Remove(artist); } } }
private static void ScrubAlbumTable(mediadbContext dbContext) { //should be fixed now var albums = dbContext.Album; foreach (var album in albums) { int songCount = dbContext.Song.Where(s => s.AlbumName == album.Name && s.AlbumArtistName == album.ArtistName).Count(); if (songCount == 0) { dbContext.Album.Remove(album); } } }
public static void Scan(mediadbContext dbContext, CancellationToken cancellationToken) { Stopwatch sw = Stopwatch.StartNew(); //grab/create lists Dictionary <string, string> OldSongs = GetOldSongs(dbContext); Dictionary <string, string> ExistingSongs = new Dictionary <string, string>(OldSongs.Count); Dictionary <string, SongInfo> NewSongs = new Dictionary <string, SongInfo>(); //enumerate songs in library folders //TODO try/catch (resilience) int scannedFiles = 0; foreach (string libraryFolder in UserConfig.Instance.MediaFolders) { Console.WriteLine($"[MediaScanner] Scanning library folder {libraryFolder}"); foreach (string filePath in GetFiles(libraryFolder)) { string extension = Path.GetExtension(filePath); if (!UserConfig.Instance.MediaFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) { continue; } try { SongInfo songInfo = ReadSongInfo(filePath); //ignore duplicates if (ExistingSongs.ContainsKey(songInfo.Hash) || NewSongs.ContainsKey(songInfo.Hash)) { //Console.WriteLine($"[MediaScanner] Skipping song {songInfo.Hash} at {filePath} because it already exists"); continue; } if (OldSongs.ContainsKey(songInfo.Hash)) { string oldPath = OldSongs[songInfo.Hash]; if (oldPath == songInfo.Path) { //path has not changed OldSongs.Remove(songInfo.Hash); ExistingSongs.Add(songInfo.Hash, songInfo.Path); //Console.WriteLine($"[MediaScanner] Readded song {songInfo.Hash} at {songInfo.Path}"); } else { //path has changed //OldSongs.Remove(songInfo.Hash); NewSongs.Add(songInfo.Hash, songInfo); //Console.WriteLine($"[MediaScanner] Readded song {songInfo.Hash} at {songInfo.Path} (moved from {oldPath})"); } } else { NewSongs.Add(songInfo.Hash, songInfo); //Console.WriteLine($"[MediaScanner] Added song {songInfo.Hash} at {songInfo.Path}"); } } catch (Exception ex) { Console.Error.WriteLine($"[MediaScanner] failed to add song {filePath} because of {ex.GetType().Name}"); } scannedFiles++; //reporting if (scannedFiles % UserConfig.Instance.MediaScannerReportInterval == 0) { Console.WriteLine($"[MediaScanner] Scanned {scannedFiles} files"); } cancellationToken.ThrowIfCancellationRequested(); } } Console.WriteLine($"[MediaScanner] Scanned {scannedFiles} files"); int totalRows = OldSongs.Count + NewSongs.Count; int maxDBErrors = Math.Max(UserConfig.Instance.MediaScannerMaxDBErrorMinCount, (int)(totalRows * UserConfig.Instance.MediaScannerMaxDBErrorRatio)); int dbErrors = 0; //clear songs that no longer exist Console.WriteLine($"[MediaScanner] Clearing {OldSongs.Count} songs from database"); foreach (var song in OldSongs) { try { var oldSong = dbContext.Song.Where(s => s.Hash == song.Key).First(); if (oldSong != null) { //manually scrub ArtistSong, because EF Core is f*****g us var songArtists = dbContext.ArtistSong.Where(a => a.SongHash == oldSong.Hash); dbContext.ArtistSong.RemoveRange(songArtists); dbContext.Song.Remove(oldSong); } else { Console.Error.WriteLine($"[MediaScanner] Failed to remove song {song.Key} because it doesn't exist in the DB"); } dbContext.SaveChanges(); cancellationToken.ThrowIfCancellationRequested(); } catch (Exception ex) { Console.Error.WriteLine($"[MediaScanner] Database Error: {ex.GetType().Name}\n{ex.Message}"); dbErrors++; } } //dbContext.SaveChanges(); //add new songs (adding new albums and artists as necessary) int totalSongs = NewSongs.Count; int insertReportInterval = UserConfig.Instance.MediaScannerReportInterval; //will be more complex later int insertedSongs = 0; Console.WriteLine($"[MediaScanner] Adding {totalSongs} songs to database"); foreach (var song in NewSongs) { try { AddSong(song.Value, dbContext); dbContext.SaveChanges(); } catch (Exception ex) { Console.Error.WriteLine($"[MediaScanner] Database Error: {ex.GetType().Name}\n{ex.Message}"); dbErrors++; ThrowIfMaxErrors(dbErrors, maxDBErrors); } insertedSongs++; if (insertedSongs % insertReportInterval == 0) { Console.WriteLine($"[MediaScanner] Added {insertedSongs}/{totalSongs} to database"); } cancellationToken.ThrowIfCancellationRequested(); //safe? } Console.WriteLine($"[MediaScanner] Added {insertedSongs}/{totalSongs} to database"); //scrub album table Console.WriteLine($"[MediaScanner] Scrubbing album table"); try { ScrubAlbumTable(dbContext); dbContext.SaveChanges(); } catch (Exception ex) { Console.Error.WriteLine($"[MediaScanner] Database Error: {ex.GetType().Name}\n{ex.Message}"); dbErrors++; ThrowIfMaxErrors(dbErrors, maxDBErrors); } //scrub artist table Console.WriteLine($"[MediaScanner] Scrubbing artist table"); try { ScrubArtistTable(dbContext); dbContext.SaveChanges(); } catch (Exception ex) { Console.Error.WriteLine($"[MediaScanner] Database Error: {ex.GetType().Name}\n{ex.Message}"); dbErrors++; ThrowIfMaxErrors(dbErrors, maxDBErrors); } sw.Stop(); Console.WriteLine($"[MediaScanner] Done scanning media library ({sw.Elapsed.TotalSeconds:F2}s, {dbErrors} errors)"); }
private static void AddSong(SongInfo song, mediadbContext dbContext) { //check to see if artists exit and add them if they do not //var artistsCNames = song.Artists.Select(a => new KeyValuePair<string, string>(MediaUtils.GetCanonicalName(a), a)).Distinct().ToDictionary(kvp => kvp.Key,; var artistsCNames = new Dictionary <string, string>(); foreach (var artist in song.Artists) { string artistCName = MediaUtils.GetCanonicalName(artist); if (artistsCNames.ContainsKey(artistCName)) { continue; } artistsCNames.Add(artistCName, artist); } foreach (var kvp in artistsCNames) { string artistCName = kvp.Key; string artistName = kvp.Value; if (string.IsNullOrEmpty(artistCName)) { continue; } if (dbContext.Artist.Where(a => a.Name == artistCName).Count() == 0) { var artist = new Artist() { Name = artistCName, NiceName = artistName }; dbContext.Artist.Add(artist); } } //check if album artist exists and add it if it does not string albumArtistCName = MediaUtils.GetCanonicalName(song.AlbumArtistName); if (!string.IsNullOrEmpty(albumArtistCName) && !artistsCNames.ContainsKey(albumArtistCName)) { if (dbContext.Artist.Where(a => a.Name == albumArtistCName).Count() == 0) { var artist = new Artist() { Name = albumArtistCName, NiceName = song.AlbumArtistName }; dbContext.Artist.Add(artist); } } //check if album exists and add it if it does not string albumCName = MediaUtils.GetCanonicalName(song.AlbumName); if (!string.IsNullOrEmpty(albumCName) && !string.IsNullOrEmpty(albumArtistCName)) { if (dbContext.Album.Where(a => a.Name == albumCName && a.ArtistName == albumArtistCName).Count() == 0) { var album = new Album() { Name = albumCName, ArtistName = albumArtistCName, Title = song.AlbumName }; dbContext.Album.Add(album); } } //genre should be a cname string genreCName = MediaUtils.GetCanonicalName(song.Genre); //create song object and add! var songObject = new Song() { Hash = song.Hash, Title = song.Title, Genre = genreCName, Length = song.Length, Set = song.Set, Track = song.Track, Path = song.Path, AlbumName = albumCName, AlbumArtistName = albumArtistCName }; dbContext.Song.Add(songObject); //create artist-song link objects foreach (var artistCName in artistsCNames.Keys) { var artistsong = new ArtistSong() { ArtistName = artistCName, SongHash = song.Hash }; dbContext.ArtistSong.Add(artistsong); } }
private void OpenDatabase() { DBContext = new mediadbContext(); }