diff --git a/ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs b/ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs index 6eda1708d..38782c108 100644 --- a/ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs +++ b/ErsatzTV.Core.Tests/Fakes/FakeTelevisionRepository.cs @@ -57,11 +57,12 @@ namespace ErsatzTV.Core.Tests.Fakes public Task> GetOrAddEpisode(Season season, LibraryPath libraryPath, string path) => throw new NotSupportedException(); - public Task DeleteEmptyShows() => throw new NotSupportedException(); + public Task> FindEpisodePaths(LibraryPath libraryPath) => throw new NotSupportedException(); - public Task> GetShowByPath(int mediaSourceId, string path) => throw new NotSupportedException(); + public Task DeleteByPath(LibraryPath libraryPath, string path) => throw new NotSupportedException(); - public Task DeleteMissingSources(int localMediaSourceId, List allFolders) => - throw new NotSupportedException(); + public Task DeleteEmptySeasons(LibraryPath libraryPath) => throw new NotSupportedException(); + + public Task DeleteEmptyShows(LibraryPath libraryPath) => throw new NotSupportedException(); } } diff --git a/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs index 9ac405b84..dd3287cc1 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/ITelevisionRepository.cs @@ -27,6 +27,9 @@ namespace ErsatzTV.Core.Interfaces.Repositories Task> AddShow(int libraryPathId, string showFolder, ShowMetadata metadata); Task> GetOrAddSeason(Show show, int libraryPathId, int seasonNumber); Task> GetOrAddEpisode(Season season, LibraryPath libraryPath, string path); - Task DeleteEmptyShows(); + Task> FindEpisodePaths(LibraryPath libraryPath); + Task DeleteByPath(LibraryPath libraryPath, string path); + Task DeleteEmptySeasons(LibraryPath libraryPath); + Task DeleteEmptyShows(LibraryPath libraryPath); } } diff --git a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs index 1e7227a9b..050589ca6 100644 --- a/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs +++ b/ErsatzTV.Core/Metadata/TelevisionFolderScanner.cs @@ -63,7 +63,17 @@ namespace ErsatzTV.Core.Metadata _ => Task.FromResult(Unit.Default)); } - await _televisionRepository.DeleteEmptyShows(); + foreach (string path in await _televisionRepository.FindEpisodePaths(libraryPath)) + { + if (!_localFileSystem.FileExists(path)) + { + _logger.LogInformation("Removing missing episode at {Path}", path); + await _televisionRepository.DeleteByPath(libraryPath, path); + } + } + + await _televisionRepository.DeleteEmptySeasons(libraryPath); + await _televisionRepository.DeleteEmptyShows(libraryPath); return Unit.Default; } diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs index 5dbf6cbb8..9a4469eb5 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MovieRepository.cs @@ -109,7 +109,6 @@ namespace ErsatzTV.Infrastructure.Data.Repositories @"SELECT M.Id FROM Movie M INNER JOIN MediaItem MI on M.Id = MI.Id - INNER JOIN MovieMetadata MM on M.Id = MM.MovieId INNER JOIN MediaVersion MV on M.Id = MV.MovieId INNER JOIN MediaFile MF on MV.Id = MF.MediaVersionId WHERE MI.LibraryPathId = @LibraryPathId AND MF.Path = @Path", @@ -117,17 +116,12 @@ namespace ErsatzTV.Infrastructure.Data.Repositories foreach (int movieId in ids) { - await Delete(movieId); + Movie movie = await _dbContext.Movies.FindAsync(movieId); + _dbContext.Movies.Remove(movie); } - return Unit.Default; - } - - private async Task Delete(int movieId) - { - Movie movie = await _dbContext.Movies.FindAsync(movieId); - _dbContext.Movies.Remove(movie); await _dbContext.SaveChangesAsync(); + return Unit.Default; } diff --git a/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs index 9dd94ed82..c46781116 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/TelevisionRepository.cs @@ -230,9 +230,55 @@ namespace ErsatzTV.Infrastructure.Data.Repositories () => AddEpisode(season, libraryPath.Id, path)); } - public Task DeleteEmptyShows() => + public Task> FindEpisodePaths(LibraryPath libraryPath) => + _dbConnection.QueryAsync( + @"SELECT MF.Path + FROM MediaFile MF + INNER JOIN MediaVersion MV on MF.MediaVersionId = MV.Id + INNER JOIN Episode E on MV.EpisodeId = E.Id + INNER JOIN MediaItem MI on E.Id = MI.Id + WHERE MI.LibraryPathId = @LibraryPathId", + new { LibraryPathId = libraryPath.Id }); + + public async Task DeleteByPath(LibraryPath libraryPath, string path) + { + IEnumerable ids = await _dbConnection.QueryAsync( + @"SELECT E.Id + FROM Episode E + INNER JOIN MediaItem MI on E.Id = MI.Id + INNER JOIN MediaVersion MV on E.Id = MV.EpisodeId + INNER JOIN MediaFile MF on MV.Id = MF.MediaVersionId + WHERE MI.LibraryPathId = @LibraryPathId AND MF.Path = @Path", + new { LibraryPathId = libraryPath.Id, Path = path }); + + foreach (int episodeId in ids) + { + Episode episode = await _dbContext.Episodes.FindAsync(episodeId); + _dbContext.Episodes.Remove(episode); + } + + await _dbContext.SaveChangesAsync(); + + return Unit.Default; + } + + public Task DeleteEmptySeasons(LibraryPath libraryPath) => + _dbContext.Seasons + .Filter(s => s.LibraryPathId == libraryPath.Id) + .Filter(s => s.Episodes.Count == 0) + .ToListAsync() + .Bind( + list => + { + _dbContext.Seasons.RemoveRange(list); + return _dbContext.SaveChangesAsync(); + }) + .ToUnit(); + + public Task DeleteEmptyShows(LibraryPath libraryPath) => _dbContext.Shows - .Where(s => s.Seasons.Count == 0) + .Filter(s => s.LibraryPathId == libraryPath.Id) + .Filter(s => s.Seasons.Count == 0) .ToListAsync() .Bind( list =>