mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-12-14 11:23:42 +02:00
parent
84b9488cfb
commit
00821b7ad6
@ -44,6 +44,23 @@ public void should_parse_daily_episode(string postTitle, string title, int year,
|
||||
result.FullSeason.Should().BeFalse();
|
||||
}
|
||||
|
||||
[TestCase("Series.Title.2015.09.07.Part1.720p.HULU.WEBRip.AAC2.0.H.264-Sonarr", "Series Title", 2015, 9, 7, 1)]
|
||||
[TestCase("Series.Title.2015.09.07.Part2.720p.HULU.WEBRip.AAC2.0.H.264-Sonarr", "Series Title", 2015, 9, 7, 2)]
|
||||
[TestCase("Series.Title.2015.09.07.Part.1.720p.HULU.WEBRip.AAC2.0.H.264-Sonarr", "Series Title", 2015, 9, 7, 1)]
|
||||
[TestCase("Series.Title.2015.09.07.Part.2.720p.HULU.WEBRip.AAC2.0.H.264-Sonarr", "Series Title", 2015, 9, 7, 2)]
|
||||
public void should_parse_daily_episode_with_multiple_parts(string postTitle, string title, int year, int month, int day, int part)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var airDate = new DateTime(year, month, day);
|
||||
result.Should().NotBeNull();
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.AirDate.Should().Be(airDate.ToString(Episode.AIR_DATE_FORMAT));
|
||||
result.EpisodeNumbers.Should().BeEmpty();
|
||||
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
result.FullSeason.Should().BeFalse();
|
||||
result.DailyPart.Should().Be(part);
|
||||
}
|
||||
|
||||
[TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")]
|
||||
[TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")]
|
||||
[TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")]
|
||||
|
@ -86,7 +86,7 @@ public void should_get_daily_episode_episode_when_search_criteria_is_null()
|
||||
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>()), Times.Once());
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), null), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -98,7 +98,7 @@ public void should_use_search_criteria_episode_when_it_matches_daily()
|
||||
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>()), Times.Never());
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), null), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -110,7 +110,20 @@ public void should_fallback_to_daily_episode_lookup_when_search_criteria_episode
|
||||
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>()), Times.Once());
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), null), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_daily_episode_episode_should_lookup_including_daily_part()
|
||||
{
|
||||
GivenDailySeries();
|
||||
GivenDailyParseResult();
|
||||
_parsedEpisodeInfo.DailyPart = 1;
|
||||
|
||||
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), 1), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -125,7 +138,7 @@ public void should_use_search_criteria_episode_when_it_matches_absolute()
|
||||
Subject.Map(_parsedEpisodeInfo, _series.TvdbId, _series.TvRageId, _singleEpisodeSearchCriteria);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>()), Times.Never());
|
||||
.Verify(v => v.FindEpisode(It.IsAny<int>(), It.IsAny<string>(), null), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -1,71 +0,0 @@
|
||||
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<EpisodeRepository, Episode>
|
||||
{
|
||||
private const int SERIES_ID = 1;
|
||||
private const string AIR_DATE = "2014-04-02";
|
||||
|
||||
private void GivenEpisode(int seasonNumber)
|
||||
{
|
||||
var episode = Builder<Episode>.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<InvalidOperationException>(() => Subject.Get(SERIES_ID, AIR_DATE));
|
||||
Assert.Throws<InvalidOperationException>(() => Subject.Find(SERIES_ID, AIR_DATE));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_get_finds_no_episode()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ByAirDateFixture : CoreTest<EpisodeService>
|
||||
{
|
||||
private const int SERIES_ID = 1;
|
||||
private const string AIR_DATE = "2014-04-02";
|
||||
|
||||
private Episode CreateEpisode(int seasonNumber, int episodeNumber)
|
||||
{
|
||||
var episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.SeriesId = 1)
|
||||
.With(e => e.SeasonNumber = seasonNumber)
|
||||
.With(e => e.EpisodeNumber = episodeNumber)
|
||||
.With(e => e.AirDate = AIR_DATE)
|
||||
.BuildNew();
|
||||
|
||||
return episode;
|
||||
}
|
||||
|
||||
private void GivenEpisodes(params Episode[] episodes)
|
||||
{
|
||||
Mocker.GetMock<IEpisodeRepository>()
|
||||
.Setup(s => s.Find(It.IsAny<int>(), It.IsAny<string>()))
|
||||
.Returns(episodes.ToList());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_multiple_regular_episodes_are_found_and_not_part_provided()
|
||||
{
|
||||
GivenEpisodes(CreateEpisode(1, 1), CreateEpisode(2, 1));
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => Subject.FindEpisode(SERIES_ID, AIR_DATE, null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_when_finds_no_episode()
|
||||
{
|
||||
GivenEpisodes();
|
||||
|
||||
Subject.FindEpisode(SERIES_ID, AIR_DATE, null).Should().BeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_episode_when_single_episode_exists_for_air_date()
|
||||
{
|
||||
GivenEpisodes(CreateEpisode(1, 1));
|
||||
|
||||
Subject.FindEpisode(SERIES_ID, AIR_DATE, null).Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_episode_when_regular_episode_and_special_share_the_same_air_date()
|
||||
{
|
||||
GivenEpisodes(CreateEpisode(1, 1), CreateEpisode(0, 1));
|
||||
|
||||
Subject.FindEpisode(SERIES_ID, AIR_DATE, null).Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_special_when_its_the_only_episode_for_the_date_provided()
|
||||
{
|
||||
GivenEpisodes(CreateEpisode(0, 1));
|
||||
|
||||
Subject.FindEpisode(SERIES_ID, AIR_DATE, null).Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_episode_when_two_regular_episodes_share_the_same_air_date_and_part_is_provided()
|
||||
{
|
||||
var episode1 = CreateEpisode(1, 1);
|
||||
var episode2 = CreateEpisode(1, 2);
|
||||
|
||||
GivenEpisodes(episode1, episode2);
|
||||
|
||||
Subject.FindEpisode(SERIES_ID, AIR_DATE, 1).Should().Be(episode1);
|
||||
Subject.FindEpisode(SERIES_ID, AIR_DATE, 2).Should().Be(episode2);
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ public class ParsedEpisodeInfo
|
||||
public string ReleaseHash { get; set; }
|
||||
public int SeasonPart { get; set; }
|
||||
public string ReleaseTokens { get; set; }
|
||||
public int? DailyPart { get; set; }
|
||||
|
||||
public ParsedEpisodeInfo()
|
||||
{
|
||||
|
@ -148,6 +148,10 @@ public static class Parser
|
||||
new Regex(@"^(?<title>.+?)(?:[-._ ][e])(?<episode>\d{2,3}(?!\d+))(?:(?:\-?[e])(?<episode>\d{2,3}(?!\d+)))+",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
|
||||
//Episodes with airdate and part (2018.04.28.Part.2)
|
||||
new Regex(@"^(?<title>.+?)?\W*(?<airyear>\d{4})[-_. ]+(?<airmonth>[0-1][0-9])[-_. ]+(?<airday>[0-3][0-9])(?![-_. ]+[0-3][0-9])[-_. ]+Part[-_. ]?(?<part>[1-9])",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
|
||||
//Mini-Series, treated as season 1, episodes are labelled as Part01, Part 01, Part.1
|
||||
new Regex(@"^(?<title>.+?)(?:\W+(?:(?:Part\W?|(?<!\d+\W+)e)(?<episode>\d{1,2}(?!\d+)))+)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||
@ -808,7 +812,7 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle
|
||||
//Try to Parse as a daily show
|
||||
var airmonth = Convert.ToInt32(matchCollection[0].Groups["airmonth"].Value);
|
||||
var airday = Convert.ToInt32(matchCollection[0].Groups["airday"].Value);
|
||||
|
||||
|
||||
//Swap day and month if month is bigger than 12 (scene fail)
|
||||
if (airmonth > 12)
|
||||
{
|
||||
@ -843,12 +847,23 @@ private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchColle
|
||||
ReleaseTitle = releaseTitle,
|
||||
AirDate = airDate.ToString(Episode.AIR_DATE_FORMAT),
|
||||
};
|
||||
|
||||
var partMatch = matchCollection[0].Groups["part"];
|
||||
|
||||
if (partMatch.Success)
|
||||
{
|
||||
result.DailyPart = Convert.ToInt32(partMatch.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastSeasonEpisodeStringIndex != releaseTitle.Length)
|
||||
{
|
||||
result.ReleaseTokens = releaseTitle.Substring(lastSeasonEpisodeStringIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.ReleaseTokens = releaseTitle;
|
||||
}
|
||||
|
||||
result.SeriesTitle = seriesName;
|
||||
result.SeriesTitleInfo = GetSeriesTitleInfo(result.SeriesTitle);
|
||||
|
@ -113,7 +113,7 @@ public List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series ser
|
||||
|
||||
if (parsedEpisodeInfo.IsDaily)
|
||||
{
|
||||
var episodeInfo = GetDailyEpisode(series, parsedEpisodeInfo.AirDate, searchCriteria);
|
||||
var episodeInfo = GetDailyEpisode(series, parsedEpisodeInfo.AirDate, parsedEpisodeInfo.DailyPart, searchCriteria);
|
||||
|
||||
if (episodeInfo != null)
|
||||
{
|
||||
@ -314,7 +314,7 @@ private Series GetSeries(ParsedEpisodeInfo parsedEpisodeInfo, int tvdbId, int tv
|
||||
return series;
|
||||
}
|
||||
|
||||
private Episode GetDailyEpisode(Series series, string airDate, SearchCriteriaBase searchCriteria)
|
||||
private Episode GetDailyEpisode(Series series, string airDate, int? part, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
Episode episodeInfo = null;
|
||||
|
||||
@ -326,7 +326,7 @@ private Episode GetDailyEpisode(Series series, string airDate, SearchCriteriaBas
|
||||
|
||||
if (episodeInfo == null)
|
||||
{
|
||||
episodeInfo = _episodeService.FindEpisode(series.Id, airDate);
|
||||
episodeInfo = _episodeService.FindEpisode(series.Id, airDate, part);
|
||||
}
|
||||
|
||||
return episodeInfo;
|
||||
|
@ -3,7 +3,6 @@
|
||||
using System.Linq;
|
||||
using Marr.Data.QGen;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Datastore.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
@ -17,8 +16,7 @@ public interface IEpisodeRepository : IBasicRepository<Episode>
|
||||
{
|
||||
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);
|
||||
List<Episode> Find(int seriesId, string date);
|
||||
List<Episode> GetEpisodes(int seriesId);
|
||||
List<Episode> GetEpisodes(int seriesId, int seasonNumber);
|
||||
List<Episode> GetEpisodeByFileId(int fileId);
|
||||
@ -61,21 +59,11 @@ public Episode Find(int seriesId, int absoluteEpisodeNumber)
|
||||
.SingleOrDefault();
|
||||
}
|
||||
|
||||
public Episode Get(int seriesId, string date)
|
||||
public List<Episode> Find(int seriesId, string date)
|
||||
{
|
||||
var episode = FindOneByAirDate(seriesId, date);
|
||||
|
||||
if (episode == null)
|
||||
{
|
||||
throw new InvalidOperationException("Expected at one episode");
|
||||
}
|
||||
|
||||
return episode;
|
||||
}
|
||||
|
||||
public Episode Find(int seriesId, string date)
|
||||
{
|
||||
return FindOneByAirDate(seriesId, date);
|
||||
return Query.Where(s => s.SeriesId == seriesId)
|
||||
.AndWhere(s => s.AirDate == date)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodes(int seriesId)
|
||||
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
@ -21,8 +20,7 @@ public interface IEpisodeService
|
||||
Episode FindEpisodeByTitle(int seriesId, int seasonNumber, string releaseTitle);
|
||||
List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber);
|
||||
List<Episode> FindEpisodesBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber);
|
||||
Episode GetEpisode(int seriesId, string date);
|
||||
Episode FindEpisode(int seriesId, string date);
|
||||
Episode FindEpisode(int seriesId, string date, int? part);
|
||||
List<Episode> GetEpisodeBySeries(int seriesId);
|
||||
List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber);
|
||||
List<Episode> EpisodesWithFiles(int seriesId);
|
||||
@ -85,14 +83,9 @@ public List<Episode> FindEpisodesBySceneNumbering(int seriesId, int sceneAbsolut
|
||||
return _episodeRepository.FindEpisodesBySceneNumbering(seriesId, sceneAbsoluteEpisodeNumber);
|
||||
}
|
||||
|
||||
public Episode GetEpisode(int seriesId, string date)
|
||||
public Episode FindEpisode(int seriesId, string date, int? part)
|
||||
{
|
||||
return _episodeRepository.Get(seriesId, date);
|
||||
}
|
||||
|
||||
public Episode FindEpisode(int seriesId, string date)
|
||||
{
|
||||
return _episodeRepository.Find(seriesId, date);
|
||||
return FindOneByAirDate(seriesId, date, part);
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodeBySeries(int seriesId)
|
||||
@ -240,5 +233,34 @@ public void Handle(EpisodeFileAddedEvent message)
|
||||
_logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.RelativePath, episode);
|
||||
}
|
||||
}
|
||||
|
||||
private Episode FindOneByAirDate(int seriesId, string date, int? part)
|
||||
{
|
||||
var episodes = _episodeRepository.Find(seriesId, date);
|
||||
|
||||
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 && !part.HasValue)
|
||||
{
|
||||
_logger.Debug("Left with one episode after excluding specials");
|
||||
return regularEpisodes.First();
|
||||
}
|
||||
else if (part.HasValue && part.Value <= regularEpisodes.Count)
|
||||
{
|
||||
var sortedEpisodes = regularEpisodes.OrderBy(e => e.SeasonNumber)
|
||||
.ThenBy(e => e.EpisodeNumber)
|
||||
.ToList();
|
||||
|
||||
return sortedEpisodes[part.Value - 1];
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Multiple episodes with the same air date found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user