1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-11-26 04:33:01 +01:00

SeriesProvider is now Subsonic free.

This commit is contained in:
kay.one 2011-06-15 23:33:01 -07:00
parent 63f6899894
commit cb8cb1691f
10 changed files with 195 additions and 140 deletions

View File

@ -13,6 +13,7 @@ using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using PetaPoco;
using SubSonic.Repository; using SubSonic.Repository;
using TvdbLib.Data; using TvdbLib.Data;
@ -22,6 +23,29 @@ namespace NzbDrone.Core.Test
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class EpisodeProviderTest : TestBase public class EpisodeProviderTest : TestBase
{ {
[Test]
public void GetEpisodesBySeason_success()
{
var episodes = Builder<Episode>.CreateListOfSize(10)
.WhereAll().Have(c => c.SeriesId = 12)
.WhereTheFirst(5).Have(c => c.SeasonNumber = 1)
.AndTheRemaining().Have(c => c.SeasonNumber = 2).Build();
var db = MockLib.GetEmptyDatabase();
var mocker = new AutoMoqer();
mocker.SetConstant(db);
episodes.ToList().ForEach(c => db.Insert(c));
//Act
var seasonEposodes = mocker.Resolve<EpisodeProvider>().GetEpisodesBySeason(12, 2);
//Assert
db.Fetch<Episode>().Should().HaveCount(10);
seasonEposodes.Should().HaveCount(5);
}
[Test] [Test]
public void RefreshEpisodeInfo_emptyRepo() public void RefreshEpisodeInfo_emptyRepo()
{ {
@ -42,7 +66,7 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.SetConstant(MockLib.GetEmptyRepository()); mocker.SetConstant(MockLib.GetEmptyDatabase());
mocker.GetMock<TvDbProvider>() mocker.GetMock<TvDbProvider>()
.Setup(c => c.GetSeries(seriesId, true)) .Setup(c => c.GetSeries(seriesId, true))
@ -61,65 +85,72 @@ namespace NzbDrone.Core.Test
[Test] [Test]
public void new_episodes_only_calls_AddMany() public void new_episodes_only_calls_Insert()
{ {
const int seriesId = 71663; const int seriesId = 71663;
var fakeEpisodes = Builder<TvdbSeries>.CreateNew() var tvdbSeries = Builder<TvdbSeries>.CreateNew()
.With(c => c.Episodes = new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(5).Build()) .With(c => c.Episodes = new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(5).Build())
).With(c => c.Id = seriesId).Build(); ).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build(); var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build();
var currentEpisodes = new List<Episode>();
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.GetMock<TvDbProvider>(MockBehavior.Strict) mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true)) .Setup(c => c.GetSeries(seriesId, true))
.Returns(fakeEpisodes); .Returns(tvdbSeries);
mocker.GetMock<IDatabase>()
.Setup(d => d.Fetch<Episode>(It.IsAny<String>(), It.IsAny<Object[]>()))
.Returns(currentEpisodes);
//Act //Act
mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries); mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries);
//Assert //Assert
mocker.GetMock<IRepository>().Verify( mocker.GetMock<IDatabase>().Verify(c => c.Insert(It.IsAny<Object>()), Times.Exactly(tvdbSeries.Episodes.Count));
c => c.AddMany(It.Is<IEnumerable<Episode>>(e => e.Count() == fakeEpisodes.Episodes.Count)), Times.Once()); mocker.GetMock<IDatabase>().Verify(c => c.Update(It.IsAny<Object>()), Times.Never());
mocker.GetMock<IRepository>().Verify(c => c.UpdateMany(It.Is<IEnumerable<Episode>>(e => e.Count() == 0)),
Times.AtMostOnce());
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
} }
[Test] [Test]
public void existing_episodes_only_calls_UpdateMany() public void existing_episodes_only_calls_Update()
{ {
const int seriesId = 71663; const int seriesId = 71663;
var fakeEpisodes = Builder<TvdbSeries>.CreateNew() var tvdbSeries = Builder<TvdbSeries>.CreateNew()
.With(c => c.Episodes = new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(5).Build()) .With(c => c.Episodes = new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(5).Build())
).With(c => c.Id = seriesId).Build(); ).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build(); var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build();
var currentEpisodes = new List<Episode>();
foreach (var tvDbEpisode in tvdbSeries.Episodes)
{
currentEpisodes.Add(new Episode { TvDbEpisodeId = tvDbEpisode.Id });
}
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.GetMock<TvDbProvider>(MockBehavior.Strict) mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true)) .Setup(c => c.GetSeries(seriesId, true))
.Returns(fakeEpisodes); .Returns(tvdbSeries);
mocker.GetMock<IRepository>() mocker.GetMock<IDatabase>()
.Setup(c => c.Single(It.IsAny<Expression<Func<Episode, bool>>>())) .Setup(d => d.Fetch<Episode>(It.IsAny<String>(), It.IsAny<Object[]>()))
.Returns(Builder<Episode>.CreateNew().Build); .Returns(currentEpisodes);
//Act //Act
mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries); mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries);
//Assert //Assert
mocker.GetMock<IRepository>().Verify(c => c.AddMany(It.Is<IEnumerable<Episode>>(e => e.Count() == 0)), mocker.GetMock<IDatabase>().Verify(c => c.Insert(It.IsAny<Object>()), Times.Never());
Times.AtMostOnce()); mocker.GetMock<IDatabase>().Verify(c => c.Update(It.IsAny<Object>()), Times.Exactly(tvdbSeries.Episodes.Count));
mocker.GetMock<IRepository>().Verify(
c => c.UpdateMany(It.Is<IEnumerable<Episode>>(e => e.Count() == fakeEpisodes.Episodes.Count)),
Times.Once());
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
} }
@ -128,7 +159,7 @@ namespace NzbDrone.Core.Test
public void should_try_to_get_existing_episode_using_tvdbid_first() public void should_try_to_get_existing_episode_using_tvdbid_first()
{ {
const int seriesId = 71663; const int seriesId = 71663;
var fakeEpisodes = Builder<TvdbSeries>.CreateNew() var fakeTvDbResult = Builder<TvdbSeries>.CreateNew()
.With(c => c.Id = seriesId) .With(c => c.Id = seriesId)
.With(c => c.Episodes = new List<TvdbEpisode>( .With(c => c.Episodes = new List<TvdbEpisode>(
Builder<TvdbEpisode>.CreateListOfSize(1) Builder<TvdbEpisode>.CreateListOfSize(1)
@ -137,33 +168,31 @@ namespace NzbDrone.Core.Test
) )
.Build(); .Build();
var fakeEpisodeList = new List<Episode> { new Episode { TvDbEpisodeId = 99, SeasonNumber = 10, EpisodeNumber = 10 } };
var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build(); var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build();
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.GetMock<IDatabase>()
.Setup(d => d.Fetch<Episode>(It.IsAny<String>(), It.IsAny<Object[]>()))
.Returns(fakeEpisodeList);
var repo = MockLib.GetEmptyRepository(); mocker.GetMock<TvDbProvider>()
repo.Add<Episode>(
Builder<Episode>.CreateNew().With(c => c.TvDbEpisodeId = fakeEpisodes.Episodes[0].Id).Build());
mocker.SetConstant(repo);
mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true)) .Setup(c => c.GetSeries(seriesId, true))
.Returns(fakeEpisodes); .Returns(fakeTvDbResult);
//Act //Act
mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries); mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries);
//Assert //Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
repo.All<Episode>().Should().HaveCount(1); mocker.GetMock<IDatabase>().Verify(c => c.Update(fakeEpisodeList[0]), Times.Once());
} }
[Test] [Test]
public void should_try_to_get_existing_episode_using_tvdbid_first_then_season_episode() public void should_try_to_get_existing_episode_using_tvdbid_first_then_season_episode()
{ {
const int seriesId = 71663; const int seriesId = 71663;
var fakeEpisodes = Builder<TvdbSeries>.CreateNew() var tvdbSeries = Builder<TvdbSeries>.CreateNew()
.With(c => c.Id = seriesId) .With(c => c.Id = seriesId)
.With(c => c.Episodes = new List<TvdbEpisode>{ .With(c => c.Episodes = new List<TvdbEpisode>{
Builder<TvdbEpisode>.CreateNew() Builder<TvdbEpisode>.CreateNew()
@ -187,20 +216,20 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
var repo = MockLib.GetEmptyRepository();
repo.Add<Episode>(localEpisode);
mocker.SetConstant(repo);
mocker.GetMock<TvDbProvider>(MockBehavior.Strict) mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true)) .Setup(c => c.GetSeries(seriesId, true))
.Returns(fakeEpisodes); .Returns(tvdbSeries);
mocker.GetMock<IDatabase>()
.Setup(d => d.Fetch<Episode>(It.IsAny<String>(), It.IsAny<Object[]>()))
.Returns(new List<Episode> { localEpisode });
//Act //Act
mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries); mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries);
//Assert //Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
repo.All<Episode>().Should().HaveCount(1); mocker.GetMock<IDatabase>().Verify(c => c.Update(localEpisode), Times.Once());
} }
@ -208,51 +237,43 @@ namespace NzbDrone.Core.Test
public void existing_episodes_keep_their_episodeId_file_id() public void existing_episodes_keep_their_episodeId_file_id()
{ {
const int seriesId = 71663; const int seriesId = 71663;
var faketvDbResponse = Builder<TvdbSeries>.CreateNew() var tvdbSeries = Builder<TvdbSeries>.CreateNew()
.With(c => c.Episodes = new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(5).Build()) .With(c => c.Episodes = new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(5).Build())
).With(c => c.Id = seriesId).Build(); ).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build(); var fakeSeries = Builder<Series>.CreateNew().With(c => c.SeriesId = seriesId).Build();
var fakeEpisode =
Builder<Episode>.CreateNew().With(c => c.EpisodeFileId = 69).And(c => c.EpisodeId = 99).Build(); var currentEpisodes = new List<Episode>();
foreach (var tvDbEpisode in tvdbSeries.Episodes)
{
currentEpisodes.Add(new Episode { TvDbEpisodeId = tvDbEpisode.Id, EpisodeId = 99, EpisodeFileId = 69, Ignored = true });
}
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.GetMock<TvDbProvider>(MockBehavior.Strict) mocker.GetMock<TvDbProvider>(MockBehavior.Strict)
.Setup(c => c.GetSeries(seriesId, true)) .Setup(c => c.GetSeries(seriesId, true))
.Returns(faketvDbResponse); .Returns(tvdbSeries);
IEnumerable<Episode> updatedEpisodes = null; var updatedEpisodes = new List<Episode>();
mocker.GetMock<IRepository>() mocker.GetMock<IDatabase>()
.Setup(c => c.Single(It.IsAny<Expression<Func<Episode, bool>>>())) .Setup(d => d.Fetch<Episode>(It.IsAny<String>(), It.IsAny<Object[]>()))
.Returns(fakeEpisode); .Returns(currentEpisodes);
mocker.GetMock<IRepository>() mocker.GetMock<IDatabase>()
.Setup(c => c.UpdateMany(It.IsAny<IEnumerable<Episode>>())) .Setup(c => c.Update(It.IsAny<Episode>()))
.Returns(faketvDbResponse.Episodes.Count) .Returns(1)
.Callback<IEnumerable<Episode>>(r => updatedEpisodes = r); .Callback<Episode>(ep => updatedEpisodes.Add(ep));
//Act //Act
mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries); mocker.Resolve<EpisodeProvider>().RefreshEpisodeInfo(fakeSeries);
//Assert //Assert
mocker.GetMock<IRepository>().Verify(c => c.AddMany(It.Is<IEnumerable<Episode>>(e => e.Count() == 0)), updatedEpisodes.Should().HaveSameCount(tvdbSeries.Episodes);
Times.AtMostOnce());
mocker.GetMock<IRepository>().Verify(
c => c.UpdateMany(It.Is<IEnumerable<Episode>>(e => e.Count() == faketvDbResponse.Episodes.Count)),
Times.Once());
mocker.GetMock<IRepository>().Verify(
c =>
c.UpdateMany(
It.Is<IEnumerable<Episode>>(
e => e.Where(g => g.EpisodeFileId == 69).Count() == faketvDbResponse.Episodes.Count)),
Times.Once());
updatedEpisodes.Should().HaveSameCount(faketvDbResponse.Episodes);
updatedEpisodes.Should().OnlyContain(c => c.EpisodeId == 99); updatedEpisodes.Should().OnlyContain(c => c.EpisodeId == 99);
updatedEpisodes.Should().OnlyContain(c => c.EpisodeFileId == 69); updatedEpisodes.Should().OnlyContain(c => c.EpisodeFileId == 69);
updatedEpisodes.Should().OnlyContain(c => c.Ignored == true);
} }
@ -347,7 +368,7 @@ namespace NzbDrone.Core.Test
public void Add_daily_show_episodes() public void Add_daily_show_episodes()
{ {
var mocker = new AutoMoqer(); var mocker = new AutoMoqer();
mocker.SetConstant(MockLib.GetEmptyRepository()); mocker.SetConstant(MockLib.GetEmptyDatabase());
mocker.Resolve<TvDbProvider>(); mocker.Resolve<TvDbProvider>();
const int tvDbSeriesId = 71256; const int tvDbSeriesId = 71256;
//act //act

View File

@ -14,6 +14,7 @@ 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;
@ -90,7 +91,7 @@ namespace NzbDrone.Core.Test
[Test] [Test]
public void get_episode_by_series_seasons_episode_x5000() public void get_episode_by_series_seasons_episode_x5000()
{ {
var epProvider = new EpisodeProvider(repo, null); var epProvider = new EpisodeProvider(null, null);
Thread.Sleep(1000); Thread.Sleep(1000);
@ -114,7 +115,7 @@ 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(repo, null); var epProvider = new EpisodeProvider( null, null);
Thread.Sleep(1000); Thread.Sleep(1000);

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Web.Hosting; using System.Web.Hosting;
@ -9,14 +8,10 @@ using NLog;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Providers.ExternalNotification; using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Providers.Indexer; using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Jobs; using NzbDrone.Core.Providers.Jobs;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using PetaPoco; using PetaPoco;
using SubSonic.DataProviders;
using SubSonic.Repository; using SubSonic.Repository;
namespace NzbDrone.Core namespace NzbDrone.Core
@ -73,30 +68,8 @@ namespace NzbDrone.Core
Logger.Debug("Binding Ninject's Kernel"); Logger.Debug("Binding Ninject's Kernel");
_kernel = new StandardKernel(); _kernel = new StandardKernel();
//dbProvider.Log = new NlogWriter(); _kernel.Bind<IDatabase>().ToMethod(c => Connection.GetPetaPocoDb(Connection.MainConnectionString)).InRequestScope();
_kernel.Bind<QualityProvider>().ToSelf().InSingletonScope();
_kernel.Bind<TvDbProvider>().ToSelf().InTransientScope();
_kernel.Bind<HttpProvider>().ToSelf().InSingletonScope();
_kernel.Bind<SeriesProvider>().ToSelf().InSingletonScope();
_kernel.Bind<EpisodeProvider>().ToSelf().InSingletonScope();
_kernel.Bind<UpcomingEpisodesProvider>().ToSelf().InSingletonScope();
_kernel.Bind<DiskProvider>().ToSelf().InSingletonScope();
_kernel.Bind<SabProvider>().ToSelf().InSingletonScope();
_kernel.Bind<HistoryProvider>().ToSelf().InSingletonScope();
_kernel.Bind<RootDirProvider>().ToSelf().InSingletonScope();
_kernel.Bind<ExternalNotificationProvider>().ToSelf().InSingletonScope();
_kernel.Bind<XbmcProvider>().ToSelf().InSingletonScope();
_kernel.Bind<ConfigProvider>().To<ConfigProvider>().InSingletonScope();
_kernel.Bind<NotificationProvider>().ToSelf().InSingletonScope();
_kernel.Bind<LogProvider>().ToSelf().InSingletonScope();
_kernel.Bind<MediaFileProvider>().ToSelf().InSingletonScope();
_kernel.Bind<JobProvider>().ToSelf().InSingletonScope();
_kernel.Bind<IndexerProvider>().ToSelf().InSingletonScope();
_kernel.Bind<WebTimer>().ToSelf().InSingletonScope();
_kernel.Bind<AutoConfigureProvider>().ToSelf().InSingletonScope();
_kernel.Bind<IRepository>().ToConstant(Connection.CreateSimpleRepository(Connection.MainConnectionString)).InSingletonScope(); _kernel.Bind<IRepository>().ToConstant(Connection.CreateSimpleRepository(Connection.MainConnectionString)).InSingletonScope();
_kernel.Bind<IDatabase>().ToConstant(Connection.GetPetaPocoDb(Connection.MainConnectionString)).InRequestScope();
_kernel.Bind<IRepository>().ToConstant(Connection.CreateSimpleRepository(Connection.LogConnectionString)).WhenInjectedInto<SubsonicTarget>().InSingletonScope(); _kernel.Bind<IRepository>().ToConstant(Connection.CreateSimpleRepository(Connection.LogConnectionString)).WhenInjectedInto<SubsonicTarget>().InSingletonScope();
_kernel.Bind<IRepository>().ToConstant(Connection.CreateSimpleRepository(Connection.LogConnectionString)).WhenInjectedInto<LogProvider>().InSingletonScope(); _kernel.Bind<IRepository>().ToConstant(Connection.CreateSimpleRepository(Connection.LogConnectionString)).WhenInjectedInto<LogProvider>().InSingletonScope();
} }
@ -104,10 +77,10 @@ namespace NzbDrone.Core
private static void BindIndexers() private static void BindIndexers()
{ {
_kernel.Bind<IndexerBase>().To<NzbsOrg>().InSingletonScope(); _kernel.Bind<IndexerBase>().To<NzbsOrg>().InTransientScope();
_kernel.Bind<IndexerBase>().To<NzbMatrix>().InSingletonScope(); _kernel.Bind<IndexerBase>().To<NzbMatrix>().InTransientScope();
_kernel.Bind<IndexerBase>().To<NzbsRUs>().InSingletonScope(); _kernel.Bind<IndexerBase>().To<NzbsRUs>().InTransientScope();
_kernel.Bind<IndexerBase>().To<Newzbin>().InSingletonScope(); _kernel.Bind<IndexerBase>().To<Newzbin>().InTransientScope();
var indexers = _kernel.GetAll<IndexerBase>(); var indexers = _kernel.GetAll<IndexerBase>();
_kernel.Get<IndexerProvider>().InitializeIndexers(indexers.ToList()); _kernel.Get<IndexerProvider>().InitializeIndexers(indexers.ToList());

View File

@ -11,7 +11,8 @@ namespace NzbDrone.Core.Datastore
if ((SourceType == typeof(Int32) || SourceType == typeof(Int64)) && destinationInfo.Type.IsGenericType && destinationInfo.Type.GetGenericTypeDefinition() == typeof(Nullable<>)) if ((SourceType == typeof(Int32) || SourceType == typeof(Int64)) && destinationInfo.Type.IsGenericType && destinationInfo.Type.GetGenericTypeDefinition() == typeof(Nullable<>))
{ {
// If it is NULLABLE, then get the underlying type. eg if "Nullable<int>" then this will return just "int" // If it is NULLABLE, then get the underlying type. eg if "Nullable<int>" then this will return just "int"
if (destinationInfo.Type.GetGenericArguments()[0].IsEnum) Type genericArgument = destinationInfo.Type.GetGenericArguments()[0];
if (genericArgument == typeof(DayOfWeek))
{ {
return delegate(object s) return delegate(object s)
{ {
@ -25,6 +26,20 @@ namespace NzbDrone.Core.Datastore
return (Nullable<DayOfWeek>)value; return (Nullable<DayOfWeek>)value;
}; };
} }
else
{
return delegate(object s)
{
int value;
Int32.TryParse(s.ToString(), out value);
if (value == 0)
{
return null;
}
return value;
};
}
} }
return base.GetFromDbConverter(destinationInfo, SourceType); return base.GetFromDbConverter(destinationInfo, SourceType);

View File

@ -27,6 +27,25 @@ namespace NzbDrone.Core.Datastore.Migrations
.WithNotNullableColumn("SeasonFolder", DbType.Boolean) .WithNotNullableColumn("SeasonFolder", DbType.Boolean)
.WithNullableColumn("LastInfoSync", DbType.DateTime) .WithNullableColumn("LastInfoSync", DbType.DateTime)
.WithNullableColumn("LastDiskSync", DbType.DateTime); .WithNullableColumn("LastDiskSync", DbType.DateTime);
db.CreateTable("Episodes")
.WithPrimaryKeyColumn("EpisodeId", DbType.Int32).AsIdentity()
.WithNullableColumn("TvDbEpisodeId", DbType.Int32)
.WithNotNullableColumn("SeriesId", DbType.Int32)
.WithNotNullableColumn("SeasonNumber", DbType.Int16)
.WithNotNullableColumn("EpisodeNumber", DbType.Int16)
.WithNotNullableColumn("Title", DbType.String).HavingDefault(String.Empty)
.WithNotNullableColumn("Overview", DbType.String).HavingDefault(String.Empty)
.WithNotNullableColumn("Ignored", DbType.Boolean).HavingDefault(false)
.WithNullableColumn("EpisodeFileId", DbType.Int32)
.WithNullableColumn("AirDate", DbType.DateTime)
.WithNullableColumn("GrabDate", DbType.DateTime);
} }
} }
} }

View File

@ -26,7 +26,6 @@ using System.Linq.Expressions;
// ReSharper disable // ReSharper disable
namespace PetaPoco namespace PetaPoco
{ {
// Poco's marked [Explicit] require all column properties to be marked // Poco's marked [Explicit] require all column properties to be marked
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
@ -354,12 +353,16 @@ namespace PetaPoco
{ {
_sharedConnection = _factory.CreateConnection(); _sharedConnection = _factory.CreateConnection();
_sharedConnection.ConnectionString = _connectionString; _sharedConnection.ConnectionString = _connectionString;
_sharedConnection.Open();
if (KeepConnectionAlive) if (KeepConnectionAlive)
_sharedConnectionDepth++; // Make sure you call Dispose _sharedConnectionDepth++; // Make sure you call Dispose
} }
if (_sharedConnection.State != ConnectionState.Open)
_sharedConnection.Open();
_sharedConnectionDepth++; _sharedConnectionDepth++;
} }
// Close a previously opened connection // Close a previously opened connection
@ -860,9 +863,6 @@ namespace PetaPoco
var pd = PocoData.ForType(typeof(T)); var pd = PocoData.ForType(typeof(T));
try try
{ {
if (_sharedConnection.State != ConnectionState.Open)
_sharedConnection.Open();
r = cmd.ExecuteReader(); r = cmd.ExecuteReader();
OnExecutedCommand(cmd); OnExecutedCommand(cmd);
} }
@ -1297,9 +1297,7 @@ namespace PetaPoco
{ {
using (var cmd = CreateCommand(_sharedConnection, "")) using (var cmd = CreateCommand(_sharedConnection, ""))
{ {
if(_sharedConnection.State != ConnectionState.Open)
_sharedConnection.Open();
var pd = PocoData.ForObject(poco, primaryKeyName); var pd = PocoData.ForObject(poco, primaryKeyName);
var names = new List<string>(); var names = new List<string>();
var values = new List<string>(); var values = new List<string>();

View File

@ -185,7 +185,7 @@
<Compile Include="Instrumentation\SubsonicTarget.cs" /> <Compile Include="Instrumentation\SubsonicTarget.cs" />
<Compile Include="Instrumentation\ExceptioneerTarget.cs" /> <Compile Include="Instrumentation\ExceptioneerTarget.cs" />
<Compile Include="Instrumentation\NlogWriter.cs" /> <Compile Include="Instrumentation\NlogWriter.cs" />
<Compile Include="Models\PetaPoco.cs" /> <Compile Include="Datastore\PetaPoco\PetaPoco.cs" />
<Compile Include="Model\ConnectionInfoModel.cs" /> <Compile Include="Model\ConnectionInfoModel.cs" />
<Compile Include="Model\ExternalNotificationType.cs" /> <Compile Include="Model\ExternalNotificationType.cs" />
<Compile Include="Model\LanguageType.cs" /> <Compile Include="Model\LanguageType.cs" />
@ -306,6 +306,9 @@
<ItemGroup> <ItemGroup>
<WCFMetadata Include="Service References\" /> <WCFMetadata Include="Service References\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -14,14 +14,12 @@ namespace NzbDrone.Core.Providers
public class EpisodeProvider public class EpisodeProvider
{ {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IRepository _repository;
private readonly TvDbProvider _tvDbProvider; private readonly TvDbProvider _tvDbProvider;
private readonly IDatabase _database; private readonly IDatabase _database;
[Inject] [Inject]
public EpisodeProvider(IRepository repository, TvDbProvider tvDbProviderProvider, IDatabase database) public EpisodeProvider(TvDbProvider tvDbProviderProvider, IDatabase database)
{ {
_repository = repository;
_tvDbProvider = tvDbProviderProvider; _tvDbProvider = tvDbProviderProvider;
_database = database; _database = database;
} }
@ -32,36 +30,32 @@ namespace NzbDrone.Core.Providers
public virtual void AddEpisode(Episode episode) public virtual void AddEpisode(Episode episode)
{ {
_repository.Add(episode); _database.Insert(episode);
} }
public virtual Episode GetEpisode(long id) public virtual Episode GetEpisode(long id)
{ {
return _repository.Single<Episode>(id); return _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 return _database.Single<Episode>("WHERE SeriesId = @0 AND SeasonNumber = @2 AND EpisodeNumber = @3", seriesId, seasonNumber, episodeNumber);
_repository.Single<Episode>(
c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber && c.EpisodeNumber == episodeNumber);
} }
public virtual Episode GetEpisode(int seriesId, DateTime date) public virtual Episode GetEpisode(int seriesId, DateTime date)
{ {
return return _database.Single<Episode>("WHERE SeriesId = @0 AND AirDate = @2", seriesId, date.Date);
_repository.Single<Episode>(
c => c.SeriesId == seriesId && c.AirDate == date.Date);
} }
public virtual IEnumerable<Episode> GetEpisodeBySeries(long seriesId) public virtual IList<Episode> GetEpisodeBySeries(long seriesId)
{ {
return _database.Query<Episode>("WHERE SeriesId = @0", seriesId); return _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 _repository.Find<Episode>(e => e.SeriesId == seriesId && e.SeasonNumber == seasonNumber); return _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)
@ -89,15 +83,17 @@ namespace NzbDrone.Core.Providers
public virtual IList<Episode> EpisodesWithoutFiles(bool includeSpecials) public virtual IList<Episode> EpisodesWithoutFiles(bool includeSpecials)
{ {
var episodes = _database.Query<Episode>("WHERE (EpisodeFileId=0 OR EpisodeFileId=NULL) AND AirDate<=@0",
DateTime.Now.Date);
if (includeSpecials) if (includeSpecials)
return _repository.All<Episode>().Where(e => e.EpisodeFileId == 0 && e.AirDate <= DateTime.Today && e.AirDate > new DateTime(1899, 12, 31)).ToList(); return episodes.Where(e => e.SeasonNumber > 0).ToList();
return _repository.All<Episode>().Where(e => e.EpisodeFileId == 0 && e.AirDate <= DateTime.Today && e.AirDate > new DateTime(1899, 12, 31) && e.SeasonNumber > 0).ToList(); return episodes.ToList();
} }
public virtual IList<Episode> EpisodesByFileId(int episodeFileId) public virtual IList<Episode> EpisodesByFileId(int episodeFileId)
{ {
return _repository.All<Episode>().Where(e => e.EpisodeFileId == episodeFileId).ToList(); return _database.Fetch<Episode>("WHERE EpisodeFileId = @0", episodeFileId);
} }
public virtual void RefreshEpisodeInfo(Series series) public virtual void RefreshEpisodeInfo(Series series)
@ -107,6 +103,7 @@ namespace NzbDrone.Core.Providers
int failCount = 0; int failCount = 0;
var tvDbSeriesInfo = _tvDbProvider.GetSeries(series.SeriesId, true); var tvDbSeriesInfo = _tvDbProvider.GetSeries(series.SeriesId, true);
var seriesEpisodes = GetEpisodeBySeries(series.SeriesId);
var updateList = new List<Episode>(); var updateList = new List<Episode>();
var newList = new List<Episode>(); var newList = new List<Episode>();
@ -124,12 +121,12 @@ namespace NzbDrone.Core.Providers
Logger.Trace("Updating info for [{0}] - S{1}E{2}", tvDbSeriesInfo.SeriesName, episode.SeasonNumber, episode.EpisodeNumber); Logger.Trace("Updating info for [{0}] - S{1}E{2}", tvDbSeriesInfo.SeriesName, episode.SeasonNumber, episode.EpisodeNumber);
//first check using tvdbId, this should cover cases when and episode number in a season is changed //first check using tvdbId, this should cover cases when and episode number in a season is changed
var episodeToUpdate = _repository.Single<Episode>(c => c.TvDbEpisodeId == episode.Id); var episodeToUpdate = seriesEpisodes.Where(e => e.TvDbEpisodeId == episode.Id).FirstOrDefault();
//not found, try using season/episode number //not found, try using season/episode number
if (episodeToUpdate == null) if (episodeToUpdate == null)
{ {
episodeToUpdate = GetEpisode(series.SeriesId, episode.SeasonNumber, episode.EpisodeNumber); episodeToUpdate = seriesEpisodes.Where(e => e.SeasonNumber == episode.SeasonNumber && e.EpisodeNumber == episode.EpisodeNumber).FirstOrDefault();
} }
//Episode doesn't exist locally //Episode doesn't exist locally
@ -161,31 +158,45 @@ namespace NzbDrone.Core.Providers
} }
} }
_repository.AddMany(newList); using (var tran = _database.GetTransaction())
_repository.UpdateMany(updateList); {
newList.ForEach(episode => _database.Insert(episode));
updateList.ForEach(episode => _database.Update(episode));
#if DEBUG
//Shouldn't run if Database is a mock since transaction will be null
if (_database.GetType().Namespace != "Castle.Proxies" && tran != null)
{
tran.Complete();
}
#else
tran.Complete();
#endif
}
Logger.Debug("Finished episode refresh for series:{0}. Successful:{1} - Failed:{2} ", Logger.Debug("Finished episode refresh for series:{0}. Successful:{1} - Failed:{2} ",
tvDbSeriesInfo.SeriesName, successCount, failCount); tvDbSeriesInfo.SeriesName, successCount, failCount);
} }
public virtual void DeleteEpisode(int episodeId)
{
_repository.Delete<Episode>(episodeId);
}
public virtual void UpdateEpisode(Episode episode) public virtual void UpdateEpisode(Episode episode)
{ {
_repository.Update(episode); _database.Update(episode);
} }
public virtual bool IsIgnored(int seriesId, int seasonNumber) public virtual bool IsIgnored(int seriesId, int seasonNumber)
{ {
return !_repository.Exists<Episode>(e => e.SeriesId == seriesId && e.SeasonNumber == seasonNumber && !e.Ignored);
var unIgnoredCount = _database.ExecuteScalar<int>(
"SELECT COUNT (*) FROM Episodes WHERE SeriesId=@0 AND SeasonNumber=@1 AND Ignored=False");
return unIgnoredCount != 0;
} }
public virtual IList<int> GetSeasons(int seriesId) public virtual IList<int> GetSeasons(int seriesId)
{ {
return _repository.All<Episode>().Where(e => e.SeriesId == seriesId).Select(s => s.SeasonNumber).Distinct().OrderBy(c => c).ToList(); return _database.Fetch<Int32>("SELECT DISTINCT SeasonNumber FROM Episodes WHERE SeriesId=@0", seriesId).OrderBy(c => c).ToList();
} }
public virtual void SetSeasonIgnore(long seriesId, int seasonNumber, bool isIgnored) public virtual void SetSeasonIgnore(long seriesId, int seasonNumber, bool isIgnored)
@ -193,14 +204,27 @@ namespace NzbDrone.Core.Providers
Logger.Info("Setting ignore flag on Series:{0} Season:{1} to {2}", seriesId, seasonNumber, isIgnored); Logger.Info("Setting ignore flag on Series:{0} Season:{1} to {2}", seriesId, seasonNumber, isIgnored);
var episodes = GetEpisodesBySeason(seriesId, seasonNumber); var episodes = GetEpisodesBySeason(seriesId, seasonNumber);
foreach (var episode in episodes) using (var tran = _database.GetTransaction())
{ {
episode.Ignored = isIgnored; foreach (var episode in episodes)
{
episode.Ignored = isIgnored;
_database.Update(episode);
}
#if DEBUG
//Shouldn't run if Database is a mock since transaction will be null
if (_database.GetType().Namespace != "Castle.Proxies" && tran != null)
{
tran.Complete();
}
#else
tran.Complete();
#endif
Logger.Info("Ignore flag for Series:{0} Season:{1} successfully set to {2}", seriesId, seasonNumber, isIgnored);
} }
_repository.UpdateMany(episodes);
Logger.Info("Ignore flag for Series:{0} Season:{1} successfully set to {2}", seriesId, seasonNumber, isIgnored);
} }
} }
} }

View File

@ -7,7 +7,8 @@ using SubSonic.SqlGeneration.Schema;
namespace NzbDrone.Core.Repository namespace NzbDrone.Core.Repository
{ {
[PetaPoco.TableName("Episodes")] [TableName("Episodes")]
[PrimaryKey("EpisodeId", autoIncrement = true)]
public class Episode public class Episode
{ {
[SubSonicPrimaryKey] [SubSonicPrimaryKey]