diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
index 70086788a..6a967392b 100644
--- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
+++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
@@ -213,6 +213,7 @@
+
diff --git a/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/ByAirDateFixture.cs b/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/ByAirDateFixture.cs
new file mode 100644
index 000000000..2f6c0cef5
--- /dev/null
+++ b/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/ByAirDateFixture.cs
@@ -0,0 +1,71 @@
+using System;
+using FizzWare.NBuilder;
+using FluentAssertions;
+using NUnit.Framework;
+using NzbDrone.Core.Test.Framework;
+using NzbDrone.Core.Tv;
+
+namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
+{
+ [TestFixture]
+ public class ByAirDateFixture : DbTest
+ {
+ private const int SERIES_ID = 1;
+ private const string AIR_DATE = "2014-04-02";
+
+ private void GivenEpisode(int seasonNumber)
+ {
+ var episode = Builder.CreateNew()
+ .With(e => e.SeriesId = 1)
+ .With(e => e.SeasonNumber = seasonNumber)
+ .With(e => e.AirDate = AIR_DATE)
+ .BuildNew();
+
+ Db.Insert(episode);
+ }
+
+ [Test]
+ public void should_throw_when_multiple_regular_episodes_are_found()
+ {
+ GivenEpisode(1);
+ GivenEpisode(2);
+
+ Assert.Throws(() => Subject.Get(SERIES_ID, AIR_DATE));
+ Assert.Throws(() => Subject.Find(SERIES_ID, AIR_DATE));
+ }
+
+ [Test]
+ public void should_throw_when_get_finds_no_episode()
+ {
+ Assert.Throws(() => Subject.Get(SERIES_ID, AIR_DATE));
+ }
+
+ [Test]
+ public void should_get_episode_when_single_episode_exists_for_air_date()
+ {
+ GivenEpisode(1);
+
+ Subject.Get(SERIES_ID, AIR_DATE).Should().NotBeNull();
+ Subject.Find(SERIES_ID, AIR_DATE).Should().NotBeNull();
+ }
+
+ [Test]
+ public void should_get_episode_when_regular_episode_and_special_share_the_same_air_date()
+ {
+ GivenEpisode(1);
+ GivenEpisode(0);
+
+ Subject.Get(SERIES_ID, AIR_DATE).Should().NotBeNull();
+ Subject.Find(SERIES_ID, AIR_DATE).Should().NotBeNull();
+ }
+
+ [Test]
+ public void should_get_special_when_its_the_only_episode_for_the_date_provided()
+ {
+ GivenEpisode(0);
+
+ Subject.Get(SERIES_ID, AIR_DATE).Should().NotBeNull();
+ Subject.Find(SERIES_ID, AIR_DATE).Should().NotBeNull();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Tv/EpisodeRepository.cs b/src/NzbDrone.Core/Tv/EpisodeRepository.cs
index ed750848f..2a6a1792e 100644
--- a/src/NzbDrone.Core/Tv/EpisodeRepository.cs
+++ b/src/NzbDrone.Core/Tv/EpisodeRepository.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using Marr.Data.QGen;
+using NLog;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Extentions;
using NzbDrone.Core.Messaging.Events;
@@ -14,8 +16,8 @@ namespace NzbDrone.Core.Tv
{
Episode Find(int seriesId, int season, int episodeNumber);
Episode Find(int seriesId, int absoluteEpisodeNumber);
- Episode Get(int seriesId, String date);
- Episode Find(int seriesId, String date);
+ Episode Get(int seriesId, string date);
+ Episode Find(int seriesId, string date);
List GetEpisodes(int seriesId);
List GetEpisodes(int seriesId, int seasonNumber);
List GetEpisodeByFileId(int fileId);
@@ -32,11 +34,13 @@ namespace NzbDrone.Core.Tv
public class EpisodeRepository : BasicRepository, IEpisodeRepository
{
private readonly IDatabase _database;
+ private readonly Logger _logger;
- public EpisodeRepository(IDatabase database, IEventAggregator eventAggregator)
+ public EpisodeRepository(IDatabase database, IEventAggregator eventAggregator, Logger logger)
: base(database, eventAggregator)
{
_database = database;
+ _logger = logger;
}
public Episode Find(int seriesId, int season, int episodeNumber)
@@ -54,18 +58,21 @@ namespace NzbDrone.Core.Tv
.SingleOrDefault();
}
- public Episode Get(int seriesId, String date)
+ public Episode Get(int seriesId, string date)
{
- return Query.Where(s => s.SeriesId == seriesId)
- .AndWhere(s => s.AirDate == date)
- .Single();
+ var episode = FindOneByAirDate(seriesId, date);
+
+ if (episode == null)
+ {
+ throw new InvalidOperationException("Expected at one episode");
+ }
+
+ return episode;
}
- public Episode Find(int seriesId, String date)
+ public Episode Find(int seriesId, string date)
{
- return Query.Where(s => s.SeriesId == seriesId)
- .AndWhere(s => s.AirDate == date)
- .SingleOrDefault();
+ return FindOneByAirDate(seriesId, date);
}
public List GetEpisodes(int seriesId)
@@ -207,5 +214,28 @@ namespace NzbDrone.Core.Tv
return String.Format("({0})", String.Join(" OR ", clauses));
}
+
+ private Episode FindOneByAirDate(int seriesId, string date)
+ {
+ var episodes = Query.Where(s => s.SeriesId == seriesId)
+ .AndWhere(s => s.AirDate == date)
+ .ToList();
+
+ if (!episodes.Any()) return null;
+
+ if (episodes.Count == 1) return episodes.First();
+
+ _logger.Debug("Multiple episodes with the same air date were found, will exclude specials");
+
+ var regularEpisodes = episodes.Where(e => e.SeasonNumber > 0).ToList();
+
+ if (regularEpisodes.Count == 1)
+ {
+ _logger.Debug("Left with one episode after excluding specials");
+ return regularEpisodes.First();
+ }
+
+ throw new InvalidOperationException("Multiple episodes with the same air date found");
+ }
}
}