Merge branch 'master' of git://github.com/kayone/NzbDrone

pull/4/head
Mark McDowall 13 years ago
commit 7b5556199f

@ -166,7 +166,7 @@ namespace Migrator.Providers
public virtual string Default(object defaultValue) public virtual string Default(object defaultValue)
{ {
if (defaultValue is String && defaultValue == String.Empty) if (defaultValue is String && defaultValue.ToString() == String.Empty)
{ {
defaultValue = "''"; defaultValue = "''";
} }

@ -19,6 +19,123 @@ namespace NzbDrone.Core.Test
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class EpisodeProviderTest : TestBase public class EpisodeProviderTest : TestBase
{ {
[Test]
public void GetEpisodes_exists()
{
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
var fakeSeries = Builder<Series>.CreateNew().Build();
var fakeEpisodes = Builder<Episode>.CreateListOfSize(5)
.WhereAll().Have(e => e.SeriesId = 1).Build();
db.InsertMany(fakeEpisodes);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetSeries(1))
.Returns(fakeSeries);
//Act
var episode = mocker.Resolve<EpisodeProvider>().GetEpisode(1);
//Assert
episode.ShouldHave().AllPropertiesBut(e => e.Series).EqualTo(fakeEpisodes.First());
episode.Series.ShouldHave().AllProperties().EqualTo(fakeSeries);
}
[Test]
[ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Sequence contains no elements")]
public void GetEpisodes_invalid_series()
{
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
mocker.Resolve<SeriesProvider>();
var fakeEpisodes = Builder<Episode>.CreateListOfSize(5)
.WhereAll().Have(e => e.SeriesId = 1).Build();
db.InsertMany(fakeEpisodes);
//Act
mocker.Resolve<EpisodeProvider>().GetEpisode(1);
}
[Test]
public void AttachSeries_empty_list()
{
var mocker = new AutoMoqer();
//Act
var result = mocker.Resolve<EpisodeProvider>().AttachSeries(new List<Episode>());
//Assert
result.Should().HaveCount(0);
}
[Test]
public void AttachSeries_list_success()
{
var mocker = new AutoMoqer();
var fakeSeries = Builder<Series>.CreateNew().With(s => s.SeriesId = 12).Build();
var fakeEpisodes = Builder<Episode>.CreateListOfSize(5)
.WhereAll().Have(e => e.SeriesId = 12).Build();
mocker.GetMock<SeriesProvider>()
.Setup(c => c.GetSeries(12))
.Returns(fakeSeries);
//Act
fakeEpisodes.Should().OnlyContain(e => e.Series == null);
var returnedSeries = mocker.Resolve<EpisodeProvider>().AttachSeries(fakeEpisodes);
//Assert
fakeEpisodes.Should().OnlyContain(e => e.Series == fakeSeries);
returnedSeries.Should().BeEquivalentTo(fakeEpisodes);
}
[Test]
public void AttachSeries_single_success()
{
var mocker = new AutoMoqer();
var fakeSeries = Builder<Series>.CreateNew().With(s => s.SeriesId = 12).Build();
var fakeEpisodes = Builder<Episode>.CreateNew().With(e => e.SeriesId = 12).Build();
mocker.GetMock<SeriesProvider>()
.Setup(c => c.GetSeries(12))
.Returns(fakeSeries);
//Act
var returnedEpisode = mocker.Resolve<EpisodeProvider>().AttachSeries(fakeEpisodes);
//Assert
fakeEpisodes.Series.Should().Be(fakeSeries);
returnedEpisode.Should().Be(fakeEpisodes);
}
[Test]
[ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Sequence contains no elements")]
public void AttachSeries_single_invalid_series()
{
var mocker = new AutoMoqer();
mocker.SetConstant(MockLib.GetEmptyDatabase());
mocker.Resolve<SeriesProvider>();
var fakeEpisodes = Builder<Episode>.CreateNew().With(e => e.SeriesId = 12).Build();
//Act
var returnedEpisode = mocker.Resolve<EpisodeProvider>().AttachSeries(fakeEpisodes);
}
[Test] [Test]
public void GetEpisodesBySeason_success() public void GetEpisodesBySeason_success()
@ -311,7 +428,7 @@ namespace NzbDrone.Core.Test
.Build(); .Build();
episodes.ToList().ForEach(c => db.Insert(c)); episodes.ToList().ForEach(c => db.Insert(c));
//Act //Act
var result = mocker.Resolve<EpisodeProvider>().IsIgnored(10, 2); var result = mocker.Resolve<EpisodeProvider>().IsIgnored(10, 2);

@ -26,8 +26,6 @@ namespace NzbDrone.Core.Test
.AndTheNext(1).Has(s => s.SeriesId = 15) .AndTheNext(1).Has(s => s.SeriesId = 15)
.Build(); .Build();
var episodes = Builder<Episode>.CreateListOfSize(10).Build();
var notification = new ProgressNotification("Test"); var notification = new ProgressNotification("Test");
var mocker = new AutoMoqer(MockBehavior.Strict); var mocker = new AutoMoqer(MockBehavior.Strict);
@ -39,23 +37,21 @@ namespace NzbDrone.Core.Test
mocker.GetMock<DiskScanJob>() mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[0].SeriesId)) .Setup(j => j.Start(notification, series[0].SeriesId))
.Callback(() => series[0].LastDiskSync = DateTime.Now) .Callback(() => series[0].LastDiskSync = DateTime.Now);
.AtMostOnce();
mocker.GetMock<DiskScanJob>() mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[1].SeriesId)) .Setup(j => j.Start(notification, series[1].SeriesId))
.Callback(() => series[1].LastDiskSync = DateTime.Now) .Callback(() => series[1].LastDiskSync = DateTime.Now);
.AtMostOnce();
mocker.GetMock<UpdateInfoJob>() mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[0].SeriesId)) .Setup(j => j.Start(notification, series[0].SeriesId))
.Callback(() => series[0].LastInfoSync = DateTime.Now) .Callback(() => series[0].LastInfoSync = DateTime.Now);
.AtMostOnce();
mocker.GetMock<UpdateInfoJob>() mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[1].SeriesId)) .Setup(j => j.Start(notification, series[1].SeriesId))
.Callback(() => series[1].LastInfoSync = DateTime.Now) .Callback(() => series[1].LastInfoSync = DateTime.Now);
.AtMostOnce();
mocker.GetMock<SeriesProvider>() mocker.GetMock<SeriesProvider>()
.Setup(s => s.GetSeries(series[0].SeriesId)).Returns(series[0]); .Setup(s => s.GetSeries(series[0].SeriesId)).Returns(series[0]);
@ -63,13 +59,6 @@ namespace NzbDrone.Core.Test
mocker.GetMock<SeriesProvider>() mocker.GetMock<SeriesProvider>()
.Setup(s => s.GetSeries(series[1].SeriesId)).Returns(series[1]); .Setup(s => s.GetSeries(series[1].SeriesId)).Returns(series[1]);
mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodeBySeries(series[0].SeriesId)).Returns(episodes);
mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodeBySeries(series[1].SeriesId)).Returns(episodes);
mocker.GetMock<MediaFileProvider>() mocker.GetMock<MediaFileProvider>()
.Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>()); .Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>());
@ -78,6 +67,13 @@ namespace NzbDrone.Core.Test
//Assert //Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, series[0].SeriesId), Times.Once());
mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, series[1].SeriesId), Times.Once());
mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, series[0].SeriesId), Times.Once());
mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, series[1].SeriesId), Times.Once());
} }
@ -93,8 +89,6 @@ namespace NzbDrone.Core.Test
.AndTheNext(1).Has(s => s.SeriesId = 15) .AndTheNext(1).Has(s => s.SeriesId = 15)
.Build(); .Build();
var episodes = Builder<Episode>.CreateListOfSize(10).Build();
var notification = new ProgressNotification("Test"); var notification = new ProgressNotification("Test");
var mocker = new AutoMoqer(MockBehavior.Strict); var mocker = new AutoMoqer(MockBehavior.Strict);
@ -105,18 +99,15 @@ namespace NzbDrone.Core.Test
mocker.GetMock<UpdateInfoJob>() mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[0].SeriesId)) .Setup(j => j.Start(notification, series[0].SeriesId))
.Callback(() => series[0].LastInfoSync = DateTime.Now) .Callback(() => series[0].LastInfoSync = DateTime.Now);
.AtMostOnce();
mocker.GetMock<UpdateInfoJob>() mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[1].SeriesId)) .Setup(j => j.Start(notification, series[1].SeriesId))
.Throws(new InvalidOperationException()) .Throws(new InvalidOperationException());
.AtMostOnce();
mocker.GetMock<DiskScanJob>() mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[0].SeriesId)) .Setup(j => j.Start(notification, series[0].SeriesId))
.Callback(() => series[0].LastDiskSync = DateTime.Now) .Callback(() => series[0].LastDiskSync = DateTime.Now);
.AtMostOnce();
mocker.GetMock<SeriesProvider>() mocker.GetMock<SeriesProvider>()
@ -125,17 +116,98 @@ namespace NzbDrone.Core.Test
mocker.GetMock<MediaFileProvider>() mocker.GetMock<MediaFileProvider>()
.Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>()); .Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>());
mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodeBySeries(It.IsAny<long>())).Returns(episodes);
//Act //Act
mocker.Resolve<ImportNewSeriesJob>().Start(notification, 0); mocker.Resolve<ImportNewSeriesJob>().Start(notification, 0);
//Assert //Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, series[0].SeriesId), Times.Once());
mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, series[1].SeriesId), Times.Once());
mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, series[0].SeriesId), Times.Once());
ExceptionVerification.ExcpectedErrors(1); ExceptionVerification.ExcpectedErrors(1);
} }
[Test]
public void AutoIgnoreSeason_new_series_should_not_ignore_any()
{
int seriesId = 12;
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<MediaFileProvider>()
.Setup(p => p.GetSeriesFiles(seriesId))
.Returns(new List<EpisodeFile>());
mocker.GetMock<EpisodeProvider>()
.Setup(p => p.GetSeasons(seriesId))
.Returns(new List<int> { 0, 1, 2, 3, 4 });
mocker.Resolve<ImportNewSeriesJob>().AutoIgnoreSeasons(seriesId);
mocker.GetMock<EpisodeProvider>().Verify(p => p.SetSeasonIgnore(seriesId, It.IsAny<int>(), It.IsAny<Boolean>()), Times.Never());
}
[Test]
public void AutoIgnoreSeason_existing_should_not_ignore_currentseason()
{
int seriesId = 12;
var episodesFiles = Builder<EpisodeFile>.CreateListOfSize(2)
.WhereAll().Have(e => e.SeriesId = seriesId)
.Build();
episodesFiles[0].SeasonNumber = 0;
episodesFiles[1].SeasonNumber = 1;
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<MediaFileProvider>()
.Setup(p => p.GetSeriesFiles(seriesId))
.Returns(episodesFiles);
mocker.GetMock<EpisodeProvider>()
.Setup(p => p.GetSeasons(seriesId))
.Returns(new List<int> { 0, 1, 2 });
mocker.Resolve<ImportNewSeriesJob>().AutoIgnoreSeasons(seriesId);
mocker.GetMock<EpisodeProvider>().Verify(p => p.SetSeasonIgnore(seriesId, 2, It.IsAny<Boolean>()), Times.Never());
}
[Test]
public void AutoIgnoreSeason_existing_should_ignore_seasons_with_no_file()
{
int seriesId = 12;
var episodesFiles = Builder<EpisodeFile>.CreateListOfSize(2)
.WhereAll().Have(e => e.SeriesId = seriesId)
.Build();
episodesFiles[0].SeasonNumber = 1;
var mocker = new AutoMoqer();
mocker.GetMock<MediaFileProvider>()
.Setup(p => p.GetSeriesFiles(seriesId))
.Returns(episodesFiles);
mocker.GetMock<EpisodeProvider>()
.Setup(p => p.GetSeasons(seriesId))
.Returns(new List<int> { 0, 1, 2 });
mocker.Resolve<ImportNewSeriesJob>().AutoIgnoreSeasons(seriesId);
mocker.GetMock<EpisodeProvider>().Verify(p => p.SetSeasonIgnore(seriesId, 0, true), Times.Once());
mocker.GetMock<EpisodeProvider>().Verify(p => p.SetSeasonIgnore(seriesId, 1, true), Times.Never());
mocker.GetMock<EpisodeProvider>().Verify(p => p.SetSeasonIgnore(seriesId, 2, It.IsAny<Boolean>()), Times.Never());
}
} }
} }

@ -106,6 +106,7 @@ namespace NzbDrone.Core.Test
[Test] [Test]
[ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Sequence contains no elements")]
public void Get_series_invalid_series_id_should_return_null() public void Get_series_invalid_series_id_should_return_null()
{ {
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();

@ -84,6 +84,21 @@ namespace NzbDrone.Core.Test
Assert.IsNull(result); Assert.IsNull(result);
} }
[Test]
public void none_unique_season_episode_number()
{
//setup
var tvdbProvider = new TvDbProvider();
//act
var result = tvdbProvider.GetSeries(75978, true);//Family guy
//Asserts that when episodes are grouped by Season/Episode each group contains maximum of
//one item.
result.Episodes.GroupBy(e => e.SeasonNumber.ToString("000") + e.EpisodeNumber.ToString("000"))
.Max(e => e.Count()).Should().Be(1);
}
[Test] [Test]
public void American_dad_fix() public void American_dad_fix()
@ -97,11 +112,11 @@ namespace NzbDrone.Core.Test
var seasonsNumbers = result.Episodes.Select(e => e.SeasonNumber) var seasonsNumbers = result.Episodes.Select(e => e.SeasonNumber)
.Distinct().ToList(); .Distinct().ToList();
var seasons = new List<List<TvdbEpisode>>(seasonsNumbers.Count); var seasons = new Dictionary<int, List<TvdbEpisode>>(seasonsNumbers.Count);
foreach (var season in seasonsNumbers) foreach (var season in seasonsNumbers)
{ {
seasons.Insert(season, result.Episodes.Where(e => e.SeasonNumber == season).ToList()); seasons.Add(season, result.Episodes.Where(e => e.SeasonNumber == season).ToList());
} }
foreach (var episode in result.Episodes) foreach (var episode in result.Episodes)
@ -119,16 +134,16 @@ namespace NzbDrone.Core.Test
foreach (var season in seasons) foreach (var season in seasons)
{ {
season.Should().OnlyHaveUniqueItems(); season.Value.Should().OnlyHaveUniqueItems();
} }
//Make sure no episode number is skipped //Make sure no episode number is skipped
foreach (var season in seasons) foreach (var season in seasons)
{ {
for (int i = 1; i < season.Count; i++) for (int i = 1; i < season.Value.Count; i++)
{ {
season.Should().Contain(c => c.EpisodeNumber == i, "Can't find Episode S{0:00}E{1:00}", season.Value.Should().Contain(c => c.EpisodeNumber == i, "Can't find Episode S{0:00}E{1:00}",
season[0].SeasonNumber, i); season.Value[0].SeasonNumber, i);
} }
} }

@ -18,7 +18,6 @@ namespace NzbDrone.Core.Test
private Episode tomorrow; private Episode tomorrow;
private Episode twoDays; private Episode twoDays;
private Episode sevenDays; private Episode sevenDays;
private Episode eightDays;
[SetUp] [SetUp]
public new void Setup() public new void Setup()

@ -8,13 +8,14 @@ using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using PetaPoco;
namespace NzbDrone.Core.Test namespace NzbDrone.Core.Test
{ {
[TestFixture] [TestFixture]
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
[Ignore]
public class DbBenchmark : TestBase public class DbBenchmark : TestBase
{ {
const int Episodes_Per_Season = 20; const int Episodes_Per_Season = 20;
@ -22,6 +23,7 @@ namespace NzbDrone.Core.Test
private readonly List<int> seriesIds = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; private readonly List<int> seriesIds = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
private readonly List<Episode> episodes = new List<Episode>(); private readonly List<Episode> episodes = new List<Episode>();
private readonly List<EpisodeFile> files = new List<EpisodeFile>(); private readonly List<EpisodeFile> files = new List<EpisodeFile>();
private IDatabase db;
[TestFixtureSetUp] [TestFixtureSetUp]
@ -30,8 +32,18 @@ namespace NzbDrone.Core.Test
base.Setup(); base.Setup();
db = MockLib.GetEmptyDatabase();
int currentFileId = 0; int currentFileId = 0;
var qulityProfile = new QualityProfile
{
Name = "TestProfile",
Allowed = new List<QualityTypes> { QualityTypes.DVD, QualityTypes.Bluray1080p },
Cutoff = QualityTypes.DVD
};
db.Insert(qulityProfile);
foreach (var _seriesId in seriesIds) foreach (var _seriesId in seriesIds)
{ {
int seriesId = _seriesId; int seriesId = _seriesId;
@ -40,7 +52,7 @@ namespace NzbDrone.Core.Test
.With(s => s.Monitored = true) .With(s => s.Monitored = true)
.Build(); .Build();
//repo.Add(series); db.Insert(series);
foreach (var _seasonNumber in seasonsNumbers) foreach (var _seasonNumber in seasonsNumbers)
{ {
@ -52,8 +64,7 @@ namespace NzbDrone.Core.Test
{ {
var epFile = Builder<EpisodeFile>.CreateNew() var epFile = Builder<EpisodeFile>.CreateNew()
.With(e => e.SeriesId = seriesId) .With(e => e.SeriesId = seriesId)
.With(e => e.SeriesId = seriesId) .And(e => e.SeasonNumber = _seasonNumber)
.And(e => e.SeasonNumber = _seasonNumber)
.And(e => e.Path = Guid.NewGuid().ToString()) .And(e => e.Path = Guid.NewGuid().ToString())
.Build(); .Build();
@ -83,30 +94,32 @@ namespace NzbDrone.Core.Test
} }
//repo.AddMany(episodes); db.InsertMany(episodes);
//repo.AddMany(files); db.InsertMany(files);
} }
[Test] [Test]
public void get_episode_by_series_seasons_episode_x5000() public void get_episode_by_series_seasons_episode_x5000()
{ {
var epProvider = new EpisodeProvider(null, null); var mocker = new AutoMoqer();
mocker.SetConstant(db);
mocker.Resolve<SeriesProvider>();
var epProvider = mocker.Resolve<EpisodeProvider>();
Thread.Sleep(1000); Thread.Sleep(1000);
var random = new Random(); var random = new Random();
Console.WriteLine("Starting Test"); Console.WriteLine("Starting Test");
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
for (int i = 0; i < 5000; i++) for (int i = 0; i < 5000; i++)
{ {
epProvider.GetEpisode(6, random.Next(2, 5), random.Next(2, Episodes_Per_Season - 10)).Should().NotBeNull(); var ep = epProvider.GetEpisode(6, random.Next(2, 5), random.Next(2, Episodes_Per_Season - 10));
ep.Series.Should().NotBeNull();
} }
sw.Stop(); sw.Stop();
Console.WriteLine("Took " + sw.Elapsed); Console.WriteLine("Took " + sw.Elapsed);
@ -115,7 +128,11 @@ namespace NzbDrone.Core.Test
[Test] [Test]
public void get_episode_by_series_seasons_x1000() public void get_episode_by_series_seasons_x1000()
{ {
var epProvider = new EpisodeProvider( null, null); var mocker = new AutoMoqer();
mocker.SetConstant(db);
mocker.Resolve<SeriesProvider>();
var epProvider = mocker.Resolve<EpisodeProvider>();
Thread.Sleep(1000); Thread.Sleep(1000);
@ -140,8 +157,9 @@ namespace NzbDrone.Core.Test
public void get_episode_file_count_x100() public void get_episode_file_count_x100()
{ {
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
//mocker.SetConstant(repo); mocker.SetConstant(db);
mocker.SetConstant(mocker.Resolve<EpisodeProvider>()); mocker.Resolve<SeriesProvider>();
mocker.Resolve<EpisodeProvider>();
var mediaProvider = mocker.Resolve<MediaFileProvider>(); var mediaProvider = mocker.Resolve<MediaFileProvider>();
@ -163,13 +181,14 @@ namespace NzbDrone.Core.Test
Console.WriteLine("Took " + sw.Elapsed); Console.WriteLine("Took " + sw.Elapsed);
} }
[Test] [Test]
public void get_season_count_x5000() public void get_episode_file_count_x1000()
{ {
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
//mocker.SetConstant(repo); mocker.SetConstant(db);
var provider = mocker.Resolve<EpisodeProvider>(); mocker.Resolve<SeriesProvider>();
mocker.Resolve<EpisodeProvider>();
var mediaProvider = mocker.Resolve<MediaFileProvider>();
Thread.Sleep(1000); Thread.Sleep(1000);
@ -179,9 +198,9 @@ namespace NzbDrone.Core.Test
Console.WriteLine("Starting Test"); Console.WriteLine("Starting Test");
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
for (int i = 0; i < 5000; i++) for (int i = 0; i < 1000; i++)
{ {
provider.GetSeasons(random.Next(1, 10)).Should().HaveSameCount(seasonsNumbers); mediaProvider.GetEpisodeFilesCount(random.Next(1, 5)).Should().NotBeNull();
} }
@ -192,12 +211,11 @@ namespace NzbDrone.Core.Test
[Test] [Test]
public void get_episode_file_count_x10() public void get_season_count_x500()
{ {
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
//mocker.SetConstant(repo); mocker.SetConstant(db);
mocker.SetConstant(mocker.Resolve<EpisodeProvider>()); var provider = mocker.Resolve<EpisodeProvider>();
var provider = mocker.Resolve<MediaFileProvider>();
Thread.Sleep(1000); Thread.Sleep(1000);
@ -207,11 +225,9 @@ namespace NzbDrone.Core.Test
Console.WriteLine("Starting Test"); Console.WriteLine("Starting Test");
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
for (int i = 0; i < 100; i++) for (int i = 0; i < 500; i++)
{ {
var result = provider.GetEpisodeFilesCount(random.Next(1, 10)); provider.GetSeasons(random.Next(1, 10)).Should().HaveSameCount(seasonsNumbers);
result.Item1.Should().NotBe(0);
result.Item2.Should().NotBe(0);
} }
@ -220,5 +236,7 @@ namespace NzbDrone.Core.Test
Console.WriteLine("Took " + sw.Elapsed); Console.WriteLine("Took " + sw.Elapsed);
} }
} }
} }

@ -0,0 +1,24 @@
using System;
using System.Data;
using Migrator.Framework;
namespace NzbDrone.Core.Datastore.Migrations
{
[Migration(20110619)]
public class Migration20110619 : Migration
{
public override void Up()
{
if (Database.TableExists("Histories"))
{
Database.RemoveTable("Histories");
}
}
public override void Down()
{
throw new NotImplementedException();
}
}
}

@ -85,5 +85,31 @@ namespace NzbDrone.Core.Model
return result; return result;
} }
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 23 + Proper.GetHashCode();
hash = hash * 23 + QualityType.GetHashCode();
return hash;
}
}
public bool Equals(Quality other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(other.QualityType, QualityType) && other.Proper.Equals(Proper);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof (Quality)) return false;
return Equals((Quality) obj);
}
} }
} }

@ -163,7 +163,8 @@
<Compile Include="Datastore\MigrationLogger.cs" /> <Compile Include="Datastore\MigrationLogger.cs" />
<Compile Include="Datastore\MigrationsHelper.cs" /> <Compile Include="Datastore\MigrationsHelper.cs" />
<Compile Include="Datastore\CustomeMapper.cs" /> <Compile Include="Datastore\CustomeMapper.cs" />
<Compile Include="Datastore\Migrations\Migration.cs" /> <Compile Include="Datastore\Migrations\Migration20110619.cs" />
<Compile Include="Datastore\Migrations\Migration20110616.cs" />
<Compile Include="Datastore\SqliteProvider.cs" /> <Compile Include="Datastore\SqliteProvider.cs" />
<Compile Include="Fluent.cs" /> <Compile Include="Fluent.cs" />
<Compile Include="Helpers\EpisodeRenameHelper.cs" /> <Compile Include="Helpers\EpisodeRenameHelper.cs" />

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using Ninject; using Ninject;
using NLog; using NLog;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
@ -15,12 +14,14 @@ namespace NzbDrone.Core.Providers
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly TvDbProvider _tvDbProvider; private readonly TvDbProvider _tvDbProvider;
private readonly IDatabase _database; private readonly IDatabase _database;
private readonly SeriesProvider _seriesProvider;
[Inject] [Inject]
public EpisodeProvider(TvDbProvider tvDbProviderProvider, IDatabase database) public EpisodeProvider(IDatabase database, SeriesProvider seriesProvider, TvDbProvider tvDbProviderProvider)
{ {
_tvDbProvider = tvDbProviderProvider; _tvDbProvider = tvDbProviderProvider;
_database = database; _database = database;
_seriesProvider = seriesProvider;
} }
public EpisodeProvider() public EpisodeProvider()
@ -34,27 +35,27 @@ namespace NzbDrone.Core.Providers
public virtual Episode GetEpisode(long id) public virtual Episode GetEpisode(long id)
{ {
return _database.Single<Episode>(id); return AttachSeries(_database.Single<Episode>(id));
} }
public virtual Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber) public virtual Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber)
{ {
return _database.SingleOrDefault<Episode>("WHERE SeriesId = @0 AND SeasonNumber = @1 AND EpisodeNumber = @2", seriesId, seasonNumber, episodeNumber); return AttachSeries(_database.SingleOrDefault<Episode>("WHERE SeriesId = @0 AND SeasonNumber = @1 AND EpisodeNumber = @2", seriesId, seasonNumber, episodeNumber));
} }
public virtual Episode GetEpisode(int seriesId, DateTime date) public virtual Episode GetEpisode(int seriesId, DateTime date)
{ {
return _database.SingleOrDefault<Episode>("WHERE SeriesId = @0 AND AirDate = @1", seriesId, date.Date); return AttachSeries(_database.SingleOrDefault<Episode>("WHERE SeriesId = @0 AND AirDate = @1", seriesId, date.Date));
} }
public virtual IList<Episode> GetEpisodeBySeries(long seriesId) public virtual IList<Episode> GetEpisodeBySeries(long seriesId)
{ {
return _database.Fetch<Episode>("WHERE SeriesId = @0", seriesId); return AttachSeries(_database.Fetch<Episode>("WHERE SeriesId = @0", seriesId));
} }
public virtual IList<Episode> GetEpisodesBySeason(long seriesId, int seasonNumber) public virtual IList<Episode> GetEpisodesBySeason(long seriesId, int seasonNumber)
{ {
return _database.Fetch<Episode>("WHERE SeriesId = @0 AND SeasonNumber = @1", seriesId, seasonNumber); return AttachSeries(_database.Fetch<Episode>("WHERE SeriesId = @0 AND SeasonNumber = @1", seriesId, seasonNumber));
} }
public virtual List<Episode> GetEpisodes(EpisodeParseResult parseResult) public virtual List<Episode> GetEpisodes(EpisodeParseResult parseResult)
@ -87,12 +88,12 @@ namespace NzbDrone.Core.Providers
if (includeSpecials) if (includeSpecials)
return episodes.Where(e => e.SeasonNumber > 0).ToList(); return episodes.Where(e => e.SeasonNumber > 0).ToList();
return episodes.ToList(); return AttachSeries(episodes.ToList());
} }
public virtual IList<Episode> EpisodesByFileId(int episodeFileId) public virtual IList<Episode> EpisodesByFileId(int episodeFileId)
{ {
return _database.Fetch<Episode>("WHERE EpisodeFileId = @0", episodeFileId); return AttachSeries(_database.Fetch<Episode>("WHERE EpisodeFileId = @0", episodeFileId));
} }
public virtual void RefreshEpisodeInfo(Series series) public virtual void RefreshEpisodeInfo(Series series)
@ -219,5 +220,24 @@ namespace NzbDrone.Core.Providers
} }
public IList<Episode> AttachSeries(IList<Episode> episodes)
{
if (episodes.Count == 0) return episodes;
if (episodes.Select(c => c.SeriesId).Distinct().Count() > 1)
throw new ArgumentException("Episodes belong to more than one series.");
var series = _seriesProvider.GetSeries(episodes.First().SeriesId);
episodes.ToList().ForEach(c => c.Series = series);
return episodes;
}
public Episode AttachSeries(Episode episode)
{
episode.Series = _seriesProvider.GetSeries(episode.SeriesId);
return episode;
}
} }
} }

@ -71,7 +71,7 @@ namespace NzbDrone.Core.Providers.Jobs
_diskScanJob.Start(notification, currentSeries.SeriesId); _diskScanJob.Start(notification, currentSeries.SeriesId);
var updatedSeries = _seriesProvider.GetSeries(currentSeries.SeriesId); var updatedSeries = _seriesProvider.GetSeries(currentSeries.SeriesId);
AutoIgnoreSeasons(updatedSeries); AutoIgnoreSeasons(updatedSeries.SeriesId);
} }
catch (Exception e) catch (Exception e)
@ -84,20 +84,20 @@ namespace NzbDrone.Core.Providers.Jobs
ScanSeries(notification); ScanSeries(notification);
} }
private void AutoIgnoreSeasons(Series updatedSeries) public void AutoIgnoreSeasons(int seriesId)
{ {
var episodeFiles = _mediaFileProvider.GetSeriesFiles(updatedSeries.SeriesId); var episodeFiles = _mediaFileProvider.GetSeriesFiles(seriesId);
var episodes = _episodeProvider.GetEpisodeBySeries(updatedSeries.SeriesId);
if (episodeFiles.Count() != 0) if (episodeFiles.Count() != 0)
{ {
var seasons = episodes.Select(c => c.SeasonNumber).Distinct(); var seasons = _episodeProvider.GetSeasons(seriesId);
var currentSeasons = seasons.Max(); var currentSeasons = seasons.Max();
foreach (var season in seasons) foreach (var season in seasons)
{ {
if (season != currentSeasons) if (season != currentSeasons && !episodeFiles.Any(e => e.SeasonNumber == season))
{ {
_episodeProvider.SetSeasonIgnore(seriesId, season, true);
} }
} }
} }

@ -49,7 +49,7 @@ namespace NzbDrone.Core.Providers
return new List<EpisodeFile>(); return new List<EpisodeFile>();
} }
var mediaFileList = GetMediaFileList(series.Path); var mediaFileList = GetVideoFiles(series.Path);
var fileList = new List<EpisodeFile>(); var fileList = new List<EpisodeFile>();
foreach (var filePath in mediaFileList) foreach (var filePath in mediaFileList)
@ -137,7 +137,7 @@ namespace NzbDrone.Core.Providers
episodeFile.Quality = parseResult.Quality.QualityType; episodeFile.Quality = parseResult.Quality.QualityType;
episodeFile.Proper = parseResult.Quality.Proper; episodeFile.Proper = parseResult.Quality.Proper;
episodeFile.SeasonNumber = parseResult.SeasonNumber; episodeFile.SeasonNumber = parseResult.SeasonNumber;
var fileId = (int)_database.Insert(episodeFile); var fileId = Convert.ToInt32(_database.Insert(episodeFile));
//This is for logging + updating the episodes that are linked to this EpisodeFile //This is for logging + updating the episodes that are linked to this EpisodeFile
string episodeList = String.Empty; string episodeList = String.Empty;
@ -192,7 +192,7 @@ namespace NzbDrone.Core.Providers
public virtual void Update(EpisodeFile episodeFile) public virtual void Update(EpisodeFile episodeFile)
{ {
_database.Update(episodeFile); _database.Update(episodeFile);
} }
public virtual EpisodeFile GetEpisodeFile(int episodeFileId) public virtual EpisodeFile GetEpisodeFile(int episodeFileId)
{ {
@ -204,7 +204,7 @@ namespace NzbDrone.Core.Providers
return _database.Fetch<EpisodeFile>(); return _database.Fetch<EpisodeFile>();
} }
public virtual List<EpisodeFile> GetSeriesFiles(int seriesId) public virtual IList<EpisodeFile> GetSeriesFiles(int seriesId)
{ {
return _database.Fetch<EpisodeFile>("WHERE seriesId= @0", seriesId); return _database.Fetch<EpisodeFile>("WHERE seriesId= @0", seriesId);
} }
@ -219,7 +219,7 @@ namespace NzbDrone.Core.Providers
return new Tuple<int, int>(avilableEpisodes.Count, episodeTotal.Count); return new Tuple<int, int>(avilableEpisodes.Count, episodeTotal.Count);
} }
private List<string> GetMediaFileList(string path) private List<string> GetVideoFiles(string path)
{ {
Logger.Debug("Scanning '{0}' for episodes", path); Logger.Debug("Scanning '{0}' for episodes", path);
@ -236,7 +236,7 @@ namespace NzbDrone.Core.Providers
var result = new List<EpisodeFile>(); var result = new List<EpisodeFile>();
//Get all the files except those that are considered samples //Get all the files except those that are considered samples
var files = GetMediaFileList(path).Where(f => _diskProvider.GetSize(f) > 40000000 || !f.ToLower().Contains("sample")).ToList(); var files = GetVideoFiles(path).Where(f => _diskProvider.GetSize(f) > 40000000 || !f.ToLower().Contains("sample")).ToList();
foreach (var file in files) foreach (var file in files)
{ {

@ -44,11 +44,9 @@ namespace NzbDrone.Core.Providers
public virtual Series GetSeries(int seriesId) public virtual Series GetSeries(int seriesId)
{ {
var series = _database.SingleOrDefault<Series>("WHERE seriesId= @0", seriesId); var series = _database.Single<Series>("WHERE seriesId= @0", seriesId);
if (series != null) series.QualityProfile = _qualityProvider.Get(series.QualityProfileId);
{
series.QualityProfile = _qualityProvider.Get(series.QualityProfileId);
}
return series; return series;
} }

@ -105,6 +105,13 @@ namespace NzbDrone.Core.Providers
} }
} }
//Remove duplicated episodes
var episodes = result.Episodes.OrderByDescending(e => e.FirstAired).ThenByDescending(e => e.EpisodeName)
.GroupBy(e => e.SeriesId.ToString("000000") + e.SeasonNumber.ToString("000") + e.EpisodeNumber.ToString("000"))
.Select(e => e.First());
result.Episodes = episodes.ToList();
return result; return result;
} }
} }

@ -139,7 +139,7 @@ namespace NzbDrone.Web.Controllers
return new JsonResult { Data = "ok" }; return new JsonResult { Data = "ok" };
} }
catch (Exception ex) catch (Exception)
{ {
return new JsonResult { Data = "failed" }; return new JsonResult { Data = "failed" };
} }

@ -50,7 +50,7 @@ namespace NzbDrone.Web.Controllers
return new SelectList(dirs, dirs.FirstOrDefault()); return new SelectList(dirs, dirs.FirstOrDefault());
} }
} }
catch(Exception ex) catch
{ {
//Swallow the exceptions so proper JSON is returned to the client (Empty results) //Swallow the exceptions so proper JSON is returned to the client (Empty results)
} }

@ -45,10 +45,6 @@
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Castle.Core, Version=2.5.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\MVC3\Microsoft.Web.Infrastructure.dll</HintPath> <HintPath>..\Libraries\MVC3\Microsoft.Web.Infrastructure.dll</HintPath>

@ -91,8 +91,7 @@
Loading...</span> Loading...</span>
</div> </div>
} }
@{var specialSeason = Model.Seasons.Where(s => s == 0).FirstOrDefault();} @if (Model.Seasons.Any(s => s == 0))
@if (specialSeason != null)
{ {
<br /> <br />
@ -127,7 +126,7 @@
.DataBinding( .DataBinding(
d => d =>
d.Ajax().Select("_AjaxSeasonGrid", "Series", d.Ajax().Select("_AjaxSeasonGrid", "Series",
new RouteValueDictionary { { "seriesId", Model.SeriesId }, { "seasonNumber", specialSeason } } new RouteValueDictionary { { "seriesId", Model.SeriesId }, { "seasonNumber", 0 } }
)).Render(); } )).Render(); }
<span class="grid-loader"> <span class="grid-loader">
<img src="@Url.Content("~/Content/Images/Loading.gif")" alt="Loading"/> <img src="@Url.Content("~/Content/Images/Loading.gif")" alt="Loading"/>

Loading…
Cancel
Save