From 63bd972af9685272d9181f6fac1772f456a564bd Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Sun, 19 Jun 2011 20:04:08 -0700 Subject: [PATCH] Refactored MediaFileProvider --- NzbDrone.Core.Test/DiskScanJobTest.cs | 16 +- NzbDrone.Core.Test/MediaFileProviderTests.cs | 135 +----- ...MediaFileProvider_ImportNewDownloadTest.cs | 444 ------------------ NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 1 - NzbDrone.Core/NzbDrone.Core.csproj | 1 + NzbDrone.Core/Providers/DiskScanProvider.cs | 413 +++++----------- NzbDrone.Core/Providers/Jobs/DiskScanJob.cs | 8 +- .../Providers/Jobs/PostDownloadScanJob.cs | 8 +- .../Providers/Jobs/RenameEpisodeJob.cs | 16 +- NzbDrone.Core/Providers/MediaFileProvider.cs | 267 +---------- 10 files changed, 154 insertions(+), 1155 deletions(-) delete mode 100644 NzbDrone.Core.Test/MediaFileProvider_ImportNewDownloadTest.cs diff --git a/NzbDrone.Core.Test/DiskScanJobTest.cs b/NzbDrone.Core.Test/DiskScanJobTest.cs index f653e9624..4c6636827 100644 --- a/NzbDrone.Core.Test/DiskScanJobTest.cs +++ b/NzbDrone.Core.Test/DiskScanJobTest.cs @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test .Setup(p => p.GetSeries(series.SeriesId)) .Returns(series); - mocker.GetMock() + mocker.GetMock() .Setup(p => p.Scan(series)) .Returns(new List()); @@ -58,11 +58,11 @@ namespace NzbDrone.Core.Test .Setup(p => p.GetAllSeries()) .Returns(series); - mocker.GetMock() + mocker.GetMock() .Setup(s => s.Scan(series[0])) .Returns(new List()); - mocker.GetMock() + mocker.GetMock() .Setup(s => s.Scan(series[1])) .Returns(new List()); @@ -86,11 +86,11 @@ namespace NzbDrone.Core.Test .Setup(p => p.GetAllSeries()) .Returns(series); - mocker.GetMock() + mocker.GetMock() .Setup(s => s.Scan(series[0])) .Throws(new InvalidOperationException("Bad Job")); - mocker.GetMock() + mocker.GetMock() .Setup(s => s.Scan(series[1])) .Throws(new InvalidOperationException("Bad Job")); @@ -115,11 +115,11 @@ namespace NzbDrone.Core.Test .Setup(p => p.GetAllSeries()) .Returns(series); - mocker.GetMock() + mocker.GetMock() .Setup(s => s.Scan(series[0])) .Returns(new List()); - mocker.GetMock() + mocker.GetMock() .Setup(s => s.Scan(series[1])) .Returns(new List()); @@ -128,7 +128,7 @@ namespace NzbDrone.Core.Test mocker.VerifyAllMocks(); - mocker.GetMock().Verify(s => s.Scan(It.IsAny()), Times.Exactly(2)); + mocker.GetMock().Verify(s => s.Scan(It.IsAny()), Times.Exactly(2)); } } diff --git a/NzbDrone.Core.Test/MediaFileProviderTests.cs b/NzbDrone.Core.Test/MediaFileProviderTests.cs index 1e734652a..8f6ad61c1 100644 --- a/NzbDrone.Core.Test/MediaFileProviderTests.cs +++ b/NzbDrone.Core.Test/MediaFileProviderTests.cs @@ -60,7 +60,7 @@ namespace NzbDrone.Core.Test .Setup(e => e.GetEpisode(fakeSeries.SeriesId, seasonNumber, episodeNumner)).Returns(fakeEpisode); //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert Assert.IsNotNull(result); @@ -107,7 +107,7 @@ namespace NzbDrone.Core.Test .Setup(e => e.GetSize(fileName)).Returns(size).Verifiable(); //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert Assert.IsNotNull(result); @@ -147,7 +147,7 @@ namespace NzbDrone.Core.Test .Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(true).Verifiable(); //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert mocker.VerifyAllMocks(); @@ -178,7 +178,7 @@ namespace NzbDrone.Core.Test .Setup(e => e.GetSize(fileName)).Returns(size).Verifiable(); //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert mocker.VerifyAllMocks(); @@ -218,7 +218,7 @@ namespace NzbDrone.Core.Test //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert Assert.IsNull(result); @@ -238,7 +238,7 @@ namespace NzbDrone.Core.Test mocker.GetMock(MockBehavior.Strict); //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert result.Should().BeNull(); @@ -275,7 +275,7 @@ namespace NzbDrone.Core.Test //Act - var result = mocker.Resolve().ImportFile(fakeSeries, fileName); + var result = mocker.Resolve().ImportFile(fakeSeries, fileName); //Assert mocker.VerifyAllMocks(); @@ -296,7 +296,7 @@ namespace NzbDrone.Core.Test .Setup(c => c.GetEpisodeBySeries(It.IsAny())) .Returns(new List { new Episode() }); - mocker.Resolve().Scan(new Series()); + mocker.Resolve().Scan(new Series()); mocker.VerifyAllMocks(); @@ -330,123 +330,6 @@ namespace NzbDrone.Core.Test result.Should().HaveSameCount(firstSeriesFiles); } - [Test] - [Description("Verifies that a new download will import successfully")] - public void import_new_download_success() - { - //Fakes - var fakeSeries = Builder.CreateNew() - .With(s => s.Title = "30 Rock") - .With(s => s.Path = @"C:\Test\TV\30 Rock") - .Build(); - - var fakeEpisode = Builder.CreateNew() - .With(e => e.SeriesId = fakeSeries.SeriesId) - .With(e => e.EpisodeFileId = 0) - .With(e => e.SeasonNumber = 1) - .With(e => e.EpisodeNumber = 5) - .Build(); - - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05 - Episode Title\30.Rock.S01E05.Gibberish.XviD.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.RenameFile(It.IsAny(), It.IsAny())); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".avi"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { fakeEpisode }); - episodeProvider.Setup(e => e.GetEpisode(fakeSeries.SeriesId, 1, 5)).Returns(fakeEpisode); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - var database = mocker.GetMock(MockBehavior.Strict); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1).Verifiable(); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05 - Episode Title", fakeSeries); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(1, result.Count); - } - - [Test] - [Description("Verifies that a new download will import successfully, deletes previous episode")] - public void import_new_download_success_delete_equal_quality() - { - //Fakes - var fakeSeries = Builder.CreateNew() - .With(s => s.Title = "30 Rock") - .With(s => s.Path = @"C:\Test\TV\30 Rock") - .Build(); - - var fakeEpisode = Builder.CreateNew() - .With(e => e.SeriesId = fakeSeries.SeriesId) - .With(e => e.SeasonNumber = 1) - .With(e => e.EpisodeNumber = 5) - .With(e => e.EpisodeFileId = 1) - .Build(); - - var fakeEpisodeFile = Builder.CreateNew() - .With(e => e.SeriesId = fakeSeries.SeriesId) - .With(e => e.EpisodeFileId = 1) - .With(e => e.Quality = QualityTypes.SDTV) - .With(e => e.Episodes = new List { fakeEpisode }) - .Build(); - - fakeEpisode.EpisodeFile = fakeEpisodeFile; - - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05 - Episode Title\30.Rock.S01E05.Gibberish.XviD.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.RenameFile(It.IsAny(), It.IsAny())); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".avi"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { fakeEpisode }); - episodeProvider.Setup(e => e.GetEpisode(fakeSeries.SeriesId, 1, 5)).Returns(fakeEpisode); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - var database = mocker.GetMock(MockBehavior.Strict); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1); - database.Setup(r => r.Delete(It.IsAny())).Returns(1); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05 - Episode Title", fakeSeries); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(1, result.Count); - } - - [Test] public void Scan_series_should_skip_series_with_no_episodes() { @@ -459,7 +342,7 @@ namespace NzbDrone.Core.Test .With(s => s.SeriesId = 12).Build(); //Act - mocker.Resolve().Scan(series); + mocker.Resolve().Scan(series); //Assert mocker.VerifyAllMocks(); diff --git a/NzbDrone.Core.Test/MediaFileProvider_ImportNewDownloadTest.cs b/NzbDrone.Core.Test/MediaFileProvider_ImportNewDownloadTest.cs deleted file mode 100644 index c3a46ab16..000000000 --- a/NzbDrone.Core.Test/MediaFileProvider_ImportNewDownloadTest.cs +++ /dev/null @@ -1,444 +0,0 @@ -// ReSharper disable RedundantUsingDirective -using System.Collections.Generic; -using System.IO; -using AutoMoq; -using FizzWare.NBuilder; -using Moq; -using NUnit.Framework; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.Providers.Core; -using NzbDrone.Core.Repository; -using NzbDrone.Core.Repository.Quality; -using NzbDrone.Core.Test.Framework; -using PetaPoco; - -namespace NzbDrone.Core.Test -{ - [TestFixture] - // ReSharper disable InconsistentNaming - public class MediaFileProvider_ImportNewDownloadTest : TestBase - { - private Episode episode; - private Episode episode2; - private EpisodeFile episodeFile; - private EpisodeFile episodeFile2; - private Series series; - - [SetUp] - public new void Setup() - { - series = Builder.CreateNew() - .With(s => s.Title = "30 Rock") - .With(s => s.Path = @"C:\Test\TV\30 Rock") - .Build(); - - episode = Builder.CreateNew() - .With(e => e.SeriesId = series.SeriesId) - .With(e => e.SeasonNumber = 1) - .With(e => e.EpisodeNumber = 5) - .With(e => e.EpisodeFileId = 1) - .With(e => e.Title = "Episode One Title") - .Build(); - - episode2 = Builder.CreateNew() - .With(e => e.SeriesId = series.SeriesId) - .With(e => e.SeasonNumber = 1) - .With(e => e.EpisodeNumber = 6) - .With(e => e.EpisodeFileId = 1) - .With(e => e.Title = "Episode Two Title") - .Build(); - - episodeFile = Builder.CreateNew() - .With(e => e.SeriesId = series.SeriesId) - .With(e => e.EpisodeFileId = 1) - .With(e => e.Quality = QualityTypes.SDTV) - .With(e => e.Episodes = new List { episode }) - .Build(); - - episodeFile2 = Builder.CreateNew() - .With(e => e.SeriesId = series.SeriesId) - .With(e => e.EpisodeFileId = 1) - .With(e => e.Quality = QualityTypes.SDTV) - .With(e => e.Episodes = new List { episode }) - .Build(); - - episode.EpisodeFile = episodeFile; - - base.Setup(); - } - - [Test] - [Description("Verifies that a new download will import successfully")] - public void import_new_download_imported() - { - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05 - Episode Title\30.Rock.S01E05.Gibberish.XviD.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.RenameFile(It.IsAny(), It.IsAny())); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".avi"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List {episode}); - episodeProvider.Setup(e => e.GetEpisode(series.SeriesId, 1, 5)).Returns(episode); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - var database = mocker.GetMock(); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(1, result.Count); - } - - [Test] - [Description("Verifies that a new download will import successfully, deletes previous episode")] - public void import_new_download_imported_delete_equal_quality() - { - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05 - Episode Title\30.Rock.S01E05.Gibberish.XviD.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.RenameFile(It.IsAny(), It.IsAny())); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".avi"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { episode }); - episodeProvider.Setup(e => e.GetEpisode(series.SeriesId, 1, 5)).Returns(episode); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - var database = mocker.GetMock(); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(1, result.Count); - } - - [Test] - [Description("Verifies that a new download will not import successfully, because existing episode is better")] - public void import_new_download_not_imported_greater_quality() - { - //Alternate Setups - episodeFile.Quality = QualityTypes.DVD; - - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05 - Episode Title\30.Rock.S01E05.Gibberish.XviD.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".avi"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { episode }); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(0, result.Count); - } - - [Test] - [Description("Verifies that a new download will not import successfully, because of invalid episode in new file")] - public void import_new_download_not_imported_non_existant_episode() - { - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05 - Episode Title\30.Rock.S01E05.Gibberish.XviD.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List()); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(0, result.Count); - ExceptionVerification.ExcpectedErrors(1); - } - - [Test] - [Description("Verifies that a new download will import successfully, deletes previous episode")] - public void import_new_download_imported_delete_lesser_quality_multi_episodes() - { - //Alternate Setup - episodeFile.Episodes.Add(episode2); - episode2.EpisodeFile = episodeFile; - - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05x06 - Episode Title\30.Rock.S01E05E06.Gibberish.x264.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.RenameFile(It.IsAny(), It.IsAny())); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".mkv"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { episode, episode2 }); - episodeProvider.Setup(e => e.GetEpisode(series.SeriesId, 1, 5)).Returns(episode); - episodeProvider.Setup(e => e.GetEpisode(series.SeriesId, 1, 6)).Returns(episode2); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - var database = mocker.GetMock(); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05x06 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(1, result.Count); - } - - [Test] - [Description("Verifies that a new download will import successfully, deletes previous episode")] - public void import_new_download_imported_delete_lesser_quality_multi_episode_files() - { - //Alternate Setup - episodeFile2.Episodes.Add(episode2); - episode2.EpisodeFile = episodeFile2; - - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05x06 - Episode Title\30.Rock.S01E05E06.Gibberish.x264.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.RenameFile(It.IsAny(), It.IsAny())); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".mkv"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { episode, episode2 }); - episodeProvider.Setup(e => e.GetEpisode(series.SeriesId, 1, 5)).Returns(episode); - episodeProvider.Setup(e => e.GetEpisode(series.SeriesId, 1, 6)).Returns(episode2); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - var database = mocker.GetMock(); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05x06 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(1, result.Count); - } - - [Test] - [Description("Verifies that a new download will not import successfully, previous episode is better quality")] - public void import_new_download_not_imported_multi_episode_files() - { - //Alternate Setup - episodeFile2.Episodes.Add(episode2); - episode2.EpisodeFile = episodeFile2; - episodeFile2.Quality = QualityTypes.Bluray720p; - - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05x06 - Episode Title\30.Rock.S01E05E06.Gibberish.x264.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".mkv"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { episode, episode2 }); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05x06 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(0, result.Count); - } - - [Test] - [Description("Verifies that a new download will not import successfully, episode is sample under 40MB")] - public void import_new_download_not_imported_episode_sample_under_40MB() - { - //Alternate Setup - episodeFile2.Episodes.Add(episode2); - episode2.EpisodeFile = episodeFile2; - episodeFile2.Quality = QualityTypes.Bluray720p; - - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05x06 - Episode Title\30.Rock.S01E05.Gibberish.x264-sample.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(30000000); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05x06 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(0, result.Count); - } - - [Test] - [Description("Verifies that a new download will import successfully, even though the episode title contains Sample")] - public void import_new_download_imported_contains_sample_over_40MB() - { - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05 - Episode Title\30.Rock.S01E05.Fourty.Samples.Gibberish.XviD.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(90000000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.RenameFile(It.IsAny(), It.IsAny())); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".avi"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { episode }); - episodeProvider.Setup(e => e.GetEpisode(series.SeriesId, 1, 5)).Returns(episode); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - var database = mocker.GetMock(); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05 - Fourty Samples", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(1, result.Count); - } - - [Test] - [Description("Verifies that a new download will import successfully, even though the efile size is under 40MB")] - public void import_new_download_imported_under_40MB() - { - //Mocks - var mocker = new AutoMoqer(); - - var diskProvider = mocker.GetMock(); - diskProvider.Setup(d => d.GetFiles(It.IsAny(), "*.*", SearchOption.AllDirectories)).Returns(new string[] { @"C:\Test\30 Rock - 1x05 - Episode Title\30.Rock.S01E05.Gibberish.XviD.avi" }); - diskProvider.Setup(d => d.GetSize(It.IsAny())).Returns(30000000); - diskProvider.Setup(d => d.CreateDirectory(It.IsAny())).Returns("ok"); - diskProvider.Setup(d => d.RenameFile(It.IsAny(), It.IsAny())); - diskProvider.Setup(d => d.GetExtension(It.IsAny())).Returns(".avi"); - - var episodeProvider = mocker.GetMock(); - episodeProvider.Setup(e => e.GetEpisodes(It.IsAny())).Returns(new List { episode }); - episodeProvider.Setup(e => e.GetEpisode(series.SeriesId, 1, 5)).Returns(episode); - - var configProvider = mocker.GetMock(); - configProvider.SetupGet(c => c.UseSeasonFolder).Returns(true); - configProvider.SetupGet(c => c.SeasonFolderFormat).Returns(@"Season %0s"); - configProvider.SetupGet(c => c.SeriesName).Returns(true); - configProvider.SetupGet(c => c.EpisodeName).Returns(true); - configProvider.SetupGet(c => c.AppendQuality).Returns(true); - configProvider.SetupGet(c => c.SeparatorStyle).Returns(0); - configProvider.SetupGet(c => c.NumberStyle).Returns(2); - configProvider.SetupGet(c => c.ReplaceSpaces).Returns(false); - - var database = mocker.GetMock(); - database.Setup(r => r.Exists(It.IsAny(), It.IsAny())).Returns(false).Verifiable(); - database.Setup(r => r.Insert(It.IsAny())).Returns(1); - - //Act - var result = mocker.Resolve().ImportNewFiles(@"C:\Test\30 Rock - 1x05 - Episode Title", series); - - //Assert - mocker.VerifyAllMocks(); - Assert.AreEqual(1, result.Count); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index fd96cd025..ff97e5004 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -87,7 +87,6 @@ - diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index d1daa6c0d..785b24271 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -180,6 +180,7 @@ + diff --git a/NzbDrone.Core/Providers/DiskScanProvider.cs b/NzbDrone.Core/Providers/DiskScanProvider.cs index 0483d14d2..996be81b7 100644 --- a/NzbDrone.Core/Providers/DiskScanProvider.cs +++ b/NzbDrone.Core/Providers/DiskScanProvider.cs @@ -14,41 +14,50 @@ using PetaPoco; namespace NzbDrone.Core.Providers { - class DiskScanProvider + public class DiskScanProvider { - + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly string[] MediaExtentions = new[] { ".mkv", ".avi", ".wmv", ".mp4" }; private readonly DiskProvider _diskProvider; private readonly EpisodeProvider _episodeProvider; private readonly SeriesProvider _seriesProvider; - private readonly ConfigProvider _configProvider; + private readonly MediaFileProvider _mediaFileProvider; private readonly IDatabase _database; [Inject] public DiskScanProvider(DiskProvider diskProvider, EpisodeProvider episodeProvider, - SeriesProvider seriesProvider, ConfigProvider configProvider, + SeriesProvider seriesProvider, MediaFileProvider mediaFileProvider, IDatabase database) { _diskProvider = diskProvider; _episodeProvider = episodeProvider; _seriesProvider = seriesProvider; - _configProvider = configProvider; + _mediaFileProvider = mediaFileProvider; _database = database; } public DiskScanProvider() { - - } + } /// /// Scans the specified series folder for media files /// /// The series to be scanned public virtual List Scan(Series series) + { + return Scan(series, series.Path); + } + + /// + /// Scans the specified series folder for media files + /// + /// The series to be scanned + /// Path to scan + public virtual List Scan(Series series, string path) { if (_episodeProvider.GetEpisodeBySeries(series.SeriesId).Count == 0) { @@ -56,7 +65,7 @@ namespace NzbDrone.Core.Providers return new List(); } - var mediaFileList = GetVideoFiles(series.Path); + var mediaFileList = GetVideoFiles(path); var fileList = new List(); foreach (var filePath in mediaFileList) @@ -72,104 +81,125 @@ namespace NzbDrone.Core.Providers return fileList; } + public virtual EpisodeFile ImportFile(Series series, string filePath) { Logger.Trace("Importing file to database [{0}]", filePath); - try + if (_database.Exists("Path =@0", Parser.NormalizePath(filePath))) { - var size = _diskProvider.GetSize(filePath); + Logger.Trace("[{0}] already exists in the database. skipping.", filePath); + return null; + } - //If Size is less than 50MB and contains sample. Check for Size to ensure its not an episode with sample in the title - if (size < 40000000 && filePath.ToLower().Contains("sample")) - { - Logger.Trace("[{0}] appears to be a sample. skipping.", filePath); - return null; - } + var size = _diskProvider.GetSize(filePath); - //Check to see if file already exists in the database - if (!_database.Exists("Path =@0", Parser.NormalizePath(filePath))) - { - var parseResult = Parser.ParseEpisodeInfo(filePath); + //If Size is less than 50MB and contains sample. Check for Size to ensure its not an episode with sample in the title + if (size < 40000000 && filePath.ToLower().Contains("sample")) + { + Logger.Trace("[{0}] appears to be a sample. skipping.", filePath); + return null; + } + + var parseResult = Parser.ParseEpisodeInfo(filePath); - if (parseResult == null) - return null; + if (parseResult == null) + return null; - parseResult.CleanTitle = series.Title;//replaces the nasty path as title to help with logging + parseResult.CleanTitle = series.Title;//replaces the nasty path as title to help with logging - //Stores the list of episodes to add to the EpisodeFile - var episodes = new List(); + //Stores the list of episodes to add to the EpisodeFile + var episodes = new List(); - //Check for daily shows - if (parseResult.EpisodeNumbers == null) + //Check for daily shows + if (parseResult.EpisodeNumbers == null) + { + var episode = _episodeProvider.GetEpisode(series.SeriesId, parseResult.AirDate.Date); + + if (episode != null) + { + episodes.Add(episode); + } + else + { + Logger.Warn("Unable to find [{0}] in the database.[{1}]", parseResult, filePath); + } + } + else + { + foreach (var episodeNumber in parseResult.EpisodeNumbers) + { + var episode = _episodeProvider.GetEpisode(series.SeriesId, parseResult.SeasonNumber, + episodeNumber); + + if (episode != null) { - var episode = _episodeProvider.GetEpisode(series.SeriesId, parseResult.AirDate.Date); - - if (episode != null) - { - episodes.Add(episode); - } - else - { - Logger.Warn("Unable to find [{0}] in the database.[{1}]", parseResult, filePath); - } + episodes.Add(episode); } else { - foreach (var episodeNumber in parseResult.EpisodeNumbers) - { - var episode = _episodeProvider.GetEpisode(series.SeriesId, parseResult.SeasonNumber, - episodeNumber); - - if (episode != null) - { - episodes.Add(episode); - } - else - { - Logger.Warn("Unable to find [{0}] in the database.[{1}]", parseResult, filePath); - } - } - } - - //Return null if no Episodes exist in the DB for the parsed episodes from file - if (episodes.Count <= 0) - return null; - - var episodeFile = new EpisodeFile(); - episodeFile.DateAdded = DateTime.Now; - episodeFile.SeriesId = series.SeriesId; - episodeFile.Path = Parser.NormalizePath(filePath); - episodeFile.Size = size; - episodeFile.Quality = parseResult.Quality.QualityType; - episodeFile.Proper = parseResult.Quality.Proper; - episodeFile.SeasonNumber = parseResult.SeasonNumber; - var fileId = Convert.ToInt32(_database.Insert(episodeFile)); - - //This is for logging + updating the episodes that are linked to this EpisodeFile - string episodeList = String.Empty; - foreach (var ep in episodes) - { - ep.EpisodeFileId = fileId; - _episodeProvider.UpdateEpisode(ep); - episodeList += String.Format(", {0}", ep.EpisodeId).Trim(' ', ','); + Logger.Warn("Unable to find [{0}] in the database.[{1}]", parseResult, filePath); } - Logger.Trace("File {0}:{1} attached to episode(s): '{2}'", episodeFile.EpisodeFileId, filePath, - episodeList); - - return episodeFile; } - - Logger.Trace("[{0}] already exists in the database. skipping.", filePath); } - catch (Exception ex) + + //Return null if no Episodes exist in the DB for the parsed episodes from file + if (episodes.Count <= 0) + return null; + + var episodeFile = new EpisodeFile(); + episodeFile.DateAdded = DateTime.Now; + episodeFile.SeriesId = series.SeriesId; + episodeFile.Path = Parser.NormalizePath(filePath); + episodeFile.Size = size; + episodeFile.Quality = parseResult.Quality.QualityType; + episodeFile.Proper = parseResult.Quality.Proper; + episodeFile.SeasonNumber = parseResult.SeasonNumber; + var fileId = Convert.ToInt32(_database.Insert(episodeFile)); + + //This is for logging + updating the episodes that are linked to this EpisodeFile + string episodeList = String.Empty; + foreach (var ep in episodes) { - Logger.ErrorException("An error has occurred while importing file " + filePath, ex); - throw; + ep.EpisodeFileId = fileId; + _episodeProvider.UpdateEpisode(ep); + episodeList += String.Format(", {0}", ep.EpisodeId).Trim(' ', ','); } - return null; + Logger.Trace("File {0}:{1} attached to episode(s): '{2}'", episodeFile.EpisodeFileId, filePath, + episodeList); + + return episodeFile; + } + + + + public virtual bool RenameEpisodeFile(EpisodeFile episodeFile) + { + if (episodeFile == null) + throw new ArgumentNullException("episodeFile"); + + var series = _seriesProvider.GetSeries(episodeFile.SeriesId); + var ext = _diskProvider.GetExtension(episodeFile.Path); + var episodes = _episodeProvider.GetEpisodesByFileId(episodeFile.EpisodeFileId); + var newFileName = _mediaFileProvider.GetNewFilename(episodes, series.Title, episodeFile.Quality); + + var newFile = _mediaFileProvider.CalculateFilePath(series, episodes.First().SeasonNumber, newFileName, ext); + + //Do the rename + _diskProvider.RenameFile(episodeFile.Path, newFile.FullName); + + //Update the filename in the DB + episodeFile.Path = newFile.FullName; + _mediaFileProvider.Update(episodeFile); + + + return true; + } + + + /// /// Removes files that no longer exist from the database /// @@ -197,7 +227,6 @@ namespace NzbDrone.Core.Providers } - private List GetVideoFiles(string path) { Logger.Debug("Scanning '{0}' for episodes", path); @@ -210,219 +239,5 @@ namespace NzbDrone.Core.Providers return mediaFileList; } - public virtual List ImportNewFiles(string path, Series series) - { - var result = new List(); - - //Get all the files except those that are considered samples - var files = GetVideoFiles(path).Where(f => _diskProvider.GetSize(f) > 40000000 || !f.ToLower().Contains("sample")).ToList(); - - foreach (var file in files) - { - try - { - //Parse the filename - var parseResult = Parser.ParseEpisodeInfo(Path.GetFileName(file)); - parseResult.Series = series; - parseResult.Episodes = _episodeProvider.GetEpisodes(parseResult); - - if (parseResult.Episodes.Count == 0) - { - Logger.Error("File '{0}' contains invalid episode information, skipping import", file); - continue; - } - - var ext = _diskProvider.GetExtension(file); - var filename = GetNewFilename(parseResult.Episodes, series.Title, parseResult.Quality.QualityType) + ext; - var folder = series.Path + Path.DirectorySeparatorChar; - if (_configProvider.UseSeasonFolder) - folder += _configProvider.SeasonFolderFormat - .Replace("%0s", parseResult.SeasonNumber.ToString("00")) - .Replace("%s", parseResult.SeasonNumber.ToString()) - + Path.DirectorySeparatorChar; - - _diskProvider.CreateDirectory(folder); - - //Get a list of episodeFiles that we need to delete and cleanup - var episodeFilesToClean = new List(); - - foreach (var episode in parseResult.Episodes) - { - if (episode.EpisodeFileId > 0) - episodeFilesToClean.Add(episode.EpisodeFile); - } - - if (episodeFilesToClean.Count != episodeFilesToClean.Where(e => parseResult.Quality.QualityType >= e.Quality).Count()) - { - Logger.Debug("Episode isn't an upgrade for all episodes in file: [{0}]. Skipping.", file); - continue; - } - - //Delete the files and then cleanup! - foreach (var e in episodeFilesToClean) - { - if (_diskProvider.FileExists(e.Path)) - _diskProvider.DeleteFile(e.Path); - } - - CleanUp(episodeFilesToClean); - - //Move the file - _diskProvider.RenameFile(file, folder + filename); - - //Import into DB - result.Add(ImportFile(series, folder + filename)); - } - - catch (Exception ex) - { - Logger.WarnException("Error importing new download: " + file, ex); - } - } - - //If we have imported all the non-sample files, delete the folder, requires a minimum of 1 file to be imported. - if (files.Count() > 0 && files.Count() == result.Count) - { - Logger.Debug("All non-sample files have been processed, deleting folder: {0}", path); - _diskProvider.DeleteFolder(path, true); - } - - return result; - } - - public virtual string GetNewFilename(IList episodes, string seriesName, QualityTypes quality) - { - var separatorStyle = EpisodeSortingHelper.GetSeparatorStyle(_configProvider.SeparatorStyle); - var numberStyle = EpisodeSortingHelper.GetNumberStyle(_configProvider.NumberStyle); - var useSeriesName = _configProvider.SeriesName; - var useEpisodeName = _configProvider.EpisodeName; - var replaceSpaces = _configProvider.ReplaceSpaces; - var appendQuality = _configProvider.AppendQuality; - - var title = String.Empty; - - if (episodes.Count == 1) - { - if (useSeriesName) - { - title += seriesName; - title += separatorStyle.Pattern; - } - - title += numberStyle.Pattern.Replace("%s", String.Format("{0}", episodes[0].SeasonNumber)) - .Replace("%0s", String.Format("{0:00}", episodes[0].SeasonNumber)) - .Replace("%0e", String.Format("{0:00}", episodes[0].EpisodeNumber)); - - if (useEpisodeName) - { - title += separatorStyle.Pattern; - title += episodes[0].Title; - } - - if (appendQuality) - title += String.Format(" [{0}]", quality); - - if (replaceSpaces) - title = title.Replace(' ', '.'); - - Logger.Debug("New File Name is: {0}", title); - return title; - } - - var multiEpisodeStyle = EpisodeSortingHelper.GetMultiEpisodeStyle(_configProvider.MultiEpisodeStyle); - - if (useSeriesName) - { - title += seriesName; - title += separatorStyle.Pattern; - } - - title += numberStyle.Pattern.Replace("%s", String.Format("{0}", episodes[0].SeasonNumber)) - .Replace("%0s", String.Format("{0:00}", episodes[0].SeasonNumber)) - .Replace("%0e", String.Format("{0:00}", episodes[0].EpisodeNumber)); - - var numbers = String.Empty; - var episodeNames = episodes[0].Title; - - for (int i = 1; i < episodes.Count; i++) - { - var episode = episodes[i]; - - if (multiEpisodeStyle.Name == "Duplicate") - { - numbers += separatorStyle.Pattern + numberStyle.Pattern.Replace("%s", String.Format("{0}", episode.SeasonNumber)) - .Replace("%0s", String.Format("{0:00}", episode.SeasonNumber)) - .Replace("%0e", String.Format("{0:00}", episode.EpisodeNumber)); - } - else - { - numbers += multiEpisodeStyle.Pattern.Replace("%s", String.Format("{0}", episode.SeasonNumber)) - .Replace("%0s", String.Format("{0:00}", episode.SeasonNumber)) - .Replace("%0e", String.Format("{0:00}", episode.EpisodeNumber)) - .Replace("%x", numberStyle.EpisodeSeparator) - .Replace("%p", separatorStyle.Pattern); - } - - episodeNames += String.Format(" + {0}", episode.Title); - } - - title += numbers; - - if (useEpisodeName) - { - episodeNames = episodeNames.TrimEnd(' ', '+'); - - title += separatorStyle.Pattern; - title += episodeNames; - } - - if (appendQuality) - title += String.Format(" [{0}]", quality); - - if (replaceSpaces) - title = title.Replace(' ', '.'); - - Logger.Debug("New File Name is: {0}", title); - return title; - } - - public virtual bool RenameEpisodeFile(int episodeFileId, ProgressNotification notification) - { - var episodeFile = GetEpisodeFile(episodeFileId); - - if (episodeFile == null) - return false; - - try - { - notification.CurrentMessage = String.Format("Renaming '{0}'", episodeFile.Path); - - var series = _seriesProvider.GetSeries(episodeFile.SeriesId); - var folder = new FileInfo(episodeFile.Path).DirectoryName; - var episodes = _episodeProvider.EpisodesByFileId(episodeFileId); - var ext = _diskProvider.GetExtension(episodeFile.Path); - - var newFileName = GetNewFilename(episodes, series.Title, episodeFile.Quality); - - var newFile = folder + Path.DirectorySeparatorChar + newFileName + ext; - - //Do the rename - _diskProvider.RenameFile(episodeFile.Path, newFile); - - //Update the filename in the DB - episodeFile.Path = newFile; - Update(episodeFile); - - notification.CurrentMessage = String.Format("Finished Renaming '{0}'", newFile); - } - - catch (Exception e) - { - notification.CurrentMessage = String.Format("Failed to Rename '{0}'", episodeFile.Path); - Logger.ErrorException("An error has occurred while renaming episode: " + episodeFile.Path, e); - throw; - } - return true; - } } } diff --git a/NzbDrone.Core/Providers/Jobs/DiskScanJob.cs b/NzbDrone.Core/Providers/Jobs/DiskScanJob.cs index 58bdcf0c2..fc1ea6cf1 100644 --- a/NzbDrone.Core/Providers/Jobs/DiskScanJob.cs +++ b/NzbDrone.Core/Providers/Jobs/DiskScanJob.cs @@ -11,14 +11,14 @@ namespace NzbDrone.Core.Providers.Jobs public class DiskScanJob : IJob { private readonly SeriesProvider _seriesProvider; - private readonly MediaFileProvider _mediaFileProvider; + private readonly DiskScanProvider _diskScanProvider; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); [Inject] - public DiskScanJob(SeriesProvider seriesProvider, MediaFileProvider mediaFileProvider) + public DiskScanJob(SeriesProvider seriesProvider, DiskScanProvider diskScanProvider) { _seriesProvider = seriesProvider; - _mediaFileProvider = mediaFileProvider; + _diskScanProvider = diskScanProvider; } public DiskScanJob() @@ -52,7 +52,7 @@ namespace NzbDrone.Core.Providers.Jobs try { notification.CurrentMessage = string.Format("Scanning disk for '{0}'", series.Title); - _mediaFileProvider.Scan(series); + _diskScanProvider.Scan(series); notification.CurrentMessage = string.Format("Media File Scan completed for '{0}'", series.Title); } catch (Exception e) diff --git a/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs b/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs index 7ca43f30f..599dad96b 100644 --- a/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs +++ b/NzbDrone.Core/Providers/Jobs/PostDownloadScanJob.cs @@ -11,17 +11,17 @@ namespace NzbDrone.Core.Providers.Jobs { private readonly ConfigProvider _configProvider; private readonly DiskProvider _diskProvider; - private readonly MediaFileProvider _mediaFileProvider; + private readonly DiskScanProvider _diskScanProvider; private readonly SeriesProvider _seriesProvider; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); [Inject] public PostDownloadScanJob(ConfigProvider configProvider, DiskProvider diskProvider, - MediaFileProvider mediaFileProvider, SeriesProvider seriesProvider) + DiskScanProvider diskScanProvider, SeriesProvider seriesProvider) { _configProvider = configProvider; _diskProvider = diskProvider; - _mediaFileProvider = mediaFileProvider; + _diskScanProvider = diskScanProvider; _seriesProvider = seriesProvider; } @@ -84,7 +84,7 @@ namespace NzbDrone.Core.Providers.Jobs return; } - _mediaFileProvider.ImportNewFiles(subfolder, series); + _diskScanProvider.Scan(series, subfolder); } Logger.Debug("New Download Scan Job completed successfully"); } diff --git a/NzbDrone.Core/Providers/Jobs/RenameEpisodeJob.cs b/NzbDrone.Core/Providers/Jobs/RenameEpisodeJob.cs index e9f4373d9..cc39c455a 100644 --- a/NzbDrone.Core/Providers/Jobs/RenameEpisodeJob.cs +++ b/NzbDrone.Core/Providers/Jobs/RenameEpisodeJob.cs @@ -7,21 +7,17 @@ namespace NzbDrone.Core.Providers.Jobs { public class RenameEpisodeJob : IJob { - private readonly DiskProvider _diskProvider; - private readonly EpisodeProvider _episodeProvider; + private readonly DiskScanProvider _diskScanProvider; private readonly MediaFileProvider _mediaFileProvider; - private readonly SeriesProvider _seriesProvider; + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); [Inject] - public RenameEpisodeJob(DiskProvider diskProvider, EpisodeProvider episodeProvider, - MediaFileProvider mediaFileProvider, SeriesProvider seriesProvider) + public RenameEpisodeJob(DiskScanProvider diskScanProvider, MediaFileProvider mediaFileProvider) { - _diskProvider = diskProvider; - _episodeProvider = episodeProvider; + _diskScanProvider = diskScanProvider; _mediaFileProvider = mediaFileProvider; - _seriesProvider = seriesProvider; } public string Name @@ -36,8 +32,8 @@ namespace NzbDrone.Core.Providers.Jobs public void Start(ProgressNotification notification, int targetId) { - var episode = _mediaFileProvider.GetEpisodeFile(targetId); - _mediaFileProvider.RenameEpisodeFile(episode); + var episode = _mediaFileProvider.GetEpisodeFile(targetId); + _diskScanProvider.RenameEpisodeFile(episode); } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/MediaFileProvider.cs b/NzbDrone.Core/Providers/MediaFileProvider.cs index 4e003eeb7..d510949cb 100644 --- a/NzbDrone.Core/Providers/MediaFileProvider.cs +++ b/NzbDrone.Core/Providers/MediaFileProvider.cs @@ -16,170 +16,27 @@ namespace NzbDrone.Core.Providers public class MediaFileProvider { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private static readonly string[] MediaExtentions = new[] { ".mkv", ".avi", ".wmv", ".mp4" }; - private readonly DiskProvider _diskProvider; private readonly EpisodeProvider _episodeProvider; - private readonly SeriesProvider _seriesProvider; private readonly ConfigProvider _configProvider; private readonly IDatabase _database; [Inject] - public MediaFileProvider(DiskProvider diskProvider, EpisodeProvider episodeProvider, - SeriesProvider seriesProvider, ConfigProvider configProvider, - IDatabase database) + public MediaFileProvider(EpisodeProvider episodeProvider, ConfigProvider configProvider, IDatabase database) { - _diskProvider = diskProvider; _episodeProvider = episodeProvider; - _seriesProvider = seriesProvider; _configProvider = configProvider; _database = database; } public MediaFileProvider() { } - /// - /// Scans the specified series folder for media files - /// - /// The series to be scanned - public virtual List Scan(Series series) - { - if (_episodeProvider.GetEpisodeBySeries(series.SeriesId).Count == 0) - { - Logger.Debug("Series {0} has no episodes. skipping", series.Title); - return new List(); - } - - var mediaFileList = GetVideoFiles(series.Path); - var fileList = new List(); - - foreach (var filePath in mediaFileList) - { - var file = ImportFile(series, filePath); - if (file != null) - fileList.Add(file); - } - series.LastDiskSync = DateTime.Now; - _seriesProvider.UpdateSeries(series); - return fileList; - } - public virtual EpisodeFile ImportFile(Series series, string filePath) - { - Logger.Trace("Importing file to database [{0}]", filePath); - if (_database.Exists("Path =@0", Parser.NormalizePath(filePath))) - { - Logger.Trace("[{0}] already exists in the database. skipping.", filePath); - return null; - } - - var size = _diskProvider.GetSize(filePath); - - //If Size is less than 50MB and contains sample. Check for Size to ensure its not an episode with sample in the title - if (size < 40000000 && filePath.ToLower().Contains("sample")) - { - Logger.Trace("[{0}] appears to be a sample. skipping.", filePath); - return null; - } - var parseResult = Parser.ParseEpisodeInfo(filePath); - if (parseResult == null) - return null; - parseResult.CleanTitle = series.Title;//replaces the nasty path as title to help with logging - - //Stores the list of episodes to add to the EpisodeFile - var episodes = new List(); - - //Check for daily shows - if (parseResult.EpisodeNumbers == null) - { - var episode = _episodeProvider.GetEpisode(series.SeriesId, parseResult.AirDate.Date); - - if (episode != null) - { - episodes.Add(episode); - } - else - { - Logger.Warn("Unable to find [{0}] in the database.[{1}]", parseResult, filePath); - } - } - else - { - foreach (var episodeNumber in parseResult.EpisodeNumbers) - { - var episode = _episodeProvider.GetEpisode(series.SeriesId, parseResult.SeasonNumber, - episodeNumber); - - if (episode != null) - { - episodes.Add(episode); - } - else - { - Logger.Warn("Unable to find [{0}] in the database.[{1}]", parseResult, filePath); - } - } - } - - //Return null if no Episodes exist in the DB for the parsed episodes from file - if (episodes.Count <= 0) - return null; - - var episodeFile = new EpisodeFile(); - episodeFile.DateAdded = DateTime.Now; - episodeFile.SeriesId = series.SeriesId; - episodeFile.Path = Parser.NormalizePath(filePath); - episodeFile.Size = size; - episodeFile.Quality = parseResult.Quality.QualityType; - episodeFile.Proper = parseResult.Quality.Proper; - episodeFile.SeasonNumber = parseResult.SeasonNumber; - var fileId = Convert.ToInt32(_database.Insert(episodeFile)); - - //This is for logging + updating the episodes that are linked to this EpisodeFile - string episodeList = String.Empty; - foreach (var ep in episodes) - { - ep.EpisodeFileId = fileId; - _episodeProvider.UpdateEpisode(ep); - episodeList += String.Format(", {0}", ep.EpisodeId).Trim(' ', ','); - } - Logger.Trace("File {0}:{1} attached to episode(s): '{2}'", episodeFile.EpisodeFileId, filePath, - episodeList); - - return episodeFile; - - } - - /// - /// Removes files that no longer exist from the database - /// - /// list of files to verify - public virtual void CleanUp(List files) - { - //TODO: remove orphaned files. in files table but not linked to from episode table. - foreach (var episodeFile in files) - { - if (!_diskProvider.FileExists(episodeFile.Path)) - { - Logger.Trace("File {0} no longer exists on disk. removing from database.", episodeFile.Path); - - //Set the EpisodeFileId for each episode attached to this file to 0 - foreach (var episode in episodeFile.Episodes) - { - episode.EpisodeFileId = 0; - _episodeProvider.UpdateEpisode(episode); - } - - //Delete it from the DB - _database.Delete(episodeFile.EpisodeFileId); - } - } - } public virtual void Update(EpisodeFile episodeFile) { @@ -211,98 +68,20 @@ namespace NzbDrone.Core.Providers return new Tuple(avilableEpisodes.Count, episodeTotal.Count); } - private List GetVideoFiles(string path) - { - Logger.Debug("Scanning '{0}' for episodes", path); - - var filesOnDisk = _diskProvider.GetFiles(path, "*.*", SearchOption.AllDirectories); - - var mediaFileList = filesOnDisk.Where(c => MediaExtentions.Contains(Path.GetExtension(c).ToLower())).ToList(); - - Logger.Debug("{0} media files were found in {1}", mediaFileList.Count, path); - return mediaFileList; - } - - public virtual List ImportNewFiles(string path, Series series) + public virtual FileInfo CalculateFilePath(Series series, int seasonNumber, string fileName, string extention) { - var result = new List(); - - //Get all the files except those that are considered samples - var files = GetVideoFiles(path).Where(f => _diskProvider.GetSize(f) > 40000000 || !f.ToLower().Contains("sample")).ToList(); - - foreach (var file in files) + var path = series.Path; + if (series.SeasonFolder) { - try - { - //Parse the filename - var parseResult = Parser.ParseEpisodeInfo(Path.GetFileName(file)); - parseResult.Series = series; - parseResult.Episodes = _episodeProvider.GetEpisodes(parseResult); - - if (parseResult.Episodes.Count == 0) - { - Logger.Error("File '{0}' contains invalid episode information, skipping import", file); - continue; - } - - var ext = _diskProvider.GetExtension(file); - var filename = GetNewFilename(parseResult.Episodes, series.Title, parseResult.Quality.QualityType) + ext; - var folder = series.Path + Path.DirectorySeparatorChar; - if (_configProvider.UseSeasonFolder) - folder += _configProvider.SeasonFolderFormat - .Replace("%0s", parseResult.SeasonNumber.ToString("00")) - .Replace("%s", parseResult.SeasonNumber.ToString()) - + Path.DirectorySeparatorChar; - - _diskProvider.CreateDirectory(folder); - - //Get a list of episodeFiles that we need to delete and cleanup - var episodeFilesToClean = new List(); - - foreach (var episode in parseResult.Episodes) - { - if (episode.EpisodeFileId > 0) - episodeFilesToClean.Add(episode.EpisodeFile); - } - - if (episodeFilesToClean.Count != episodeFilesToClean.Where(e => parseResult.Quality.QualityType >= e.Quality).Count()) - { - Logger.Debug("Episode isn't an upgrade for all episodes in file: [{0}]. Skipping.", file); - continue; - } - - //Delete the files and then cleanup! - foreach (var e in episodeFilesToClean) - { - if (_diskProvider.FileExists(e.Path)) - _diskProvider.DeleteFile(e.Path); - } - - CleanUp(episodeFilesToClean); - - //Move the file - _diskProvider.RenameFile(file, folder + filename); - - //Import into DB - result.Add(ImportFile(series, folder + filename)); - } - - catch (Exception ex) - { - Logger.WarnException("Error importing new download: " + file, ex); - } + path = Path.Combine(path, "Season " + seasonNumber); } - //If we have imported all the non-sample files, delete the folder, requires a minimum of 1 file to be imported. - if (files.Count() > 0 && files.Count() == result.Count) - { - Logger.Debug("All non-sample files have been processed, deleting folder: {0}", path); - _diskProvider.DeleteFolder(path, true); - } + path = Path.Combine(path, fileName + extention); - return result; + return new FileInfo(path); } + public virtual string GetNewFilename(IList episodes, string seriesTitle, QualityTypes quality) { var separatorStyle = EpisodeSortingHelper.GetSeparatorStyle(_configProvider.SeparatorStyle); @@ -361,40 +140,10 @@ namespace NzbDrone.Core.Providers return result.Trim(); } - public virtual FileInfo CalculateFilePath(Series series, int seasonNumber, string fileName, string extention) - { - var path = series.Path; - if (series.SeasonFolder) - { - path = Path.Combine(path, "Season " + seasonNumber); - } - - path = Path.Combine(path, fileName + extention); - - return new FileInfo(path); - } - - public virtual bool RenameEpisodeFile(EpisodeFile episodeFile) - { - if (episodeFile == null) - throw new ArgumentNullException("episodeFile"); - - var series = _seriesProvider.GetSeries(episodeFile.SeriesId); - var ext = _diskProvider.GetExtension(episodeFile.Path); - var episodes = _episodeProvider.GetEpisodesByFileId(episodeFile.EpisodeFileId); - var newFileName = GetNewFilename(episodes, series.Title, episodeFile.Quality); - var newFile = CalculateFilePath(series, episodes.First().SeasonNumber, newFileName, ext); - //Do the rename - _diskProvider.RenameFile(episodeFile.Path, newFile.FullName); - //Update the filename in the DB - episodeFile.Path = newFile.FullName; - Update(episodeFile); - return true; - } } } \ No newline at end of file