Using string for airdate instead of DateTime in models to prevent timezone issues

Fixed: Manual search air by date shows can now be sent to download client
This commit is contained in:
Mark McDowall 2013-10-22 22:17:02 -07:00
parent 46bd5d1767
commit 52da5b643d
14 changed files with 79 additions and 40 deletions

View File

@ -18,7 +18,7 @@ namespace NzbDrone.Api.Indexers
public Boolean SceneSource { get; set; } public Boolean SceneSource { get; set; }
public Int32 SeasonNumber { get; set; } public Int32 SeasonNumber { get; set; }
public Language Language { get; set; } public Language Language { get; set; }
public DateTime? AirDate { get; set; } public String AirDate { get; set; }
public String SeriesTitle { get; set; } public String SeriesTitle { get; set; }
public int[] EpisodeNumbers { get; set; } public int[] EpisodeNumbers { get; set; }
public Boolean Approved { get; set; } public Boolean Approved { get; set; }

View File

@ -6,6 +6,7 @@ using NUnit.Framework;
using NzbDrone.Common.Expansive; using NzbDrone.Common.Expansive;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ParserTests namespace NzbDrone.Core.Test.ParserTests
@ -169,7 +170,7 @@ namespace NzbDrone.Core.Test.ParserTests
var airDate = new DateTime(year, month, day); var airDate = new DateTime(year, month, day);
result.Should().NotBeNull(); result.Should().NotBeNull();
result.SeriesTitle.Should().Be(title.CleanSeriesTitle()); result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.AirDate.Should().Be(airDate); result.AirDate.Should().Be(airDate.ToString(Episode.AIR_DATE_FORMAT));
result.EpisodeNumbers.Should().BeNull(); result.EpisodeNumbers.Should().BeNull();
} }

View File

@ -61,7 +61,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
private void GivenDailyParseResult() private void GivenDailyParseResult()
{ {
_parsedEpisodeInfo.AirDate = DateTime.Today; _parsedEpisodeInfo.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT);
} }
private void GivenSceneNumberingSeries() private void GivenSceneNumberingSeries()
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
Subject.Map(_parsedEpisodeInfo, _series.TvRageId); Subject.Map(_parsedEpisodeInfo, _series.TvRageId);
Mocker.GetMock<IEpisodeService>() Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), It.IsAny<DateTime>()), Times.Once()); .Verify(v => v.FindEpisode(It.IsAny<Int32>(), It.IsAny<String>()), Times.Once());
} }
[Test] [Test]
@ -90,19 +90,19 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria); Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>() Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), It.IsAny<DateTime>()), Times.Never()); .Verify(v => v.FindEpisode(It.IsAny<Int32>(), It.IsAny<String>()), Times.Never());
} }
[Test] [Test]
public void should_fallback_to_daily_episode_lookup_when_search_criteria_episode_doesnt_match() public void should_fallback_to_daily_episode_lookup_when_search_criteria_episode_doesnt_match()
{ {
GivenDailySeries(); GivenDailySeries();
_parsedEpisodeInfo.AirDate = DateTime.Today.AddDays(-5); _parsedEpisodeInfo.AirDate = DateTime.Today.AddDays(-5).ToString(Episode.AIR_DATE_FORMAT); ;
Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria); Subject.Map(_parsedEpisodeInfo, _series.TvRageId, _singleEpisodeSearchCriteria);
Mocker.GetMock<IEpisodeService>() Mocker.GetMock<IEpisodeService>()
.Verify(v => v.FindEpisode(It.IsAny<Int32>(), It.IsAny<DateTime>()), Times.Once()); .Verify(v => v.FindEpisode(It.IsAny<Int32>(), It.IsAny<String>()), Times.Once());
} }
[Test] [Test]

View File

@ -34,9 +34,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.Search
if (dailySearchSpec == null) return true; if (dailySearchSpec == null) return true;
var episode = _episodeService.GetEpisode(dailySearchSpec.Series.Id, dailySearchSpec.Airtime); var episode = _episodeService.GetEpisode(dailySearchSpec.Series.Id, dailySearchSpec.AirDate.ToString(Episode.AIR_DATE_FORMAT));
if (!remoteEpisode.ParsedEpisodeInfo.AirDate.HasValue || remoteEpisode.ParsedEpisodeInfo.AirDate.Value.ToString(Episode.AIR_DATE_FORMAT) != episode.AirDate) if (!remoteEpisode.ParsedEpisodeInfo.IsDaily() || remoteEpisode.ParsedEpisodeInfo.AirDate != episode.AirDate)
{ {
_logger.Trace("Episode AirDate does not match searched episode number, skipping."); _logger.Trace("Episode AirDate does not match searched episode number, skipping.");
return false; return false;

View File

@ -4,11 +4,11 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
{ {
public class DailyEpisodeSearchCriteria : SearchCriteriaBase public class DailyEpisodeSearchCriteria : SearchCriteriaBase
{ {
public DateTime Airtime { get; set; } public DateTime AirDate { get; set; }
public override string ToString() public override string ToString()
{ {
return string.Format("[{0} : {1}", SceneTitle, Airtime); return string.Format("[{0} : {1}", SceneTitle, AirDate);
} }
} }
} }

View File

@ -98,7 +98,7 @@ namespace NzbDrone.Core.IndexerSearch
{ {
var airDate = DateTime.ParseExact(episode.AirDate, Episode.AIR_DATE_FORMAT, CultureInfo.InvariantCulture); var airDate = DateTime.ParseExact(episode.AirDate, Episode.AIR_DATE_FORMAT, CultureInfo.InvariantCulture);
var searchSpec = Get<DailyEpisodeSearchCriteria>(series, new List<Episode>{ episode }); var searchSpec = Get<DailyEpisodeSearchCriteria>(series, new List<Episode>{ episode });
searchSpec.Airtime = airDate; searchSpec.AirDate = airDate;
return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec); return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
} }

View File

@ -87,7 +87,7 @@ namespace NzbDrone.Core.Indexers
{ {
_logger.Debug("Searching for {0}", searchCriteria); _logger.Debug("Searching for {0}", searchCriteria);
var searchUrls = indexer.GetDailyEpisodeSearchUrls(searchCriteria.QueryTitle, searchCriteria.Series.TvRageId, searchCriteria.Airtime); var searchUrls = indexer.GetDailyEpisodeSearchUrls(searchCriteria.QueryTitle, searchCriteria.Series.TvRageId, searchCriteria.AirDate);
var result = Fetch(indexer, searchUrls); var result = Fetch(indexer, searchUrls);
_logger.Info("Finished searching {0} for {1}. Found {2}", indexer, searchCriteria, result.Count); _logger.Info("Finished searching {0} for {1}. Found {2}", indexer, searchCriteria, result.Count);

View File

@ -307,6 +307,7 @@
<Compile Include="Notifications\Xbmc\Model\VersionResult.cs" /> <Compile Include="Notifications\Xbmc\Model\VersionResult.cs" />
<Compile Include="Notifications\Xbmc\Model\XbmcJsonResult.cs" /> <Compile Include="Notifications\Xbmc\Model\XbmcJsonResult.cs" />
<Compile Include="Notifications\Xbmc\Model\XbmcVersion.cs" /> <Compile Include="Notifications\Xbmc\Model\XbmcVersion.cs" />
<Compile Include="Parser\InvalidDateException.cs" />
<Compile Include="ProgressMessaging\CommandUpdatedEvent.cs" /> <Compile Include="ProgressMessaging\CommandUpdatedEvent.cs" />
<Compile Include="ProgressMessaging\ProgressMessageTarget.cs" /> <Compile Include="ProgressMessaging\ProgressMessageTarget.cs" />
<Compile Include="Instrumentation\SetLoggingLevel.cs" /> <Compile Include="Instrumentation\SetLoggingLevel.cs" />

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Core.Parser
{
public class InvalidDateException : NzbDroneException
{
public InvalidDateException(string message, params object[] args) : base(message, args)
{
}
public InvalidDateException(string message) : base(message)
{
}
}
}

View File

@ -10,7 +10,7 @@ namespace NzbDrone.Core.Parser.Model
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
public int SeasonNumber { get; set; } public int SeasonNumber { get; set; }
public int[] EpisodeNumbers { get; set; } public int[] EpisodeNumbers { get; set; }
public DateTime? AirDate { get; set; } public String AirDate { get; set; }
public Language Language { get; set; } public Language Language { get; set; }
public bool FullSeason { get; set; } public bool FullSeason { get; set; }
@ -19,9 +19,9 @@ namespace NzbDrone.Core.Parser.Model
{ {
string episodeString = "[Unknown Episode]"; string episodeString = "[Unknown Episode]";
if (AirDate != null && EpisodeNumbers == null) if (IsDaily() && EpisodeNumbers == null)
{ {
episodeString = string.Format("{0}", AirDate.Value.ToString("yyyy-MM-dd")); episodeString = string.Format("{0}", AirDate);
} }
else if (FullSeason) else if (FullSeason)
{ {
@ -34,5 +34,10 @@ namespace NzbDrone.Core.Parser.Model
return string.Format("{0} - {1} {2}", SeriesTitle, episodeString, Quality); return string.Format("{0} - {1} {2}", SeriesTitle, episodeString, Quality);
} }
public bool IsDaily()
{
return !String.IsNullOrWhiteSpace(AirDate);
}
} }
} }

View File

@ -6,6 +6,7 @@ using System.Text.RegularExpressions;
using NLog; using NLog;
using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Parser namespace NzbDrone.Core.Parser
{ {
@ -109,19 +110,23 @@ namespace NzbDrone.Core.Parser
var match = regex.Matches(simpleTitle); var match = regex.Matches(simpleTitle);
if (match.Count != 0) if (match.Count != 0)
{
try
{ {
var result = ParseMatchCollection(match); var result = ParseMatchCollection(match);
if (result != null) if (result != null)
{ {
//Check if episode is in the future (most likely a parse error)
if (result.AirDate > DateTime.Now.AddDays(1).Date || result.AirDate < new DateTime(1970, 1, 1))
break;
result.Language = ParseLanguage(title); result.Language = ParseLanguage(title);
result.Quality = QualityParser.ParseQuality(title); result.Quality = QualityParser.ParseQuality(title);
return result; return result;
} }
} }
catch (InvalidDateException ex)
{
Logger.TraceException(ex.Message, ex);
break;
}
}
} }
} }
catch (Exception e) catch (Exception e)
@ -212,9 +217,17 @@ namespace NzbDrone.Core.Parser
airmonth = tempDay; airmonth = tempDay;
} }
var airDate = new DateTime(airYear, airmonth, airday);
//Check if episode is in the future (most likely a parse error)
if (airDate > DateTime.Now.AddDays(1).Date || airDate < new DateTime(1970, 1, 1))
{
throw new InvalidDateException("Invalid date found: {0}", airDate);
}
result = new ParsedEpisodeInfo result = new ParsedEpisodeInfo
{ {
AirDate = new DateTime(airYear, airmonth, airday).Date, AirDate = airDate.ToString(Episode.AIR_DATE_FORMAT),
}; };
} }

View File

@ -104,7 +104,7 @@ namespace NzbDrone.Core.Parser
{ {
var result = new List<Episode>(); var result = new List<Episode>();
if (parsedEpisodeInfo.AirDate.HasValue) if (parsedEpisodeInfo.IsDaily())
{ {
if (series.SeriesType == SeriesTypes.Standard) if (series.SeriesType == SeriesTypes.Standard)
{ {
@ -112,7 +112,7 @@ namespace NzbDrone.Core.Parser
return null; return null;
} }
var episodeInfo = GetDailyEpisode(series, parsedEpisodeInfo.AirDate.Value, searchCriteria); var episodeInfo = GetDailyEpisode(series, parsedEpisodeInfo.AirDate, searchCriteria);
if (episodeInfo != null) if (episodeInfo != null)
{ {
@ -223,14 +223,14 @@ namespace NzbDrone.Core.Parser
return series; return series;
} }
private Episode GetDailyEpisode(Series series, DateTime airDate, SearchCriteriaBase searchCriteria) private Episode GetDailyEpisode(Series series, String airDate, SearchCriteriaBase searchCriteria)
{ {
Episode episodeInfo = null; Episode episodeInfo = null;
if (searchCriteria != null) if (searchCriteria != null)
{ {
episodeInfo = searchCriteria.Episodes.SingleOrDefault( episodeInfo = searchCriteria.Episodes.SingleOrDefault(
e => e.AirDate == airDate.ToString(Episode.AIR_DATE_FORMAT)); e => e.AirDate == airDate);
} }
if (episodeInfo == null) if (episodeInfo == null)

View File

@ -11,8 +11,8 @@ namespace NzbDrone.Core.Tv
public interface IEpisodeRepository : IBasicRepository<Episode> public interface IEpisodeRepository : IBasicRepository<Episode>
{ {
Episode Find(int seriesId, int season, int episodeNumber); Episode Find(int seriesId, int season, int episodeNumber);
Episode Get(int seriesId, DateTime date); Episode Get(int seriesId, String date);
Episode Find(int seriesId, DateTime date); Episode Find(int seriesId, String date);
List<Episode> GetEpisodes(int seriesId); List<Episode> GetEpisodes(int seriesId);
List<Episode> GetEpisodes(int seriesId, int seasonNumber); List<Episode> GetEpisodes(int seriesId, int seasonNumber);
List<Episode> GetEpisodeByFileId(int fileId); List<Episode> GetEpisodeByFileId(int fileId);
@ -39,14 +39,14 @@ namespace NzbDrone.Core.Tv
return Query.SingleOrDefault(s => s.SeriesId == seriesId && s.SeasonNumber == season && s.EpisodeNumber == episodeNumber); return Query.SingleOrDefault(s => s.SeriesId == seriesId && s.SeasonNumber == season && s.EpisodeNumber == episodeNumber);
} }
public Episode Get(int seriesId, DateTime date) public Episode Get(int seriesId, String date)
{ {
return Query.Single(s => s.SeriesId == seriesId && s.AirDate == date.ToString(Episode.AIR_DATE_FORMAT)); return Query.Single(s => s.SeriesId == seriesId && s.AirDate == date);
} }
public Episode Find(int seriesId, DateTime date) public Episode Find(int seriesId, String date)
{ {
return Query.SingleOrDefault(s => s.SeriesId == seriesId && s.AirDate == date.ToString(Episode.AIR_DATE_FORMAT)); return Query.SingleOrDefault(s => s.SeriesId == seriesId && s.AirDate == date);
} }
public List<Episode> GetEpisodes(int seriesId) public List<Episode> GetEpisodes(int seriesId)

View File

@ -14,8 +14,8 @@ namespace NzbDrone.Core.Tv
{ {
Episode GetEpisode(int id); Episode GetEpisode(int id);
Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber, bool useScene = false); Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber, bool useScene = false);
Episode GetEpisode(int seriesId, DateTime date); Episode GetEpisode(int seriesId, String date);
Episode FindEpisode(int seriesId, DateTime date); Episode FindEpisode(int seriesId, String date);
List<Episode> GetEpisodeBySeries(int seriesId); List<Episode> GetEpisodeBySeries(int seriesId);
List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber); List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber);
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec); PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec);
@ -62,12 +62,12 @@ namespace NzbDrone.Core.Tv
return _episodeRepository.Find(seriesId, seasonNumber, episodeNumber); return _episodeRepository.Find(seriesId, seasonNumber, episodeNumber);
} }
public Episode GetEpisode(int seriesId, DateTime date) public Episode GetEpisode(int seriesId, String date)
{ {
return _episodeRepository.Get(seriesId, date); return _episodeRepository.Get(seriesId, date);
} }
public Episode FindEpisode(int seriesId, DateTime date) public Episode FindEpisode(int seriesId, String date)
{ {
return _episodeRepository.Find(seriesId, date); return _episodeRepository.Find(seriesId, date);
} }