fixed diskscan

removed all stored status fields from episode
pull/6/head
kay.one 12 years ago
parent feb947fb74
commit cbe4be814c

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Api.Extensions; using NzbDrone.Api.Extensions;
using NzbDrone.Common.Composition;
using NzbDrone.Common.Messaging; using NzbDrone.Common.Messaging;
namespace NzbDrone.Api.Commands namespace NzbDrone.Api.Commands
@ -9,20 +10,22 @@ namespace NzbDrone.Api.Commands
public class CommandModule : NzbDroneRestModule<CommandResource> public class CommandModule : NzbDroneRestModule<CommandResource>
{ {
private readonly IMessageAggregator _messageAggregator; private readonly IMessageAggregator _messageAggregator;
private readonly IEnumerable<ICommand> _commands; private readonly IContainer _container;
public CommandModule(IMessageAggregator messageAggregator, IEnumerable<ICommand> commands) public CommandModule(IMessageAggregator messageAggregator, IContainer container)
{ {
_messageAggregator = messageAggregator; _messageAggregator = messageAggregator;
_commands = commands; _container = container;
CreateResource = RunCommand; CreateResource = RunCommand;
} }
private CommandResource RunCommand(CommandResource resource) private CommandResource RunCommand(CommandResource resource)
{ {
var commandType = _commands.Single(c => c.GetType().Name.Replace("Command", "").Equals(resource.Command, StringComparison.InvariantCultureIgnoreCase)) var commandType =
.GetType(); _container.GetImplementations(typeof(ICommand))
.Single(c => c.Name.Replace("Command", "")
.Equals(resource.Command, StringComparison.InvariantCultureIgnoreCase));
var command = Request.Body.FromJson<ICommand>(commandType); var command = Request.Body.FromJson<ICommand>(commandType);

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using TinyIoC; using TinyIoC;
namespace NzbDrone.Common.Composition namespace NzbDrone.Common.Composition
@ -7,10 +8,12 @@ namespace NzbDrone.Common.Composition
public class Container : IContainer public class Container : IContainer
{ {
private readonly TinyIoCContainer _container; private readonly TinyIoCContainer _container;
private readonly List<Type> _loadedTypes;
public Container(TinyIoCContainer container) public Container(TinyIoCContainer container, List<Type> loadedTypes)
{ {
_container = container; _container = container;
_loadedTypes = loadedTypes;
_container.Register<IContainer>(this); _container.Register<IContainer>(this);
} }
@ -92,5 +95,15 @@ namespace NzbDrone.Common.Composition
{ {
return _container.CanResolve(type); return _container.CanResolve(type);
} }
public IEnumerable<Type> GetImplementations(Type contractType)
{
return _loadedTypes
.Where(implementation =>
contractType.IsAssignableFrom(implementation) &&
!implementation.IsInterface &&
!implementation.IsAbstract
);
}
} }
} }

@ -18,8 +18,6 @@ namespace NzbDrone.Common.Composition
protected ContainerBuilderBase(params string[] assemblies) protected ContainerBuilderBase(params string[] assemblies)
{ {
Container = new Container(new TinyIoCContainer());
_loadedTypes = new List<Type>(); _loadedTypes = new List<Type>();
foreach (var assembly in assemblies) foreach (var assembly in assemblies)
@ -27,6 +25,7 @@ namespace NzbDrone.Common.Composition
_loadedTypes.AddRange(Assembly.Load(assembly).GetTypes()); _loadedTypes.AddRange(Assembly.Load(assembly).GetTypes());
} }
Container = new Container(new TinyIoCContainer(), _loadedTypes);
AutoRegisterInterfaces(); AutoRegisterInterfaces();
} }
@ -52,7 +51,7 @@ namespace NzbDrone.Common.Composition
private void AutoRegisterImplementations(Type contractType) private void AutoRegisterImplementations(Type contractType)
{ {
var implementations = GetImplementations(contractType).Where(c => !c.IsGenericTypeDefinition).ToList(); var implementations = Container.GetImplementations(contractType).Where(c => !c.IsGenericTypeDefinition).ToList();
@ -84,14 +83,5 @@ namespace NzbDrone.Common.Composition
} }
} }
private IEnumerable<Type> GetImplementations(Type contractType)
{
return _loadedTypes
.Where(implementation =>
contractType.IsAssignableFrom(implementation) &&
!implementation.IsInterface &&
!implementation.IsAbstract
);
}
} }
} }

@ -26,5 +26,7 @@ namespace NzbDrone.Common.Composition
void Register(Type registrationType, object instance); void Register(Type registrationType, object instance);
void RegisterAll(Type registrationType, IEnumerable<Type> implementationList); void RegisterAll(Type registrationType, IEnumerable<Type> implementationList);
bool IsTypeRegistered(Type type); bool IsTypeRegistered(Type type);
IEnumerable<Type> GetImplementations(Type contractType);
} }
} }

@ -34,8 +34,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
firstFile = new EpisodeFile { Quality = new QualityModel(Quality.Bluray1080p, true), DateAdded = DateTime.Now }; firstFile = new EpisodeFile { Quality = new QualityModel(Quality.Bluray1080p, true), DateAdded = DateTime.Now };
secondFile = new EpisodeFile { Quality = new QualityModel(Quality.Bluray1080p, true), DateAdded = DateTime.Now }; secondFile = new EpisodeFile { Quality = new QualityModel(Quality.Bluray1080p, true), DateAdded = DateTime.Now };
var singleEpisodeList = new List<Episode> { new Episode { EpisodeFile = firstFile }, new Episode { EpisodeFile = null } }; var singleEpisodeList = new List<Episode> { new Episode { EpisodeFile = firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } };
var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = firstFile }, new Episode { EpisodeFile = secondFile }, new Episode { EpisodeFile = null } }; var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = secondFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } };
var fakeSeries = Builder<Series>.CreateNew() var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p }) .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p })
@ -66,6 +66,13 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
secondFile.Quality = new QualityModel(Quality.SDTV); secondFile.Quality = new QualityModel(Quality.SDTV);
} }
[Test]
public void should_return_true_if_episode_has_no_existing_file()
{
parseResultSingle.Episodes.ForEach(c => c.EpisodeFileId = 0);
_upgradeDisk.IsSatisfiedBy(parseResultSingle).Should().BeTrue();
}
[Test] [Test]
public void should_return_true_if_single_episode_doesnt_exist_on_disk() public void should_return_true_if_single_episode_doesnt_exist_on_disk()
{ {

@ -11,79 +11,15 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test namespace NzbDrone.Core.Test
{ {
[TestFixture] [TestFixture]
public class EpisodeStatusTest : CoreTest public class EpisodeStatusTest : CoreTest
{ {
[TestCase(1, false, false, EpisodeStatuses.NotAired)]
[TestCase(-2, false, false, EpisodeStatuses.Missing)]
[TestCase(0, false, false, EpisodeStatuses.AirsToday)]
[TestCase(1, true, false, EpisodeStatuses.Ready)]
public void no_grab_date(int offsetDays, bool hasEpisodes, bool ignored, EpisodeStatuses status)
{
Episode episode = Builder<Episode>.CreateNew()
.With(e => e.AirDate = DateTime.Now.AddDays(offsetDays))
.With(e => e.Ignored = ignored)
.With(e => e.GrabDate = null)
.Build();
if (hasEpisodes)
{
episode.EpisodeFile = new EpisodeFile();
}
episode.Status.Should().Be(status);
}
[TestCase(1, false, false, EpisodeStatuses.Missing)]
[TestCase(-2, false, false, EpisodeStatuses.Missing)]
[TestCase(1, true, false, EpisodeStatuses.Ready)]
public void old_grab_date(int offsetDays, bool hasEpisodes, bool ignored,
EpisodeStatuses status)
{
Episode episode = Builder<Episode>.CreateNew()
.With(e => e.Ignored = ignored)
.With(e => e.GrabDate = DateTime.Now.AddDays(-2).AddHours(-1))
.With(e => e.AirDate = DateTime.Today.AddDays(-2))
.Build();
if (hasEpisodes)
{
episode.EpisodeFile = new EpisodeFile();
}
episode.Status.Should().Be(status);
}
[TestCase(1, false, false, EpisodeStatuses.Downloading)]
[TestCase(-2, false, false, EpisodeStatuses.Downloading)]
[TestCase(1, true, false, EpisodeStatuses.Ready)]
[TestCase(1, true, true, EpisodeStatuses.Ready)]
[TestCase(1, false, true, EpisodeStatuses.Downloading)]
public void recent_grab_date(int offsetDays, bool hasEpisodes, bool ignored,
EpisodeStatuses status)
{
Episode episode = Builder<Episode>.CreateNew()
.With(e => e.AirDate = DateTime.Now.AddDays(offsetDays))
.With(e => e.Ignored = ignored)
.With(e => e.GrabDate = DateTime.Now.AddHours(22))
.Build();
if (hasEpisodes)
{
episode.EpisodeFile = new EpisodeFile();
}
episode.Status.Should().Be(status);
}
[TestCase(1, true, true, EpisodeStatuses.Ready)] [TestCase(1, true, true, EpisodeStatuses.Ready)]
public void ignored_episode(int offsetDays, bool ignored, bool hasEpisodes, EpisodeStatuses status) public void ignored_episode(int offsetDays, bool ignored, bool hasEpisodes, EpisodeStatuses status)
{ {
Episode episode = Builder<Episode>.CreateNew() Episode episode = Builder<Episode>.CreateNew()
.With(e => e.AirDate = DateTime.Now.AddDays(offsetDays)) .With(e => e.AirDate = DateTime.Now.AddDays(offsetDays))
.With(e => e.Ignored = ignored) .With(e => e.Ignored = ignored)
.With(e => e.GrabDate = null)
.Build(); .Build();
if (hasEpisodes) if (hasEpisodes)
@ -101,33 +37,11 @@ namespace NzbDrone.Core.Test
Episode episode = Builder<Episode>.CreateNew() Episode episode = Builder<Episode>.CreateNew()
.With(e => e.AirDate = DateTime.Now.AddDays(20)) .With(e => e.AirDate = DateTime.Now.AddDays(20))
.With(e => e.Ignored = false) .With(e => e.Ignored = false)
.With(e => e.GrabDate = null) .With(e => e.EpisodeFileId = 0)
.Build(); .Build();
episode.Status.Should().Be(EpisodeStatuses.NotAired); episode.Status.Should().Be(EpisodeStatuses.NotAired);
} }
[TestCase(false, false, EpisodeStatuses.Failed, PostDownloadStatusType.Failed)]
[TestCase(false, false, EpisodeStatuses.Unpacking, PostDownloadStatusType.Unpacking)]
[TestCase(true, false, EpisodeStatuses.Ready, PostDownloadStatusType.Failed)]
[TestCase(true, true, EpisodeStatuses.Ready, PostDownloadStatusType.Unpacking)]
public void episode_downloaded_post_download_status_is_used(bool hasEpisodes, bool ignored,
EpisodeStatuses status, PostDownloadStatusType postDownloadStatus)
{
Episode episode = Builder<Episode>.CreateNew()
.With(e => e.Ignored = ignored)
.With(e => e.GrabDate = DateTime.Now.AddHours(22))
.With(e => e.PostDownloadStatus = postDownloadStatus)
.Build();
if (hasEpisodes)
{
episode.EpisodeFile = new EpisodeFile();
}
episode.Status.Should().Be(status);
}
} }
} }

@ -5,13 +5,14 @@ using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using System.Linq; using System.Linq;
namespace NzbDrone.Core.Test.MediaFileTests namespace NzbDrone.Core.Test.MediaFileTests
{ {
public class GhostFileCleanupFixture : CoreTest<GhostFileCleanupService> public class MediaFileTableCleanupServiceFixture : CoreTest<MediaFileTableCleanupService>
{ {
private void GiveEpisodeFiles(IEnumerable<EpisodeFile> episodeFiles) private void GiveEpisodeFiles(IEnumerable<EpisodeFile> episodeFiles)
@ -30,6 +31,10 @@ namespace NzbDrone.Core.Test.MediaFileTests
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(e => e.FileExists(It.Is<String>(c => c != DeletedPath))) .Setup(e => e.FileExists(It.Is<String>(c => c != DeletedPath)))
.Returns(true); .Returns(true);
Mocker.GetMock<IEpisodeService>()
.Setup(c => c.GetEpisodesByFileId(It.IsAny<int>()))
.Returns(new List<Episode> { new Episode() });
} }
[Test] [Test]
@ -40,7 +45,7 @@ namespace NzbDrone.Core.Test.MediaFileTests
GiveEpisodeFiles(episodeFiles); GiveEpisodeFiles(episodeFiles);
Subject.RemoveNonExistingFiles(0); Subject.Execute(new CleanMediaFileDb(0));
Mocker.GetMock<IEpisodeService>().Verify(c => c.UpdateEpisode(It.IsAny<Episode>()), Times.Never()); Mocker.GetMock<IEpisodeService>().Verify(c => c.UpdateEpisode(It.IsAny<Episode>()), Times.Never());
} }
@ -55,10 +60,33 @@ namespace NzbDrone.Core.Test.MediaFileTests
GiveEpisodeFiles(episodeFiles); GiveEpisodeFiles(episodeFiles);
Subject.RemoveNonExistingFiles(0); Subject.Execute(new CleanMediaFileDb(0));
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.Is<EpisodeFile>(e => e.Path == DeletedPath)), Times.Exactly(2)); Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.Is<EpisodeFile>(e => e.Path == DeletedPath)), Times.Exactly(2));
} }
[Test]
public void should_delete_files_that_dont_belong_to_any_episodes()
{
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(10)
.Random(10)
.With(c => c.Path = "ExistingPath")
.Build();
GiveEpisodeFiles(episodeFiles);
GivenFilesAreNotAttachedToEpisode();
Subject.Execute(new CleanMediaFileDb(0));
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.IsAny<EpisodeFile>()), Times.Exactly(10));
}
private void GivenFilesAreNotAttachedToEpisode()
{
Mocker.GetMock<IEpisodeService>()
.Setup(c => c.GetEpisodesByFileId(It.IsAny<int>()))
.Returns(new List<Episode>());
}
} }
} }

@ -142,7 +142,7 @@
<Compile Include="DecisionEngineTests\LanguageSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\LanguageSpecificationFixture.cs" />
<Compile Include="JobTests\TestJobs.cs" /> <Compile Include="JobTests\TestJobs.cs" />
<Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" /> <Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" />
<Compile Include="MediaFileTests\GhostFileCleanupFixture.cs" /> <Compile Include="MediaFileTests\MediaFileTableCleanupServiceFixture.cs" />
<Compile Include="MediaFileTests\MediaFileRepositoryFixture.cs" /> <Compile Include="MediaFileTests\MediaFileRepositoryFixture.cs" />
<Compile Include="MediaFileTests\EpisodeFileMoverFixture.cs" /> <Compile Include="MediaFileTests\EpisodeFileMoverFixture.cs" />
<Compile Include="MetadataSourceTests\TracktProxyFixture.cs" /> <Compile Include="MetadataSourceTests\TracktProxyFixture.cs" />
@ -160,6 +160,7 @@
<Compile Include="ProviderTests\RecycleBinProviderTests\DeleteFileFixture.cs" /> <Compile Include="ProviderTests\RecycleBinProviderTests\DeleteFileFixture.cs" />
<Compile Include="ProviderTests\RecycleBinProviderTests\DeleteDirectoryFixture.cs" /> <Compile Include="ProviderTests\RecycleBinProviderTests\DeleteDirectoryFixture.cs" />
<Compile Include="ProviderTests\PlexProviderTest.cs" /> <Compile Include="ProviderTests\PlexProviderTest.cs" />
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesRepositoryReadFixture.cs" />
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWithoutFilesFixture.cs" /> <Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWithoutFilesFixture.cs" />
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesBetweenDatesFixture.cs" /> <Compile Include="TvTests\EpisodeRepositoryTests\EpisodesBetweenDatesFixture.cs" />
<Compile Include="TvTests\SeasonProviderTest.cs" /> <Compile Include="TvTests\SeasonProviderTest.cs" />

@ -4,6 +4,7 @@ using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
@ -23,7 +22,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
private long _fileSize = 80.Megabytes(); private long _fileSize = 80.Megabytes();
private Series _fakeSeries; private Series _fakeSeries;
private List<Episode> _fakeEpisodes; private Episode[] _fakeEpisodes;
private Episode _fakeEpisode; private Episode _fakeEpisode;
[SetUp] [SetUp]
@ -35,14 +34,16 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
_fakeEpisode = Builder<Episode> _fakeEpisode = Builder<Episode>
.CreateNew() .CreateNew()
.With(c => c.EpisodeFileId = 0)
.Build(); .Build();
_fakeEpisodes = Builder<Episode>.CreateListOfSize(2) _fakeEpisodes = Builder<Episode>.CreateListOfSize(2)
.All() .All()
.With(c => c.SeasonNumber = 3) .With(c => c.SeasonNumber = 3)
.With(c => c.EpisodeFileId = 1)
.With(e => e.EpisodeFile = new EpisodeFile()) .With(e => e.EpisodeFile = new EpisodeFile())
.BuildList(); .BuildList().ToArray();
GivenNewFile(); GivenNewFile();
@ -69,8 +70,20 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
} }
private void GivenEpisodes(IEnumerable<Episode> episodes, QualityModel quality) private void GivenEpisodes(Episode[] episodes, QualityModel quality)
{ {
foreach (var episode in episodes)
{
if (episode.EpisodeFile == null)
{
episode.EpisodeFileId = 0;
}
else
{
episode.EpisodeFileId = episode.EpisodeFile.Value.Id;
}
}
Mocker.GetMock<IParsingService>() Mocker.GetMock<IParsingService>()
.Setup(c => c.GetEpisodes(It.IsAny<string>(), It.IsAny<Series>())) .Setup(c => c.GetEpisodes(It.IsAny<string>(), It.IsAny<Series>()))
.Returns(new LocalEpisode .Returns(new LocalEpisode
@ -102,6 +115,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
public void import_new_file_with_same_quality_should_succeed() public void import_new_file_with_same_quality_should_succeed()
{ {
_fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.SDTV) }; _fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.SDTV) };
GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.SDTV)); GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.SDTV));
var result = Subject.ImportFile(_fakeSeries, "file.ext"); var result = Subject.ImportFile(_fakeSeries, "file.ext");
@ -112,6 +126,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
public void import_new_file_with_better_quality_should_succeed() public void import_new_file_with_better_quality_should_succeed()
{ {
_fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.SDTV) }; _fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.SDTV) };
GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.HDTV1080p)); GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.HDTV1080p));
var result = Subject.ImportFile(_fakeSeries, "file.ext"); var result = Subject.ImportFile(_fakeSeries, "file.ext");
@ -121,7 +136,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
[Test] [Test]
public void import_new_file_episode_has_better_quality_should_skip() public void import_new_file_episode_has_better_quality_should_skip()
{ {
_fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p) }; _fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p), Id = 1 };
GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.SDTV)); GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.SDTV));
var result = Subject.ImportFile(_fakeSeries, "file.ext"); var result = Subject.ImportFile(_fakeSeries, "file.ext");
@ -158,7 +174,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
[Test] [Test]
public void import_file_with_no_episode_in_db_should_skip() public void import_file_with_no_episode_in_db_should_skip()
{ {
GivenEpisodes(new List<Episode>(), new QualityModel()); GivenEpisodes(new Episode[0], new QualityModel());
var result = Subject.ImportFile(_fakeSeries, "file.ext"); var result = Subject.ImportFile(_fakeSeries, "file.ext");
@ -185,8 +201,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
[Test] [Test]
public void skip_import_new_multi_part_file_episode_existing_has_better_quality() public void skip_import_new_multi_part_file_episode_existing_has_better_quality()
{ {
_fakeEpisodes[0].EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p) }; _fakeEpisodes[0].EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p), Id = 1 };
_fakeEpisodes[1].EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p) }; _fakeEpisodes[1].EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p), Id = 1 };
GivenEpisodes(_fakeEpisodes, new QualityModel(Quality.SDTV)); GivenEpisodes(_fakeEpisodes, new QualityModel(Quality.SDTV));

@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;

@ -0,0 +1,45 @@
using System;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
{
[TestFixture]
public class EpisodesRepositoryReadFixture : DbTest<EpisodeRepository, Episode>
{
private Series series;
[SetUp]
public void Setup()
{
series = Builder<Series>.CreateNew()
.With(s => s.Runtime = 30)
.BuildNew();
Db.Insert(series);
}
[Test]
public void should_get_episodes_by_file()
{
var episodeFile = Builder<EpisodeFile>.CreateNew().BuildNew();
Db.Insert(episodeFile);
var episode = Builder<Episode>.CreateListOfSize(2)
.All()
.With(e => e.SeriesId = series.Id)
.With(e => e.EpisodeFileId = episodeFile.Id)
.BuildListOfNew();
Db.InsertMany(episode);
var episodes = Subject.GetEpisodeByFileId(episodeFile.Id);
episodes.Should().HaveCount(2);
}
}
}

@ -1,9 +1,4 @@
using System; using FizzWare.NBuilder;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;

@ -59,8 +59,6 @@ namespace NzbDrone.Core.Datastore.Migration
.WithColumn("Ignored").AsBoolean().Nullable() .WithColumn("Ignored").AsBoolean().Nullable()
.WithColumn("EpisodeFileId").AsInt32().Nullable() .WithColumn("EpisodeFileId").AsInt32().Nullable()
.WithColumn("AirDate").AsDateTime().Nullable() .WithColumn("AirDate").AsDateTime().Nullable()
.WithColumn("GrabDate").AsDateTime().Nullable()
.WithColumn("PostDownloadStatus").AsInt32().Nullable()
.WithColumn("AbsoluteEpisodeNumber").AsInt32().Nullable() .WithColumn("AbsoluteEpisodeNumber").AsInt32().Nullable()
.WithColumn("SceneAbsoluteEpisodeNumber").AsInt32().Nullable() .WithColumn("SceneAbsoluteEpisodeNumber").AsInt32().Nullable()
.WithColumn("SceneSeasonNumber").AsInt32().Nullable() .WithColumn("SceneSeasonNumber").AsInt32().Nullable()

@ -14,7 +14,7 @@ namespace NzbDrone.Core.Datastore
{ {
return relationshipBuilder.For(portalExpression.GetMemberName()) return relationshipBuilder.For(portalExpression.GetMemberName())
.LazyLoad((db, parent) => db.Query<TChild>() .LazyLoad((db, parent) => db.Query<TChild>()
.Single(c => c.Id == childIdSelector(parent))); .SingleOrDefault(c => c.Id == childIdSelector(parent)));
} }

@ -56,9 +56,12 @@ namespace NzbDrone.Core.Datastore
Mapper.Entity<Episode>().RegisterModel("Episodes") Mapper.Entity<Episode>().RegisterModel("Episodes")
.Ignore(e => e.SeriesTitle) .Ignore(e => e.SeriesTitle)
.Relationships.AutoMapICollectionOrComplexProperties(); .Relationship()
.HasOne(episode => episode.EpisodeFile, episode => episode.EpisodeFileId);
//.Relationships.AutoMapICollectionOrComplexProperties();
Mapper.Entity<EpisodeFile>().RegisterModel("EpisodeFiles"); Mapper.Entity<EpisodeFile>().RegisterModel("EpisodeFiles")
.Relationships.AutoMapICollectionOrComplexProperties();
Mapper.Entity<QualityProfile>().RegisterModel("QualityProfiles"); Mapper.Entity<QualityProfile>().RegisterModel("QualityProfiles");

@ -26,7 +26,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public virtual bool IsSatisfiedBy(RemoteEpisode subject) public virtual bool IsSatisfiedBy(RemoteEpisode subject)
{ {
foreach (var file in subject.Episodes.Select(c => c.EpisodeFile).Where(c => c != null)) foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
{ {
_logger.Trace("Comparing file quality with report. Existing file is {0}", file.Quality); _logger.Trace("Comparing file quality with report. Existing file is {0}", file.Quality);

@ -69,8 +69,12 @@ namespace NzbDrone.Core.Jobs
public void HandleAsync(CommandExecutedEvent message) public void HandleAsync(CommandExecutedEvent message)
{ {
var commandId = _scheduledTaskRepository.GetDefinition(message.Command.GetType()).Id; var scheduledTask = _scheduledTaskRepository.All().SingleOrDefault(c => c.TypeName == message.Command.GetType().FullName);
_scheduledTaskRepository.SetLastExecutionTime(commandId, DateTime.UtcNow);
if (scheduledTask != null)
{
_scheduledTaskRepository.SetLastExecutionTime(scheduledTask.Id, DateTime.UtcNow);
}
} }
} }
} }

@ -0,0 +1,14 @@
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.MediaFiles.Commands
{
public class CleanMediaFileDb : ICommand
{
public int SeriesId { get; private set; }
public CleanMediaFileDb(int seriesId)
{
SeriesId = seriesId;
}
}
}

@ -0,0 +1,17 @@
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.MediaFiles.Commands
{
public class DiskScanCommand : ICommand
{
public int? SeriesId { get; private set; }
public DiskScanCommand(int seriesId = 0)
{
if (seriesId != 0)
{
SeriesId = seriesId;
}
}
}
}

@ -4,40 +4,43 @@ using System.IO;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.MediaFiles; using NzbDrone.Common.Messaging;
using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Providers namespace NzbDrone.Core.MediaFiles
{ {
public interface IDiskScanService public interface IDiskScanService
{ {
void Scan(Series series);
EpisodeFile ImportFile(Series series, string filePath); EpisodeFile ImportFile(Series series, string filePath);
string[] GetVideoFiles(string path, bool allDirectories = true); string[] GetVideoFiles(string path, bool allDirectories = true);
} }
public class DiskScanService : IDiskScanService public class DiskScanService : IDiskScanService, IExecute<DiskScanCommand>
{ {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly string[] MediaExtensions = new[] { ".mkv", ".avi", ".wmv", ".mp4", ".mpg", ".mpeg", ".xvid", ".flv", ".mov", ".rm", ".rmvb", ".divx", ".dvr-ms", ".ts", ".ogm", ".m4v", ".strm" }; private static readonly string[] MediaExtensions = new[] { ".mkv", ".avi", ".wmv", ".mp4", ".mpg", ".mpeg", ".xvid", ".flv", ".mov", ".rm", ".rmvb", ".divx", ".dvr-ms", ".ts", ".ogm", ".m4v", ".strm" };
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly ICleanGhostFiles _ghostFileCleaner; private readonly ISeriesService _seriesService;
private readonly IMediaFileService _mediaFileService; private readonly IMediaFileService _mediaFileService;
private readonly IVideoFileInfoReader _videoFileInfoReader; private readonly IVideoFileInfoReader _videoFileInfoReader;
private readonly IParsingService _parsingService; private readonly IParsingService _parsingService;
private readonly IMessageAggregator _messageAggregator;
public DiskScanService(IDiskProvider diskProvider, ICleanGhostFiles ghostFileCleaner, IMediaFileService mediaFileService, IVideoFileInfoReader videoFileInfoReader, public DiskScanService(IDiskProvider diskProvider, ISeriesService seriesService, IMediaFileService mediaFileService, IVideoFileInfoReader videoFileInfoReader,
IParsingService parsingService) IParsingService parsingService, IMessageAggregator messageAggregator)
{ {
_diskProvider = diskProvider; _diskProvider = diskProvider;
_ghostFileCleaner = ghostFileCleaner; _seriesService = seriesService;
_mediaFileService = mediaFileService; _mediaFileService = mediaFileService;
_videoFileInfoReader = videoFileInfoReader; _videoFileInfoReader = videoFileInfoReader;
_parsingService = parsingService; _parsingService = parsingService;
_messageAggregator = messageAggregator;
} }
public virtual void Scan(Series series) private void Scan(Series series)
{ {
if (!_diskProvider.FolderExists(series.Path)) if (!_diskProvider.FolderExists(series.Path))
{ {
@ -45,7 +48,7 @@ namespace NzbDrone.Core.Providers
return; return;
} }
_ghostFileCleaner.RemoveNonExistingFiles(series.Id); _messageAggregator.PublishCommand(new CleanMediaFileDb(series.Id));
var mediaFileList = GetVideoFiles(series.Path); var mediaFileList = GetVideoFiles(series.Path);
@ -58,7 +61,7 @@ namespace NzbDrone.Core.Providers
//Todo: Move the episode linking to here, instead of import (or rename import) //Todo: Move the episode linking to here, instead of import (or rename import)
} }
public virtual EpisodeFile ImportFile(Series series, string filePath) public EpisodeFile ImportFile(Series series, string filePath)
{ {
Logger.Trace("Importing file to database [{0}]", filePath); Logger.Trace("Importing file to database [{0}]", filePath);
@ -87,7 +90,7 @@ namespace NzbDrone.Core.Providers
} }
} }
if (parsedEpisode.Episodes.Any(e => e.EpisodeFile != null && e.EpisodeFile.Quality > parsedEpisode.Quality)) if (parsedEpisode.Episodes.Any(e => e.EpisodeFileId != 0 && e.EpisodeFile.Value.Quality > parsedEpisode.Quality))
{ {
Logger.Trace("This file isn't an upgrade for all episodes. Skipping {0}", filePath); Logger.Trace("This file isn't an upgrade for all episodes. Skipping {0}", filePath);
return null; return null;
@ -101,6 +104,7 @@ namespace NzbDrone.Core.Providers
episodeFile.Quality = parsedEpisode.Quality; episodeFile.Quality = parsedEpisode.Quality;
episodeFile.SeasonNumber = parsedEpisode.SeasonNumber; episodeFile.SeasonNumber = parsedEpisode.SeasonNumber;
episodeFile.SceneName = Path.GetFileNameWithoutExtension(filePath.CleanPath()); episodeFile.SceneName = Path.GetFileNameWithoutExtension(filePath.CleanPath());
episodeFile.Episodes = parsedEpisode.Episodes;
//Todo: We shouldn't actually import the file until we confirm its the only one we want. //Todo: We shouldn't actually import the file until we confirm its the only one we want.
//Todo: Separate episodeFile creation from importing (pass file to import to import) //Todo: Separate episodeFile creation from importing (pass file to import to import)
@ -108,7 +112,7 @@ namespace NzbDrone.Core.Providers
return episodeFile; return episodeFile;
} }
public virtual string[] GetVideoFiles(string path, bool allDirectories = true) public string[] GetVideoFiles(string path, bool allDirectories = true)
{ {
Logger.Debug("Scanning '{0}' for video files", path); Logger.Debug("Scanning '{0}' for video files", path);
@ -120,5 +124,24 @@ namespace NzbDrone.Core.Providers
Logger.Trace("{0} video files were found in {1}", mediaFileList.Count, path); Logger.Trace("{0} video files were found in {1}", mediaFileList.Count, path);
return mediaFileList.ToArray(); return mediaFileList.ToArray();
} }
public void Execute(DiskScanCommand message)
{
var seriesToScan = new List<Series>();
if (message.SeriesId.HasValue)
{
seriesToScan.Add(_seriesService.GetSeries(message.SeriesId.Value));
}
else
{
seriesToScan.AddRange(_seriesService.GetAllSeries());
}
foreach (var series in seriesToScan)
{
Scan(series);
}
}
} }
} }

@ -6,20 +6,6 @@ namespace NzbDrone.Core.MediaFiles
{ {
public class EpisodeFile : ModelBase public class EpisodeFile : ModelBase
{ {
public EpisodeFile()
{
}
public EpisodeFile(EpisodeFile source)
{
Id = source.Id;
SeriesId = source.SeriesId;
SeasonNumber = source.SeasonNumber;
Path = source.Path;
Size = source.Size;
}
public int SeriesId { get; set; } public int SeriesId { get; set; }
public int SeasonNumber { get; set; } public int SeasonNumber { get; set; }
public string Path { get; set; } public string Path { get; set; }

@ -1,48 +0,0 @@
using System;
using NLog;
using NzbDrone.Common;
namespace NzbDrone.Core.MediaFiles
{
public interface ICleanGhostFiles
{
void RemoveNonExistingFiles(int seriesId);
}
public class GhostFileCleanupService : ICleanGhostFiles
{
private readonly IMediaFileService _mediaFileService;
private readonly IDiskProvider _diskProvider;
private readonly Logger _logger;
public GhostFileCleanupService(IMediaFileService mediaFileService, IDiskProvider diskProvider, Logger logger)
{
_mediaFileService = mediaFileService;
_diskProvider = diskProvider;
_logger = logger;
}
public void RemoveNonExistingFiles(int seriesId)
{
var seriesFile = _mediaFileService.GetFilesBySeries(seriesId);
foreach (var episodeFile in seriesFile)
{
try
{
if (!_diskProvider.FileExists(episodeFile.Path))
{
_logger.Trace("File [{0}] no longer exists on disk. removing from db", episodeFile.Path);
_mediaFileService.Delete(episodeFile);
}
}
catch (Exception ex)
{
var message = String.Format("Unable to cleanup EpisodeFile in DB: {0}", episodeFile.Id);
_logger.ErrorException(message, ex);
}
}
}
}
}

@ -0,0 +1,55 @@
using System;
using System.Linq;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.MediaFiles
{
public class MediaFileTableCleanupService : IExecute<CleanMediaFileDb>
{
private readonly IMediaFileService _mediaFileService;
private readonly IDiskProvider _diskProvider;
private readonly IEpisodeService _episodeService;
private readonly Logger _logger;
public MediaFileTableCleanupService(IMediaFileService mediaFileService, IDiskProvider diskProvider, IEpisodeService episodeService, Logger logger)
{
_mediaFileService = mediaFileService;
_diskProvider = diskProvider;
_episodeService = episodeService;
_logger = logger;
}
public void Execute(CleanMediaFileDb message)
{
var seriesFile = _mediaFileService.GetFilesBySeries(message.SeriesId);
foreach (var episodeFile in seriesFile)
{
try
{
if (!_diskProvider.FileExists(episodeFile.Path))
{
_logger.Trace("File [{0}] no longer exists on disk. removing from db", episodeFile.Path);
_mediaFileService.Delete(episodeFile);
}
if (!_episodeService.GetEpisodesByFileId(episodeFile.Id).Any())
{
_logger.Trace("File [{0}] is not assigned to any episodes. removing from db", episodeFile.Path);
_mediaFileService.Delete(episodeFile);
}
}
catch (Exception ex)
{
var errorMessage = String.Format("Unable to cleanup EpisodeFile in DB: {0}", episodeFile.Id);
_logger.ErrorException(errorMessage, ex);
}
}
}
}
}

@ -247,7 +247,9 @@
<Compile Include="Indexers\RssSyncCommand.cs" /> <Compile Include="Indexers\RssSyncCommand.cs" />
<Compile Include="Jobs\TaskManager.cs" /> <Compile Include="Jobs\TaskManager.cs" />
<Compile Include="Lifecycle\ApplicationShutdownRequested.cs" /> <Compile Include="Lifecycle\ApplicationShutdownRequested.cs" />
<Compile Include="MediaFiles\Commands\CleanMediaFileDb.cs" />
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" /> <Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
<Compile Include="MediaFiles\Commands\DiskScanCommand.cs" />
<Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" /> <Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" />
<Compile Include="Download\EpisodeGrabbedEvent.cs" /> <Compile Include="Download\EpisodeGrabbedEvent.cs" />
<Compile Include="Download\SeriesRenamedEvent.cs" /> <Compile Include="Download\SeriesRenamedEvent.cs" />
@ -296,7 +298,7 @@
<Compile Include="MediaFiles\EpisodeFileMovingService.cs" /> <Compile Include="MediaFiles\EpisodeFileMovingService.cs" />
<Compile Include="MediaFiles\Events\EpisodeFileAddedEvent.cs" /> <Compile Include="MediaFiles\Events\EpisodeFileAddedEvent.cs" />
<Compile Include="MediaFiles\Events\EpisodeFileDeletedEvent.cs" /> <Compile Include="MediaFiles\Events\EpisodeFileDeletedEvent.cs" />
<Compile Include="MediaFiles\GhostFileCleanupService.cs" /> <Compile Include="MediaFiles\MediaFileTableCleanupService.cs" />
<Compile Include="MediaFiles\MediaFileRepository.cs" /> <Compile Include="MediaFiles\MediaFileRepository.cs" />
<Compile Include="MetadataSource\IProvideEpisodeInfo.cs" /> <Compile Include="MetadataSource\IProvideEpisodeInfo.cs" />
<Compile Include="MetadataSource\IProvideSeriesInfo.cs" /> <Compile Include="MetadataSource\IProvideSeriesInfo.cs" />
@ -404,7 +406,7 @@
<Compile Include="DecisionEngine\Specifications\RetentionSpecification.cs"> <Compile Include="DecisionEngine\Specifications\RetentionSpecification.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\IDiskScanService.cs"> <Compile Include="MediaFiles\DiskScanService.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Download\Clients\BlackholeProvider.cs"> <Compile Include="Download\Clients\BlackholeProvider.cs">

@ -40,7 +40,7 @@ namespace NzbDrone.Core.Providers.Converting
var outputFile = _configService.GetValue("iPodConvertDir", ""); var outputFile = _configService.GetValue("iPodConvertDir", "");
var handBrakePreset = _configService.GetValue("HandBrakePreset", "iPhone & iPod Touch"); var handBrakePreset = _configService.GetValue("HandBrakePreset", "iPhone & iPod Touch");
var handBrakeCommand = String.Format("-i \"{0}\" -o \"{1}\" --preset=\"{2}\"", episode.EpisodeFile.Path, outputFile, handBrakePreset); var handBrakeCommand = String.Format("-i \"{0}\" -o \"{1}\" --preset=\"{2}\"", episode.EpisodeFile.Value.Path, outputFile, handBrakePreset);
var handBrakeFile = @"C:\Program Files (x86)\Handbrake\HandBrakeCLI.exe"; var handBrakeFile = @"C:\Program Files (x86)\Handbrake\HandBrakeCLI.exe";
try try

@ -30,7 +30,7 @@ namespace NzbDrone.Core.Providers
var misnamedFilesSelect = episodesWithFiles.AsParallel().Where( var misnamedFilesSelect = episodesWithFiles.AsParallel().Where(
w => w =>
w.First().EpisodeFile.Path != w.First().EpisodeFile.Value.Path !=
_buildFileNames.BuildFilename(w.Select(e => e).ToList(), w.First().Series, w.First().EpisodeFile)).Skip(Math.Max(pageSize * (pageNumber - 1), 0)).Take(pageSize); _buildFileNames.BuildFilename(w.Select(e => e).ToList(), w.First().Series, w.First().EpisodeFile)).Skip(Math.Max(pageSize * (pageNumber - 1), 0)).Take(pageSize);
//Process the episodes //Process the episodes
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Providers
var properName = _buildFileNames.BuildFilename(episodes, firstEpisode.Series, var properName = _buildFileNames.BuildFilename(episodes, firstEpisode.Series,
firstEpisode.EpisodeFile); firstEpisode.EpisodeFile);
var currentName = Path.GetFileNameWithoutExtension(firstEpisode.EpisodeFile.Path); var currentName = Path.GetFileNameWithoutExtension(firstEpisode.EpisodeFile.Value.Path);
if (properName != currentName) if (properName != currentName)
{ {

@ -1,4 +1,5 @@
using System; using System;
using Marr.Data;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
@ -18,38 +19,21 @@ namespace NzbDrone.Core.Tv
public string Overview { get; set; } public string Overview { get; set; }
public Boolean Ignored { get; set; } public Boolean Ignored { get; set; }
public PostDownloadStatusType PostDownloadStatus { get; set; }
public Nullable<Int32> AbsoluteEpisodeNumber { get; set; } public Nullable<Int32> AbsoluteEpisodeNumber { get; set; }
public int SceneSeasonNumber { get; set; } public int SceneSeasonNumber { get; set; }
public int SceneEpisodeNumber { get; set; } public int SceneEpisodeNumber { get; set; }
public DateTime? GrabDate { get; set; }
public bool HasFile public bool HasFile
{ {
get { return EpisodeFile != null; } get { return EpisodeFileId != 0; }
} }
public EpisodeStatuses Status public EpisodeStatuses Status
{ {
get get
{ {
if (HasFile) return EpisodeStatuses.Ready; if (HasFile) return EpisodeStatuses.Ready;
if (GrabDate != null)
{
if (PostDownloadStatus == PostDownloadStatusType.Unpacking)
return EpisodeStatuses.Unpacking;
if (PostDownloadStatus == PostDownloadStatusType.Failed)
return EpisodeStatuses.Failed;
if (GrabDate.Value.AddDays(1) >= DateTime.Now)
return EpisodeStatuses.Downloading;
}
if (GrabDate != null && GrabDate.Value.AddDays(1) >= DateTime.Now)
return EpisodeStatuses.Downloading;
if (AirDate != null && AirDate.Value.Date == DateTime.Today) if (AirDate != null && AirDate.Value.Date == DateTime.Today)
return EpisodeStatuses.AirsToday; return EpisodeStatuses.AirsToday;
@ -75,7 +59,7 @@ namespace NzbDrone.Core.Tv
public Series Series { get; set; } public Series Series { get; set; }
public EpisodeFile EpisodeFile { get; set; } public LazyLoaded<EpisodeFile> EpisodeFile { get; set; }
public override string ToString() public override string ToString()
{ {

@ -1,10 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq; using System.Linq;
using FluentMigrator.Runner;
using Marr.Data; using Marr.Data;
using Marr.Data.QGen; using Marr.Data.QGen;
using NzbDrone.Common.Messaging; using NzbDrone.Common.Messaging;
@ -26,7 +22,6 @@ namespace NzbDrone.Core.Tv
List<Episode> EpisodesWithFiles(); List<Episode> EpisodesWithFiles();
List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate); List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate);
void SetIgnoreFlat(Episode episode, bool ignoreFlag); void SetIgnoreFlat(Episode episode, bool ignoreFlag);
void SetPostDownloadStatus(int episodeId, PostDownloadStatusType status);
void SetFileId(int episodeId, int fileId); void SetFileId(int episodeId, int fileId);
} }
@ -62,7 +57,7 @@ namespace NzbDrone.Core.Tv
public List<Episode> GetEpisodeByFileId(int fileId) public List<Episode> GetEpisodeByFileId(int fileId)
{ {
return Query.Where(s => s.EpisodeFile != null && s.EpisodeFile.Id == fileId).ToList(); return Query.Where(e => e.EpisodeFileId == fileId).ToList();
} }
public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials) public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials)
@ -74,7 +69,7 @@ namespace NzbDrone.Core.Tv
{ {
startingSeasonNumber = 0; startingSeasonNumber = 0;
} }
var pagingQuery = Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id) var pagingQuery = Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
.Where(e => e.EpisodeFileId == 0) .Where(e => e.EpisodeFileId == 0)
.AndWhere(e => e.SeasonNumber >= startingSeasonNumber) .AndWhere(e => e.SeasonNumber >= startingSeasonNumber)
@ -98,7 +93,7 @@ namespace NzbDrone.Core.Tv
public List<Episode> EpisodesWithFiles() public List<Episode> EpisodesWithFiles()
{ {
return Query.Where(s => s.EpisodeFile != null).ToList(); return Query.Where(s => s.EpisodeFileId != 0).ToList();
} }
public List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate) public List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate)
@ -113,11 +108,6 @@ namespace NzbDrone.Core.Tv
SetFields(episode, p => p.Ignored); SetFields(episode, p => p.Ignored);
} }
public void SetPostDownloadStatus(int episodeId, PostDownloadStatusType status)
{
SetFields(new Episode { Id = episodeId, PostDownloadStatus = status }, episode => episode.PostDownloadStatus);
}
public void SetFileId(int episodeId, int fileId) public void SetFileId(int episodeId, int fileId)
{ {
SetFields(new Episode { Id = episodeId, EpisodeFileId = fileId }, episode => episode.EpisodeFileId); SetFields(new Episode { Id = episodeId, EpisodeFileId = fileId }, episode => episode.EpisodeFileId);

@ -29,16 +29,14 @@ namespace NzbDrone.Core.Tv
List<int> GetEpisodeNumbersBySeason(int seriesId, int seasonNumber); List<int> GetEpisodeNumbersBySeason(int seriesId, int seasonNumber);
void SetEpisodeIgnore(int episodeId, bool isIgnored); void SetEpisodeIgnore(int episodeId, bool isIgnored);
bool IsFirstOrLastEpisodeOfSeason(int episodeId); bool IsFirstOrLastEpisodeOfSeason(int episodeId);
void SetPostDownloadStatus(List<int> episodeIds, PostDownloadStatusType postDownloadStatus);
void UpdateEpisodes(List<Episode> episodes); void UpdateEpisodes(List<Episode> episodes);
List<Episode> EpisodesBetweenDates(DateTime start, DateTime end); List<Episode> EpisodesBetweenDates(DateTime start, DateTime end);
} }
public class EpisodeService : IEpisodeService, public class EpisodeService : IEpisodeService,
IHandle<EpisodeGrabbedEvent>,
IHandle<EpisodeFileDeletedEvent>, IHandle<EpisodeFileDeletedEvent>,
IHandle<EpisodeFileAddedEvent>, IHandle<EpisodeFileAddedEvent>,
IHandleAsync<SeriesDeletedEvent>, IHandleAsync<SeriesDeletedEvent>,
IHandleAsync<SeriesAddedEvent> IHandleAsync<SeriesAddedEvent>
{ {
@ -166,7 +164,7 @@ namespace NzbDrone.Core.Tv
episodeToUpdate.EpisodeFileId > 0) episodeToUpdate.EpisodeFileId > 0)
{ {
logger.Info("Unlinking episode file because TheTVDB changed the episode number..."); logger.Info("Unlinking episode file because TheTVDB changed the episode number...");
episodeToUpdate.EpisodeFile = null; episodeToUpdate.EpisodeFileId = 0;
} }
episodeToUpdate.SeriesId = series.Id; episodeToUpdate.SeriesId = series.Id;
@ -268,22 +266,6 @@ namespace NzbDrone.Core.Tv
return false; return false;
} }
public void SetPostDownloadStatus(List<int> episodeIds, PostDownloadStatusType postDownloadStatus)
{
if (episodeIds.Count == 0) throw new ArgumentException("episodeIds should contain one or more episode ids.");
foreach (var episodeId in episodeIds)
{
var episode = _episodeRepository.Get(episodeId);
episode.PostDownloadStatus = postDownloadStatus;
_episodeRepository.Update(episode);
}
logger.Trace("Updating PostDownloadStatus for {0} episode(s) to {1}", episodeIds.Count, postDownloadStatus);
}
public void UpdateEpisodes(List<Episode> episodes) public void UpdateEpisodes(List<Episode> episodes)
{ {
_episodeRepository.UpdateMany(episodes); _episodeRepository.UpdateMany(episodes);
@ -296,16 +278,6 @@ namespace NzbDrone.Core.Tv
return LinkSeriesToEpisodes(episodes); return LinkSeriesToEpisodes(episodes);
} }
public void Handle(EpisodeGrabbedEvent message)
{
foreach (var episode in message.Episode.Episodes)
{
logger.Trace("Marking episode {0} as fetched.", episode.Id);
episode.GrabDate = DateTime.UtcNow;
_episodeRepository.Update(episode);
}
}
public void HandleAsync(SeriesDeletedEvent message) public void HandleAsync(SeriesDeletedEvent message)
{ {
var episodes = GetEpisodeBySeries(message.Series.Id); var episodes = GetEpisodeBySeries(message.Series.Id);
@ -317,10 +289,8 @@ namespace NzbDrone.Core.Tv
foreach (var episode in GetEpisodesByFileId(message.EpisodeFile.Id)) foreach (var episode in GetEpisodesByFileId(message.EpisodeFile.Id))
{ {
_logger.Trace("Detaching episode {0} from file.", episode.Id); _logger.Trace("Detaching episode {0} from file.", episode.Id);
episode.EpisodeFile = null; episode.EpisodeFileId = 0;
episode.Ignored = _configService.AutoIgnorePreviouslyDownloadedEpisodes; episode.Ignored = _configService.AutoIgnorePreviouslyDownloadedEpisodes;
episode.GrabDate = null;
episode.PostDownloadStatus = PostDownloadStatusType.Unknown;
UpdateEpisode(episode); UpdateEpisode(episode);
} }
} }
@ -335,7 +305,6 @@ namespace NzbDrone.Core.Tv
foreach (var episode in message.EpisodeFile.Episodes.Value) foreach (var episode in message.EpisodeFile.Episodes.Value)
{ {
_episodeRepository.SetFileId(episode.Id, message.EpisodeFile.Id); _episodeRepository.SetFileId(episode.Id, message.EpisodeFile.Id);
_episodeRepository.SetPostDownloadStatus(episode.Id, PostDownloadStatusType.NoError);
_logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.Path, episode); _logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.Path, episode);
} }
} }

@ -25,7 +25,7 @@
layout="${date:format=yy-M-d HH\:mm\:ss.f}|${logger}}|${level}|${message}|${exception:format=ToString}"/> layout="${date:format=yy-M-d HH\:mm\:ss.f}|${logger}}|${level}|${message}|${exception:format=ToString}"/>
</targets> </targets>
<rules> <rules>
<logger name="*" minlevel="Debug" writeTo="consoleLogger"/> <logger name="*" minlevel="Trace" writeTo="consoleLogger"/>
<logger name="*" minlevel="Off" writeTo="udpTarget"/> <logger name="*" minlevel="Off" writeTo="udpTarget"/>
<logger name="*" minlevel="Warn" writeTo="rollingFileLogger"/> <logger name="*" minlevel="Warn" writeTo="rollingFileLogger"/>
</rules> </rules>

@ -156,7 +156,7 @@ define([
{ {
title : 'Update Library', title : 'Update Library',
icon : 'icon-refresh', icon : 'icon-refresh',
command : 'updatelibrary', command : 'diskscan',
successMessage: 'Library was updated!', successMessage: 'Library was updated!',
errorMessage : 'Library update failed!' errorMessage : 'Library update failed!'
}, },

Loading…
Cancel
Save