Esempio n. 1
0
File: MediaDB.cs Progetto: XCVG/XSMP
 private void CloseDatabase()
 {
     if (DBContext != null)
     {
         DBContext.Dispose();
         DBContext = null;
     }
 }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
                }
            }
        }
Esempio n. 4
0
        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);
                }
            }
        }
Esempio n. 5
0
        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)");
        }
Esempio n. 6
0
        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);
            }
        }
Esempio n. 7
0
File: MediaDB.cs Progetto: XCVG/XSMP
 private void OpenDatabase()
 {
     DBContext = new mediadbContext();
 }