Added two new Episode Statuses - Unpacking and Failed.

Tests added to support new Statuses.
PostDownloadScanJob will update PostDownloadStatus for failed or unpacking.
ImportFile will set the PostDownloadStatus to Processed when added to the database.
This commit is contained in:
Mark McDowall 2011-10-11 20:44:19 -07:00
parent c534d47b0a
commit 5098ea3249
15 changed files with 234 additions and 10 deletions

View File

@ -7,6 +7,7 @@ using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
@ -1464,5 +1465,42 @@ namespace NzbDrone.Core.Test
//Assert
result.Should().BeFalse();
}
[TestCase("The Office (US) - S01E05 - Episode Title", PostDownloadStatusType.Unpacking, 1)]
[TestCase("The Office (US) - S01E05 - Episode Title", PostDownloadStatusType.Failed, 1)]
[TestCase("The Office (US) - S01E05E06 - Episode Title", PostDownloadStatusType.Unpacking, 2)]
[TestCase("The Office (US) - S01E05E06 - Episode Title", PostDownloadStatusType.Failed, 2)]
[TestCase("The Office (US) - Season 01 - Episode Title", PostDownloadStatusType.Unpacking, 10)]
[TestCase("The Office (US) - Season 01 - Episode Title", PostDownloadStatusType.Failed, 10)]
public void SetPostDownloadStatus(string folderName, PostDownloadStatusType postDownloadStatus, int episodeCount)
{
var db = MockLib.GetEmptyDatabase();
var mocker = new AutoMoqer();
mocker.SetConstant(db);
var fakeSeries = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 12345)
.With(s => s.CleanTitle = "officeus")
.Build();
var fakeEpisodes = Builder<Episode>.CreateListOfSize(10)
.WhereAll()
.Have(c => c.SeriesId = 12345)
.Have(c => c.SeasonNumber = 1)
.Have(c => c.PostDownloadStatus = PostDownloadStatusType.Unknown)
.Build();
db.Insert(fakeSeries);
db.InsertMany(fakeEpisodes);
mocker.GetMock<SeriesProvider>().Setup(s => s.FindSeries("officeus")).Returns(fakeSeries);
//Act
mocker.Resolve<EpisodeProvider>().SetPostDownloadStatus(folderName, postDownloadStatus);
//Assert
var result = db.Fetch<Episode>();
result.Where(e => e.PostDownloadStatus == postDownloadStatus).Count().Should().Be(episodeCount);
}
}
}

View File

@ -101,7 +101,6 @@ namespace NzbDrone.Core.Test
db.Fetch<Episode>().Should().HaveCount(1);
}
[Test]
public void Multi_GetSeason_Episode_Exists()
{
@ -235,5 +234,69 @@ namespace NzbDrone.Core.Test
db.Fetch<Episode>().Should().HaveCount(2);
ep.First().Ignored.Should().BeFalse();
}
[Test]
public void Full_Season_return_all_episodes_for_season()
{
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
var fakeSeries = Builder<Series>.CreateNew().Build();
var fakeEpisodes = Builder<Episode>.CreateListOfSize(10)
.WhereAll()
.Have(e => e.SeriesId = fakeSeries.SeriesId)
.Have(e => e.SeasonNumber = 2)
.Build();
db.Insert(fakeSeries);
db.InsertMany(fakeEpisodes);
var parseResult = new EpisodeParseResult
{
Series = fakeSeries,
SeasonNumber = 2,
EpisodeNumbers = new List<int>(),
FullSeason = true
};
var ep = mocker.Resolve<EpisodeProvider>().GetEpisodesByParseResult(parseResult);
ep.Should().HaveCount(10);
db.Fetch<Episode>().Should().HaveCount(10);
}
[Test]
public void No_Episodes_Not_a_proper_full_season_release()
{
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
var fakeSeries = Builder<Series>.CreateNew().Build();
var fakeEpisodes = Builder<Episode>.CreateListOfSize(10)
.WhereAll()
.Have(e => e.SeriesId = fakeSeries.SeriesId)
.Have(e => e.SeasonNumber = 2)
.Build();
db.Insert(fakeSeries);
db.InsertMany(fakeEpisodes);
var parseResult = new EpisodeParseResult
{
Series = fakeSeries,
SeasonNumber = 2,
EpisodeNumbers = new List<int>(),
FullSeason = false
};
var ep = mocker.Resolve<EpisodeProvider>().GetEpisodesByParseResult(parseResult);
ep.Should().HaveCount(0);
db.Fetch<Episode>().Should().HaveCount(10);
}
}
}

View File

@ -108,5 +108,27 @@ namespace NzbDrone.Core.Test
episode.Status.Should().Be(EpisodeStatusType.NotAired);
}
[TestCase(false, false, EpisodeStatusType.Failed, PostDownloadStatusType.Failed)]
[TestCase(false, false, EpisodeStatusType.Unpacking, PostDownloadStatusType.Unpacking)]
[TestCase(true, false, EpisodeStatusType.Ready, PostDownloadStatusType.Failed)]
[TestCase(true, true, EpisodeStatusType.Ready, PostDownloadStatusType.Unpacking)]
public void episode_downloaded_post_download_status_is_used(bool hasEpisodes, bool ignored,
EpisodeStatusType status, PostDownloadStatusType postDownloadStatus)
{
Episode episode = Builder<Episode>.CreateNew()
.With(e => e.Ignored = ignored)
.With(e => e.EpisodeFileId = 0)
.With(e => e.GrabDate = DateTime.Now.AddHours(22))
.With(e => e.PostDownloadStatus = postDownloadStatus)
.Build();
if (hasEpisodes)
{
episode.EpisodeFileId = 12;
}
Assert.AreEqual(status, episode.Status);
}
}
}

View File

@ -21,7 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>

View File

@ -0,0 +1,21 @@
using System;
using System.Data;
using Migrator.Framework;
namespace NzbDrone.Core.Datastore.Migrations
{
[Migration(20111011)]
public class Migration20111011 : Migration
{
public override void Up()
{
Database.AddColumn("Episodes", "PostDownloadStatus", DbType.Int32, ColumnProperty.Null);
}
public override void Down()
{
throw new NotImplementedException();
}
}
}

View File

@ -5,7 +5,7 @@
/// <summary>
/// Episode has not aired yet
/// </summary>
NotAired ,
NotAired,
/// <summary>
/// Episode is ignored
@ -16,12 +16,22 @@
/// Episode has aired but no episode
/// files have avilable
/// </summary>
Missing ,
Missing,
/// <summary>
/// Episode is being downloaded
/// </summary>
Downloading ,
Downloading,
/// <summary>
/// Episode has been downloaded and is unpacking (_UNPACK_)
/// </summary>
Unpacking,
/// <summary>
/// Episode has failed to download properly (_FAILED_)
/// </summary>
Failed,
/// <summary>
/// Episode is present in disk

View File

@ -0,0 +1,25 @@
namespace NzbDrone.Core.Model
{
public enum PostDownloadStatusType
{
/// <summary>
/// Unknown (Default)
/// </summary>
Unknown = 0,
/// <summary>
/// Unpacking
/// </summary>
Unpacking = 1,
/// <summary>
/// Failed
/// </summary>
Failed = 2,
/// <summary>
/// Processed
/// </summary>
Processed = 3
}
}

View File

@ -176,6 +176,7 @@
<Compile Include="Datastore\MigrationLogger.cs" />
<Compile Include="Datastore\MigrationsHelper.cs" />
<Compile Include="Datastore\CustomeMapper.cs" />
<Compile Include="Datastore\Migrations\Migration20111011.cs" />
<Compile Include="Datastore\Migrations\Migration20110909.cs" />
<Compile Include="Datastore\Migrations\Migration20110726.cs" />
<Compile Include="Datastore\Migrations\Migration20110707.cs" />
@ -192,6 +193,7 @@
<Compile Include="Model\AtomicParsleyTitleType.cs" />
<Compile Include="Model\AuthenticationType.cs" />
<Compile Include="Model\ConnectionInfoModel.cs" />
<Compile Include="Model\PostDownloadStatusType.cs" />
<Compile Include="Model\ExternalNotificationType.cs" />
<Compile Include="Model\JobQueueItem.cs" />
<Compile Include="Model\LanguageType.cs" />

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using Ninject;
using NLog;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using PetaPoco;
@ -146,6 +147,7 @@ namespace NzbDrone.Core.Providers
foreach (var ep in episodes)
{
ep.EpisodeFileId = fileId;
ep.PostDownloadStatus = PostDownloadStatusType.Processed;
_episodeProvider.UpdateEpisode(ep);
Logger.Debug("Linking [{0}] > [{1}]", filePath, ep);
}

View File

@ -125,6 +125,14 @@ namespace NzbDrone.Core.Providers
{
var result = new List<Episode>();
if (parseResult.EpisodeNumbers.Count == 0 && parseResult.FullSeason)
{
result.AddRange(GetEpisodesBySeason(parseResult.Series.SeriesId, parseResult.SeasonNumber));
//Return now as no further processing is required
return result;
}
foreach (var episodeNumber in parseResult.EpisodeNumbers)
{
var episodeInfo = GetEpisode(parseResult.Series.SeriesId, parseResult.SeasonNumber, episodeNumber);
@ -396,5 +404,20 @@ namespace NzbDrone.Core.Providers
Logger.Trace("Finished deleting invalid episodes for {0}", series.SeriesId);
}
public virtual void SetPostDownloadStatus(string folderName, PostDownloadStatusType postDownloadStatus)
{
var parseResult = Parser.ParseTitle(folderName);
parseResult.Series = _seriesProvider.FindSeries(parseResult.CleanTitle);
var episodeIds = GetEpisodesByParseResult(parseResult).Select(e => e.EpisodeId);
var episodeIdString = String.Join(", ", episodeIds);
var episodeIdQuery = String.Format(@"UPDATE Episodes SET PostDownloadStatus = {0}
WHERE EpisodeId IN ({1})", (int)postDownloadStatus, episodeIdString);
Logger.Trace("Updating PostDownloadStatus for all episodeIds in {0}", episodeIdString);
_database.Execute(episodeIdQuery);
}
}
}

View File

@ -2,6 +2,7 @@
using System.IO;
using Ninject;
using NLog;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers.Core;
@ -13,16 +14,19 @@ namespace NzbDrone.Core.Providers.Jobs
private readonly DiskProvider _diskProvider;
private readonly DiskScanProvider _diskScanProvider;
private readonly SeriesProvider _seriesProvider;
private readonly EpisodeProvider _episodeProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
[Inject]
public PostDownloadScanJob(ConfigProvider configProvider, DiskProvider diskProvider,
DiskScanProvider diskScanProvider, SeriesProvider seriesProvider)
DiskScanProvider diskScanProvider, SeriesProvider seriesProvider,
EpisodeProvider episodeProvider)
{
_configProvider = configProvider;
_diskProvider = diskProvider;
_diskScanProvider = diskScanProvider;
_seriesProvider = seriesProvider;
_episodeProvider = episodeProvider;
}
public PostDownloadScanJob()
@ -63,12 +67,14 @@ namespace NzbDrone.Core.Providers.Jobs
if (subfolderInfo.Name.StartsWith("_UNPACK_", StringComparison.CurrentCultureIgnoreCase))
{
_episodeProvider.SetPostDownloadStatus(subfolderInfo.Name.Substring(8), PostDownloadStatusType.Unpacking);
Logger.Debug("Folder [{0}] is still being unpacked. skipping.", subfolder);
continue;
}
if (subfolderInfo.Name.StartsWith("_FAILED_", StringComparison.CurrentCultureIgnoreCase))
{
_episodeProvider.SetPostDownloadStatus(subfolderInfo.Name.Substring(8), PostDownloadStatusType.Failed);
Logger.Debug("Folder [{0}] is marked as failed. skipping.", subfolder);
continue;
}

View File

@ -23,6 +23,8 @@ namespace NzbDrone.Core.Repository
public Boolean Ignored { get; set; }
public PostDownloadStatusType PostDownloadStatus { get; set; }
/// <summary>
/// Gets or sets the grab date.
/// </summary>
@ -39,15 +41,23 @@ namespace NzbDrone.Core.Repository
{
if (EpisodeFileId != 0) return EpisodeStatusType.Ready;
if (GrabDate != null && GrabDate.Value.AddDays(1) >= DateTime.Now)
if (GrabDate != null)
{
return EpisodeStatusType.Downloading;
if (PostDownloadStatus == PostDownloadStatusType.Unpacking)
return EpisodeStatusType.Unpacking;
if (PostDownloadStatus == PostDownloadStatusType.Failed)
return EpisodeStatusType.Failed;
if (GrabDate.Value.AddDays(1) >= DateTime.Now)
return EpisodeStatusType.Downloading;
}
if (GrabDate != null && GrabDate.Value.AddDays(1) >= DateTime.Now)
return EpisodeStatusType.Downloading;
if (AirDate != null && AirDate.Value.Date < DateTime.Now)
{
return EpisodeStatusType.Missing;
}
return EpisodeStatusType.NotAired;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -333,6 +333,7 @@
<Content Include="Content\Images\close.png" />
<Content Include="Content\Images\Downloading.png" />
<Content Include="Content\Images\error.png" />
<Content Include="Content\Images\Failed.png" />
<Content Include="Content\Images\gritter.png" />
<Content Include="Content\Images\Missing.png" />
<Content Include="Content\Images\NotAired.png" />
@ -340,6 +341,7 @@
<Content Include="Content\Images\Rename.png" />
<Content Include="Content\Images\Search.png" />
<Content Include="Content\Images\success.png" />
<Content Include="Content\Images\Unpacking.png" />
<Content Include="Content\jquery.gritter.css" />
<Content Include="Content\Menu.css" />
<Compile Include="App_GlobalResources\EditorLocalization.bg-BG.designer.cs">