diff --git a/src/NzbDrone.Common/Extensions/PathExtensions.cs b/src/NzbDrone.Common/Extensions/PathExtensions.cs index 074a67fe3..66c4e1a49 100644 --- a/src/NzbDrone.Common/Extensions/PathExtensions.cs +++ b/src/NzbDrone.Common/Extensions/PathExtensions.cs @@ -37,10 +37,15 @@ namespace NzbDrone.Common.Extensions return info.FullName.TrimEnd('/').Trim('\\', ' '); } - public static bool PathEquals(this string firstPath, string secondPath) + public static bool PathEquals(this string firstPath, string secondPath, StringComparison? comparison = null) { - if (firstPath.Equals(secondPath, OsInfo.PathStringComparison)) return true; - return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), OsInfo.PathStringComparison); + if (!comparison.HasValue) + { + comparison = OsInfo.PathStringComparison; + } + + if (firstPath.Equals(secondPath, comparison.Value)) return true; + return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), comparison.Value); } public static string GetRelativePath(this string parentPath, string childPath) diff --git a/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs index 55ffbfd19..5bb18e455 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs @@ -56,7 +56,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests ExceptionVerification.ExpectedWarns(1); Mocker.GetMock() - .Verify(v => v.Clean(It.IsAny()), Times.Never()); + .Verify(v => v.Clean(It.IsAny(), It.IsAny>()), Times.Never()); } [Test] @@ -75,7 +75,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests ExceptionVerification.ExpectedWarns(1); Mocker.GetMock() - .Verify(v => v.Clean(It.IsAny()), Times.Never()); + .Verify(v => v.Clean(It.IsAny(), new List()), Times.Never()); } [Test] diff --git a/src/NzbDrone.Core.Test/MediaFiles/MediaFileTableCleanupServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MediaFileTableCleanupServiceFixture.cs index ca8d62a75..47a671d02 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MediaFileTableCleanupServiceFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MediaFileTableCleanupServiceFixture.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.IO; using FizzWare.NBuilder; using Moq; using NUnit.Framework; @@ -25,6 +26,7 @@ namespace NzbDrone.Core.Test.MediaFiles .ToList(); _series = Builder.CreateNew() + .With(s => s.Path = @"C:\Test\TV\Series") .Build(); Mocker.GetMock() @@ -52,6 +54,11 @@ namespace NzbDrone.Core.Test.MediaFiles .Returns(_episodes); } + private List FilesOnDisk(IEnumerable episodeFiles) + { + return episodeFiles.Select(e => Path.Combine(_series.Path, e.RelativePath)).ToList(); + } + [Test] public void should_skip_files_that_exist_in_disk() { @@ -60,7 +67,7 @@ namespace NzbDrone.Core.Test.MediaFiles GivenEpisodeFiles(episodeFiles); - Subject.Clean(_series); + Subject.Clean(_series, FilesOnDisk(episodeFiles)); Mocker.GetMock().Verify(c => c.UpdateEpisode(It.IsAny()), Times.Never()); } @@ -75,7 +82,7 @@ namespace NzbDrone.Core.Test.MediaFiles GivenEpisodeFiles(episodeFiles); - Subject.Clean(_series); + Subject.Clean(_series, FilesOnDisk(episodeFiles.Where(e => e.RelativePath != DELETED_PATH))); Mocker.GetMock().Verify(c => c.Delete(It.Is(e => e.RelativePath == DELETED_PATH), DeleteMediaFileReason.MissingFromDisk), Times.Exactly(2)); } @@ -91,7 +98,7 @@ namespace NzbDrone.Core.Test.MediaFiles GivenEpisodeFiles(episodeFiles); GivenFilesAreNotAttachedToEpisode(); - Subject.Clean(_series); + Subject.Clean(_series, FilesOnDisk(episodeFiles)); Mocker.GetMock().Verify(c => c.Delete(It.IsAny(), DeleteMediaFileReason.NoLinkedEpisodes), Times.Exactly(10)); } @@ -101,7 +108,7 @@ namespace NzbDrone.Core.Test.MediaFiles { GivenEpisodeFiles(new List()); - Subject.Clean(_series); + Subject.Clean(_series, new List()); Mocker.GetMock().Verify(c => c.UpdateEpisode(It.Is(e => e.EpisodeFileId == 0)), Times.Exactly(10)); } @@ -116,7 +123,7 @@ namespace NzbDrone.Core.Test.MediaFiles GivenEpisodeFiles(episodeFiles); - Subject.Clean(_series); + Subject.Clean(_series, FilesOnDisk(episodeFiles)); Mocker.GetMock().Verify(c => c.UpdateEpisode(It.IsAny()), Times.Never()); } diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/FileNameBuilderFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/FileNameBuilderFixture.cs index c70992827..d53192b1a 100644 --- a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/FileNameBuilderFixture.cs +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderTests/FileNameBuilderFixture.cs @@ -686,5 +686,17 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests Subject.BuildFileName(new List { _episode1 }, _series, _episodeFile) .Should().Be("Sonarr"); } + + [TestCase("0SEC")] + [TestCase("2HD")] + [TestCase("IMMERSE")] + public void should_use_existing_casing_for_release_group(string releaseGroup) + { + _episodeFile.ReleaseGroup = releaseGroup; + _namingConfig.StandardEpisodeFormat = "{Release Group}"; + + Subject.BuildFileName(new List { _episode1 }, _series, _episodeFile) + .Should().Be(releaseGroup); + } } } diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs index 456908945..5c8896fdf 100644 --- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -80,8 +80,7 @@ namespace NzbDrone.Core.MediaFiles } _logger.ProgressInfo("Scanning disk for {0}", series.Title); - _mediaFileTableCleanupService.Clean(series); - + if (!_diskProvider.FolderExists(series.Path)) { if (_configService.CreateEmptySeriesFolders && @@ -106,6 +105,9 @@ namespace NzbDrone.Core.MediaFiles videoFilesStopwatch.Stop(); _logger.Trace("Finished getting episode files for: {0} [{1}]", series, videoFilesStopwatch.Elapsed); + _logger.Debug("{0} Cleaning up media files in DB", series); + _mediaFileTableCleanupService.Clean(series, mediaFileList); + var decisionsStopwatch = Stopwatch.StartNew(); var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, series); decisionsStopwatch.Stop(); diff --git a/src/NzbDrone.Core/MediaFiles/MediaFileTableCleanupService.cs b/src/NzbDrone.Core/MediaFiles/MediaFileTableCleanupService.cs index 38801be74..263500dd8 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaFileTableCleanupService.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaFileTableCleanupService.cs @@ -1,55 +1,55 @@ using System; +using System.Collections.Generic; using System.IO; -using System.Linq; using NLog; -using NzbDrone.Common.Disk; +using NzbDrone.Common; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Tv; namespace NzbDrone.Core.MediaFiles { public interface IMediaFileTableCleanupService { - void Clean(Series series); + void Clean(Series series, List filesOnDisk); } public class MediaFileTableCleanupService : IMediaFileTableCleanupService { private readonly IMediaFileService _mediaFileService; - private readonly IDiskProvider _diskProvider; private readonly IEpisodeService _episodeService; private readonly Logger _logger; public MediaFileTableCleanupService(IMediaFileService mediaFileService, - IDiskProvider diskProvider, IEpisodeService episodeService, - ISeriesService seriesService, Logger logger) { _mediaFileService = mediaFileService; - _diskProvider = diskProvider; _episodeService = episodeService; _logger = logger; } - public void Clean(Series series) + public void Clean(Series series, List filesOnDisk) { - var seriesFile = _mediaFileService.GetFilesBySeries(series.Id); + var seriesFiles = _mediaFileService.GetFilesBySeries(series.Id); var episodes = _episodeService.GetEpisodeBySeries(series.Id); - foreach (var episodeFile in seriesFile) + var filesOnDiskKeys = new HashSet(filesOnDisk, PathEqualityComparer.Instance); + + foreach (var seriesFile in seriesFiles) { + var episodeFile = seriesFile; var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath); try { - if (!_diskProvider.FileExists(episodeFilePath)) + if (!filesOnDiskKeys.Contains(episodeFilePath)) { _logger.Debug("File [{0}] no longer exists on disk, removing from db", episodeFilePath); - _mediaFileService.Delete(episodeFile, DeleteMediaFileReason.MissingFromDisk); + _mediaFileService.Delete(seriesFile, DeleteMediaFileReason.MissingFromDisk); continue; } - if (!episodes.Any(e => e.EpisodeFileId == episodeFile.Id)) + if (episodes.None(e => e.EpisodeFileId == episodeFile.Id)) { _logger.Debug("File [{0}] is not assigned to any episodes, removing from db", episodeFilePath); _mediaFileService.Delete(episodeFile, DeleteMediaFileReason.NoLinkedEpisodes); @@ -73,9 +73,11 @@ namespace NzbDrone.Core.MediaFiles } } - foreach (var episode in episodes) + foreach (var e in episodes) { - if (episode.EpisodeFileId > 0 && !seriesFile.Any(f => f.Id == episode.EpisodeFileId)) + var episode = e; + + if (episode.EpisodeFileId > 0 && seriesFiles.None(f => f.Id == episode.EpisodeFileId)) { episode.EpisodeFileId = 0; _episodeService.UpdateEpisode(episode); diff --git a/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs b/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs index 6570fee99..5f6cb6709 100644 --- a/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs @@ -89,7 +89,7 @@ namespace NzbDrone.Core.MediaFiles var newName = _filenameBuilder.BuildFileName(episodesInFile, series, file); var newPath = _filenameBuilder.BuildFilePath(series, seasonNumber, newName, Path.GetExtension(episodeFilePath)); - if (!episodeFilePath.PathEquals(newPath)) + if (!episodeFilePath.PathEquals(newPath, StringComparison.Ordinal)) { yield return new RenameEpisodeFilePreview {